diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2003-09-27 10:01:11 +0000 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2003-09-27 10:01:11 +0000 |
commit | 109101faebaa56cc93916803898608328016bf46 (patch) | |
tree | 476e7ab1951995c0a980954d7a271cf272e4a835 | |
download | weechat-109101faebaa56cc93916803898608328016bf46.zip |
First CVS upload.
108 files changed, 22604 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..dcb0ba274 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,29 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +Developers: +---------- + +All developers are connected to IRC: +server: irc.freenode.net, channel: #weechat + +FlashCode <flashcode@flashtux.org> + Web : http://www.flashtux.org + IRC : nick is "FlashCode" + Jabber: flashcode@jabber.org + ICQ : 160677660 + AIM : FlashCode AIM + Yahoo : FlashCode_Y + +Bounga <bounga@altern.org> + Web : http://bounga.ath.cx + IRC : nick is "Bounga" + Jabber: Bounga@jabber.org + ICQ : 178297842 + +Xahlexx <xahlexx@tuxisland.org> + Web : http://www.tuxisland.org + IRC : nick is "xahlexx" + + +See README file for licence detail. @@ -0,0 +1,17 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +WeeChat known bugs, 2003-09-27 + +- too much nicks in the channel (> height of window) => display bug +- some IRC commands are marked as 'unknown' when received + (irc protocol is under dev!) +- bug in nicklist resize (sometimes resize doesn't work and there is display + problem) +- alias/unalias commands doesn't work +- config is not saved (to ~/.weechat/weechatrc) +- intercept Ctrl-C (do not quit immediately if Ctrl-C pressed!) +- program is stopped when bad option in config file (it should not, only display + warning) +- too much opened channel => display bug +- when kicked, channel is not prefixed by '(' and sufixed by ')' diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..5b6e7c66c --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..2bc1255bd --- /dev/null +++ b/ChangeLog @@ -0,0 +1,88 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +ChangeLog - 2003-09-27 + +* 2003-09-27: + - WeeChat 0.0.1 released! + +* 2003-09-26: + - added completor prefix (in config: look_nick_completor) + - fixef log_printf command (bug with year & month) + - added "/kill" command + - fixed /version and /ctcp commands (missing ":" before message) + +* 2003-09-25: + - added "/kick" command + - added IRC errors 402 to 407 + - added "/invite" command + +* 2003-09-24: + - "ctcp version" received is now correctly displayed + - "/version" command is ok + +* 2003-09-23: + - log file (~/.weechat/weechat.log) + - renamed config file (~/.weechat/weechatrc to ~/.weechat/weechat.rc) + +* 2003-09-21: + - "demi-highlight": 2 types of windows highlight: lightred for windows with + unread messages (from other users), lightmagenta for windows with other + unread data (join, part, quit, away, ...) + - "320" IRC message management + - "/clear" command + +* 2003-09-19: + - préparation des sources pour l'internationalisation avec gettext + - "301" IRC command (away message) + - functions renamed in rc-commands.c, irc-server.c, + command.c and config.c (all functions are beginning with a prefix: + irc_cmd_recv_xxx, irc_cmd_send_xxx, server_xxx, weechat_cmd_xxx and + config_xxx). Moreover, all commands (sent and received) return a value + (success or not) + - "/quote" command + - "/whois" command (and colored display of /whois result in server window) + +* 2003-09-18: + - use of alternate nickname (and 2nd alternate) if nick is already used + on server (changed/added in config file: options "nick1", "nick2", "nick3" + for a server, all are mandatory) + - "433" IRC error management (nickname already in use) + - "mode" command received correctly for "channel flags" and + op/deop/voice/devoice actions for a nick + - "401" IRC error management (no such nick/channel) + - private windows management (when received and opened, with /privmsg), + "/privmsg" completed consequently + +* 2003-09-17: + - nickmode display ((half)op/voice) before nicks (as option, look at config + options beginning with "look_nickmode") + - windows history is now ok (pgup/pgdn on any window type) + - "/me" command (and OK when received) + - display nicks count when joining channel or with "/names" command + (total, ops, halfops, voices et normaux) + +* 2003-09-16: + - added and normalized chat window colors + (new colors in config file) + - "/topic" command + - nicklist can be moved on top, bottom, left or right of window + +* 2003-09-15: + - auto-resize of nicklist, according to nick max length + - IRC multi-servers is OK + +* 2003-09-14: + - no hangup if "/part" command is executed on server window + - continue if no server is declared in config file + (empty window will be opened for executing WeeChat commands) + - string array for strings in config file + example: cfg_look_nicklist_position can take values "left", "right", + "top", "bottom", which are converted to int (from 0 for "left" to 3 for + "bottom") + - messages are aligned under time (server window) or under time + nick + (channel window) + +* 2003-09-13: + - sources exploded in many directories: ./irc, ./gui/curses, ./gui/gtk, + ./gui/qt and ./gui/text @@ -0,0 +1,6 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +WeeChat FAQ, 2003-09-19 + +<<< TO DO ! >>> diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..8ef31434c --- /dev/null +++ b/INSTALL @@ -0,0 +1,10 @@ +WeeChat - Installation instructions +=================================== + +1) Run 'make' + +2) As root, run 'make install' + +3) Enjoy ! :-) + +See AUTHORS for any support, feel free to contact us for any problem ;) diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..22b2a4ec1 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +OUTPUT=weechat + +all: + cd src && make + +install: + @mkdir -v -p $(DESTDIR)/usr/$(LOCALRPM)/bin + @cp -v src/$(OUTPUT) $(DESTDIR)/usr/$(LOCALRPM)/bin/ + @mkdir -v -p $(DESTDIR)/usr/share/man/man1 + @cp -v weechat.1 $(DESTDIR)/usr/share/man/man1/ + @echo -e "\n=== WeeChat installed!\n" + +clean: + cd src && make clean @@ -0,0 +1,6 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +FlashCode, 2003-09-27 + +WeeChat 0.0.1 released. @@ -0,0 +1,50 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + + +WeeChat (Wee Enhanced Environment for Chat) is a fast and light chat +environment for many operating systems. Everything can be done with a keyboard. +It is customizable and extensible with scripts. + + +Features +-------- + * IRC chat client with multi-server connection + * many GUI (curses, text, Gtk, QT) (1) + * small, fast and very light + * customizable and extensible with scripts (Perl, Python, Ruby) (2) + * compliant with RFC 1459,2810,2811,2812,2813 + * multi-platform (GNU/Linux, *BSD, Windows & other) (3) + * 100% GPL & free + + +Copyright +--------- + +WeeChat (c) Copyright 2003 + by: FlashCode <flashcode@flashtux.org> + Xahlexx <xahlex@tuxisland.org> + Bounga <bounga@altern.org> +(see AUTHORS file if you want to contact authors) + +WeeChat is distributed under GPL licence (see COPYING file for complete license): + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +--- +(1) only curses & text interfaces are available today +(2) plugin interfaces are not yet developed +(3) only GNU/Linux version is available today @@ -0,0 +1,130 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +TODO - 2003-09-27 + +Legend: + # done + + currently in development + - pending + ? is this really necessary? + + +v0.0.1: + + * IRC protocol: + # "/quote" command: send a raw string to the server without parsing it + # "/me" command (for user actions description) + # "/away" command (to toggle the away status) + # "/op", "/deop", "/voice", "/devoice" commands + # "/invite" command + # "/kick", "/ban", "/unban" commands + # "/kill" command + # "/list" command: list of channels + # "/names" command: view who is on a given channel without being + on it (for example /names #weechat gives all the nicks present on + #weechat, except those who have the +i flag (server side)) + # "/oper" command: become operator on the irc network + # "/topic" command: change the topic of a channel + # "/version" command: give the irc client version (CTCP VERSION) + of a given nick/channel (without parameter: gives WeeChat version) + # "/whois" command + + * WeeChat commands: + # "/clear": to clear window content + + * Interface: + # "demi-highlight" when joins/quits etc + # log messages/warning/errors to ~/.weechat/log file + # improve editing zone (left arrow <> backspace) + # sort nick list + # choose nick list position (top, left, right (default), bottom) + # auto-resize nicklist (when nick too long) + # do pretty cutting of long lines (align on the nick or after hour for server) + # keep history of commands and call them again with up/down arrow + # text GUI + # ncurses GUI: + # one window for each channel + # color display + # private windows + # redraw window when term size is modified + # chat history (pgup/pgdn for displaying history) + # switch to other channel window + + * TCP/IP communication: + # IPv4 protocol implementation + + * Configuration: + # write default config file + + +Future versions: + + * IRC protocol: + - implement RFC 2812 + + "/mode" command: change the user/channels modes + - "/dcc" command (for chat and sending/receiving files) + - manage "halfop" status + - complete "/list" command: add regexp search, display only channels that + match regexp + - "/connect" and "/disconnect" commands (for multiservers use) + - "/ignore" and "/unignore" commands: hide all that is write by a given + nick/host + - when we're away, WeeChat should log all the lines begenning by our nick. + When we come back from our away it should print it to the current window + - "/rehash" command: tell the server to reload its config file + - "/restart" command: tell the server to restart itself + - "/notify" and "/unnotify" command to be warn by WeeChat when a given + nick/host connect to the given irc network + - "/wallops" command: write the same string to all the + persons with the flag +w enable + + * WeeChat commands: + - "/completion" command: do shortcuts (for example when we type "u" + in the text bar it send it to the server as "you") + - "/exec" command: execute a command as if we was in shell + and show us the output on the current window. An option to exec + like -o could send the output to the server, on the current + channel/private + - "/reload" command: reload the WeeChat's config file + - "/set" command: allow the user to set the WeeChat variables + under WeeChat without editing the config file (colours, time + format, etc) + - "/highlight" command: highlight a given word when it appears on + channels/privates + + * Interface: + - display current channel modes (example : #weechat(+nt)) + - interpret ^B in messages (this means bold text) + - internationalization (traduce WeeChat in many languages) + - many channel windows in one window/term (window split) + - add lag indicator + - log chats to file + - forget some old lines that were displayed long time ago (now all is saved, + if WeeChat is running for long time, a lot of memory is used!) + - improve completion (for example complete command parameters when possible) + - understand incomplete commands if unambigous (for example: /he for /help is ok) + - add clock (in status bar?) + - Gtk GUI + ? Qt GUI + + * TCP/IP communication: + - IPv6 protocol implementation + + * Configuration: + - add key bindings to config file + - add missing options for config file + - write config file + - add an option for each server in order to run commands on join + (example: /msg nickserv identify password) + - channel list for auto-join (for each server) + - do not stop program if problem with options in config file + - load config file after GUI (so init values by default (colors, ...) before + loading config) + + * Plugins: + - add Perl plugin + - add Python plugin + - add Ruby plugin + - "/load" and "/unload" commands to (un)load extension scripts + (perl, python, ruby, ...) diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 000000000..7ab78b78a --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +weechat (0.0.1-1) unstable; urgency=low + + * First version. + + -- FlashCode <flashcode@flashtux.org> Sat, 27 Jun 2003 12:00:00 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 000000000..b8626c4cf --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/control b/debian/control new file mode 100644 index 000000000..0a4844738 --- /dev/null +++ b/debian/control @@ -0,0 +1,14 @@ +Source: weechat +Section: net +Priority: optional +Maintainer: FlashCode <flashcode@flashtux.org> +Build-Depends: debhelper (>> 4.0.0) +Standards-Version: 3.5.8 + +Package: weechat +Architecture: any +Depends: ${shlibs:Depends} +Description: Fast, light and extensible IRC client + WeeChat (Wee Enhanced Environment for Chat) is a fast and light IRC client + for many operating systems. Everything can be done with a keyboard. + It is customizable and extensible with scripts. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 000000000..1a1dbdde6 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,17 @@ +This package was debianized by FlashCode <flashcode@flashtux.org> on +Sat, 27 Sep 2003 10:00:00 +0200. + +It was downloaded from http://weechat.flashtux.org/download + +Upstream Author(s): FlashCode <flashcode@flashtux.org> + +Copyright: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +On Debian systems, the complete text of the GNU General Public +License, Version 2 can be found in the file +/usr/share/common-licenses/GPL diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 000000000..e77248175 --- /dev/null +++ b/debian/dirs @@ -0,0 +1 @@ +usr/bin diff --git a/debian/docs b/debian/docs new file mode 100644 index 000000000..a204c4610 --- /dev/null +++ b/debian/docs @@ -0,0 +1,9 @@ +AUTHORS +BUGS +ChangeLog +COPYING +FAQ +INSTALL +NEWS +README +TODO diff --git a/debian/files b/debian/files new file mode 100644 index 000000000..48f4dc400 --- /dev/null +++ b/debian/files @@ -0,0 +1 @@ +weechat_0.0.1-1_i386.deb net optional diff --git a/debian/rules b/debian/rules new file mode 100755 index 000000000..db43ab7e6 --- /dev/null +++ b/debian/rules @@ -0,0 +1,97 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + + + + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + #/usr/bin/docbook-to-man debian/weechat.sgml > weechat.1 + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) clean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/weechat. + $(MAKE) install DESTDIR=$(CURDIR)/debian/weechat + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples +# dh_install +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman weechat.1 + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_perl +# dh_python +# dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/debian/weechat.substvars b/debian/weechat.substvars new file mode 100644 index 000000000..0e328c3d3 --- /dev/null +++ b/debian/weechat.substvars @@ -0,0 +1 @@ +shlibs:Depends=libc6 (>= 2.3.2-1), libncurses5 (>= 5.3.20030510-1) diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 000000000..575773bb1 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,91 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=weechat + +OBJS=weechat.o config.o command.o completion.o history.o +OBJS_IRC=irc/irc.a +OBJS_GUI=gui/gui.a + + +# WeeChat with Curses interface +ifeq ($(GUI), curses) +LIBS_CURSES=-lcurses +DEFINES=WEE_CURSES + +curses: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_CURSES) +endif + +# WeeChat with Gtk+ interface +ifeq ($(GUI), gtk) +OBJS_GTK=gui-gtk.o +LIBS_GTK= +DEFINES=WEE_GTK +gtk: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_GTK) +endif + +# WeeChat with Qt interface +ifeq ($(GUI), qt) +OBJS_QT=gui-qt.o +LIBS_QT= +DEFINES=WEE_QT +qt: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_QT) +endif + +# WeeChat with Text interface +ifeq ($(GUI), text) +OBJS_TEXT=gui-text.o +LIBS_TEXT= +DEFINES=WEE_TEXT +text: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_TEXT) +endif + + +all: + make curses GUI=curses + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +irc/irc.a: + cd irc && make + +gui/gui.a: + cd gui && make $(GUI) GUI=$(GUI) + +clean: + rm -f *.o *.a *~ core $(OUTPUT) + cd irc && make clean + cd gui && make clean + +command.o: command.c weechat.h command.h irc/irc.h gui/gui.h completion.h \ + history.h config.h +completion.o: completion.c weechat.h completion.h irc/irc.h gui/gui.h \ + history.h command.h +config.o: config.c weechat.h config.h irc/irc.h gui/gui.h completion.h \ + history.h +history.o: history.c weechat.h history.h gui/gui.h completion.h +weechat.o: weechat.c weechat.h config.h command.h irc/irc.h gui/gui.h \ + completion.h history.h diff --git a/src/command.c b/src/command.c new file mode 100644 index 000000000..ddd3ce202 --- /dev/null +++ b/src/command.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* command.c: WeeChat internal commands */ + + +#include <stdlib.h> +#include <string.h> + +#include "weechat.h" +#include "command.h" +#include "irc/irc.h" +#include "config.h" +#include "gui/gui.h" + + +/* WeeChat internal commands */ + +t_weechat_command weechat_commands[] = +{ { "alias", N_("create an alias for a command"), + N_("[alias_name [command [arguments]]"), + N_("alias_name: name of alias\ncommand: command name (" WEECHAT_NAME + " or IRC command)\n" "arguments: arguments for command"), + 0, MAX_ARGS, weechat_cmd_alias, NULL }, + { "clear", N_("clear window(s)"), + N_("[-all]"), + N_("-all: clear all windows"), + 0, 1, weechat_cmd_clear, NULL }, + { "help", N_("display help about commands"), + N_("[command]"), N_("command: name of a " WEECHAT_NAME " or IRC command"), + 0, 1, weechat_cmd_help, NULL }, + { "set", N_("set config parameters"), + N_("[option [value]]"), N_("option: name of an option\nvalue: value for option"), + 0, 2, weechat_cmd_set, NULL }, + { "unalias", N_("remove an alias"), + N_("alias_name"), N_("alias_name: name of alias to remove"), + 1, 1, weechat_cmd_unalias, NULL }, + { NULL, NULL, NULL, NULL, 0, 0, NULL, NULL } +}; + +t_index_command *index_commands; +t_index_command *last_index_command; + + +/* + * index_find_pos: find position for a command index (for sorting index) + */ + +t_index_command * +index_command_find_pos (char *command) +{ + t_index_command *ptr_index; + + for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index) + { + if (strcasecmp (command, ptr_index->command_name) < 0) + return ptr_index; + } + return NULL; +} + +/* + * index_command_insert_sorted: insert index into sorted list + */ + +void +index_command_insert_sorted (t_index_command *index) +{ + t_index_command *pos_index; + + pos_index = index_command_find_pos (index->command_name); + + if (index_commands) + { + if (pos_index) + { + /* insert index into the list (before index found) */ + index->prev_index = pos_index->prev_index; + index->next_index = pos_index; + if (pos_index->prev_index) + pos_index->prev_index->next_index = index; + else + index_commands = index; + pos_index->prev_index = index; + } + else + { + /* add index to the end */ + index->prev_index = last_index_command; + index->next_index = NULL; + last_index_command->next_index = index; + last_index_command = index; + } + } + else + { + index->prev_index = NULL; + index->next_index = NULL; + index_commands = index; + last_index_command = index; + } + return; +} + +/* + * index_command_build: build an index of commands (internal, irc and alias) + * This list will be sorted, and used for completion + */ + +void +index_command_build () +{ + int i; + t_index_command *new_index; + + index_commands = NULL; + last_index_command = NULL; + i = 0; + while (weechat_commands[i].command_name) + { + if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command))))) + { + new_index->command_name = strdup (weechat_commands[i].command_name); + index_command_insert_sorted (new_index); + } + i++; + } + i = 0; + while (irc_commands[i].command_name) + { + if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg) + { + if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command))))) + { + new_index->command_name = strdup (irc_commands[i].command_name); + index_command_insert_sorted (new_index); + } + } + i++; + } +} + +/* + * explode_string: explode a string according to separators + */ + +char ** +explode_string (char *string, char *separators, int num_items_max, + int *num_items) +{ + int i, n_items; + char **array; + char *ptr, *ptr1, *ptr2; + + if (num_items != NULL) + *num_items = 0; + + n_items = num_items_max; + + if (string == NULL) + return NULL; + + if (num_items_max == 0) + { + /* calculate number of items */ + ptr = string; + i = 1; + while ((ptr = strpbrk (ptr, separators))) + { + while (strchr (separators, ptr[0]) != NULL) + ptr++; + i++; + } + n_items = i; + } + + array = + (char **) malloc ((num_items_max ? n_items : n_items + 1) * + sizeof (char *)); + + ptr1 = string; + ptr2 = string; + + for (i = 0; i < n_items; i++) + { + while (strchr (separators, ptr1[0]) != NULL) + ptr1++; + if (i == (n_items - 1) || (ptr2 = strpbrk (ptr1, separators)) == NULL) + if ((ptr2 = strchr (ptr1, '\r')) == NULL) + if ((ptr2 = strchr (ptr1, '\n')) == NULL) + ptr2 = strchr (ptr1, '\0'); + + if ((ptr1 == NULL) || (ptr2 == NULL)) + { + array[i] = NULL; + } + else + { + if (ptr2 - ptr1 > 0) + { + array[i] = + (char *) malloc ((ptr2 - ptr1 + 1) * sizeof (char)); + array[i] = strncpy (array[i], ptr1, ptr2 - ptr1); + array[i][ptr2 - ptr1] = '\0'; + ptr1 = ++ptr2; + } + else + { + array[i] = NULL; + } + } + } + if (num_items_max == 0) + { + array[i] = NULL; + if (num_items != NULL) + *num_items = i; + } + else + { + if (num_items != NULL) + *num_items = num_items_max; + } + + return array; +} + +/* + * exec_weechat_command: executes a command (WeeChat internal or IRC) + * returns: 1 if command was executed succesfully + * 0 if error (command not executed) + */ + +int +exec_weechat_command (t_irc_server *server, char *string) +{ + int i, j, argc, return_code; + char *pos, *ptr_args, **argv; + + if ((!string[0]) || (string[0] != '/')) + return 0; + + /* look for end of command */ + ptr_args = NULL; + pos = strchr (string, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + ptr_args = pos; + if (!ptr_args[0]) + ptr_args = NULL; + } + + argv = explode_string (ptr_args, " ", 0, &argc); + + for (i = 0; weechat_commands[i].command_name; i++) + { + if (strcasecmp (weechat_commands[i].command_name, string + 1) == 0) + { + if ((argc < weechat_commands[i].min_arg) + || (argc > weechat_commands[i].max_arg)) + { + if (weechat_commands[i].min_arg == + weechat_commands[i].max_arg) + gui_printf (NULL, + _("%s wrong argument count for " + WEECHAT_NAME " command '%s' " + "(expected: %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + weechat_commands[i].max_arg, + (weechat_commands[i].max_arg > + 1) ? "s" : ""); + else + gui_printf (NULL, + _("%s wrong argument count for " + WEECHAT_NAME " command '%s' " + "(expected: between %d and %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + weechat_commands[i].min_arg, + weechat_commands[i].max_arg, + (weechat_commands[i].max_arg > + 1) ? "s" : ""); + } + else + { + if (weechat_commands[i].cmd_function_args != NULL) + return_code = (int) (weechat_commands[i].cmd_function_args) + (argc, argv); + else + return_code = (int) (weechat_commands[i].cmd_function_1arg) + (ptr_args); + if (return_code < 0) + gui_printf (NULL, + _("%s " WEECHAT_NAME " command \"%s\" failed\n"), + WEECHAT_ERROR, string + 1); + } + if (argv) + { + for (j = 0; argv[j]; j++) + free (argv[j]); + free (argv); + } + return 1; + } + } + for (i = 0; irc_commands[i].command_name; i++) + { + if (strcasecmp (irc_commands[i].command_name, string + 1) == 0) + { + if ((argc < irc_commands[i].min_arg) + || (argc > irc_commands[i].max_arg)) + { + if (irc_commands[i].min_arg == irc_commands[i].max_arg) + gui_printf + (NULL, + _("%s wrong argument count for IRC command '%s' " + "(expected: %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + irc_commands[i].max_arg, + (irc_commands[i].max_arg > 1) ? "s" : ""); + else + gui_printf + (NULL, + _("%s wrong argument count for IRC command '%s' " + "(expected: between %d and %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + irc_commands[i].min_arg, irc_commands[i].max_arg, + (irc_commands[i].max_arg > 1) ? "s" : ""); + } + else + { + if ((irc_commands[i].need_connection) && + ((!server) || (!server->is_connected))) + { + gui_printf (NULL, + _("%s command '%s' needs a server connection!\n"), + WEECHAT_ERROR, irc_commands[i].command_name); + return 0; + } + if (irc_commands[i].cmd_function_args != NULL) + return_code = (int) (irc_commands[i].cmd_function_args) + (server, argc, argv); + else + return_code = (int) (irc_commands[i].cmd_function_1arg) + (server, ptr_args); + if (return_code < 0) + gui_printf (NULL, + _("%s IRC command \"%s\" failed\n"), + WEECHAT_ERROR, string + 1); + } + if (argv) + { + for (j = 0; argv[j]; j++) + free (argv[j]); + free (argv); + } + return 1; + } + } + gui_printf (server->window, + _("%s unknown command '%s' (type /help for help)\n"), + WEECHAT_ERROR, + string + 1); + if (argv) + { + for (j = 0; argv[j]; j++) + free (argv[j]); + free (argv); + } + return 0; +} + +/* + * user_command: interprets user command (if beginning with '/') + * any other text is sent to the server, if connected + */ + +void +user_command (t_irc_server *server, char *command) +{ + t_irc_nick *ptr_nick; + + if ((!command) || (command[0] == '\r') || (command[0] == '\n')) + return; + if ((command[0] == '/') && (command[1] != '/')) + { + /* WeeChat internal command (or IRC command) */ + exec_weechat_command (server, command); + } + else + { + if ((command[0] == '/') && (command[1] == '/')) + command++; + if (!WIN_IS_SERVER(gui_current_window)) + { + server_sendf (server, "PRIVMSG %s :%s\r\n", + CHANNEL(gui_current_window)->name, + command); + + if (WIN_IS_PRIVATE(gui_current_window)) + { + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "<"); + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_NICK, + COLOR_WIN_NICK_SELF, + "%s", server->nick); + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "> "); + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", command); + } + else + { + ptr_nick = nick_search (CHANNEL(gui_current_window), server->nick); + if (ptr_nick) + { + irc_display_nick (CHANNEL(gui_current_window)->window, ptr_nick, + MSG_TYPE_NICK, 1, 1, 0); + gui_printf_color (CHANNEL(gui_current_window)->window, + COLOR_WIN_CHAT, "%s\n", command); + } + else + gui_printf (server->window, + _("%s cannot find nick for sending message\n"), + WEECHAT_ERROR); + } + } + else + gui_printf (server->window, _("This window is not a channel!\n")); + } +} + +/* + * weechat_cmd_alias: display or create alias + */ + +int +weechat_cmd_alias (int argc, char **argv) +{ + if (argc == 0) + { + /* List all aliases */ + } + argv = NULL; + gui_printf (NULL, _("(TODO) \"/alias\" command not developed!\n")); + return 0; +} + +/* + * weechat_cmd_clear: display or create alias + */ + +int +weechat_cmd_clear (int argc, char **argv) +{ + if (argc == 1) + { + if (strcmp (argv[0], "-all") == 0) + gui_window_clear_all (); + else + { + gui_printf (NULL, + _("unknown parameter \"%s\" for /clear command\n"), + argv[0]); + return -1; + } + } + else + gui_window_clear (gui_current_window); + return 0; +} + +/* + * weechat_cmd_help: display help + */ + +int +weechat_cmd_help (int argc, char **argv) +{ + int i; + + if (argc == 0) + { + gui_printf (NULL, + _("> List of " WEECHAT_NAME " internal commands:\n")); + for (i = 0; weechat_commands[i].command_name; i++) + gui_printf (NULL, " %s - %s\n", + weechat_commands[i].command_name, + weechat_commands[i].command_description); + gui_printf (NULL, _("> List of IRC commands:\n")); + for (i = 0; irc_commands[i].command_name; i++) + if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg) + gui_printf (NULL, " %s - %s\n", + irc_commands[i].command_name, + irc_commands[i].command_description); + } + if (argc == 1) + { + for (i = 0; weechat_commands[i].command_name; i++) + { + if (strcasecmp (weechat_commands[i].command_name, argv[0]) == 0) + { + gui_printf + (NULL, + _("> Help on " WEECHAT_NAME " internal command '%s':\n"), + weechat_commands[i].command_name); + gui_printf (NULL, + _("Syntax: /%s %s\n"), + weechat_commands[i].command_name, + (weechat_commands[i]. + arguments) ? weechat_commands[i]. + arguments : ""); + if (weechat_commands[i].arguments_description) + { + gui_printf (NULL, "%s\n", + weechat_commands[i]. + arguments_description); + } + return 0; + } + } + for (i = 0; irc_commands[i].command_name; i++) + { + if (strcasecmp (irc_commands[i].command_name, argv[0]) == 0) + { + gui_printf (NULL, + _("> Help on IRC command '%s':\n"), + irc_commands[i].command_name); + gui_printf (NULL, _("Syntax: /%s %s\n"), + irc_commands[i].command_name, + (irc_commands[i].arguments) ? + irc_commands[i].arguments : ""); + if (irc_commands[i].arguments_description) + { + gui_printf (NULL, "%s\n", + irc_commands[i]. + arguments_description); + } + return 0; + } + } + gui_printf (NULL, + _("No help available, \"%s\" is an unknown command\n"), + argv[0]); + } + return 0; +} + +/* + * weechat_cmd_set: set options + */ + +int +weechat_cmd_set (int argc, char **argv) +{ + int i, j, section_displayed; + char *color_name; + + /* TODO: complete /set command */ + for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + section_displayed = 0; + if (i != CONFIG_SECTION_SERVER) + { + for (j = 0; weechat_options[i][j].option_name; j++) + { + if ((argc == 0) || + ((argc > 0) + && (strstr (weechat_options[i][j].option_name, argv[0]) + != NULL))) + { + if (!section_displayed) + { + gui_printf (NULL, "[%s]\n", + config_sections[i].section_name); + section_displayed = 1; + } + switch (weechat_options[i][j].option_type) + { + case OPTION_TYPE_BOOLEAN: + gui_printf (NULL, " %s = %s\n", + weechat_options[i][j].option_name, + (*weechat_options[i][j].ptr_int) ? + "ON" : "OFF"); + break; + case OPTION_TYPE_INT: + gui_printf (NULL, + " %s = %d\n", + weechat_options[i][j].option_name, + *weechat_options[i][j].ptr_int); + break; + case OPTION_TYPE_INT_WITH_STRING: + gui_printf (NULL, + " %s = %s\n", + weechat_options[i][j].option_name, + weechat_options[i][j].array_values[*weechat_options[i][j].ptr_int]); + break; + case OPTION_TYPE_COLOR: + color_name = gui_get_color_by_value (*weechat_options[i][j].ptr_int); + gui_printf (NULL, + " %s = %s\n", + weechat_options[i][j].option_name, + (color_name) ? color_name : _("(unknown)")); + break; + case OPTION_TYPE_STRING: + gui_printf (NULL, " %s = %s\n", + weechat_options[i][j]. + option_name, + (*weechat_options[i][j]. + ptr_string) ? + *weechat_options[i][j]. + ptr_string : ""); + break; + } + } + } + } + } + gui_printf (NULL, _("(TODO) \"/set\" command not developed!\n")); + return 0; +} + +/* + * cmd_unalias: remove an alias + */ + +int +weechat_cmd_unalias (int argc, char **argv) +{ + if (argc != 1) + { + gui_printf + (NULL, + _("Wrong argument count for unalias function (expexted: 1 arg)\n")); + return -1; + } + argv = NULL; + gui_printf (NULL, _("(TODO) \"/unalias\" not developed!\n")); + return 0; +} diff --git a/src/command.h b/src/command.h new file mode 100644 index 000000000..5bec6c92e --- /dev/null +++ b/src/command.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_COMMAND_H +#define __WEECHAT_COMMAND_H 1 + +#include "irc/irc.h" + +#define MAX_ARGS 8192 + +typedef struct t_weechat_command t_weechat_command; + +struct t_weechat_command +{ + char *command_name; + char *command_description; + char *arguments; + char *arguments_description; + int min_arg, max_arg; + int (*cmd_function_args)(int, char **); + int (*cmd_function_1arg)(char *); +}; + +typedef struct t_index_command t_index_command; + +struct t_index_command +{ + char *command_name; + t_index_command *prev_index; + t_index_command *next_index; +}; + +extern t_index_command *index_commands; + +extern void index_command_build (); +extern int exec_weechat_command (t_irc_server *, char *); +extern void user_command (t_irc_server *, char *); +extern int weechat_cmd_alias(int, char **); +extern int weechat_cmd_clear(int, char **); +extern int weechat_cmd_help (int, char **); +extern int weechat_cmd_set (int, char **); +extern int weechat_cmd_unalias (int, char **); + +#endif /* command.h */ diff --git a/src/completion.c b/src/completion.c new file mode 100644 index 000000000..6809d8100 --- /dev/null +++ b/src/completion.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* completion.c: completes words according to context (cmd/nick) */ + + +#include <stdlib.h> +#include <string.h> + +#include "weechat.h" +#include "completion.h" +#include "irc/irc.h" +#include "command.h" + + +/* + * completion_init: init completion + */ + +void +completion_init (t_completion *completion) +{ + completion->position = -1; + completion->base_word = NULL; +} + +/* + * completion_command: complete a command + */ + +void +completion_command (t_completion *completion) +{ + int length, word_found_seen; + t_index_command *ptr_index; + + length = strlen (completion->base_word) - 1; + word_found_seen = 0; + for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index) + { + if (strncasecmp (ptr_index->command_name, completion->base_word + 1, length) == 0) + { + if ((!completion->word_found) || word_found_seen) + { + completion->word_found = ptr_index->command_name; + return; + } + } + if (completion->word_found && + (strcasecmp (ptr_index->command_name, completion->word_found) == 0)) + word_found_seen = 1; + } + if (completion->word_found) + { + completion->word_found = NULL; + completion_command (completion); + } +} + +/* + * completion_nick: complete a nick + */ + +void +completion_nick (t_completion *completion, t_irc_channel *channel) +{ + int length, word_found_seen; + t_irc_nick *ptr_nick; + + length = strlen (completion->base_word); + word_found_seen = 0; + for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + { + if (strncasecmp (ptr_nick->nick, completion->base_word, length) == 0) + { + if ((!completion->word_found) || word_found_seen) + { + completion->word_found = ptr_nick->nick; + return; + } + } + if (completion->word_found && + (strcasecmp (ptr_nick->nick, completion->word_found) == 0)) + word_found_seen = 1; + } + if (completion->word_found) + { + completion->word_found = NULL; + completion_nick (completion, channel); + } +} + +/* + * completion_search: complete word according to context + */ + +void +completion_search (t_completion *completion, void *channel, + char *buffer, int size, int pos) +{ + int i, pos_start, pos_end; + char *old_word_found; + + /* TODO: complete when no word is there with command according to context */ + if (size == 0) + { + completion->word_found = NULL; + return; + } + + /* if new complation => look for base word */ + if (pos != completion->position) + { + completion->word_found = NULL; + + if ((pos == size) || (buffer[pos-1] != ' ')) + pos--; + if ((pos > 0) && (buffer[pos] == ' ')) + return; + + i = pos; + while ((i >= 0) && (buffer[i] != ' ')) + i--; + pos_start = i + 1; + i = pos; + while ((i < size) && (buffer[i] != ' ')) + i++; + pos_end = i - 1; + + if (pos_start > pos_end) + return; + + completion->base_word_pos = pos_start; + + if (completion->base_word) + free (completion->base_word); + completion->base_word = (char *) malloc (pos_end - pos_start + 2); + + for (i = pos_start; i <= pos_end; i++) + completion->base_word[i - pos_start] = buffer[i]; + completion->base_word[pos_end - pos_start + 1] = '\0'; + + if (completion->base_word[0] == '/') + completion->position_replace = pos_start + 1; + else + completion->position_replace = pos_start; + } + + /* completion */ + old_word_found = completion->word_found; + if (completion->base_word[0] == '/') + { + completion_command (completion); + if (completion->word_found) + { + if (old_word_found) + completion->diff_size = strlen (completion->word_found) - + strlen (old_word_found); + else + completion->diff_size = strlen (completion->word_found) - + strlen (completion->base_word) + 1; + } + } + else + { + if (channel) + { + completion_nick (completion, (t_irc_channel *)channel); + if (completion->word_found) + { + if (old_word_found) + completion->diff_size = strlen (completion->word_found) - + strlen (old_word_found); + else + completion->diff_size = strlen (completion->word_found) - + strlen (completion->base_word); + } + } + } +} diff --git a/src/completion.h b/src/completion.h new file mode 100644 index 000000000..f07d4a1f7 --- /dev/null +++ b/src/completion.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_COMPLETION_H +#define __WEECHAT_COMPLETION_H 1 + +typedef struct t_completion t_completion; + +struct t_completion +{ + char *base_word; /* word to complete (when Tab was pressed) */ + int base_word_pos; /* beggining of base word */ + int position; /* position where we shoud complete */ + char *word_found; /* word found (to replace base word) */ + int position_replace; /* position where word should be replaced */ + int diff_size; /* size difference (< 0 = char(s) deleted) */ +}; + +extern void completion_init (t_completion *); +extern void completion_search (t_completion *, void *, char *, int, int); + +#endif /* completion.h */ diff --git a/src/config.c b/src/config.c new file mode 100644 index 000000000..ad93695b9 --- /dev/null +++ b/src/config.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* config.c: WeeChat configuration */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <time.h> + +#include "weechat.h" +#include "config.h" +#include "irc/irc.h" +#include "gui/gui.h" + + +/* config sections */ + +t_config_section config_sections[CONFIG_NUMBER_SECTIONS] = +{ { CONFIG_SECTION_LOOK, "look" }, + { CONFIG_SECTION_COLORS, "colors" }, + { CONFIG_SECTION_HISTORY, "history" }, + { CONFIG_SECTION_LOG, "log" }, + { CONFIG_SECTION_DCC, "dcc" }, + { CONFIG_SECTION_PROXY, "proxy" }, + { CONFIG_SECTION_SERVER, "server" } +}; + +/* config, look & feel section */ + +int cfg_look_startup_logo; +int cfg_look_startup_version; +char *cfg_look_weechat_slogan; +int cfg_look_color_nicks; +int cfg_look_color_actions; +int cfg_look_remove_colors_from_msgs; +int cfg_look_nicklist; +int cfg_look_nicklist_position; +char *cfg_look_nicklist_position_values[] = +{ "left", "right", "top", "bottom", NULL }; +int cfg_look_nicklist_min_size; +int cfg_look_nicklist_max_size; +int cfg_look_nickmode; +int cfg_look_nickmode_empty; +char *cfg_look_no_nickname; +char *cfg_look_completor; + +t_config_option weechat_options_look[] = +{ { "look_startup_logo", N_("display " WEECHAT_NAME " logo at startup"), + N_("display " WEECHAT_NAME " logo at startup"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_startup_logo, NULL, NULL }, + { "look_startup_version", N_("display " WEECHAT_NAME " version at startup"), + N_("display " WEECHAT_NAME " version at startup"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_startup_version, NULL, NULL }, + { "look_weechat_slogan", N_(WEECHAT_NAME "slogan"), + N_(WEECHAT_NAME "slogan (if empty, slogan is not used)"), + OPTION_TYPE_STRING, 0, 0, 0, + "the geekest IRC client!", NULL, NULL, &cfg_look_weechat_slogan, NULL }, + { "look_color_nicks", N_("display nick names with different colors"), + N_("display nick names with different colors"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_color_nicks, NULL, NULL }, + { "look_color_actions", N_("display actions with different colors"), + N_("display actions with different colors"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_color_actions, NULL, NULL }, + { "look_remove_colors_from_msgs", N_("remove colors from incoming messages"), + N_("remove colors from incoming messages"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_remove_colors_from_msgs, NULL, NULL }, + { "look_nicklist", N_("display nicklist window"), + N_("display nicklist window (for channel windows)"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_nicklist, NULL, NULL }, + { "look_nicklist_position", N_("nicklist position"), + N_("nicklist position (top, left, right (default), bottom)"), + OPTION_TYPE_INT_WITH_STRING, 0, 0, 0, + "right", cfg_look_nicklist_position_values, &cfg_look_nicklist_position, NULL, NULL }, + { "look_nicklist_min_size", N_("min size for nicklist"), + N_("min size for nicklist (width or height, depending on look_nicklist_position " + "(0 = no min size))"), + OPTION_TYPE_INT, 0, 100, 0, + NULL, NULL, &cfg_look_nicklist_min_size, NULL, NULL }, + { "look_nicklist_max_size", N_("max size for nicklist"), + N_("max size for nicklist (width or height, depending on look_nicklist_position " + "(0 = no max size; if min == max and > 0, then size is fixed))"), + OPTION_TYPE_INT, 0, 100, 0, + NULL, NULL, &cfg_look_nicklist_max_size, NULL, NULL }, + { "look_no_nickname", N_("text to display instead of nick when not connected"), + N_("text to display instead of nick when not connected"), + OPTION_TYPE_STRING, 0, 0, 0, + "-cmd-", NULL, NULL, &cfg_look_no_nickname, NULL }, + { "look_nickmode", N_("display nick mode ((half)op/voice) before each nick"), + N_("display nick mode ((half)op/voice) before each nick"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_nickmode, NULL, NULL }, + { "look_nickmode_empty", N_("display space if nick mode is not (half)op/voice"), + N_("display space if nick mode is not (half)op/voice"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE, + NULL, NULL, &cfg_look_nickmode_empty, NULL, NULL }, + { "look_nick_completor", N_("the string inserted after nick completion"), + N_("the string inserted after nick completion"), + OPTION_TYPE_STRING, 0, 0, 0, + ":", NULL, NULL, &cfg_look_completor, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, colors section */ + +int cfg_col_title; +int cfg_col_title_bg; +int cfg_col_chat; +int cfg_col_chat_time; +int cfg_col_chat_time_sep; +int cfg_col_chat_prefix1; +int cfg_col_chat_prefix2; +int cfg_col_chat_nick; +int cfg_col_chat_host; +int cfg_col_chat_channel; +int cfg_col_chat_dark; +int cfg_col_chat_bg; +int cfg_col_status; +int cfg_col_status_active; +int cfg_col_status_data_msg; +int cfg_col_status_data_other; +int cfg_col_status_more; +int cfg_col_status_bg; +int cfg_col_input; +int cfg_col_input_channel; +int cfg_col_input_nick; +int cfg_col_input_bg; +int cfg_col_nick; +int cfg_col_nick_op; +int cfg_col_nick_halfop; +int cfg_col_nick_voice; +int cfg_col_nick_sep; +int cfg_col_nick_self; +int cfg_col_nick_private; +int cfg_col_nick_bg; + +t_config_option weechat_options_colors[] = +{ /* title window */ + { "col_title", N_("color for title bar"), + N_("color for title bar"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_title, NULL, NULL }, + { "col_title_bg", N_("background for title bar"), + N_("background for title bar"), + OPTION_TYPE_COLOR, 0, 0, 0, + "blue", NULL, &cfg_col_title_bg, NULL, NULL }, + + /* chat window */ + { "col_chat", N_("color for chat text"), + N_("color for chat text"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_chat, NULL, NULL }, + { "col_chat_time", N_("color for time"), + N_("color for time in chat window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_chat_time, NULL, NULL }, + { "col_chat_time_sep", N_("color for time separator"), + N_("color for time separator (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "brown", NULL, &cfg_col_chat_time_sep, NULL, NULL }, + { "col_chat_prefix1", N_("color for 1st and 3rd char of prefix"), + N_("color for 1st and 3rd char of prefix"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightcyan", NULL, &cfg_col_chat_prefix1, NULL, NULL }, + { "col_chat_prefix2", N_("color for middle char of prefix"), + N_("color for middle char of prefix"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_chat_prefix2, NULL, NULL }, + { "col_chat_nick", N_("color for nicks in actions"), + N_("color for nicks in actions (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightcyan", NULL, &cfg_col_chat_nick, NULL, NULL }, + { "col_chat_host", N_("color for hostnames"), + N_("color for hostnames (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "cyan", NULL, &cfg_col_chat_host, NULL, NULL }, + { "col_chat_channel", N_("color for channel names in actions"), + N_("color for channel names in actions (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_chat_channel, NULL, NULL }, + { "col_chat_dark", N_("color for dark separators"), + N_("color for dark separators (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "green", NULL, &cfg_col_chat_dark, NULL, NULL }, + { "col_chat_bg", N_("background for chat"), + N_("background for chat window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "default", NULL, &cfg_col_chat_bg, NULL, NULL }, + + /* status window */ + { "col_status", N_("color for status bar"), + N_("color for status bar"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_status, NULL, NULL }, + { "col_status_active", N_("color for active window"), + N_("color for active window (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "yellow", NULL, &cfg_col_status_active, NULL, NULL }, + { "col_status_data_msg", N_("color for window with new messages"), + N_("color for window with new messages (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightred", NULL, &cfg_col_status_data_msg, NULL, NULL }, + { "col_status_data_other", N_("color for window with new data (not messages)"), + N_("color for window with new data (not messages) (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightmagenta", NULL, &cfg_col_status_data_other, NULL, NULL }, + { "col_status_more", N_("color for \"*MORE*\" text"), + N_("color for window with new data (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_status_more, NULL, NULL }, + { "col_status_bg", N_("background for status window"), + N_("background for status window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "blue", NULL, &cfg_col_status_bg, NULL, NULL }, + + /* input window */ + { "col_input", N_("color for input text"), + N_("color for input text"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_input, NULL, NULL }, + { "col_input_channel", N_("color for input text (channel name)"), + N_("color for input text (channel name)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_input_channel, NULL, NULL }, + { "col_input_nick", N_("color for input text (nick name)"), + N_("color for input text (nick name)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightgreen", NULL, &cfg_col_input_nick, NULL, NULL }, + { "col_input_bg", N_("background for input window"), + N_("background for input window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "default", NULL, &cfg_col_input_bg, NULL, NULL }, + + /* nick window */ + { "col_nick", N_("color for nicknames"), + N_("color for nicknames"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_nick, NULL, NULL }, + { "col_nick_op", N_("color for operator symbol"), + N_("color for operator symbol"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightgreen", NULL, &cfg_col_nick_op, NULL, NULL }, + { "col_nick_halfop", N_("color for half-operator symbol"), + N_("color for half-operator symbol"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightmagenta", NULL, &cfg_col_nick_halfop, NULL, NULL }, + { "col_nick_voice", N_("color for voice symbol"), + N_("color for voice symbol"), + OPTION_TYPE_COLOR, 0, 0, 0, + "yellow", NULL, &cfg_col_nick_voice, NULL, NULL }, + { "col_nick_sep", N_("color for nick separator"), + N_("color for nick separator"), + OPTION_TYPE_COLOR, 0, 0, 0, + "blue", NULL, &cfg_col_nick_sep, NULL, NULL }, + { "col_nick_self", N_("color for local nick"), + N_("color for local nick"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_nick_self, NULL, NULL }, + { "col_nick_private", N_("color for other nick in private window"), + N_("color for other nick in private window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "brown", NULL, &cfg_col_nick_private, NULL, NULL }, + { "col_nick_bg", N_("background for nicknames"), + N_("background for nicknames"), + OPTION_TYPE_COLOR, 0, 0, 0, + "default", NULL, &cfg_col_nick_bg, NULL, NULL }, + + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, history section */ + +int cfg_history_max_lines; +int cfg_history_max_commands; + +t_config_option weechat_options_history[] = +{ { "history_max_lines", N_("max lines in history (per window)"), + N_("maximum number of lines in history " + "for one server/channel/private window (0 = unlimited)"), + OPTION_TYPE_INT, 0, INT_MAX, 4096, + NULL, NULL, &cfg_history_max_lines, NULL, NULL }, + { "history_max_commands", N_("max user commands in history"), + N_("maximum number of user commands in history (0 = unlimited)"), + OPTION_TYPE_INT, 0, INT_MAX, 100, + NULL, NULL, &cfg_history_max_commands, NULL, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, log section */ + +int cfg_log_auto_channels; +int cfg_log_auto_private; +char *cfg_log_path; +char *cfg_log_name; +char *cfg_log_timestamp; +char *cfg_log_start_string; +char *cfg_log_end_string; + +t_config_option weechat_options_log[] = +{ { "log_auto_channels", N_("automatically log channel chats"), + N_("automatically log channel chats"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_log_auto_channels, NULL, NULL }, + { "log_auto_private", N_("automatically log private chats"), + N_("automatically log private chats"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_log_auto_private, NULL, NULL }, + { "log_path", N_("path for log files"), + N_("path for " WEECHAT_NAME " log files"), + OPTION_TYPE_STRING, 0, 0, 0, + "~/.weechat/logs/", NULL, NULL, &cfg_log_path, NULL }, + { "log_name", N_("name for log files"), + N_("name for log files (%S == irc server name, " + "%N == channel name (or nickname if private chat)"), + OPTION_TYPE_STRING, 0, 0, 0, + "%S,%N.weechatlog", NULL, NULL, &cfg_log_name, NULL }, + { "log_timestamp", N_("timestamp for log"), + N_("timestamp for log (see man strftime for date/time specifiers)"), + OPTION_TYPE_STRING, 0, 0, 0, + "~", NULL, NULL, &cfg_log_timestamp, NULL }, + { "log_start_string", N_("start string for log files"), + N_("text writed when starting new log file " + "(see man strftime for date/time specifiers)"), + OPTION_TYPE_STRING, 0, 0, 0, + "--- Log started %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_start_string, NULL }, + { "log_end_string", N_("end string for log files"), + N_("text writed when ending log file " + "(see man strftime for date/time specifiers)"), + OPTION_TYPE_STRING, 0, 0, 0, + "--- Log ended %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_end_string, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, dcc section */ + +int cfg_dcc_auto_accept_files; +int cfg_dcc_auto_accept_max_size; +int cfg_dcc_auto_accept_chats; +int cfg_dcc_timeout; +char *cfg_dcc_download_path; +char *cfg_dcc_upload_path; +int cfg_dcc_auto_rename; +int cfg_dcc_auto_resume; + +t_config_option weechat_options_dcc[] = +{ { "dcc_auto_accept_files", N_("automatically accept dcc files"), + N_("automatically accept incoming dcc files"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_accept_files, NULL, NULL }, + { "dcc_auto_accept_max_size", N_("max size when auto accepting file"), + N_("maximum size for incoming file when automatically accepted"), + OPTION_TYPE_INT, 0, INT_MAX, 0, + NULL, NULL, &cfg_dcc_auto_accept_max_size, NULL, NULL }, + { "dcc_auto_accept_chats", N_("automatically accept dcc chats"), + N_("automatically accept dcc chats (use carefully!)"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_accept_chats, NULL, NULL }, + { "dcc_timeout", N_("timeout for dcc request"), + N_("timeout for dcc request (in seconds)"), + OPTION_TYPE_INT, 1, INT_MAX, 300, + NULL, NULL, &cfg_dcc_timeout, NULL, NULL }, + { "dcc_download_path", N_("path for incoming files with dcc"), + N_("path for writing incoming files with dcc (default: user home)"), + OPTION_TYPE_STRING, 0, 0, 0, "~", + NULL, NULL, &cfg_dcc_download_path, NULL }, + { "dcc_upload_path", N_("default path for sending files with dcc"), + N_("path for reading files when sending thru dcc (when no path is specified)"), + OPTION_TYPE_STRING, 0, 0, 0, "~", + NULL, NULL, &cfg_dcc_upload_path, NULL }, + { "dcc_auto_rename", N_("automatically rename dcc files if already exists"), + N_("rename incoming files if already exists (add '.1', '.2', ...)"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_rename, NULL, NULL }, + { "dcc_auto_resume", N_("automatically resume aborted transfers"), + N_("automatically resume dcc trsnafer if connection with remote host is loosed"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_resume, NULL, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, proxy section */ + +int cfg_proxy_use; +char *cfg_proxy_address; +int cfg_proxy_port; +char *cfg_proxy_password; + +t_config_option weechat_options_proxy[] = +{ { "proxy_use", N_("use proxy"), + N_("use a proxy server to connect to irc server"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE, + NULL, NULL, &cfg_proxy_use, NULL, NULL }, + { "proxy_address", N_("proxy address"), + N_("proxy server address (IP or hostname)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &cfg_proxy_address, NULL }, + { "proxy_port", N_("port for proxy"), + N_("port for connecting to proxy server"), + OPTION_TYPE_INT, 0, 65535, 1080, + NULL, NULL, &cfg_proxy_port, NULL, NULL }, + { "proxy_password", N_("proxy password"), + N_("password for proxy server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &cfg_proxy_password, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, server section */ + +static t_irc_server cfg_server; + +t_config_option weechat_options_server[] = +{ { "server_name", N_("server name"), + N_("name associated to IRC server (for display only)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.name), NULL }, + { "server_address", N_("server address or hostname"), + N_("IP address or hostname of IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.address), NULL }, + { "server_port", N_("port for IRC server"), + N_("port for connecting to server"), + OPTION_TYPE_INT, 0, 65535, 6667, + NULL, NULL, &(cfg_server.port), NULL, NULL }, + { "server_password", N_("server password"), + N_("password for IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.password), NULL }, + { "server_nick1", N_("nickname for server"), + N_("nickname to use on IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.nick1), NULL }, + { "server_nick2", N_("alternate nickname for server"), + N_("alternate nickname to use on IRC server (if nickname is already used)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.nick2), NULL }, + { "server_nick3", N_("2nd alternate nickname for server"), + N_("2nd alternate nickname to use on IRC server (if alternate nickname is already used)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.nick3), NULL }, + { "server_username", N_("user name for server"), + N_("user name to use on IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.username), NULL }, + { "server_realname", N_("real name for server"), + N_("real name to use on IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.realname), NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* all weechat options */ + +t_config_option *weechat_options[CONFIG_NUMBER_SECTIONS] = +{ weechat_options_look, weechat_options_colors, weechat_options_history, + weechat_options_log, weechat_options_dcc, weechat_options_proxy, + weechat_options_server +}; + + +/* + * get_pos_array_values: returns position of a string in an array of values + * returns -1 if not found, otherwise position + */ + +int +get_pos_array_values (char **array, char *string) +{ + int i; + + i = 0; + while (array[i]) + { + if (strcasecmp (array[i], string) == 0) + return i; + i++; + } + /* string not found in array */ + return -1; +} + +/* + * config_init_server: init server struct + */ + +void +config_init_server () +{ + cfg_server.name = NULL; + cfg_server.address = NULL; + cfg_server.port = -1; + cfg_server.password = NULL; + cfg_server.nick1 = NULL; + cfg_server.nick2 = NULL; + cfg_server.nick3 = NULL; + cfg_server.username = NULL; + cfg_server.realname = NULL; +} + +/* + * config_allocate_server: allocate a new server + */ + +int +config_allocate_server (char *filename, int line_number) +{ + if (!cfg_server.name + || !cfg_server.address + || cfg_server.port < 0 + || !cfg_server.nick1 + || !cfg_server.nick2 + || !cfg_server.nick3 + || !cfg_server.username + || !cfg_server.realname) + { + server_free_all (); + gui_printf (NULL, + _("%s %s, line %d: new server, but previous was incomplete\n"), + WEECHAT_WARNING, filename, line_number); + return 0; + + } + if (server_name_already_exists (cfg_server.name)) + { + server_free_all (); + gui_printf (NULL, + _("%s %s, line %d: server '%s' already exists\n"), + WEECHAT_WARNING, filename, line_number, cfg_server.name); + return 0; + } + if (!server_new (cfg_server.name, + cfg_server.address, cfg_server.port, cfg_server.password, + cfg_server.nick1, cfg_server.nick2, cfg_server.nick3, + cfg_server.username, cfg_server.realname)) + { + server_free_all (); + gui_printf (NULL, + _("%s %s, line %d: unable to create server\n"), + WEECHAT_WARNING, filename, line_number); + return 0; + } + if (cfg_server.name) + free (cfg_server.name); + if (cfg_server.address) + free (cfg_server.address); + if (cfg_server.password) + free (cfg_server.password); + if (cfg_server.nick1) + free (cfg_server.nick1); + if (cfg_server.nick2) + free (cfg_server.nick2); + if (cfg_server.nick3) + free (cfg_server.nick3); + if (cfg_server.username) + free (cfg_server.username); + if (cfg_server.realname) + free (cfg_server.realname); + if (cfg_server.nick) + free (cfg_server.nick); + + config_init_server (); + + return 1; +} + +/* + * config_default_values: initialize config variables with default values + */ + +void +config_default_values () +{ + int i, j, int_value; + + for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + if (i != CONFIG_SECTION_SERVER) + { + for (j = 0; weechat_options[i][j].option_name; j++) + { + switch (weechat_options[i][j].option_type) + { + case OPTION_TYPE_BOOLEAN: + case OPTION_TYPE_INT: + *weechat_options[i][j].ptr_int = + weechat_options[i][j].default_int; + break; + case OPTION_TYPE_INT_WITH_STRING: + int_value = get_pos_array_values ( + weechat_options[i][j].array_values, + weechat_options[i][j].default_string); + if (int_value < 0) + gui_printf (NULL, + _("%s unable to assign default int with string (\"%s\")\n"), + weechat_options[i][j].default_string); + else + *weechat_options[i][j].ptr_int = + int_value; + break; + case OPTION_TYPE_COLOR: + if (!gui_assign_color ( + weechat_options[i][j].ptr_int, + weechat_options[i][j].default_string)) + gui_printf (NULL, + _("%s unable to assign default color (\"%s\")\n"), + weechat_options[i][j].default_string); + break; + case OPTION_TYPE_STRING: + *weechat_options[i][j].ptr_string = + strdup (weechat_options[i][j].default_string); + break; + } + } + } + } +} + +/* + * config_read: read WeeChat configuration + * returns: 0 = successful + * -1 = config file file not found + * < -1 = other error (fatal) + */ + +int +config_read () +{ + char *filename; + FILE *file; + int section, line_number, i, option_number, int_value; + int server_found; + char line[1024], *ptr_line, *pos, *pos2; + + filename = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME")); + if ((file = fopen (filename, "rt")) == NULL) + { + gui_printf (NULL, _("%s config file \"%s\" not found.\n"), + WEECHAT_WARNING, filename); + free (filename); + return -1; + } + + config_default_values (); + config_init_server (); + + /* read config file */ + section = CONFIG_SECTION_NONE; + server_found = 0; + line_number = 0; + while (!feof (file)) + { + ptr_line = fgets (line, sizeof (line) - 1, file); + line_number++; + if (ptr_line) + { + /* skip spaces */ + while (ptr_line[0] == ' ') + ptr_line++; + /* not a comment and not an empty line */ + if ((ptr_line[0] != '#') && (ptr_line[0] != '\r') + && (ptr_line[0] != '\n')) + { + /* beginning of section */ + if (ptr_line[0] == '[') + { + pos = strchr (line, ']'); + if (pos == NULL) + { + gui_printf (NULL, + _("%s %s, line %d: invalid syntax, missing \"]\"\n"), + WEECHAT_WARNING, filename, line_number); + fclose (file); + free (filename); + return -2; + } + pos[0] = '\0'; + pos = ptr_line + 1; + section = CONFIG_SECTION_NONE; + for (i = 0; config_sections[i].section_name; i++) + { + if (strcmp (config_sections[i].section_name, pos) == 0) + { + section = i; + break; + } + } + if (section == CONFIG_SECTION_NONE) + { + gui_printf (NULL, + _("%s %s, line %d: unknown section identifier (\"%s\")\n"), + WEECHAT_WARNING, filename, line_number, pos); + fclose (file); + free (filename); + return -2; + } + if (server_found) + { + /* if server already started => create it */ + if (!config_allocate_server (filename, line_number)) + { + fclose (file); + free (filename); + return -2; + } + } + server_found = (section == CONFIG_SECTION_SERVER) ? 1 : 0; + } + else + { + pos = strchr (line, '='); + if (pos == NULL) + { + gui_printf (NULL, + _("%s %s, line %d: invalid syntax, missing \"=\"\n"), + WEECHAT_WARNING, filename, line_number); + fclose (file); + free (filename); + return -2; + } + else + { + pos[0] = '\0'; + pos++; + pos2 = strchr (pos, '\r'); + if (pos2 != NULL) + pos2[0] = '\0'; + pos2 = strchr (pos, '\n'); + if (pos2 != NULL) + pos2[0] = '\0'; + option_number = -1; + for (i = 0; + weechat_options[section][i].option_name; i++) + { + if (strcmp + (weechat_options[section][i].option_name, + ptr_line) == 0) + { + option_number = i; + break; + } + } + if (option_number < 0) + { + gui_printf (NULL, + _("%s %s, line %d: invalid option \"%s\"\n"), + WEECHAT_WARNING, filename, line_number, ptr_line); + fclose (file); + free (filename); + return -2; + } + else + { + switch (weechat_options[section] + [option_number].option_type) + { + case OPTION_TYPE_BOOLEAN: + if (strcasecmp (pos, "on") == 0) + *weechat_options[section] + [option_number].ptr_int = BOOL_TRUE; + else if (strcasecmp (pos, "off") == 0) + *weechat_options[section] + [option_number].ptr_int = BOOL_FALSE; + else + { + gui_printf (NULL, + _("%s %s, line %d: invalid value for" + "option '%s'\n" + "Expected: boolean value: " + "'off' or 'on'\n"), + WEECHAT_WARNING, filename, + line_number, ptr_line); + fclose (file); + free (filename); + return -2; + } + break; + case OPTION_TYPE_INT: + int_value = atoi (pos); + if ((int_value < + weechat_options[section] + [option_number].min) + || (int_value > + weechat_options[section] + [option_number].max)) + { + gui_printf (NULL, + _("%s %s, line %d: invalid value for" + "option '%s'\n" + "Expected: integer between %d " + "and %d\n"), + WEECHAT_WARNING, filename, + line_number, ptr_line, + weechat_options[section][option_number].min, + weechat_options[section][option_number].max); + fclose (file); + free (filename); + return -2; + } + *weechat_options[section][option_number].ptr_int = + int_value; + break; + case OPTION_TYPE_INT_WITH_STRING: + int_value = get_pos_array_values ( + weechat_options[section][option_number].array_values, + pos); + if (int_value < 0) + { + gui_printf (NULL, + _("%s %s, line %d: invalid value for" + "option '%s'\n" + "Expected: one of these strings: "), + WEECHAT_WARNING, filename, + line_number, ptr_line); + i = 0; + while (weechat_options[section][option_number].array_values[i]) + { + gui_printf (NULL, "\"%s\" ", + weechat_options[section][option_number].array_values[i]); + i++; + } + gui_printf (NULL, "\n"); + fclose (file); + free (filename); + return -2; + } + *weechat_options[section][option_number].ptr_int = + int_value; + break; + case OPTION_TYPE_COLOR: + if (!gui_assign_color ( + weechat_options[section][option_number].ptr_int, + pos)) + { + gui_printf (NULL, + _("%s %s, line %d: invalid color " + "name for option '%s'\n"), + WEECHAT_WARNING, filename, + line_number, + ptr_line); + fclose (file); + free (filename); + return -2; + } + break; + case OPTION_TYPE_STRING: + if (*weechat_options[section] + [option_number].ptr_string) + free (*weechat_options[section][option_number].ptr_string); + *weechat_options[section][option_number].ptr_string = + strdup (pos); + break; + } + } + } + } + } + } + } + + if (server_found) + { + if (!config_allocate_server (filename, line_number)) + { + fclose (file); + free (filename); + return -2; + } + } + + /* set default colors for colors not set */ + /*for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + if (i != CONFIG_SECTION_SERVER) + { + for (j = 0; weechat_options[i][j].option_name; j++) + { + if ((weechat_options[i][j].option_type == OPTION_TYPE_COLOR) && + (*weechat_options[i][j].ptr_int == COLOR_NOT_SET)) + *weechat_options[i][j].ptr_int = + gui_get_color_by_name (weechat_options[i][j].default_string); + } + } + }*/ + + fclose (file); + free (filename); + + return 0; +} + + +/* + * config_create_default: create default WeeChat config + */ + +int +config_create_default () +{ + char *filename; + char line[1024]; + FILE *file; + int i, j; + time_t current_time; + + filename = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME")); + if ((file = fopen (filename, "wt")) == NULL) + { + free (filename); + gui_printf (NULL, _("%s cannot create file \"%s\"\n"), + WEECHAT_ERROR, filename); + return -1; + } + + printf (_(WEECHAT_NAME ": creating default config file...\n")); + + current_time = time (NULL); + sprintf (line, _("#\n# " WEECHAT_NAME " configuration file, generated by " + WEECHAT_NAME " " WEECHAT_VERSION " on %s"), ctime (¤t_time)); + fputs (line, file); + fputs (_("# This file may be edited by user. Invalid syntax will prevent " + WEECHAT_NAME " from running!\n#\n"), file); + + for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + if (i != CONFIG_SECTION_SERVER) + { + sprintf (line, "\n[%s]\n", config_sections[i].section_name); + fputs (line, file); + if ((i == CONFIG_SECTION_HISTORY) || (i == CONFIG_SECTION_LOG) || + (i == CONFIG_SECTION_DCC) || (i == CONFIG_SECTION_PROXY)) + { + sprintf (line, + "# WARNING!!! Options for section \"%s\" are not developed!\n", + config_sections[i].section_name); + fputs (line, file); + } + for (j = 0; weechat_options[i][j].option_name; j++) + { + switch (weechat_options[i][j].option_type) + { + case OPTION_TYPE_BOOLEAN: + sprintf (line, "%s=%s\n", + weechat_options[i][j].option_name, + (weechat_options[i][j]. + default_int) ? "on" : "off"); + break; + case OPTION_TYPE_INT: + sprintf (line, "%s=%d\n", + weechat_options[i][j].option_name, + weechat_options[i][j].default_int); + break; + case OPTION_TYPE_INT_WITH_STRING: + case OPTION_TYPE_COLOR: + case OPTION_TYPE_STRING: + sprintf (line, "%s=%s\n", + weechat_options[i][j].option_name, + weechat_options[i][j].default_string); + break; + } + fputs (line, file); + } + } + } + + /* default server is freenode */ + fputs ("\n[server]\n", file); + fputs ("server_name=freenode\n", file); + fputs ("server_address=irc.freenode.net\n", file); + fputs ("server_port=6667\n", file); + fputs ("server_password=\n", file); + fputs ("server_nick1=weechat_user\n", file); + fputs ("server_nick2=weechat2\n", file); + fputs ("server_nick3=weechat3\n", file); + fputs ("server_username=weechat\n", file); + fputs ("server_realname=WeeChat default realname\n", file); + + fclose (file); + free (filename); + return 0; +} + +/* + * config_write: write WeeChat configurtion + */ + +void +config_write () +{ + /* TODO: write "config_write" function! */ +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 000000000..cc84eaab6 --- /dev/null +++ b/src/config.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_CONFIG_H +#define __WEECHAT_CONFIG_H 1 + +#define WEECHAT_CONFIG_NAME "weechat.rc" + +#define CONFIG_SECTION_NONE -1 +#define CONFIG_SECTION_LOOK 0 +#define CONFIG_SECTION_COLORS 1 +#define CONFIG_SECTION_HISTORY 2 +#define CONFIG_SECTION_LOG 3 +#define CONFIG_SECTION_DCC 4 +#define CONFIG_SECTION_PROXY 5 +#define CONFIG_SECTION_SERVER 6 +#define CONFIG_NUMBER_SECTIONS 7 + +#define OPTION_TYPE_BOOLEAN 1 /* values: on/off */ +#define OPTION_TYPE_INT 2 /* values: from min to max */ +#define OPTION_TYPE_INT_WITH_STRING 3 /* values: one from **array_values */ +#define OPTION_TYPE_COLOR 4 /* values: a color name */ +#define OPTION_TYPE_STRING 5 /* values: any string, may be empty */ + +#define BOOL_FALSE 0 +#define BOOL_TRUE 1 + +#define CFG_LOOK_NICKLIST_LEFT 0 +#define CFG_LOOK_NICKLIST_RIGHT 1 +#define CFG_LOOK_NICKLIST_TOP 2 +#define CFG_LOOK_NICKLIST_BOTTOM 3 + +typedef struct t_config_section t_config_section; + +struct t_config_section +{ + int section_number; + char *section_name; +}; + +typedef struct t_config_option t_config_option; + +struct t_config_option +{ + char *option_name; + char *short_description; + char *long_description; + int option_type; + int min, max; + int default_int; + char *default_string; + char **array_values; + int *ptr_int; + char **ptr_string; + int (*handler_change)(int *, char **); +}; + +extern int cfg_look_startup_logo; +extern int cfg_look_startup_version; +extern char *cfg_look_weechat_slogan; +extern int cfg_look_color_nicks; +extern int cfg_look_color_actions; +extern int cfg_look_remove_colors_from_msgs; +extern int cfg_look_nicklist; +extern int cfg_look_nicklist_position; +extern int cfg_look_nicklist_min_size; +extern int cfg_look_nicklist_max_size; +extern int cfg_look_nickmode; +extern int cfg_look_nickmode_empty; +extern char *cfg_look_no_nickname; +extern char *cfg_look_completor; + +extern int cfg_col_title; +extern int cfg_col_title_bg; +extern int cfg_col_chat; +extern int cfg_col_chat_time; +extern int cfg_col_chat_time_sep; +extern int cfg_col_chat_prefix1; +extern int cfg_col_chat_prefix2; +extern int cfg_col_chat_nick; +extern int cfg_col_chat_host; +extern int cfg_col_chat_channel; +extern int cfg_col_chat_dark; +extern int cfg_col_chat_bg; +extern int cfg_col_status; +extern int cfg_col_status_active; +extern int cfg_col_status_data_msg; +extern int cfg_col_status_data_other; +extern int cfg_col_status_more; +extern int cfg_col_status_bg; +extern int cfg_col_input; +extern int cfg_col_input_channel; +extern int cfg_col_input_nick; +extern int cfg_col_input_bg; +extern int cfg_col_nick; +extern int cfg_col_nick_op; +extern int cfg_col_nick_halfop; +extern int cfg_col_nick_voice; +extern int cfg_col_nick_sep; +extern int cfg_col_nick_self; +extern int cfg_col_nick_private; +extern int cfg_col_nick_bg; + +extern int cfg_history_max_lines; +extern int cfg_history_max_commands; + +extern int cfg_log_auto_channels; +extern int cfg_log_auto_private; +extern char *cfg_log_path; +extern char *cfg_log_name; +extern char *cfg_log_timestamp; +extern char *cfg_log_start_string; +extern char *cfg_log_end_string; + +extern int cfg_dcc_auto_accept_files; +extern int cfg_dcc_auto_accept_max_size; +extern int cfg_dcc_auto_accept_chats; +extern int cfg_dcc_timeout; +extern char *cfg_dcc_download_path; +extern char *cfg_dcc_upload_path; +extern int cfg_dcc_auto_rename; +extern int cfg_dcc_auto_resume; + +extern int cfg_proxy_use; +extern char *cfg_proxy_address; +extern int cfg_proxy_port; +extern char *cfg_proxy_password; + +extern t_config_section config_sections [CONFIG_NUMBER_SECTIONS]; +extern t_config_option * weechat_options [CONFIG_NUMBER_SECTIONS]; + +extern int config_read (); +extern int config_create_default (); +extern void config_write (); + +#endif /* config.h */ diff --git a/src/gui/Makefile b/src/gui/Makefile new file mode 100644 index 000000000..77d66bea7 --- /dev/null +++ b/src/gui/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# WeeChat with Curses interface +ifeq ($(GUI), curses) +curses: curses/gui.a +curses/gui.a: + cd curses && make +endif + +# WeeChat with Gtk+ interface +ifeq ($(GUI), gtk) +gtk: gtk/gui.a +gtk/gui.a: + cd gtk && make +endif + +# WeeChat with Qt interface +ifeq ($(GUI), qt) +qt: qt/gui.a +qt/gui.a: + cd qt && make +endif + +# WeeChat with Text interface +ifeq ($(GUI), text) +text: text/gui.a +text/gui.a: + cd text && make +endif + + +all: + make curses GUI=curses + +clean: + rm -f *.o *.a *~ core + cd curses && make clean + cd gtk && make clean + cd qt && make clean + cd text && make clean diff --git a/src/gui/curses/Makefile b/src/gui/curses/Makefile new file mode 100644 index 000000000..80f800dd9 --- /dev/null +++ b/src/gui/curses/Makefile @@ -0,0 +1,38 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_CURSES + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../completion.h \ + ../../history.h ../../config.h ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h ../../completion.h \ + ../../history.h ../../command.h ../../irc/irc.h ../../gui/gui.h diff --git a/src/gui/curses/gui-display.c b/src/gui/curses/gui-display.c new file mode 100644 index 000000000..9ad67edac --- /dev/null +++ b/src/gui/curses/gui-display.c @@ -0,0 +1,1730 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-display.c: display functions for Curses GUI */ + + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <time.h> +#include <sys/socket.h> +#include <curses.h> + +#include "../../weechat.h" +#include "../gui.h" +#include "../../config.h" +#include "../../irc/irc.h" + + +int gui_ready; /* = 1 if GUI is initialized */ + +t_gui_window *gui_windows = NULL; /* pointer to first window */ +t_gui_window *last_gui_window = NULL; /* pointer to last window */ +t_gui_window *gui_current_window = NULL; /* pointer to current window */ + +t_gui_color gui_colors[] = +{ { "default", -1 | A_NORMAL }, + { "black", COLOR_BLACK | A_NORMAL }, + { "red", COLOR_RED | A_NORMAL }, + { "lightred", COLOR_RED | A_BOLD }, + { "green", COLOR_GREEN | A_NORMAL }, + { "lightgreen", COLOR_GREEN | A_BOLD }, + { "brown", COLOR_YELLOW | A_NORMAL }, + { "yellow", COLOR_YELLOW | A_BOLD }, + { "blue", COLOR_BLUE | A_NORMAL }, + { "lightblue", COLOR_BLUE | A_BOLD }, + { "magenta", COLOR_MAGENTA | A_NORMAL }, + { "lightmagenta", COLOR_MAGENTA | A_BOLD }, + { "cyan", COLOR_CYAN | A_NORMAL }, + { "lightcyan", COLOR_CYAN | A_BOLD }, + { "gray", COLOR_WHITE }, + { "white", COLOR_WHITE | A_BOLD }, + { NULL, 0 } +}; + +char *nicks_colors[COLOR_WIN_NICK_NUMBER] = +{ "cyan", "magenta", "green", "brown", "lightblue", "gray", + "lightcyan", "lightmagenta", "lightgreen", "blue" }; + +int color_attr[NUM_COLORS]; + +/* + * gui_assign_color: assign a color (read from config) + */ + +int +gui_assign_color (int *color, char *color_name) +{ + int i; + + /* look for curses colors in table */ + i = 0; + while (gui_colors[i].name) + { + if (strcasecmp (gui_colors[i].name, color_name) == 0) + { + *color = gui_colors[i].color; + return 1; + } + i++; + } + + /* color not found */ + return 0; +} + +/* + * gui_get_color_by_name: get color by name + */ + +int +gui_get_color_by_name (char *color_name) +{ + int i; + + /* look for curses colors in table */ + i = 0; + while (gui_colors[i].name) + { + if (strcasecmp (gui_colors[i].name, color_name) == 0) + return gui_colors[i].color; + i++; + } + + /* color not found */ + return -1; +} + +/* + * gui_get_color_by_value: get color name by value + */ + +char * +gui_get_color_by_value (int color_value) +{ + int i; + + /* look for curses colors in table */ + i = 0; + while (gui_colors[i].name) + { + if (gui_colors[i].color == color_value) + return gui_colors[i].name; + i++; + } + + /* color not found */ + return NULL; +} + +/* + * gui_window_set_color: set color for window + */ + +void +gui_window_set_color (WINDOW *window, int num_color) +{ + if (has_colors) + { + if (color_attr[num_color - 1] & A_BOLD) + wattron (window, COLOR_PAIR (num_color) | A_BOLD); + else + { + wattroff (window, A_BOLD); + wattron (window, COLOR_PAIR (num_color)); + } + } +} + +/* + * gui_calculate_pos_size: calculate position and size for a window & sub-win + */ + +void +gui_calculate_pos_size (t_gui_window *window) +{ + int max_length, lines; + int num_nicks, num_op, num_halfop, num_voice, num_normal; + + /* global position & size */ + /* TODO: get values from function parameters */ + window->win_x = 0; + window->win_y = 0; + window->win_width = COLS; + window->win_height = LINES; + + /* init chat & nicklist settings */ + /* TODO: calculate values from function parameters */ + if (WIN_IS_CHANNEL(window)) + { + max_length = nick_get_max_length (CHANNEL(window)); + + switch (cfg_look_nicklist_position) + { + case CFG_LOOK_NICKLIST_LEFT: + window->win_chat_x = max_length + 2; + window->win_chat_y = 1; + window->win_chat_width = COLS - max_length - 2; + window->win_chat_height = LINES - 3; + window->win_nick_x = 0; + window->win_nick_y = 1; + window->win_nick_width = max_length + 2; + window->win_nick_height = LINES - 3; + break; + case CFG_LOOK_NICKLIST_RIGHT: + window->win_chat_x = 0; + window->win_chat_y = 1; + window->win_chat_width = COLS - max_length - 2; + window->win_chat_height = LINES - 3; + window->win_nick_x = COLS - max_length - 2; + window->win_nick_y = 1; + window->win_nick_width = max_length + 2; + window->win_nick_height = LINES - 3; + break; + case CFG_LOOK_NICKLIST_TOP: + nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop, + &num_voice, &num_normal); + if (((max_length + 1) * num_nicks) % COLS == 0) + lines = ((max_length + 1) * num_nicks) / COLS; + else + lines = (((max_length + 1) * num_nicks) / COLS) + 1; + window->win_chat_x = 0; + window->win_chat_y = 1 + (lines + 1); + window->win_chat_width = COLS; + window->win_chat_height = LINES - 3 - (lines + 1); + window->win_nick_x = 0; + window->win_nick_y = 1; + window->win_nick_width = COLS; + window->win_nick_height = lines + 1; + break; + case CFG_LOOK_NICKLIST_BOTTOM: + nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop, + &num_voice, &num_normal); + if (((max_length + 1) * num_nicks) % COLS == 0) + lines = ((max_length + 1) * num_nicks) / COLS; + else + lines = (((max_length + 1) * num_nicks) / COLS) + 1; + window->win_chat_x = 0; + window->win_chat_y = 1; + window->win_chat_width = COLS; + window->win_chat_height = LINES - 3 - (lines + 1); + window->win_nick_x = 0; + window->win_nick_y = LINES - 2 - (lines + 1); + window->win_nick_width = COLS; + window->win_nick_height = lines + 1; + break; + } + + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = 0; + } + else + { + window->win_chat_x = 0; + window->win_chat_y = 1; + window->win_chat_width = COLS; + window->win_chat_height = LINES - 3; + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = 0; + window->win_nick_x = -1; + window->win_nick_y = -1; + window->win_nick_width = -1; + window->win_nick_height = -1; + } +} + +/* + * gui_curses_window_clear: clear a window + */ + +void +gui_curses_window_clear (WINDOW *window) +{ + werase (window); + wmove (window, 0, 0); + //wrefresh (window); +} + +/* + * gui_draw_window_title: draw title window + */ + +void +gui_draw_window_title (t_gui_window *window) +{ + char format[32]; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_title, COLOR_WIN_TITLE); + wborder (window->win_title, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_title); + refresh (); + } + if (CHANNEL(window)) + { + sprintf (format, "%%-%ds", window->win_width); + if (CHANNEL(window)->topic) + mvwprintw (window->win_title, 0, 0, format, + CHANNEL(window)->topic); + } + else + { + /* TODO: change this copyright as title? */ + mvwprintw (window->win_title, 0, 0, + "%s", WEECHAT_NAME_AND_VERSION " - " WEECHAT_WEBSITE); + mvwprintw (window->win_title, 0, COLS - strlen (WEECHAT_COPYRIGHT), + "%s", WEECHAT_COPYRIGHT); + } + wrefresh (window->win_title); + refresh (); +} + +/* + * gui_redraw_window_title: redraw title window + */ + +void +gui_redraw_window_title (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_title); + gui_draw_window_title (window); +} + +/* + * gui_get_line_num_splits: returns number of lines on window + * (depending on window width and type (server/channel) + * for alignment) + */ + +int +gui_get_line_num_splits (t_gui_window *window, t_gui_line *line) +{ + int length, width; + + /* TODO: modify arbitraty value for non aligning messages on time/nick? */ + if (line->length_align >= window->win_chat_width - 5) + { + length = line->length; + width = window->win_chat_width; + } + else + { + length = line->length - line->length_align; + width = window->win_chat_width - line->length_align; + } + + return (length % width == 0) ? (length / width) : ((length / width) + 1); +} + +/* + * gui_display_end_of_line: display end of a line in the chat window + */ + +void +gui_display_end_of_line (t_gui_window *window, t_gui_line *line, int count) +{ + int lines_displayed, num_lines, offset, remainder, num_displayed; + t_gui_message *ptr_message; + char saved_char, format_align[32]; + + sprintf (format_align, "%%-%ds", line->length_align); + num_lines = gui_get_line_num_splits (window, line); + ptr_message = line->messages; + offset = 0; + lines_displayed = 0; + while (ptr_message) + { + /* set text color if beginning of message */ + if (offset == 0) + gui_window_set_color (window->win_chat, ptr_message->color); + + /* insert spaces for align text under time/nick */ + if ((lines_displayed > 0) && (window->win_chat_cursor_x == 0)) + { + if (lines_displayed >= num_lines - count) + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + format_align, " "); + window->win_chat_cursor_x += line->length_align; + } + + remainder = strlen (ptr_message->message + offset); + if (window->win_chat_cursor_x + remainder > + window->win_chat_width - 1) + { + num_displayed = window->win_chat_width - + window->win_chat_cursor_x; + saved_char = ptr_message->message[offset + num_displayed]; + ptr_message->message[offset + num_displayed] = '\0'; + if (lines_displayed >= num_lines - count) + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + ptr_message->message[offset + num_displayed] = saved_char; + offset += num_displayed; + } + else + { + num_displayed = remainder; + if (lines_displayed >= num_lines - count) + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + ptr_message = ptr_message->next_message; + offset = 0; + } + window->win_chat_cursor_x += num_displayed; + if (!ptr_message || + (window->win_chat_cursor_x > (window->win_chat_width - 1))) + { + window->win_chat_cursor_x = 0; + if (lines_displayed >= num_lines - count) + { + window->win_chat_cursor_y++; + } + lines_displayed++; + } + } +} + +/* + * gui_display_line: display a line in the chat window + * if stop_at_end == 1, screen will not scroll and then we + * exit since chat window is full + * returns: 1 if stop_at_end == 0 or screen not full + * 0 if screen is full and if stop_at_end == 1 + */ + +int +gui_display_line (t_gui_window *window, t_gui_line *line, int stop_at_end) +{ + int offset, remainder, num_displayed; + t_gui_message *ptr_message; + char saved_char, format_align[32]; + + sprintf (format_align, "%%-%ds", line->length_align); + ptr_message = line->messages; + offset = 0; + while (ptr_message) + { + /* cursor is below end line of chat window */ + if (window->win_chat_cursor_y > window->win_chat_height - 1) + { + /*if (!stop_at_end) + wscrl (window->win_chat, +1);*/ + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = window->win_chat_height - 1; + if (stop_at_end) + return 0; + window->first_line_displayed = 0; + } + + /* set text color if beginning of message */ + if (offset == 0) + gui_window_set_color (window->win_chat, ptr_message->color); + + /* insert spaces for align text under time/nick */ + if ((window->win_chat_cursor_x == 0) && + (ptr_message->type != MSG_TYPE_TIME) && + (ptr_message->type != MSG_TYPE_NICK) && + (line->length_align > 0) && + /* TODO: modify arbitraty value for non aligning messages on time/nick? */ + (line->length_align < (window->win_chat_width - 5))) + { + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + format_align, " "); + window->win_chat_cursor_x += line->length_align; + } + + remainder = strlen (ptr_message->message + offset); + if (window->win_chat_cursor_x + remainder > window->win_chat_width) + { + num_displayed = window->win_chat_width - + window->win_chat_cursor_x; + saved_char = ptr_message->message[offset + num_displayed]; + ptr_message->message[offset + num_displayed] = '\0'; + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + ptr_message->message[offset + num_displayed] = saved_char; + offset += num_displayed; + } + else + { + num_displayed = remainder; + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + offset = 0; + ptr_message = ptr_message->next_message; + } + window->win_chat_cursor_x += num_displayed; + if (!ptr_message || + (window->win_chat_cursor_x > (window->win_chat_width - 1))) + { + if (!ptr_message || + ((window->win_chat_cursor_y <= window->win_chat_height - 1) && + (window->win_chat_cursor_x > window->win_chat_width - 1))) + window->win_chat_cursor_y++; + window->win_chat_cursor_x = 0; + } + } + return 1; +} + +/* + * gui_draw_window_chat: draw chat window + */ + +void +gui_draw_window_chat (t_gui_window *window) +{ + t_gui_line *ptr_line; + int lines_used; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_chat, COLOR_WIN_CHAT); + wborder (window->win_chat, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_chat); + } + + ptr_line = window->last_line; + lines_used = 0; + while (ptr_line + && (lines_used < (window->win_chat_height + window->sub_lines))) + { + lines_used += gui_get_line_num_splits (window, ptr_line); + ptr_line = ptr_line->prev_line; + } + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = 0; + if (lines_used > (window->win_chat_height + window->sub_lines)) + { + /* screen will be full (we'll display only end of 1st line) */ + ptr_line = (ptr_line) ? ptr_line->next_line : window->lines; + gui_display_end_of_line (window, ptr_line, + gui_get_line_num_splits (window, ptr_line) - + (lines_used - (window->win_chat_height + window->sub_lines))); + ptr_line = ptr_line->next_line; + window->first_line_displayed = 0; + } + else + { + /* all lines are displayed */ + if (!ptr_line) + { + window->first_line_displayed = 1; + ptr_line = window->lines; + } + else + { + window->first_line_displayed = 0; + ptr_line = ptr_line->next_line; + } + } + while (ptr_line) + { + if (!gui_display_line (window, ptr_line, 1)) + break; + + ptr_line = ptr_line->next_line; + } + /*if (window->win_chat_cursor_y <= window->win_chat_height - 1) + window->sub_lines = 0;*/ + wrefresh (window->win_chat); + refresh (); +} + +/* + * gui_redraw_window_chat: redraw chat window + */ + +void +gui_redraw_window_chat (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_chat); + gui_draw_window_chat (window); +} + +/* + * gui_draw_window_nick: draw nick window + */ + +void +gui_draw_window_nick (t_gui_window *window) +{ + int i, x, y, column, max_length; + char format[32]; + t_irc_nick *ptr_nick; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (CHANNEL(window) && CHANNEL(window)->nicks) + { + max_length = nick_get_max_length (CHANNEL(window)); + if ((max_length + 2) != window->win_nick_width) + { + gui_calculate_pos_size (window); + delwin (window->win_chat); + delwin (window->win_nick); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + window->win_nick = newwin (window->win_nick_height, + window->win_nick_width, + window->win_nick_y, + window->win_nick_x); + //scrollok (window->win_chat, TRUE); + gui_redraw_window_chat (window); + } + sprintf (format, "%%-%ds", max_length); + + if (has_colors ()) + { + switch (cfg_look_nicklist_position) + { + case CFG_LOOK_NICKLIST_LEFT: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP); + for (i = 0; i < window->win_chat_height; i++) + mvwprintw (window->win_nick, + i, window->win_nick_width - 1, " "); + break; + case CFG_LOOK_NICKLIST_RIGHT: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP); + for (i = 0; i < window->win_chat_height; i++) + mvwprintw (window->win_nick, + i, 0, " "); + break; + case CFG_LOOK_NICKLIST_TOP: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + for (i = 0; i < window->win_chat_width; i += 2) + mvwprintw (window->win_nick, + window->win_nick_height - 1, i, "-"); + break; + case CFG_LOOK_NICKLIST_BOTTOM: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + for (i = 0; i < window->win_chat_width; i += 2) + mvwprintw (window->win_nick, + 0, i, "-"); + break; + } + } + + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + x = 0; + y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM) ? 1 : 0; + column = 0; + for (ptr_nick = CHANNEL(window)->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + switch (cfg_look_nicklist_position) + { + case CFG_LOOK_NICKLIST_LEFT: + x = 0; + break; + case CFG_LOOK_NICKLIST_RIGHT: + x = 1; + break; + case CFG_LOOK_NICKLIST_TOP: + case CFG_LOOK_NICKLIST_BOTTOM: + x = column; + break; + } + if (ptr_nick->is_op) + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_OP); + mvwprintw (window->win_nick, y, x, "@"); + x++; + } + else + { + if (ptr_nick->is_halfop) + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_HALFOP); + mvwprintw (window->win_nick, y, x, "%%"); + x++; + } + else + { + if (ptr_nick->has_voice) + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_VOICE); + mvwprintw (window->win_nick, y, x, "+"); + x++; + } + else + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + mvwprintw (window->win_nick, y, x, " "); + x++; + } + } + } + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + mvwprintw (window->win_nick, y, x, format, ptr_nick->nick); + y++; + if ((cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) || + (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM)) + { + if (y >= window->win_nick_height - 1) + { + column += max_length + 1; + y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) ? + 0 : 1; + } + } + } + } + wrefresh (window->win_nick); + refresh (); +} + +/* + * gui_redraw_window_nick: redraw nick window + */ + +void +gui_redraw_window_nick (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_nick); + gui_draw_window_nick (window); +} + +/* + * gui_draw_window_status: draw status window + */ + +void +gui_draw_window_status (t_gui_window *window) +{ + t_gui_window *ptr_win; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_status, COLOR_WIN_STATUS); + wborder (window->win_status, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_status); + } + //refresh (); + wmove (window->win_status, 0, 0); + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + if (SERVER(ptr_win) && !CHANNEL(ptr_win)) + { + if (gui_current_window == SERVER(ptr_win)->window) + { + if (ptr_win->unread_data) + { + if (ptr_win->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_ACTIVE); + } + else + { + if (SERVER(ptr_win)->window && + ((SERVER(ptr_win)->window)->unread_data)) + { + if (SERVER(ptr_win)->window->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS); + } + if (SERVER(ptr_win)->is_connected) + wprintw (window->win_status, "[%s] ", + SERVER(ptr_win)->name); + else + wprintw (window->win_status, "(%s) ", + SERVER(ptr_win)->name); + } + if (SERVER(ptr_win) && CHANNEL(ptr_win)) + { + if (gui_current_window == CHANNEL(ptr_win)->window) + { + if ((CHANNEL(ptr_win)->window) && + (CHANNEL(ptr_win)->window->unread_data)) + { + if (CHANNEL(ptr_win)->window->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_ACTIVE); + } + else + { + if ((CHANNEL(ptr_win)->window) && + (CHANNEL(ptr_win)->window->unread_data)) + { + if (CHANNEL(ptr_win)->window->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS); + } + wprintw (window->win_status, "%s ", CHANNEL(ptr_win)->name); + } + if (!SERVER(ptr_win)) + { + gui_window_set_color (window->win_status, COLOR_WIN_STATUS); + wprintw (window->win_status, _("[not connected] ")); + } + } + + /* display "*MORE*" if last line is not displayed */ + gui_window_set_color (window->win_status, COLOR_WIN_STATUS_MORE); + if (window->sub_lines > 0) + mvwprintw (window->win_status, 0, COLS - 7, "-MORE-"); + else + mvwprintw (window->win_status, 0, COLS - 7, " "); + + wrefresh (window->win_status); + refresh (); +} + +/* + * gui_redraw_window_status: redraw status window + */ + +void +gui_redraw_window_status (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_status); + gui_draw_window_status (window); +} + +/* + * gui_get_input_width: return input width (max # chars displayed) + */ + +int +gui_get_input_width (t_gui_window *window) +{ + if (CHANNEL(window)) + return (COLS - strlen (CHANNEL(window)->name) - + strlen (SERVER(window)->nick) - 3); + else + { + if (SERVER(window) && (SERVER(window)->is_connected)) + return (COLS - strlen (SERVER(window)->nick) - 2); + else + return (COLS - strlen (cfg_look_no_nickname) - 2); + } +} + +/* + * gui_draw_window_input: draw input window + */ + +void +gui_draw_window_input (t_gui_window *window) +{ + char format[32]; + char *ptr_nickname; + int input_width; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_input, COLOR_WIN_INPUT); + wborder (window->win_input, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_input); + } + //refresh (); + + if (window->input_buffer_size == 0) + window->input_buffer[0] = '\0'; + + input_width = gui_get_input_width (window); + + if (window->input_buffer_pos - window->input_buffer_1st_display + 1 > + input_width) + window->input_buffer_1st_display = window->input_buffer_pos - + input_width + 1; + else + { + if (window->input_buffer_pos < window->input_buffer_1st_display) + window->input_buffer_1st_display = window->input_buffer_pos; + else + { + if ((window->input_buffer_1st_display > 0) && + (window->input_buffer_pos - + window->input_buffer_1st_display + 1) < input_width) + { + window->input_buffer_1st_display = + window->input_buffer_pos - input_width + 1; + if (window->input_buffer_1st_display < 0) + window->input_buffer_1st_display = 0; + } + } + } + if (CHANNEL(window)) + { + sprintf (format, "%%s %%s> %%-%ds", input_width); + mvwprintw (window->win_input, 0, 0, format, + CHANNEL(window)->name, + SERVER(window)->nick, + window->input_buffer + window->input_buffer_1st_display); + wclrtoeol (window->win_input); + move (LINES - 1, strlen (CHANNEL(window)->name) + + strlen (SERVER(window)->nick) + 3 + + (window->input_buffer_pos - window->input_buffer_1st_display)); + } + else + { + sprintf (format, "%%s> %%-%ds", input_width); + if (SERVER(window) && (SERVER(window)->is_connected)) + ptr_nickname = SERVER(window)->nick; + else + ptr_nickname = cfg_look_no_nickname; + mvwprintw (window->win_input, 0, 0, format, + ptr_nickname, + window->input_buffer + window->input_buffer_1st_display); + wclrtoeol (window->win_input); + move (LINES - 1, strlen (ptr_nickname) + 2 + + (window->input_buffer_pos - window->input_buffer_1st_display)); + } + + wrefresh (window->win_input); + refresh (); +} + +/* + * gui_redraw_window_input: redraw input window + */ + +void +gui_redraw_window_input (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_input); + gui_draw_window_input (window); +} + +/* + * gui_redraw_window: redraw a window + */ + +void +gui_redraw_window (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_redraw_window_title (window); + gui_redraw_window_chat (window); + if (window->win_nick) + gui_redraw_window_nick (window); + gui_redraw_window_status (window); + gui_redraw_window_input (window); +} + +/* + * gui_window_clear: clear window content + */ + +void +gui_window_clear (t_gui_window *window) +{ + t_gui_line *ptr_line; + t_gui_message *ptr_message; + + while (window->lines) + { + ptr_line = window->lines->next_line; + while (window->lines->messages) + { + ptr_message = window->lines->messages->next_message; + if (window->lines->messages->message) + free (window->lines->messages->message); + free (window->lines->messages); + window->lines->messages = ptr_message; + } + free (window->lines); + window->lines = ptr_line; + } + + window->lines = NULL; + window->last_line = NULL; + window->first_line_displayed = 1; + window->sub_lines = 0; + window->line_complete = 1; + window->unread_data = 0; + + if (window == gui_current_window) + gui_redraw_window_chat (window); +} + +/* + * gui_window_clear_all: clear all windows content + */ + +void +gui_window_clear_all () +{ + t_gui_window *ptr_win; + + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + gui_window_clear (ptr_win); +} + +/* + * gui_switch_to_window: switch to another window + */ + +void +gui_switch_to_window (t_gui_window *window) +{ + int another_window; + t_gui_window *ptr_win; + + another_window = 0; + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + if (ptr_win->win_title) + { + /* TODO: manage splitted windows */ + another_window = 1; + window->win_title = ptr_win->win_title; + window->win_chat = ptr_win->win_chat; + window->win_nick = ptr_win->win_nick; + window->win_status = ptr_win->win_status; + window->win_input = ptr_win->win_input; + ptr_win->win_title = NULL; + ptr_win->win_chat = NULL; + ptr_win->win_nick = NULL; + ptr_win->win_status = NULL; + ptr_win->win_input = NULL; + break; + } + } + + /* first time creation for windows */ + if (!another_window) + { + /* create new windows */ + gui_calculate_pos_size (window); + window->win_title = newwin (1, COLS, 0, 0); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + //scrollok (window->win_chat, TRUE); + if (CHANNEL(window)) + window->win_nick = newwin (window->win_nick_height, + window->win_nick_width, + window->win_nick_y, + window->win_nick_x); + else + window->win_nick = NULL; + window->win_status = newwin (1, COLS, LINES - 2, 0); + window->win_input = newwin (1, COLS, LINES - 1, 0); + } + else + { + gui_calculate_pos_size (window); + + /* create chat & nick windows */ + if (WIN_IS_CHANNEL(window) && !(window->win_nick)) + { + /* add nick list window */ + delwin (window->win_chat); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + //scrollok (window->win_chat, TRUE); + window->win_nick = newwin (window->win_nick_height, + window->win_nick_width, + window->win_nick_y, + window->win_nick_x); + } + if (!(WIN_IS_CHANNEL(window)) && window->win_nick) + { + /* remove nick list window */ + delwin (window->win_nick); + window->win_nick = NULL; + delwin (window->win_chat); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + //scrollok (window->win_chat, TRUE); + } + } + + /* change current window to the new window */ + gui_current_window = window; + + window->unread_data = 0; +} + +/* + * gui_switch_to_previous_window: switch to previous window + */ + +void +gui_switch_to_previous_window () +{ + /* if only one windows then return */ + if (gui_windows == last_gui_window) + return; + + if (gui_current_window->prev_window) + gui_switch_to_window (gui_current_window->prev_window); + else + gui_switch_to_window (last_gui_window); + gui_redraw_window (gui_current_window); +} + +/* + * gui_switch_to_next_window: switch to next window + */ + +void +gui_switch_to_next_window () +{ + /* if only one windows then return */ + if (gui_windows == last_gui_window) + return; + + if (gui_current_window->next_window) + gui_switch_to_window (gui_current_window->next_window); + else + gui_switch_to_window (gui_windows); + gui_redraw_window (gui_current_window); +} + +/* + * gui_move_page_up: display previous page on window + */ + +void +gui_move_page_up () +{ + if (!gui_current_window->first_line_displayed) + { + gui_current_window->sub_lines += gui_current_window->win_chat_height - 1; + gui_redraw_window_chat (gui_current_window); + gui_redraw_window_status (gui_current_window); + } +} + +/* + * gui_move_page_down: display next page on window + */ + +void +gui_move_page_down () +{ + if (gui_current_window->sub_lines > 0) + { + gui_current_window->sub_lines -= gui_current_window->win_chat_height - 1; + if (gui_current_window->sub_lines < 0) + gui_current_window->sub_lines = 0; + if (gui_current_window->sub_lines == 0) + gui_current_window->unread_data = 0; + gui_redraw_window_chat (gui_current_window); + gui_redraw_window_status (gui_current_window); + } +} + +/* + * gui_window_new: create a new window + * (TODO: add coordinates and size, for splited windows) + */ + +t_gui_window * +gui_window_new (void *server, void *channel + /*int x, int y, int width, int height*/) +{ + t_gui_window *new_window; + + if ((new_window = (t_gui_window *)(malloc (sizeof (t_gui_window))))) + { + /* assign server and channel to window */ + SERVER(new_window) = server; + CHANNEL(new_window) = channel; + /* assign window to server and channel */ + if (server && !channel) + SERVER(new_window)->window = new_window; + if (channel) + CHANNEL(new_window)->window = new_window; + + gui_calculate_pos_size (new_window); + + /* init windows */ + new_window->win_title = NULL; + new_window->win_chat = NULL; + new_window->win_nick = NULL; + new_window->win_status = NULL; + new_window->win_input = NULL; + + /* init lines */ + new_window->lines = NULL; + new_window->last_line = NULL; + new_window->first_line_displayed = 1; + new_window->sub_lines = 0; + new_window->line_complete = 1; + new_window->unread_data = 0; + + /* init input buffer */ + new_window->input_buffer_alloc = INPUT_BUFFER_BLOCK_SIZE; + new_window->input_buffer = (char *) malloc (INPUT_BUFFER_BLOCK_SIZE); + new_window->input_buffer[0] = '\0'; + new_window->input_buffer_size = 0; + new_window->input_buffer_pos = 0; + new_window->input_buffer_1st_display = 0; + + /* init completion */ + completion_init (&(new_window->completion)); + + /* init history */ + new_window->history = NULL; + new_window->ptr_history = NULL; + + /* switch to new window */ + gui_switch_to_window (new_window); + + /* add window to windows queue */ + new_window->prev_window = last_gui_window; + if (gui_windows) + last_gui_window->next_window = new_window; + else + gui_windows = new_window; + last_gui_window = new_window; + new_window->next_window = NULL; + + /* redraw whole screen */ + gui_redraw_window (new_window); + } + else + return NULL; + return new_window; +} + +/* + * gui_window_free: delete a window + */ + +void +gui_window_free (t_gui_window *window) +{ + t_gui_line *ptr_line; + t_gui_message *ptr_message; + + /* TODO: manage splitted windows! */ + if (window == gui_current_window) + gui_switch_to_previous_window (); + + /* free lines and messages */ + while (window->lines) + { + ptr_line = window->lines->next_line; + while (window->lines->messages) + { + ptr_message = window->lines->messages->next_message; + if (window->lines->messages->message) + free (window->lines->messages->message); + free (window->lines->messages); + window->lines->messages = ptr_message; + } + free (window->lines); + window->lines = ptr_line; + } + if (window->input_buffer) + free (window->input_buffer); + + /* TODO: free completion struct */ + /* there... */ + + /* remove window from windows list */ + if (window->prev_window) + window->prev_window->next_window = window->next_window; + if (window->next_window) + window->next_window->prev_window = window->prev_window; + if (gui_windows == window) + gui_windows = window->next_window; + if (last_gui_window == window) + last_gui_window = window->prev_window; + + free (window); +} + +/* + * gui_resize_term_handler: called when term size is modified + */ + +void +gui_resize_term_handler () +{ + t_gui_window *ptr_win; + int width, height; + + endwin (); + refresh (); + + getmaxyx (stdscr, height, width); + + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + gui_calculate_pos_size (ptr_win); + // TODO: manage splitted windows! + if (ptr_win->win_title) + { + if (ptr_win->win_title) + delwin (ptr_win->win_title); + if (ptr_win->win_chat) + delwin (ptr_win->win_chat); + if (ptr_win->win_nick) + delwin (ptr_win->win_nick); + if (ptr_win->win_status) + delwin (ptr_win->win_status); + if (ptr_win->win_input) + delwin (ptr_win->win_input); + ptr_win->win_title = NULL; + ptr_win->win_chat = NULL; + ptr_win->win_nick = NULL; + ptr_win->win_status = NULL; + ptr_win->win_input = NULL; + gui_switch_to_window (ptr_win); + } + } +} + +/* + * gui_init_colors: init GUI colors + */ + +void +gui_init_colors () +{ + int i, color; + + if (has_colors ()) + { + start_color (); + use_default_colors (); + + init_pair (COLOR_WIN_TITLE, + cfg_col_title & A_CHARTEXT, cfg_col_title_bg); + init_pair (COLOR_WIN_CHAT, + cfg_col_chat & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_TIME, + cfg_col_chat_time & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_TIME_SEP, + cfg_col_chat_time_sep & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_PREFIX1, + cfg_col_chat_prefix1 & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_PREFIX2, + cfg_col_chat_prefix2 & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_NICK, + cfg_col_chat_nick & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_HOST, + cfg_col_chat_host & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_CHANNEL, + cfg_col_chat_channel & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_DARK, + cfg_col_chat_dark & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_STATUS, + cfg_col_status & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_ACTIVE, + cfg_col_status_active & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_DATA_MSG, + cfg_col_status_data_msg & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_DATA_OTHER, + cfg_col_status_data_other & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_MORE, + cfg_col_status_more & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_INPUT, + cfg_col_input & A_CHARTEXT, cfg_col_input_bg); + init_pair (COLOR_WIN_INPUT_CHANNEL, + cfg_col_input_channel & A_CHARTEXT, cfg_col_input_bg); + init_pair (COLOR_WIN_INPUT_NICK, + cfg_col_input_nick & A_CHARTEXT, cfg_col_input_bg); + init_pair (COLOR_WIN_NICK, + cfg_col_nick & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_OP, + cfg_col_nick_op & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_HALFOP, + cfg_col_nick_halfop & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_VOICE, + cfg_col_nick_voice & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_SEP, + COLOR_BLACK & A_CHARTEXT, cfg_col_nick_sep); + init_pair (COLOR_WIN_NICK_SELF, + cfg_col_nick_self & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_PRIVATE, + cfg_col_nick_private & A_CHARTEXT, cfg_col_nick_bg); + + for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++) + { + gui_assign_color (&color, nicks_colors[i]); + init_pair (COLOR_WIN_NICK_FIRST + i, color & A_CHARTEXT, cfg_col_chat_bg); + color_attr[COLOR_WIN_NICK_FIRST + i - 1] = + (color & A_BOLD) ? A_BOLD : 0; + } + + color_attr[COLOR_WIN_TITLE - 1] = cfg_col_title & A_BOLD; + color_attr[COLOR_WIN_CHAT - 1] = cfg_col_chat & A_BOLD; + color_attr[COLOR_WIN_CHAT_TIME - 1] = cfg_col_chat_time & A_BOLD; + color_attr[COLOR_WIN_CHAT_TIME_SEP - 1] = cfg_col_chat_time_sep & A_BOLD; + color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD; + color_attr[COLOR_WIN_CHAT_PREFIX1 - 1] = cfg_col_chat_prefix1 & A_BOLD; + color_attr[COLOR_WIN_CHAT_PREFIX2 - 1] = cfg_col_chat_prefix2 & A_BOLD; + color_attr[COLOR_WIN_CHAT_NICK - 1] = cfg_col_chat_nick & A_BOLD; + color_attr[COLOR_WIN_CHAT_HOST - 1] = cfg_col_chat_host & A_BOLD; + color_attr[COLOR_WIN_CHAT_CHANNEL - 1] = cfg_col_chat_channel & A_BOLD; + color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD; + color_attr[COLOR_WIN_STATUS - 1] = cfg_col_status & A_BOLD; + color_attr[COLOR_WIN_STATUS_ACTIVE - 1] = cfg_col_status_active & A_BOLD; + color_attr[COLOR_WIN_STATUS_DATA_MSG - 1] = cfg_col_status_data_msg & A_BOLD; + color_attr[COLOR_WIN_STATUS_DATA_OTHER - 1] = cfg_col_status_data_other & A_BOLD; + color_attr[COLOR_WIN_STATUS_MORE - 1] = cfg_col_status_more & A_BOLD; + color_attr[COLOR_WIN_INPUT - 1] = cfg_col_input & A_BOLD; + color_attr[COLOR_WIN_INPUT_CHANNEL - 1] = cfg_col_input_channel & A_BOLD; + color_attr[COLOR_WIN_INPUT_NICK - 1] = cfg_col_input_nick & A_BOLD; + color_attr[COLOR_WIN_NICK - 1] = cfg_col_nick & A_BOLD; + color_attr[COLOR_WIN_NICK_OP - 1] = cfg_col_nick_op & A_BOLD; + color_attr[COLOR_WIN_NICK_HALFOP - 1] = cfg_col_nick_halfop & A_BOLD; + color_attr[COLOR_WIN_NICK_VOICE - 1] = cfg_col_nick_voice & A_BOLD; + color_attr[COLOR_WIN_NICK_SEP - 1] = 0; + color_attr[COLOR_WIN_NICK_SELF - 1] = cfg_col_nick_self & A_BOLD; + color_attr[COLOR_WIN_NICK_PRIVATE - 1] = cfg_col_nick_private & A_BOLD; + } +} + +/* + * gui_init: init GUI + */ + +void +gui_init () +{ + initscr (); + + curs_set (1); + keypad (stdscr, TRUE); + noecho (); + /*nonl();*/ + nodelay (stdscr, TRUE); + + gui_init_colors (); + + /* create windows */ + gui_current_window = gui_window_new (NULL, NULL /*0, 0, COLS, LINES*/); + + signal (SIGWINCH, gui_resize_term_handler); + + gui_ready = 1; +} + +/* + * gui_end: GUI end + */ + +void +gui_end () +{ + t_gui_window *ptr_win; + + /* delete all windows */ + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + if (ptr_win->win_title) + delwin (ptr_win->win_title); + if (ptr_win->win_chat) + delwin (ptr_win->win_chat); + if (ptr_win->win_nick) + delwin (ptr_win->win_nick); + if (ptr_win->win_status) + delwin (ptr_win->win_status); + if (ptr_win->win_input) + delwin (ptr_win->win_input); + /* TODO: free input buffer, lines, messages, completion */ + } + + /* end of ncurses output */ + refresh (); + endwin (); +} + +/* + * gui_new_line: create new line for a window + */ + +t_gui_line * +gui_new_line (t_gui_window *window) +{ + t_gui_line *new_line; + + if ((new_line = (t_gui_line *) malloc (sizeof (struct t_gui_line)))) + { + new_line->length = 0; + new_line->length_align = 0; + new_line->line_with_message = 0; + new_line->messages = NULL; + new_line->last_message = NULL; + if (!window->lines) + window->lines = new_line; + else + window->last_line->next_line = new_line; + new_line->prev_line = window->last_line; + new_line->next_line = NULL; + window->last_line = new_line; + } + else + { + wprintw (window->win_chat, + _("%s not enough memory for new line!\n"), + WEECHAT_ERROR); + return NULL; + } + return new_line; +} + +/* + * gui_new_message: create a new message for last line of window + */ + +t_gui_message * +gui_new_message (t_gui_window *window) +{ + t_gui_message *new_message; + + if ((new_message = (t_gui_message *) malloc (sizeof (struct t_gui_message)))) + { + if (!window->last_line->messages) + window->last_line->messages = new_message; + else + window->last_line->last_message->next_message = new_message; + new_message->prev_message = window->last_line->last_message; + new_message->next_message = NULL; + window->last_line->last_message = new_message; + } + else + { + log_printf ("not enough memory!\n"); + return NULL; + } + return new_message; +} + +/* + * gui_add_message: add a message to a window + */ + +void +gui_add_message (t_gui_window *window, int type, int color, char *message) +{ + char *pos; + int length; + + /* create new line if previous was ending by '\n' (or if 1st line) */ + if (window->line_complete) + { + window->line_complete = 0; + if (!gui_new_line (window)) + return; + } + if (!gui_new_message (window)) + return; + + window->last_line->last_message->type = type; + window->last_line->last_message->color = color; + pos = strchr (message, '\n'); + if (pos) + { + pos[0] = '\0'; + window->line_complete = 1; + } + window->last_line->last_message->message = strdup (message); + length = strlen (message); + window->last_line->length += length; + if (type == MSG_TYPE_MSG) + window->last_line->line_with_message = 1; + if ((type == MSG_TYPE_TIME) || (type == MSG_TYPE_NICK)) + window->last_line->length_align += length; + if (pos) + { + pos[0] = '\n'; + if ((window == gui_current_window) && (window->sub_lines == 0)) + { + if ((window->win_chat_cursor_y + + gui_get_line_num_splits (window, window->last_line)) > + (window->win_chat_height - 1)) + gui_redraw_window_chat (window); + else + gui_display_line (window, window->last_line, 1); + } + if ((window != gui_current_window) || (window->sub_lines > 0)) + { + window->unread_data = 1 + window->last_line->line_with_message; + gui_redraw_window_status (gui_current_window); + } + } +} + +/* + * gui_printf_color_type: display a message in a window + */ + +void +gui_printf_color_type (t_gui_window *window, int type, int color, char *message, ...) +{ + static char buffer[8192]; + char timestamp[16]; + char *pos; + va_list argptr; + static time_t seconds; + struct tm *date_tmp; + + if (gui_ready) + { + if (color == -1) + color = COLOR_WIN_CHAT; + + if (window == NULL) + { + if (SERVER(gui_current_window)) + window = SERVER(gui_current_window)->window; + else + window = gui_current_window; + } + + if (window == NULL) + { + log_printf ("gui_printf without window! this is a bug, please send to developers - thanks\n"); + return; + } + } + + va_start (argptr, message); + vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); + va_end (argptr); + + if (gui_ready) + { + seconds = time (NULL); + date_tmp = localtime (&seconds); + + pos = buffer - 1; + while (pos) + { + /* TODO: read timestamp format from config! */ + if ((!window->last_line) || (window->line_complete)) + { + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "["); + sprintf (timestamp, "%02d", date_tmp->tm_hour); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":"); + sprintf (timestamp, "%02d", date_tmp->tm_min); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":"); + sprintf (timestamp, "%02d", date_tmp->tm_sec); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "] "); + } + gui_add_message (window, type, color, pos+1); + pos = strchr (pos+1, '\n'); + if (pos) + if (pos[1] == '\0') + pos = NULL; + } + + wrefresh (window->win_chat); + refresh (); + } + else + printf ("%s", buffer); +} diff --git a/src/gui/curses/gui-input.c b/src/gui/curses/gui-input.c new file mode 100644 index 000000000..2717d3dab --- /dev/null +++ b/src/gui/curses/gui-input.c @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-input: user input functions for Curses GUI */ + + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <time.h> +#include <sys/socket.h> +#include <curses.h> + +#include "../../weechat.h" +#include "../gui.h" +#include "../../config.h" +#include "../../command.h" +#include "../../irc/irc.h" + + +/* + * gui_optimize_input_buffer_size: optimize input buffer size by adding + * or deleting data block (predefined size) + */ + +void +gui_optimize_input_buffer_size (t_gui_window *window) +{ + int optimal_size; + + optimal_size = ((window->input_buffer_size / INPUT_BUFFER_BLOCK_SIZE) * + INPUT_BUFFER_BLOCK_SIZE) + INPUT_BUFFER_BLOCK_SIZE; + if (window->input_buffer_alloc != optimal_size) + { + window->input_buffer_alloc = optimal_size; + window->input_buffer = realloc (window->input_buffer, optimal_size); + } +} + +/* + * gui_delete_previous_word: delete previous word + */ + +void +gui_delete_previous_word () +{ + int i, j, num_char_deleted, num_char_end; + + if (gui_current_window->input_buffer_pos > 0) + { + i = gui_current_window->input_buffer_pos - 1; + while ((i >= 0) && + (gui_current_window->input_buffer[i] == ' ')) + i--; + if (i >= 0) + { + while ((i >= 0) && + (gui_current_window->input_buffer[i] != ' ')) + i--; + if (i >= 0) + { + while ((i >= 0) && + (gui_current_window->input_buffer[i] == ' ')) + i--; + } + } + + if (i >= 0) + i++; + i++; + num_char_deleted = gui_current_window->input_buffer_pos - i; + num_char_end = gui_current_window->input_buffer_size - + gui_current_window->input_buffer_pos; + + for (j = 0; j < num_char_end; j++) + gui_current_window->input_buffer[i + j] = + gui_current_window->input_buffer[gui_current_window->input_buffer_pos + j]; + + gui_current_window->input_buffer_size -= num_char_deleted; + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + gui_current_window->input_buffer_pos = i; + gui_draw_window_input (gui_current_window); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->completion.position = -1; + } +} + +/* + * gui_move_previous_word: move to beginning of previous word + */ + +void +gui_move_previous_word () +{ + int i; + + if (gui_current_window->input_buffer_pos > 0) + { + i = gui_current_window->input_buffer_pos - 1; + while ((i >= 0) && + (gui_current_window->input_buffer[i] == ' ')) + i--; + if (i < 0) + gui_current_window->input_buffer_pos = 0; + else + { + while ((i >= 0) && + (gui_current_window->input_buffer[i] != ' ')) + i--; + gui_current_window->input_buffer_pos = i + 1; + } + gui_draw_window_input (gui_current_window); + } +} + +/* + * gui_move_next_word: move to the end of next + */ + +void +gui_move_next_word () +{ + int i; + + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size + 1) + { + i = gui_current_window->input_buffer_pos; + while ((i <= gui_current_window->input_buffer_size) && + (gui_current_window->input_buffer[i] == ' ')) + i++; + if (i > gui_current_window->input_buffer_size) + gui_current_window->input_buffer_pos = i - 1; + else + { + while ((i <= gui_current_window->input_buffer_size) && + (gui_current_window->input_buffer[i] != ' ')) + i++; + if (i > gui_current_window->input_buffer_size) + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + else + gui_current_window->input_buffer_pos = i; + + } + gui_draw_window_input (gui_current_window); + } +} + +/* + * gui_buffer_insert_string: insert a string into the input buffer + */ + +void +gui_buffer_insert_string (char *string, int pos) +{ + int i, start, end, length; + + length = strlen (string); + + /* increase buffer size */ + gui_current_window->input_buffer_size += length; + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + + /* move end of string to the right */ + start = pos + length; + end = gui_current_window->input_buffer_size - 1; + for (i = end; i >= start; i--) + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i - length]; + + /* insert new string */ + strncpy (gui_current_window->input_buffer + pos, string, length); +} + +/* + * gui_read_keyb: read keyboard line + */ + +void +gui_read_keyb () +{ + int key, i; + t_gui_window *ptr_window; + char new_char[2]; + + key = getch (); + if (key != ERR) + { + switch (key) + { + /* resize event: do nothing */ + case KEY_RESIZE: + gui_redraw_window (gui_current_window); + break; + case KEY_F(6): + gui_switch_to_previous_window (); + break; + /* next window */ + case KEY_F(7): + gui_switch_to_next_window (); + break; + /* cursor up */ + case KEY_UP: + if (gui_current_window->ptr_history) + { + gui_current_window->ptr_history = + gui_current_window->ptr_history->next_history; + if (!gui_current_window->ptr_history) + gui_current_window->ptr_history = + gui_current_window->history; + } + else + gui_current_window->ptr_history = + gui_current_window->history; + if (gui_current_window->ptr_history) + { + gui_current_window->input_buffer_size = + strlen (gui_current_window->ptr_history->text); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + strcpy (gui_current_window->input_buffer, + gui_current_window->ptr_history->text); + gui_draw_window_input (gui_current_window); + } + break; + /* cursor down */ + case KEY_DOWN: + if (gui_current_window->ptr_history) + { + gui_current_window->ptr_history = + gui_current_window->ptr_history->prev_history; + if (gui_current_window->ptr_history) + gui_current_window->input_buffer_size = + strlen (gui_current_window->ptr_history->text); + else + gui_current_window->input_buffer_size = 0; + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + if (gui_current_window->ptr_history) + strcpy (gui_current_window->input_buffer, + gui_current_window->ptr_history->text); + gui_draw_window_input (gui_current_window); + } + break; + /* cursor left */ + case KEY_LEFT: + if (gui_current_window->input_buffer_pos > 0) + { + gui_current_window->input_buffer_pos--; + gui_draw_window_input (gui_current_window); + } + break; + /* cursor right */ + case KEY_RIGHT: + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size) + { + gui_current_window->input_buffer_pos++; + gui_draw_window_input (gui_current_window); + } + break; + /* home key */ + case KEY_HOME: + if (gui_current_window->input_buffer_pos > 0) + { + gui_current_window->input_buffer_pos = 0; + gui_draw_window_input (gui_current_window); + } + break; + /* end key */ + case KEY_END: + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size) + { + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + gui_draw_window_input (gui_current_window); + } + break; + /* page up */ + case KEY_PPAGE: + gui_move_page_up (); + break; + /* page down */ + case KEY_NPAGE: + gui_move_page_down (); + break; + /* erase before cursor and move cursor to the left */ + case 127: + case KEY_BACKSPACE: + if (gui_current_window->input_buffer_pos > 0) + { + i = gui_current_window->input_buffer_pos-1; + while (gui_current_window->input_buffer[i]) + { + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i+1]; + i++; + } + gui_current_window->input_buffer_size--; + gui_current_window->input_buffer_pos--; + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + gui_draw_window_input (gui_current_window); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->completion.position = -1; + } + break; + /* Control + Backspace */ + case 0x08: + gui_delete_previous_word (); + break; + /* erase char under cursor */ + case KEY_DC: + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size) + { + i = gui_current_window->input_buffer_pos; + while (gui_current_window->input_buffer[i]) + { + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i+1]; + i++; + } + gui_current_window->input_buffer_size--; + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + gui_draw_window_input (gui_current_window); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->completion.position = -1; + } + break; + /* Tab : completion */ + case '\t': + completion_search (&(gui_current_window->completion), + CHANNEL(gui_current_window), + gui_current_window->input_buffer, + gui_current_window->input_buffer_size, + gui_current_window->input_buffer_pos); + if (gui_current_window->completion.word_found) + { + // replace word with new completed word into input buffer + gui_current_window->input_buffer_size += + gui_current_window->completion.diff_size; + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + + if (gui_current_window->completion.diff_size > 0) + { + for (i = gui_current_window->input_buffer_size - 1; + i >= gui_current_window->completion.position_replace + + (int)strlen (gui_current_window->completion.word_found); i--) + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i - + gui_current_window->completion.diff_size]; + } + else + { + for (i = gui_current_window->completion.position_replace + + strlen (gui_current_window->completion.word_found); + i < gui_current_window->input_buffer_size; i++) + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i - + gui_current_window->completion.diff_size]; + } + + strncpy (gui_current_window->input_buffer + gui_current_window->completion.position_replace, + gui_current_window->completion.word_found, + strlen (gui_current_window->completion.word_found)); + gui_current_window->input_buffer_pos = + gui_current_window->completion.position_replace + + strlen (gui_current_window->completion.word_found); + gui_current_window->completion.position = + gui_current_window->input_buffer_pos; + + /* add space or completor to the end of completion, if needed */ + if (gui_current_window->completion.base_word[0] == '/') + { + if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ') + gui_buffer_insert_string (" ", + gui_current_window->input_buffer_pos); + gui_current_window->completion.position++; + gui_current_window->input_buffer_pos++; + } + else + { + if (gui_current_window->completion.base_word_pos == 0) + { + if (strncmp (gui_current_window->input_buffer + gui_current_window->input_buffer_pos, + cfg_look_completor, strlen (cfg_look_completor)) != 0) + gui_buffer_insert_string (cfg_look_completor, + gui_current_window->input_buffer_pos); + gui_current_window->completion.position += strlen (cfg_look_completor); + gui_current_window->input_buffer_pos += strlen (cfg_look_completor); + if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ') + gui_buffer_insert_string (" ", + gui_current_window->input_buffer_pos); + gui_current_window->completion.position++; + gui_current_window->input_buffer_pos++; + } + } + gui_draw_window_input (gui_current_window); + } + break; + /* escape code (for control-key) */ + case KEY_ESCAPE: + if ((key = getch()) != ERR) + { + switch (key) + { + case KEY_LEFT: + gui_switch_to_previous_window (); + break; + case KEY_RIGHT: + gui_switch_to_next_window (); + break; + case 79: + /* TODO: replace 79 by constant name! */ + if (key == 79) + { + if ((key = getch()) != ERR) + { + switch (key) + { + /* Control + Right */ + case 99: + gui_move_next_word (); + break; + /* Control + Left */ + case 100: + gui_move_previous_word (); + break; + } + } + } + break; + } + } + break; + /* send command/message */ + case '\n': + if (gui_current_window->input_buffer_size > 0) + { + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + history_add (gui_current_window, gui_current_window->input_buffer); + gui_current_window->input_buffer_size = 0; + gui_current_window->input_buffer_pos = 0; + gui_current_window->input_buffer_1st_display = 0; + gui_current_window->completion.position = -1; + gui_current_window->ptr_history = NULL; + ptr_window = gui_current_window; + user_command (SERVER(gui_current_window), + gui_current_window->input_buffer); + if (ptr_window == gui_current_window) + gui_draw_window_input (ptr_window); + if (ptr_window) + ptr_window->input_buffer[0] = '\0'; + } + break; + /* other key => add to input buffer */ + default: + /*gui_printf (gui_current_window, + "[Debug] key pressed = %d, as octal: %o\n", key, key);*/ + new_char[0] = key; + new_char[1] = '\0'; + gui_buffer_insert_string (new_char, + gui_current_window->input_buffer_pos); + gui_current_window->input_buffer_pos++; + gui_draw_window_input (gui_current_window); + gui_current_window->completion.position = -1; + break; + } + } +} + +/* + * gui_main_loop: main loop for WeeChat with ncurses GUI + */ + +void +gui_main_loop () +{ + fd_set read_fd; + static struct timeval timeout; + t_irc_server *ptr_server; + + quit_weechat = 0; + while (!quit_weechat) + { + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + FD_ZERO (&read_fd); + FD_SET (STDIN_FILENO, &read_fd); + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->sock4 >= 0) + FD_SET (ptr_server->sock4, &read_fd); + } + if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout)) + { + if (FD_ISSET (STDIN_FILENO, &read_fd)) + { + gui_read_keyb (); + } + else + { + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if ((ptr_server->sock4 >= 0) && + (FD_ISSET (ptr_server->sock4, &read_fd))) + server_recv (ptr_server); + } + } + } + } +} diff --git a/src/gui/gtk/Makefile b/src/gui/gtk/Makefile new file mode 100644 index 000000000..6d2de6eba --- /dev/null +++ b/src/gui/gtk/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_GTK + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \ + ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h diff --git a/src/gui/gtk/gui-gtk.c b/src/gui/gtk/gui-gtk.c new file mode 100644 index 000000000..8e9aa5db3 --- /dev/null +++ b/src/gui/gtk/gui-gtk.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-gtk.c: Gtk+ GUI for WeeChat */ + + +/* ***** Gtk+ GUI for WeeChat, NOT developed! ***** */ diff --git a/src/gui/gtk/gui-gtk.h b/src/gui/gtk/gui-gtk.h new file mode 100644 index 000000000..889f75e60 --- /dev/null +++ b/src/gui/gtk/gui-gtk.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_GTK_H +#define __WEECHAT_GUI_GTK_H 1 + +#endif /* gui-gtk.h */ diff --git a/src/gui/gui.h b/src/gui/gui.h new file mode 100644 index 000000000..d8e3aca99 --- /dev/null +++ b/src/gui/gui.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_H +#define __WEECHAT_GUI_H 1 + +#ifdef WEE_CURSES +#include <curses.h> +#endif + +#include "../completion.h" +#include "../history.h" + +#ifdef WEE_CURSES +#define KEY_ESCAPE 27 +#endif + +#define INPUT_BUFFER_BLOCK_SIZE 256 + +#define NUM_COLORS 35 +#define COLOR_WIN_TITLE 1 +#define COLOR_WIN_CHAT 2 +#define COLOR_WIN_CHAT_TIME 3 +#define COLOR_WIN_CHAT_TIME_SEP 4 +#define COLOR_WIN_CHAT_PREFIX1 5 +#define COLOR_WIN_CHAT_PREFIX2 6 +#define COLOR_WIN_CHAT_NICK 7 +#define COLOR_WIN_CHAT_HOST 8 +#define COLOR_WIN_CHAT_CHANNEL 9 +#define COLOR_WIN_CHAT_DARK 10 +#define COLOR_WIN_STATUS 11 +#define COLOR_WIN_STATUS_ACTIVE 12 +#define COLOR_WIN_STATUS_DATA_MSG 13 +#define COLOR_WIN_STATUS_DATA_OTHER 14 +#define COLOR_WIN_STATUS_MORE 15 +#define COLOR_WIN_INPUT 16 +#define COLOR_WIN_INPUT_CHANNEL 17 +#define COLOR_WIN_INPUT_NICK 18 +#define COLOR_WIN_NICK 19 +#define COLOR_WIN_NICK_OP 20 +#define COLOR_WIN_NICK_HALFOP 21 +#define COLOR_WIN_NICK_VOICE 22 +#define COLOR_WIN_NICK_SEP 23 +#define COLOR_WIN_NICK_SELF 24 +#define COLOR_WIN_NICK_PRIVATE 25 +#define COLOR_WIN_NICK_FIRST 26 +#define COLOR_WIN_NICK_LAST 35 +#define COLOR_WIN_NICK_NUMBER (COLOR_WIN_NICK_LAST - COLOR_WIN_NICK_FIRST + 1) + +#define SERVER(window) ((t_irc_server *)(window->server)) +#define CHANNEL(window) ((t_irc_channel *)(window->channel)) + +#define WIN_IS_SERVER(window) (SERVER(window) && !CHANNEL(window)) +#define WIN_IS_CHANNEL(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_CHANNEL)) +#define WIN_IS_PRIVATE(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_PRIVATE)) + +#define MSG_TYPE_TIME 0 +#define MSG_TYPE_NICK 1 +#define MSG_TYPE_INFO 2 +#define MSG_TYPE_MSG 3 + +#define gui_printf_color(window, color, fmt, argz...) \ + gui_printf_color_type(window, MSG_TYPE_INFO, color, fmt, ##argz) + +#define gui_printf(window, fmt, argz...) \ + gui_printf_color_type(window, MSG_TYPE_INFO, -1, fmt, ##argz) + +typedef struct t_gui_message t_gui_message; + +struct t_gui_message +{ + int type; /* type of message (time, nick, other) */ + int color; /* color of message */ + char *message; /* message content */ + t_gui_message *prev_message; /* link to previous message for line */ + t_gui_message *next_message; /* link to next message for line */ +}; + +typedef struct t_gui_line t_gui_line; + +struct t_gui_line +{ + int length; /* length of the line (in char) */ + int length_align; /* alignment length (time or time/nick) */ + int line_with_message; /* line contains a message from a user? */ + t_gui_message *messages; /* messages for the line */ + t_gui_message *last_message; /* last message of the line */ + t_gui_line *prev_line; /* link to previous line */ + t_gui_line *next_line; /* link to next line */ +}; + +typedef struct t_gui_color t_gui_color; + +struct t_gui_color +{ + char *name; + int color; +}; + +typedef struct t_gui_window t_gui_window; + +struct t_gui_window +{ + /* server/channel */ + void *server; /* window's server */ + void *channel; /* window's channel */ + + /* global position & size */ + int win_x, win_y; /* position of window */ + int win_width, win_height; /* window geometry */ + + /* chat window settings */ + int win_chat_x, win_chat_y; /* chat window position */ + int win_chat_width; /* width of chat window */ + int win_chat_height; /* height of chat window */ + int win_chat_cursor_x; /* position of cursor in chat window */ + int win_chat_cursor_y; /* position of cursor in chat window */ + + /* nicklist window settings */ + int win_nick_x, win_nick_y; /* chat window position */ + int win_nick_width; /* width of chat window */ + int win_nick_height; /* height of chat window */ + + /* windows */ + #ifdef WEE_CURSES + WINDOW *win_title; /* title window */ + WINDOW *win_chat; /* chat window (exemple: channel) */ + WINDOW *win_nick; /* nick window */ + WINDOW *win_status; /* status window */ + WINDOW *win_input; /* input window */ + #endif + #ifdef WEE_GTK + /* TODO: declare Gtk+ window */ + #endif + #ifdef WEE_QT + /* TODO: declare Qt window */ + #endif + + /* chat content (lines, line is composed by many messages) */ + t_gui_line *lines; /* lines of chat window */ + t_gui_line *last_line; /* last line of chat window */ + int first_line_displayed; /* = 1 if first line is displayed */ + int sub_lines; /* if > 0 then do not display until end */ + int line_complete; /* current line complete ? (\n ending) */ + int unread_data; /* highlight windows with unread data */ + + /* inupt buffer */ + char *input_buffer; /* input buffer */ + int input_buffer_alloc; /* input buffer: allocated size in mem */ + int input_buffer_size; /* buffer size (user input length) */ + int input_buffer_pos; /* position into buffer */ + int input_buffer_1st_display; /* first char displayed on screen */ + + /* completion */ + t_completion completion; /* for cmds/nicks completion */ + + /* history */ + t_history *history; /* commands history */ + t_history *ptr_history; /* current command in history */ + + /* link to next window */ + t_gui_window *prev_window; /* link to previous window */ + t_gui_window *next_window; /* link to next window */ +}; + +/* variables */ + +extern int gui_ready; +extern t_gui_window *gui_windows; +extern t_gui_window *gui_current_window; + +/* prototypes */ + +extern int gui_assign_color (int *, char *); +extern int gui_get_color_by_name (char *); +extern char *gui_get_color_by_value (int); + +extern void gui_draw_window_title (t_gui_window *); +extern void gui_redraw_window_title (t_gui_window *); +extern void gui_draw_window_chat (t_gui_window *); +extern void gui_redraw_window_chat (t_gui_window *); +extern void gui_draw_window_nick (t_gui_window *); +extern void gui_redraw_window_nick (t_gui_window *); +extern void gui_draw_window_status (t_gui_window *); +extern void gui_redraw_window_status (t_gui_window *); +extern void gui_draw_window_input (t_gui_window *); +extern void gui_redraw_window_input (t_gui_window *); +extern void gui_redraw_window (t_gui_window *); + +extern void gui_window_clear (t_gui_window *); +extern void gui_window_clear_all (); + +extern void gui_switch_to_window (t_gui_window *); +extern void gui_switch_to_previous_window (); +extern void gui_switch_to_next_window (); + +extern void gui_move_page_up (); +extern void gui_move_page_down (); + +extern void gui_init (); +/* TODO: add coordinates and size */ +extern t_gui_window *gui_window_new (void *, void * /*int, int, int, int*/); +extern void gui_window_free (t_gui_window *); +extern void gui_end (); +extern void gui_printf_color_type (t_gui_window *, int, int, char *, ...); +extern void gui_display_nick (t_gui_window *, void *, int, int, int, int); + +extern void gui_main_loop (); + +#endif /* gui.h */ diff --git a/src/gui/qt/Makefile b/src/gui/qt/Makefile new file mode 100644 index 000000000..f0695d3a3 --- /dev/null +++ b/src/gui/qt/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_QT + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \ + ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h diff --git a/src/gui/qt/gui-qt.c b/src/gui/qt/gui-qt.c new file mode 100644 index 000000000..e8dffab14 --- /dev/null +++ b/src/gui/qt/gui-qt.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-qt.c: Qt GUI for WeeChat */ + + +/* ***** Qt GUI for WeeChat, NOT developed! ***** */ diff --git a/src/gui/qt/gui-qt.h b/src/gui/qt/gui-qt.h new file mode 100644 index 000000000..b07167d88 --- /dev/null +++ b/src/gui/qt/gui-qt.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_QT_H +#define __WEECHAT_GUI_QT_H 1 + +#endif /* gui-qt.h */ diff --git a/src/gui/text/Makefile b/src/gui/text/Makefile new file mode 100644 index 000000000..538d760a3 --- /dev/null +++ b/src/gui/text/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_TEXT + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \ + ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h diff --git a/src/gui/text/gui-text.c b/src/gui/text/gui-text.c new file mode 100644 index 000000000..7121e11e5 --- /dev/null +++ b/src/gui/text/gui-text.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-text.c: text GUI - display functions */ + + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> + +#include "weechat.h" +#include "gui-text.h" +#include "command.h" +#include "irc.h" + + +/* + * gui_init: init GUI + */ + +void +gui_init () +{ +} + + +/* + * gui_init_irc_window: allocates a window for a channel or server + */ + +void +gui_init_irc_window (t_irc_window * window) +{ + /* no window in text GUI */ + window->text = NULL; + window->window = NULL; +} + + +/* + * gui_free_irc_window: free a GUI window + */ + +void +gui_free_irc_window (t_irc_window * window) +{ + /* no window in text GUI */ +} + + +/* + * gui_end: GUI end + */ + +void +gui_end () +{ +} + + +/* + * read_keyb: read keyboard line + */ + +void +read_keyb () +{ + int num_read; + static char buffer[4096]; + static int pos_buffer = 0; + char buffer_tmp[1024]; + int pos_buffer_tmp; + + num_read = read (STDIN_FILENO, buffer_tmp, sizeof (buffer_tmp) - 1); + pos_buffer_tmp = 0; + while (pos_buffer_tmp < num_read) + { + switch (buffer_tmp[pos_buffer_tmp]) + { + case '\r': + break; + case '\n': + buffer[pos_buffer] = '\0'; + pos_buffer = 0; + user_command (buffer); + break; + default: + buffer[pos_buffer] = buffer_tmp[pos_buffer_tmp]; + if (pos_buffer < (int) (sizeof (buffer) - 2)) + pos_buffer++; + } + pos_buffer_tmp++; + } +} + + +/* + * gui_main_loop: main loop for WeeChat with text GUI + */ + +void +gui_main_loop () +{ + struct timeval timeout; + fd_set read_fd; + t_irc_server *ptr_server; + + quit_weechat = 0; + while (!quit_weechat) + { + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + FD_ZERO (&read_fd); + FD_SET (STDIN_FILENO, &read_fd); + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + FD_SET (ptr_server->sock4, &read_fd); + } + select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout); + if (FD_ISSET (STDIN_FILENO, &read_fd)) + { + read_keyb (); + } + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (FD_ISSET (ptr_server->sock4, &read_fd)) + recv_from_server (ptr_server); + } + } +} + + +/* + * gui_display_message: display a message on the screen + */ + +void +gui_display_message (char *message) +{ + printf ("%s\n", message); +} diff --git a/src/gui/text/gui-text.h b/src/gui/text/gui-text.h new file mode 100644 index 000000000..2e62d1a55 --- /dev/null +++ b/src/gui/text/gui-text.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_TEXT_H +#define __WEECHAT_GUI_TEXT_H 1 + +#endif /* gui-text.h */ diff --git a/src/history.c b/src/history.c new file mode 100644 index 000000000..9e13e6935 --- /dev/null +++ b/src/history.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* history.c: memorize and call again commands or text */ + + +#include <stdlib.h> +#include <string.h> + +#include "weechat.h" +#include "history.h" +#include "gui/gui.h" + + +t_history *history_general = NULL; +t_history *history_general_ptr = NULL; + + +/* + * history_add: add a text/command to history + */ + +void +history_add (void *window, char *string) +{ + t_history *new_history; + + new_history = (t_history *)malloc (sizeof (t_history)); + if (new_history) + { + new_history->text = strdup (string); + + /* add history to general history */ + if (history_general) + history_general->prev_history = new_history; + new_history->next_history = history_general; + new_history->prev_history = NULL; + history_general = new_history; + + /* add history to local history */ + if (((t_gui_window *)(window))->history) + ((t_gui_window *)(window))->history->prev_history = new_history; + new_history->next_history = ((t_gui_window *)(window))->history; + new_history->prev_history = NULL; + ((t_gui_window *)window)->history = new_history; + } +} diff --git a/src/history.h b/src/history.h new file mode 100644 index 000000000..946f2e792 --- /dev/null +++ b/src/history.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_HISTORY_H +#define __WEECHAT_HISTORY_H 1 + +typedef struct t_history t_history; + +struct t_history +{ + char *text; /* text or command (as entered by user) */ + t_history *next_history; /* link to next text/command */ + t_history *prev_history; /* link to previous text/command */ +}; + +extern void history_add (void *, char *); + +#endif /* history.h */ diff --git a/src/irc/Makefile b/src/irc/Makefile new file mode 100644 index 000000000..d22617bda --- /dev/null +++ b/src/irc/Makefile @@ -0,0 +1,44 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=irc.a +OBJS=irc-commands.o irc-display.o irc-server.o irc-channel.o irc-nick.o +DEFINES=WEE_CURSES + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +irc-channel.o: irc-channel.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h +irc-commands.o: irc-commands.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h ../command.h ../irc/irc.h ../config.h +irc-display.o: irc-display.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h +irc-nick.o: irc-nick.c ../weechat.h irc.h ../gui/gui.h ../completion.h \ + ../history.h +irc-server.o: irc-server.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h diff --git a/src/irc/irc-channel.c b/src/irc/irc-channel.c new file mode 100644 index 000000000..bdad12265 --- /dev/null +++ b/src/irc/irc-channel.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-channel.c: manages a chat (channel or private chat) */ + + +#include <stdlib.h> +#include <string.h> + +#include "../weechat.h" +#include "irc.h" + + +t_irc_channel *current_channel = NULL; + + +/* + * channel_new: allocate a new channel for a server and add it to the server queue + */ + +t_irc_channel * +channel_new (t_irc_server *server, int channel_type, char *channel_name) +{ + t_irc_channel *new_channel; + + #if DEBUG >= 1 + log_printf ("joining channel %s\n", channel_name); + #endif + + /* alloc memory for new channel */ + if ((new_channel = (t_irc_channel *) malloc (sizeof (t_irc_channel))) == NULL) + { + fprintf (stderr, _("%s cannot allocate new channel"), WEECHAT_ERROR); + return NULL; + } + + /* initialize new channel */ + new_channel->type = channel_type; + new_channel->name = strdup (channel_name); + new_channel->topic = NULL; + new_channel->nicks = NULL; + new_channel->last_nick = NULL; + + /* add new channel to queue */ + new_channel->prev_channel = server->last_channel; + new_channel->next_channel = NULL; + if (server->channels) + server->last_channel->next_channel = new_channel; + else + server->channels = new_channel; + server->last_channel = new_channel; + + gui_window_new (server, new_channel); + + /* all is ok, return address of new channel */ + return new_channel; +} + +/* + * channel_free: free a channel and remove it from channels queue + */ + +void +channel_free (t_irc_server *server, t_irc_channel *channel) +{ + t_irc_channel *new_channels; + + /* remove channel from queue */ + if (server->last_channel == channel) + server->last_channel = channel->prev_channel; + if (channel->prev_channel) + { + (channel->prev_channel)->next_channel = channel->next_channel; + new_channels = server->channels; + } + else + new_channels = channel->next_channel; + + if (channel->next_channel) + (channel->next_channel)->prev_channel = channel->prev_channel; + + /* free data */ + if (channel->name) + free (channel->name); + if (channel->topic) + free (channel->topic); + nick_free_all (channel); + free (channel); + server->channels = new_channels; +} + +/* + * channel_free_all: free all allocated channels + */ + +void +channel_free_all (t_irc_server *server) +{ + /* remove all channels for the server */ + while (server->channels) + channel_free (server, server->channels); +} + +/* + * channel_search: returns pointer on a channel with name + */ + +t_irc_channel * +channel_search (t_irc_server *server, char *channel_name) +{ + t_irc_channel *ptr_channel; + + for (ptr_channel = server->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + if (strcasecmp (ptr_channel->name, channel_name) == 0) + return ptr_channel; + } + return NULL; +} + +/* + * string_is_channel: returns 1 if string is channel + */ + +int +string_is_channel (char *string) +{ + char first_char[2]; + + first_char[0] = string[0]; + first_char[1] = '\0'; + return (strpbrk (first_char, CHANNEL_PREFIX)) ? 1 : 0; +} diff --git a/src/irc/irc-commands.c b/src/irc/irc-commands.c new file mode 100644 index 000000000..2b4cf33ec --- /dev/null +++ b/src/irc/irc-commands.c @@ -0,0 +1,3064 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-commands.c: implementation of IRC commands, according to + RFC 1459,2810,2811,2812 */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "../weechat.h" +#include "irc.h" +#include "../command.h" +#include "../config.h" +#include "../gui/gui.h" + + +t_irc_command irc_commands[] = +{ { "away", N_("toggle away status"), + N_("[-all] [message]"), + N_("-all: toggle away status on all connected servers\n" + "message: message for away (if no message is given, away status is removed)"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_away, NULL }, + { "ctcp", N_("send a ctcp message"), + N_("nickname type"), + N_("nickname: user to send ctcp to\ntype: \"action\" or \"version\""), + 2, MAX_ARGS, 1, NULL, irc_cmd_send_ctcp, NULL }, + { "deop", N_("removes channel operator status from nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_deop, NULL, NULL }, + { "devoice", N_("removes voice from nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_devoice, NULL, NULL }, + { "error", N_("error received from IRC server"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_error }, + { "invite", N_("invite a nick on a channel"), + N_("nickname channel"), + N_("nickname: nick to invite\nchannel: channel to invite"), + 2, 2, 1, NULL, irc_cmd_send_invite, NULL }, + { "join", N_("join a channel"), + N_("channel[,channel] [key[,key]]"), + N_("channel: channel name to join\nkey: key to join the channel"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_join, irc_cmd_recv_join }, + { "kick", N_("forcibly remove a user from a channel"), + N_("[channel] nickname [comment]"), + N_("channel: channel where user is\nnickname: nickname to kick\ncomment: comment for kick"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_kick, irc_cmd_recv_kick }, + { "kill", N_("close client-server connection"), + N_("nickname comment"), + N_("nickname: nickname\ncomment: comment for kill"), + 2, MAX_ARGS, 1, NULL, irc_cmd_send_kill, NULL }, + { "list", N_("list channels and their topic"), + N_("[channel[,channel] [server]]"), + N_("channel: channel to list\nserver: server name"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_list, NULL }, + { "me", N_("send a ctcp action to the current channel"), + N_("message"), + N_("message: message to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_me, NULL }, + { "mode", N_("change channel or user mode"), + N_("{ channel {[+|-]|o|p|s|i|t|n|b|v} [limit] [user] [ban mask] } | " + "{ nickname {[+|-]|i|w|s|o}"), + N_("channel modes:\n" + " channel: channel name to modify\n" + " o: give/take channel operator privileges\n" + " p: private channel flag\n" + " s: secret channel flag\n" + " i: invite-only channel flag\n" + " t: topic settable by channel operator only flag\n" + " n: no messages to channel from clients on the outside\n" + " m: moderated channel\n" + " l: set the user limit to channel\n" + " b: set a ban mask to keep users out\n" + " v: give/take the ability to speak on a moderated channel\n" + " k: set a channel key (password)\n" + "user modes:\n" + " nickname: nickname to modify\n" + " i: mark a user as invisible\n" + " s: mark a user for receive server notices\n" + " w: user receives wallops\n" + " o: operator flag\n"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_mode, irc_cmd_recv_mode }, + { "msg", N_("send message to a nick or channel"), + N_("receiver[,receiver] text"), N_("receiver: nick or channel (may be mask)" + "\ntext: text to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_msg, NULL }, + { "names", N_("list nicknames on channels"), + N_("[channel[,channel]]"), N_("channel: channel name"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_names, NULL }, + { "nick", N_("change current nickname"), + N_("nickname"), N_("nickname: new nickname for current IRC server"), + 1, 1, 1, irc_cmd_send_nick, NULL, irc_cmd_recv_nick }, + { "notice", N_("send notice message to user"), + N_("nickname text"), N_("nickname: user to send notice to\ntext: text to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_notice, irc_cmd_recv_notice }, + { "op", N_("gives channel operator status to nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_op, NULL, NULL }, + { "oper", N_("get operator privileges"), + N_("user password"), + N_("user/password: used to get privileges on current IRC server"), + 2, 2, 1, irc_cmd_send_oper, NULL, NULL }, + { "part", N_("leave a channel"), + N_("[channel[,channel]]"), N_("channel: channel name to join"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_part, irc_cmd_recv_part }, + { "ping", N_("ping server"), + N_("server1 [server2]"), + N_("server1: server to ping\nserver2: forward ping to this server"), + 1, 2, 1, irc_cmd_send_ping, NULL, irc_cmd_recv_ping }, + { "pong", N_("answer to a ping message"), + N_("daemon [daemon2]"), N_("daemon: daemon who has responded to Ping message\n" + "daemon2: forward message to this daemon"), + 1, 2, 1, irc_cmd_send_pong, NULL, NULL }, + { "privmsg", N_("message received"), + "", "", + 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_privmsg }, + { "quit", N_("close all connections & quit " WEECHAT_NAME), + N_("[quit_message]"), + N_("quit_message: quit message (displayed to other users)"), + 0, MAX_ARGS, 0, NULL, irc_cmd_send_quit, irc_cmd_recv_quit }, + { "quote", N_("send raw data to server without parsing"), + N_("data"), + N_("data: raw data to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_quote, NULL }, + { "topic", N_("get/set channel topic"), + N_("[channel] [topic]"), N_("channel: channel name\ntopic: new topic for channel " + "(if topic is \"-delete\" then topic is deleted)"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_topic, irc_cmd_recv_topic }, + { "version", N_("gives the version info of nick or server (current or specified)"), + N_("[server | nickname]"), N_("server: server name\nnickname: nickname"), + 0, 1, 1, NULL, irc_cmd_send_version, NULL }, + { "voice", N_("gives voice to nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_voice, NULL, NULL }, + { "whois", N_("query information about user(s)"), + N_("[server] nickname[,nickname]"), N_("server: server name\n" + "nickname: nickname (may be a mask)"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_whois, NULL }, + { "001", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "002", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "003", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "004", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_004 }, + { "005", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "250", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "251", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "252", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "253", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "254", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "255", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "256", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "257", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "258", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "259", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "260", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "261", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "262", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "263", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "264", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "265", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "266", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "267", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "268", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "269", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "301", N_("away message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_301 }, + { "305", N_("unaway"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply }, + { "306", N_("now away"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply }, + { "311", N_("whois (user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_311 }, + { "312", N_("whois (server)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_312 }, + { "313", N_("whois (operator)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_313 }, + { "317", N_("whois (idle)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_317 }, + { "318", N_("whois (end)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_318 }, + { "319", N_("whois (channels)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_319 }, + { "320", N_("whois (identified user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_320 }, + { "321", N_("/list start"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_321 }, + { "322", N_("channel (for /list)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_322 }, + { "323", N_("/list end"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_323 }, + { "331", N_("no topic for channel"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_331 }, + { "332", N_("topic of channel"), + N_("channel :topic"), + N_("channel: name of channel\ntopic: topic of the channel"), + 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_332 }, + { "333", N_("infos about topic (nick & date changed)"), + "", "", + 0, 0, 1, NULL, NULL, irc_cmd_recv_333 }, + { "351", N_("server version"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_351 }, + { "353", N_("list of nicks on channel"), + N_("channel :[[@|+]nick ...]"), + N_("channel: name of channel\nnick: nick on the channel"), + 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_353 }, + { "366", N_("end of /names list"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_366 }, + { "371", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "372", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "373", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "374", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "375", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "376", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "401", N_("no such nick/channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "402", N_("no such server"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "403", N_("no such channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "404", N_("cannot send to channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "405", N_("too many channels"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "406", N_("was no such nick"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "406", N_("was no such nick"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "407", N_("was no such nick"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "409", N_("no origin"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "411", N_("no recipient"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "412", N_("no text to send"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "413", N_("no toplevel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "414", N_("wilcard in toplevel domain"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "421", N_("unknown command"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "422", N_("MOTD is missing"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "423", N_("no administrative info"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "424", N_("file error"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "431", N_("no nickname given"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "432", N_("erroneus nickname"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "433", N_("nickname already in use"), + "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_433 }, + { "436", N_("nickname collision"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "441", N_("user not in channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "442", N_("not on channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "443", N_("user already on channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "444", N_("user not logged in"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "445", N_("summon has been disabled"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "446", N_("users has been disabled"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "451", N_("you are not registered"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "461", N_("not enough parameters"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "462", N_("you may not register"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "463", N_("your host isn't among the privileged"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "464", N_("password incorrect"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "465", N_("you are banned from this server"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "467", N_("channel key already set"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "471", N_("channel is already full"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "472", N_("unknown mode char to me"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "473", N_("cannot join channel (invite only)"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "474", N_("cannot join channel (banned from channel)"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "475", N_("cannot join channel (bad channel key)"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "481", N_("you're not an IRC operator"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "482", N_("you're not channel operator"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "483", N_("you can't kill a server!"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "491", N_("no O-lines for your host"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "501", N_("unknown mode flag"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "502", N_("can't change mode for other users"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { NULL, NULL, NULL, NULL, 0, 0, 1, NULL, NULL, NULL } +}; + + +/* + * irc_recv_command: executes action when receiving IRC command + * returns: 0 = all ok, command executed + * -1 = command failed + * -2 = no command to execute + * -3 = command not found + */ + +int +irc_recv_command (t_irc_server *server, + char *host, char *command, char *arguments) +{ + int i, cmd_found; + + #if DEBUG >= 2 + gui_printf (server->window, "recv_irc_command: cmd=%s args=%s\n", + command, arguments); + #endif + + if (command == NULL) + return -2; + + /* looks for irc command */ + cmd_found = -1; + for (i = 0; irc_commands[i].command_name; i++) + if (strcasecmp (irc_commands[i].command_name, command) == 0) + { + cmd_found = i; + break; + } + + /* command not found */ + if (cmd_found < 0) + return -3; + + if (irc_commands[i].recv_function != NULL) + return (int) (irc_commands[i].recv_function) (server, host, arguments); + + return 0; +} + +/* + * irc_login: login to irc server + */ + +void +irc_login (t_irc_server *server) +{ + char hostname[128]; + + if ((server->password) && (server->password[0])) + server_sendf (server, "PASS %s\r\n", server->password); + + gethostname (hostname, sizeof (hostname) - 1); + hostname[sizeof (hostname) - 1] = '\0'; + if (!hostname[0]) + strcpy (hostname, _("unknown")); + gui_printf (server->window, + _(WEECHAT_NAME ": using local hostname \"%s\"\n"), + hostname); + server_sendf (server, + "NICK %s\r\n" + "USER %s %s %s :%s\r\n", + server->nick, server->username, hostname, "servername", + server->realname); +} + +/* + * irc_cmd_send_away: toggle away status + */ + +int +irc_cmd_send_away (t_irc_server *server, char *arguments) +{ + char *pos; + t_irc_server *ptr_server; + + if (arguments && (strncmp (arguments, "-all", 4) == 0)) + { + pos = arguments + 4; + while (pos[0] == ' ') + pos++; + if (!pos[0]) + pos = NULL; + + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (server->is_connected) + { + if (pos) + server_sendf (ptr_server, "AWAY :%s\r\n", pos); + else + server_sendf (ptr_server, "AWAY\r\n"); + } + } + } + else + { + if (arguments) + server_sendf (server, "AWAY :%s\r\n", arguments); + else + server_sendf (server, "AWAY\r\n"); + } + return 0; +} + +/* + * irc_cmd_send_ctcp: send a ctcp message + */ + +int +irc_cmd_send_ctcp (t_irc_server *server, char *arguments) +{ + char *pos, *pos2; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + pos2 = strchr (pos, ' '); + if (pos2) + { + pos2[0] = '\0'; + pos2++; + while (pos2[0] == ' ') + pos2++; + } + else + pos2 = NULL; + + if (strcasecmp (pos, "version") == 0) + { + if (pos2) + server_sendf (server, "PRIVMSG %s :\01VERSION %s\01\r\n", + arguments, pos2); + else + server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n", + arguments); + } + if (strcasecmp (pos, "action") == 0) + { + if (pos2) + server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n", + arguments, pos2); + else + server_sendf (server, "PRIVMSG %s :\01ACTION\01\r\n", + arguments); + } + + } + return 0; +} + +/* + * irc_cmd_send_deop: remove operator privileges from nickname(s) + */ + +int +irc_cmd_send_deop (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s -o %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + gui_printf (server->window, + _("%s \"deop\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return 0; +} + +/* + * irc_cmd_send_devoice: remove voice from nickname(s) + */ + +int +irc_cmd_send_devoice (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s -v %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + { + gui_printf (server->window, + _("%s \"devoice\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_send_invite: invite a nick on a channel + */ + +int +irc_cmd_send_invite (t_irc_server *server, char *arguments) +{ + server_sendf (server, "INVITE %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_join: join a new channel + */ + +int +irc_cmd_send_join (t_irc_server *server, char *arguments) +{ + server_sendf (server, "JOIN %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_kick: forcibly remove a user from a channel + */ + +int +irc_cmd_send_kick (t_irc_server *server, char *arguments) +{ + if (string_is_channel (arguments)) + server_sendf (server, "KICK %s\r\n", arguments); + else + { + if (WIN_IS_CHANNEL (gui_current_window)) + { + server_sendf (server, + "KICK %s %s\r\n", + CHANNEL(gui_current_window)->name, arguments); + } + else + { + gui_printf (server->window, + _("%s \"kick\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + } + return 0; +} + +/* + * irc_cmd_send_kill: close client-server connection + */ + +int +irc_cmd_send_kill (t_irc_server *server, char *arguments) +{ + server_sendf (server, "KILL %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_list: close client-server connection + */ + +int +irc_cmd_send_list (t_irc_server *server, char *arguments) +{ + if (arguments) + server_sendf (server, "LIST %s\r\n", arguments); + else + server_sendf (server, "LIST\r\n"); + return 0; +} + +/* + * irc_cmd_send_me: send a ctcp action to the current channel + */ + +int +irc_cmd_send_me (t_irc_server *server, char *arguments) +{ + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"me\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n", + CHANNEL(gui_current_window)->name, arguments); + irc_display_prefix (gui_current_window, PREFIX_ACTION_ME); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_NICK, "%s", server->nick); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, " %s\n", arguments); + return 0; +} + +/* + * irc_cmd_send_mode: change mode for channel/nickname + */ + +int +irc_cmd_send_mode (t_irc_server *server, char *arguments) +{ + server_sendf (server, "MODE %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_msg: send a message to a nick or channel + */ + +int +irc_cmd_send_msg (t_irc_server *server, char *arguments) +{ + char *pos, *pos_comma; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + + while (arguments && arguments[0]) + { + pos_comma = strchr (arguments, ','); + if (pos_comma) + { + pos_comma[0] = '\0'; + pos_comma++; + } + if (string_is_channel (arguments)) + { + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + ptr_nick = nick_search (ptr_channel, server->nick); + if (ptr_nick) + { + irc_display_nick (ptr_channel->window, ptr_nick, + MSG_TYPE_NICK, 1, 1, 0); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + } + else + gui_printf (server->window, + _("%s nick not found for \"privmsg\" command\n"), + WEECHAT_ERROR); + } + server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos); + } + else + { + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + { + ptr_channel = channel_new (server, CHAT_PRIVATE, arguments); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s cannot create new private window \"%s\"\n"), + WEECHAT_ERROR, + arguments); + return -1; + } + gui_redraw_window_title (ptr_channel->window); + } + + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "<"); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_NICK_SELF, + "%s", server->nick); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "> "); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos); + } + arguments = pos_comma; + } + } + else + gui_printf (server->window, + _("%s wrong number of args for \"privmsg\" command\n"), + WEECHAT_ERROR); + return 0; +} + +/* + * irc_cmd_send_names: list nicknames on channels + */ + +int +irc_cmd_send_names (t_irc_server *server, char *arguments) +{ + if (arguments) + server_sendf (server, "NAMES %s\r\n", arguments); + else + { + if (!WIN_IS_CHANNEL(gui_current_window)) + { + gui_printf (server->window, + _("%s \"names\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + else + server_sendf (server, "NAMES %s\r\n", + CHANNEL(gui_current_window)->name); + } + return 0; +} + +/* + * irc_cmd_send_nick: change nickname + */ + +int +irc_cmd_send_nick (t_irc_server *server, int argc, char **argv) +{ + if (argc != 1) + return -1; + server_sendf (server, "NICK %s\r\n", argv[0]); + return 0; +} + +/* + * irc_cmd_send_notice: send notice message + */ + +int +irc_cmd_send_notice (t_irc_server *server, char *arguments) +{ + server_sendf (server, "NOTICE %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_op: give operator privileges to nickname(s) + */ + +int +irc_cmd_send_op (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s +o %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + { + gui_printf (server->window, + _("%s \"op\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_send_oper: get oper privileges + */ + +int +irc_cmd_send_oper (t_irc_server *server, int argc, char **argv) +{ + if (argc != 2) + return -1; + server_sendf (server, "OPER %s %s\r\n", argv[0], argv[1]); + return 0; +} + +/* + * irc_cmd_send_part: leave a channel or close a private window + */ + +int +irc_cmd_send_part (t_irc_server *server, char *arguments) +{ + char *channel_name, *pos_args; + t_irc_channel *ptr_channel; + + if (arguments) + { + if (string_is_channel (arguments)) + { + channel_name = arguments; + pos_args = strchr (arguments, ' '); + if (pos_args) + { + pos_args[0] = '\0'; + pos_args++; + while (pos_args[0] == ' ') + pos_args++; + } + } + else + { + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"part\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + channel_name = CHANNEL(gui_current_window)->name; + pos_args = arguments; + } + } + else + { + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"part\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + if (WIN_IS_PRIVATE(gui_current_window)) + { + ptr_channel = CHANNEL(gui_current_window); + gui_window_free (ptr_channel->window); + channel_free (server, ptr_channel); + gui_redraw_window_status (gui_current_window); + gui_redraw_window_input (gui_current_window); + return 0; + } + channel_name = CHANNEL(gui_current_window)->name; + pos_args = NULL; + } + + if (pos_args) + server_sendf (server, "PART %s :%s\r\n", channel_name, pos_args); + else + server_sendf (server, "PART %s\r\n", channel_name); + return 0; +} + +/* + * irc_cmd_send_ping: ping a server + */ + +int +irc_cmd_send_ping (t_irc_server *server, int argc, char **argv) +{ + if (argc == 1) + server_sendf (server, "PING %s\r\n", argv[0]); + if (argc == 2) + server_sendf (server, "PING %s %s\r\n", argv[0], + argv[1]); + return 0; +} + +/* + * irc_cmd_send_pong: send pong answer to a daemon + */ + +int +irc_cmd_send_pong (t_irc_server *server, int argc, char **argv) +{ + if (argc == 1) + server_sendf (server, "PONG %s\r\n", argv[0]); + if (argc == 2) + server_sendf (server, "PONG %s %s\r\n", argv[0], + argv[1]); + return 0; +} + +/* + * irc_cmd_send_quit: disconnect from all servers and quit WeeChat + */ + +int +irc_cmd_send_quit (t_irc_server *server, char *arguments) +{ + if (server && server->is_connected) + { + if (arguments) + server_sendf (server, "QUIT :%s\r\n", arguments); + else + server_sendf (server, "QUIT\r\n"); + } + quit_weechat = 1; + return 0; +} + +/* + * irc_cmd_send_quote: send raw data to server + */ + +int +irc_cmd_send_quote (t_irc_server *server, char *arguments) +{ + server_sendf (server, "%s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_topic: get/set topic for a channel + */ + +int +irc_cmd_send_topic (t_irc_server *server, char *arguments) +{ + char *channel_name, *new_topic, *pos; + + channel_name = NULL; + new_topic = NULL; + + if (arguments) + { + if (string_is_channel (arguments)) + { + channel_name = arguments; + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + new_topic = (pos[0]) ? pos : NULL; + } + } + else + new_topic = arguments; + } + + /* look for current channel if not specified */ + if (!channel_name) + { + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"topic\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + channel_name = CHANNEL(gui_current_window)->name; + } + + if (new_topic) + { + if (strcmp (new_topic, "-delete") == 0) + server_sendf (server, "TOPIC %s :\r\n", channel_name); + else + server_sendf (server, "TOPIC %s :%s\r\n", channel_name, new_topic); + } + else + server_sendf (server, "TOPIC %s\r\n", channel_name); + return 0; +} + +/* + * irc_cmd_send_version: gives the version info of nick or server (current or specified) + */ + +int +irc_cmd_send_version (t_irc_server *server, char *arguments) +{ + if (arguments) + { + if (WIN_IS_CHANNEL(gui_current_window) && + nick_search (CHANNEL(gui_current_window), arguments)) + server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n", + arguments); + else + server_sendf (server, "VERSION %s\r\n", + arguments); + } + else + { + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s, compiled on %s %s\n", + WEECHAT_NAME_AND_VERSION, + __DATE__, __TIME__); + server_sendf (server, "VERSION\r\n"); + } + return 0; +} + +/* + * irc_cmd_send_voice: give voice to nickname(s) + */ + +int +irc_cmd_send_voice (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s +v %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + { + gui_printf (server->window, + _("%s \"voice\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_send_whois: query information about user(s) + */ + +int +irc_cmd_send_whois (t_irc_server *server, char *arguments) +{ + server_sendf (server, "WHOIS %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_error: error received from server + */ + +int +irc_cmd_recv_error (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + int first; + + /* make gcc happy */ + (void) server; + (void) host; + + if (strncmp (arguments, "Closing Link", 12) == 0) + { + server_disconnect (server); + return 0; + } + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_ERROR); + first = 1; + + while (pos && pos[0]) + { + pos2 = strchr (pos, ' '); + if ((pos[0] == ':') || (!pos2)) + { + if (pos[0] == ':') + pos++; + gui_printf_color (server->window, + COLOR_WIN_CHAT, + "%s%s\n", (first) ? "" : ": ", pos); + pos = NULL; + } + else + { + pos2[0] = '\0'; + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s%s", + (first) ? "" : " ", pos); + first = 0; + pos = pos2 + 1; + } + } + return 0; +} + +/* + * irc_cmd_recv_join: 'join' message received + */ + +int +irc_cmd_recv_join (t_irc_server *server, char *host, char *arguments) +{ + t_irc_channel *ptr_channel; + char *pos; + + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + { + ptr_channel = channel_new (server, CHAT_CHANNEL, arguments); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s cannot create new channel \"%s\"\n"), + WEECHAT_ERROR, arguments); + return -1; + } + } + + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + irc_display_prefix (ptr_channel->window, PREFIX_JOIN); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK, + "%s ", host); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + "("); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_HOST, + "%s", pos + 1); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + ")"); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _(" has joined ")); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s\n", arguments); + nick_new (ptr_channel, host, 0, 0, 0); + gui_redraw_window_nick (gui_current_window); + return 0; +} + +/* + * irc_cmd_recv_kick: 'kick' message received + */ + +int +irc_cmd_recv_kick (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos_nick, *pos_comment; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + pos_nick[0] = '\0'; + pos_nick++; + while (pos_nick[0] == ' ') + pos_nick++; + + pos_comment = strchr (pos_nick, ' '); + if (pos_comment) + { + pos_comment[0] = '\0'; + pos_comment++; + while (pos_comment[0] == ' ') + pos_comment++; + if (pos_comment[0] == ':') + pos_comment++; + } + + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s channel not found for \"kick\" command\n"), + WEECHAT_ERROR); + return -1; + } + + irc_display_prefix (ptr_channel->window, PREFIX_PART); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK, + "%s", host); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _(" has kicked ")); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK, + "%s", pos_nick); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _(" from ")); + if (pos_comment) + { + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s ", arguments); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + "("); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + "%s", pos_comment); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + ")\n"); + } + else + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s\n", arguments); + } + else + { + gui_printf (server->window, + _("%s nick not found for \"kick\" command\n"), + WEECHAT_ERROR); + return -1; + } + ptr_nick = nick_search (ptr_channel, pos_nick); + if (ptr_nick) + { + nick_free (ptr_channel, ptr_nick); + gui_redraw_window_nick (gui_current_window); + } + return 0; +} + +/* + * irc_cmd_recv_mode: 'mode' message received + */ + +int +irc_cmd_recv_mode (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2, *pos_parm; + char set_flag; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"mode\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + pos = strchr (arguments, ' '); + if (!pos) + { + gui_printf (server->window, + _("%s \"mode\" command received without channel or nickname\n"), + WEECHAT_ERROR); + return -1; + } + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + + pos_parm = strchr (pos, ' '); + if (pos_parm) + { + pos_parm[0] = '\0'; + pos_parm++; + while (pos_parm[0] == ' ') + pos_parm++; + pos2 = strchr (pos_parm, ' '); + if (pos2) + pos2[0] = '\0'; + } + + set_flag = '+'; + + if (string_is_channel (arguments)) + { + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + /* channel modes */ + while (pos && pos[0]) + { + switch (pos[0]) + { + case '+': + set_flag = '+'; + break; + case '-': + set_flag = '-'; + break; + case 'b': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "b", host, + (set_flag == '+') ? + _("sets ban on") : + _("removes ban on"), + pos_parm); + /* TODO: change & redraw channel modes */ + break; + case 'i': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "i", host, + (set_flag == '+') ? + _("sets invite-only channel flag") : + _("removes invite-only channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 'l': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "l", host, + (set_flag == '+') ? + _("sets the user limit to") : + _("removes user limit"), + (set_flag == '+') ? pos_parm : NULL); + /* TODO: change & redraw channel modes */ + break; + case 'm': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "m", host, + (set_flag == '+') ? + _("sets moderated channel flag") : + _("removes moderated channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 'o': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "o", host, + (set_flag == '+') ? + _("gives channel operator status to") : + _("removes channel operator status from"), + pos_parm); + ptr_nick = nick_search (ptr_channel, pos_parm); + if (ptr_nick) + { + ptr_nick->is_op = (set_flag == '+') ? 1 : 0; + nick_resort (ptr_channel, ptr_nick); + gui_redraw_window_nick (ptr_channel->window); + } + break; + /* TODO: remove this obsolete (?) channel flag? */ + case 'p': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "p", host, + (set_flag == '+') ? + _("sets private channel flag") : + _("removes private channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 's': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "s", host, + (set_flag == '+') ? + _("sets secret channel flag") : + _("removes secret channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 't': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "t", host, + (set_flag == '+') ? + _("sets topic protection") : + _("removes topic protection"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 'v': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "v", host, + (set_flag == '+') ? + _("gives voice to") : + _("removes voice from"), + pos_parm); + + ptr_nick = nick_search (ptr_channel, pos_parm); + if (ptr_nick) + { + ptr_nick->has_voice = (set_flag == '+') ? 1 : 0; + nick_resort (ptr_channel, ptr_nick); + gui_redraw_window_nick (ptr_channel->window); + } + break; + } + pos++; + } + } + else + { + gui_printf (server->window, + _("%s channel not found for \"mode\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + /* nickname modes */ + gui_printf (server->window, "(TODO!) nickname modes: channel=%s, args=%s\n", arguments, pos); + } + return 0; +} + +/* + * irc_cmd_recv_nick: 'nick' message received + */ + +int +irc_cmd_recv_nick (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + int nick_is_me; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"nick\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + for (ptr_channel = server->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + ptr_nick = nick_search (ptr_channel, host); + if (ptr_nick) + { + nick_is_me = (strcmp (ptr_nick->nick, server->nick) == 0); + nick_change (ptr_channel, ptr_nick, arguments); + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + if (nick_is_me) + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + _("You are ")); + else + { + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, + "%s", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, " is "); + } + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + _("now known as ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, + "%s\n", + arguments); + if (ptr_channel->window->win_nick) + gui_redraw_window_nick (ptr_channel->window); + } + } + + if (strcmp (server->nick, host) == 0) + { + free (server->nick); + server->nick = strdup (arguments); + } + gui_redraw_window_input (gui_current_window); + + return 0; +} + +/* + * irc_cmd_recv_notice: 'notice' message received + */ + +int +irc_cmd_recv_notice (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + + if (host) + { + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + } + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + } + else + { + gui_printf (server->window, + _("%s nickname not found for \"notice\" command\n"), + WEECHAT_ERROR); + return -1; + } + irc_display_prefix (server->window, PREFIX_SERVER); + if (strncmp (pos, "\01VERSION", 8) == 0) + { + pos += 9; + pos2 = strchr (pos, '\01'); + if (pos2) + pos2[0] = '\0'; + gui_printf_color (server->window, COLOR_WIN_CHAT, "CTCP "); + gui_printf_color (server->window, COLOR_WIN_CHAT_CHANNEL, "VERSION"); + gui_printf_color (server->window, COLOR_WIN_CHAT, " reply from "); + gui_printf_color (server->window, COLOR_WIN_CHAT_NICK, "%s", host); + gui_printf_color (server->window, COLOR_WIN_CHAT, ": %s\n", pos); + } + else + gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_part: 'part' message received + */ + +int +irc_cmd_recv_part (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos_args; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (!host || !arguments) + { + gui_printf (server->window, + _("%s \"part\" command received without host or channel\n"), + WEECHAT_ERROR); + return -1; + } + + pos_args = strchr (arguments, ' '); + if (pos_args) + { + pos_args[0] = '\0'; + pos_args++; + while (pos_args[0] == ' ') + pos_args++; + if (pos_args[0] == ':') + pos_args++; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + ptr_nick = nick_search (ptr_channel, host); + if (ptr_nick) + { + if (strcmp (ptr_nick->nick, server->nick) == 0) + { + /* part request was issued by local client */ + gui_window_free (ptr_channel->window); + channel_free (server, ptr_channel); + gui_redraw_window_status (gui_current_window); + gui_redraw_window_input (gui_current_window); + } + else + { + + /* remove nick from nick list and display message */ + nick_free (ptr_channel, ptr_nick); + irc_display_prefix (ptr_channel->window, PREFIX_PART); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s ", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_HOST, "%s", pos+1); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")"); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _(" has left ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%s", ptr_channel->name); + if (pos_args && pos_args[0]) + { + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, " ("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, "%s", pos_args); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")"); + } + gui_printf (ptr_channel->window, "\n"); + + /* redraw nick list if this is current window */ + if (ptr_channel->window->win_nick) + gui_redraw_window_nick (ptr_channel->window); + } + } + } + else + { + gui_printf (server->window, + _("%s channel not found for \"part\" command\n"), + WEECHAT_ERROR); + return -1; + } + + return 0; +} + +/* + * irc_cmd_recv_ping: 'ping' command received + */ + +int +irc_cmd_recv_ping (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + (void)host; + pos = strrchr (arguments, ' '); + if (pos) + pos[0] = '\0'; + server_sendf (server, "PONG :%s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_privmsg: 'privmsg' command received + */ + +int +irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2, *host2; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"privmsg\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + { + pos[0] = '\0'; + host2 = pos+1; + } + else + host2 = host; + + /* receiver is a channel ? */ + if (string_is_channel (arguments)) + { + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + if (strncmp (pos, "\01ACTION ", 8) == 0) + { + pos += 8; + pos2 = strchr (pos, '\01'); + if (pos2) + pos2[0] = '\0'; + irc_display_prefix (ptr_channel->window, PREFIX_ACTION_ME); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, " %s\n", pos); + } + else + { + ptr_nick = nick_search (ptr_channel, host); + if (ptr_nick) + { + irc_display_nick (ptr_channel->window, ptr_nick, + MSG_TYPE_NICK, 1, 1, 0); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + } + else + { + gui_printf (server->window, + _("%s nick not found for \"privmsg\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + } + else + { + gui_printf (server->window, + _("%s channel not found for \"privmsg\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + } + else + { + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + + if (strcmp (pos, "\01VERSION\01") == 0) + server_sendf (server, + "NOTICE %s :\01VERSION " + WEECHAT_NAME " v" + WEECHAT_VERSION ", compiled on " __DATE__ "\01\r\n", + host); + else + { + /* private message received */ + ptr_channel = channel_search (server, host); + if (!ptr_channel) + { + ptr_channel = channel_new (server, CHAT_PRIVATE, host); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s cannot create new private window \"%s\"\n"), + WEECHAT_ERROR, host); + return -1; + } + } + if (!ptr_channel->topic) + { + ptr_channel->topic = strdup (host2); + gui_redraw_window_title (ptr_channel->window); + } + + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "<"); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_NICK_PRIVATE, + "%s", host); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "> "); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + } + } + else + { + gui_printf (server->window, + _("%s cannot parse \"privmsg\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + return 0; +} + +/* + * irc_cmd_recv_quit: 'quit' command received + */ + +int +irc_cmd_recv_quit (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"quit\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + for (ptr_channel = server->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + if (ptr_channel->type == CHAT_PRIVATE) + ptr_nick = NULL; + else + ptr_nick = nick_search (ptr_channel, host); + + if (ptr_nick || (strcmp (ptr_channel->name, host) == 0)) + { + if (ptr_nick) + nick_free (ptr_channel, ptr_nick); + irc_display_prefix (ptr_channel->window, PREFIX_QUIT); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s ", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_HOST, "%s", pos + 1); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")"); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _(" has quit ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, "%s", + arguments); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")\n"); + if ((ptr_channel->window == gui_current_window) && + (ptr_channel->window->win_nick)) + gui_redraw_window_nick (ptr_channel->window); + } + } + + return 0; +} + +/* + * irc_cmd_recv_server_msg: command received from server (numeric) + */ + +int +irc_cmd_recv_server_msg (t_irc_server *server, char *host, char *arguments) +{ + /* make gcc happy */ + (void) host; + + /* skip nickname if at beginning of server message */ + if (strncmp (server->nick, arguments, strlen (server->nick)) == 0) + { + arguments += strlen (server->nick) + 1; + while (arguments[0] == ' ') + arguments++; + } + + if (arguments[0] == ':') + arguments++; + + /* display server message */ + irc_display_prefix (server->window, PREFIX_SERVER); + gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_server_reply: server reply + */ + +int +irc_cmd_recv_server_reply (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + int first; + + /* make gcc happy */ + (void) server; + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_ERROR); + first = 1; + + while (pos && pos[0]) + { + pos2 = strchr (pos, ' '); + if ((pos[0] == ':') || (!pos2)) + { + if (pos[0] == ':') + pos++; + gui_printf_color (server->window, + COLOR_WIN_CHAT, + "%s%s\n", (first) ? "" : ": ", pos); + pos = NULL; + } + else + { + pos2[0] = '\0'; + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s%s", + (first) ? "" : " ", pos); + first = 0; + pos = pos2 + 1; + } + } + return 0; +} + +/* + * irc_cmd_recv_topic: 'topic' command received + */ + +int +irc_cmd_recv_topic (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + t_irc_channel *ptr_channel; + t_gui_window *window; + + /* make gcc happy */ + (void) host; + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + if (string_is_channel (arguments)) + { + gui_printf (server->window, + _("%s \"topic\" command received without channel\n"), + WEECHAT_ERROR); + return -1; + } + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + if (!pos[0]) + pos = NULL; + } + + ptr_channel = channel_search (server, arguments); + window = (ptr_channel) ? ptr_channel->window : server->window; + + irc_display_prefix (window, PREFIX_INFO); + gui_printf_color (window, + COLOR_WIN_CHAT_NICK, "%s", + host); + if (pos) + { + gui_printf_color (window, + COLOR_WIN_CHAT, _(" has changed topic for ")); + gui_printf_color (window, + COLOR_WIN_CHAT_CHANNEL, "%s", + arguments); + gui_printf_color (window, + COLOR_WIN_CHAT, _(" to: \"%s\"\n"), + pos); + } + else + { + gui_printf_color (window, + COLOR_WIN_CHAT, _(" has unset topic for ")); + gui_printf_color (window, + COLOR_WIN_CHAT_CHANNEL, "%s\n", + arguments); + } + + if (ptr_channel) + { + if (ptr_channel->topic) + free (ptr_channel->topic); + if (pos) + ptr_channel->topic = strdup (pos); + else + ptr_channel->topic = strdup (""); + gui_redraw_window_title (ptr_channel->window); + } + + return 0; +} + +/* + * irc_cmd_recv_004: '004' command (connected to irc server ?????) + */ + +int +irc_cmd_recv_004 (t_irc_server *server, char *host, char *arguments) +{ + /* make gcc happy */ + (void) host; + (void) arguments; + + irc_cmd_recv_server_msg (server, host, arguments); + + /* connection to IRC server is ok! */ + server->is_connected = 1; + gui_redraw_window_status (server->window); + gui_redraw_window_input (server->window); + return 0; +} + +/* + * irc_cmd_recv_311: '311' command (away message) + */ + +int +irc_cmd_recv_301 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) server; + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (gui_current_window, PREFIX_INFO); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, _(" is away: %s\n"), pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_311: '311' command (whois, user) + */ + +int +irc_cmd_recv_311 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_user, *pos_host, *pos_realname; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_user = strchr (pos_nick, ' '); + if (pos_user) + { + pos_user[0] = '\0'; + pos_user++; + while (pos_user[0] == ' ') + pos_user++; + pos_host = strchr (pos_user, ' '); + if (pos_host) + { + pos_host[0] = '\0'; + pos_host++; + while (pos_host[0] == ' ') + pos_host++; + pos_realname = strchr (pos_host, ' '); + if (pos_realname) + { + pos_realname[0] = '\0'; + pos_realname++; + while (pos_realname[0] == ' ') + pos_realname++; + if (pos_realname[0] == '*') + pos_realname++; + while (pos_realname[0] == ' ') + pos_realname++; + if (pos_realname[0] == ':') + pos_realname++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] ("); + gui_printf_color (server->window, + COLOR_WIN_CHAT_HOST, "%s@%s", + pos_user, pos_host); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, ")"); + gui_printf_color (server->window, + COLOR_WIN_CHAT, ": %s\n", pos_realname); + } + } + } + } + return 0; +} + +/* + * irc_cmd_recv_312: '312' command (whois, server) + */ + +int +irc_cmd_recv_312 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_server, *pos_serverinfo; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_server = strchr (pos_nick, ' '); + if (pos_server) + { + pos_server[0] = '\0'; + pos_server++; + while (pos_server[0] == ' ') + pos_server++; + pos_serverinfo = strchr (pos_server, ' '); + if (pos_serverinfo) + { + pos_serverinfo[0] = '\0'; + pos_serverinfo++; + while (pos_serverinfo[0] == ' ') + pos_serverinfo++; + if (pos_serverinfo[0] == ':') + pos_serverinfo++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s ", pos_server); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s", pos_serverinfo); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, ")\n"); + } + } + } + return 0; +} + +/* + * irc_cmd_recv_313: '313' command (whois, operator) + */ + +int +irc_cmd_recv_313 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s\n", pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_317: '317' command (whois, idle) + */ + +int +irc_cmd_recv_317 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_idle, *pos_signon, *pos_message; + int idle_time, day, hour, min, sec; + time_t datetime; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_idle = strchr (pos_nick, ' '); + if (pos_idle) + { + pos_idle[0] = '\0'; + pos_idle++; + while (pos_idle[0] == ' ') + pos_idle++; + pos_signon = strchr (pos_idle, ' '); + if (pos_signon) + { + pos_signon[0] = '\0'; + pos_signon++; + while (pos_signon[0] == ' ') + pos_signon++; + pos_message = strchr (pos_signon, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + + idle_time = atoi (pos_idle); + day = idle_time / (60 * 60 * 24); + hour = (idle_time % (60 * 60 * 24)) / (60 * 60); + min = ((idle_time % (60 * 60 * 24)) % (60 * 60)) / 60; + sec = ((idle_time % (60 * 60 * 24)) % (60 * 60)) % 60; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, _("idle: ")); + if (day > 0) + { + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", day); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (day > 1) ? _("days") : _("day")); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + ", "); + } + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%02d ", hour); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (hour > 1) ? _("hours") : _("hour")); + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + " %02d ", min); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (min > 1) ? _("minutes") : _("minute")); + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + " %02d ", sec); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (sec > 1) ? _("seconds") : _("second")); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, _("signon at: ")); + datetime = (time_t)(atol (pos_signon)); + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s", ctime (&datetime)); + } + } + } + } + return 0; +} + +/* + * irc_cmd_recv_318: '318' command (whois, end) + */ + +int +irc_cmd_recv_318 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s\n", pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_319: '319' command (whois, end) + */ + +int +irc_cmd_recv_319 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_channel, *pos; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_channel = strchr (pos_nick, ' '); + if (pos_channel) + { + pos_channel[0] = '\0'; + pos_channel++; + while (pos_channel[0] == ' ') + pos_channel++; + if (pos_channel[0] == ':') + pos_channel++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, _("Channels: ")); + + while (pos_channel && pos_channel[0]) + { + if (pos_channel[0] == '@') + { + gui_printf_color (server->window, + COLOR_WIN_NICK_OP, "@"); + pos_channel++; + } + else + { + if (pos_channel[0] == '%') + { + gui_printf_color (server->window, + COLOR_WIN_NICK_HALFOP, "%"); + pos_channel++; + } + else + if (pos_channel[0] == '+') + { + gui_printf_color (server->window, + COLOR_WIN_NICK_VOICE, "+"); + pos_channel++; + } + } + pos = strchr (pos_channel, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s%s", + pos_channel, + (pos && pos[0]) ? " " : "\n"); + pos_channel = pos; + } + } + } + return 0; +} + +/* + * irc_cmd_recv_320: '320' command (whois, identified user) + */ + +int +irc_cmd_recv_320 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s\n", pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_321: '321' command (/list start) + */ + +int +irc_cmd_recv_321 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_322: '322' command (channel for /list) + */ + +int +irc_cmd_recv_322 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_323: '323' command (/list end) + */ + +int +irc_cmd_recv_323 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_331: '331' command received (no topic for channel) + */ + +int +irc_cmd_recv_331 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) server; + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + pos[0] = '\0'; + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, _("No topic set for ")); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_CHANNEL, "%s\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_332: '332' command received (topic of channel) + */ + +int +irc_cmd_recv_332 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + t_irc_channel *ptr_channel; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + while (pos[0] == ' ') + pos++; + pos2 = strchr (pos, ' '); + if (pos2) + { + pos2[0] = '\0'; + ptr_channel = channel_search (server, pos); + if (ptr_channel) + { + pos2++; + while (pos2[0] == ' ') + pos2++; + if (pos2[0] == ':') + pos2++; + if (ptr_channel->topic) + free (ptr_channel->topic); + ptr_channel->topic = strdup (pos2); + + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _("Topic for ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, "%s", pos); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _(" is: \"%s\"\n"), pos2); + + gui_redraw_window_title (ptr_channel->window); + } + else + { + gui_printf (server->window, + _("%s channel not found for \"332\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + } + else + { + gui_printf (server->window, + _("%s cannot identify channel for \"332\" command\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_recv_333: '333' command received (infos about topic (nick / date) + */ + +int +irc_cmd_recv_333 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_channel, *pos_nick, *pos_date; + t_irc_channel *ptr_channel; + time_t datetime; + + /* make gcc happy */ + (void) host; + + pos_channel = strchr (arguments, ' '); + if (pos_channel) + { + while (pos_channel[0] == ' ') + pos_channel++; + pos_nick = strchr (pos_channel, ' '); + if (pos_nick) + { + pos_nick[0] = '\0'; + pos_nick++; + while (pos_nick[0] == ' ') + pos_nick++; + pos_date = strchr (pos_nick, ' '); + if (pos_date) + { + pos_date[0] = '\0'; + pos_date++; + while (pos_date[0] == ' ') + pos_date++; + + ptr_channel = channel_search (server, pos_channel); + if (ptr_channel) + { + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _("Topic set by ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + datetime = (time_t)(atol (pos_date)); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, ", %s", ctime (&datetime)); + } + else + { + gui_printf (server->window, + _("%s channel not found for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + gui_printf (server->window, + _("%s cannot identify date/time for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + gui_printf (server->window, + _("%s cannot identify nickname for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + gui_printf (server->window, + _("%s cannot identify channel for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_recv_351: '351' command received (server version) + */ + +int +irc_cmd_recv_351 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + + /* make gcc happy */ + (void) server; + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + } + else + pos = arguments; + + pos2 = strstr (pos, " :"); + if (pos2) + { + pos2[0] = '\0'; + pos2 += 2; + } + + irc_display_prefix (server->window, PREFIX_SERVER); + if (pos2) + gui_printf (server->window, "%s %s\n", pos, pos2); + else + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_353: '353' command received (list of users on a channel) + */ + +int +irc_cmd_recv_353 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos_nick; + int is_op, is_halfop, has_voice; + t_irc_channel *ptr_channel; + + /* make gcc happy */ + (void) host; + + pos = strstr (arguments, " = "); + if (pos) + arguments = pos + 3; + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + return 0; + + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] != ':') + { + gui_printf (server->window, + _("%s cannot parse \"353\" command\n"), + WEECHAT_ERROR); + return -1; + } + pos++; + if (pos[0]) + { + while (pos && pos[0]) + { + is_op = 0; + is_halfop = 0; + has_voice = 0; + while ((pos[0] == '@') || (pos[0] == '%') || (pos[0] == '+')) + { + if (pos[0] == '@') + is_op = 1; + if (pos[0] == '%') + is_halfop = 1; + if (pos[0] == '+') + has_voice = 1; + pos++; + } + pos_nick = pos; + pos = strchr (pos, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + } + if (!nick_new (ptr_channel, pos_nick, is_op, is_halfop, has_voice)) + gui_printf (server->window, + _("%s cannot create nick \"%s\" for channel \"%s\"\n"), + WEECHAT_ERROR, pos_nick, ptr_channel->name); + } + } + gui_redraw_window_nick (ptr_channel->window); + } + else + { + gui_printf (server->window, + _("%s cannot parse \"353\" command\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_recv_366: '366' command received (end of /names list) + */ + +int +irc_cmd_recv_366 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + int num_nicks, num_op, num_halfop, num_voice, num_normal; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + while (pos[0] == ' ') + pos++; + pos2 = strchr (pos, ' '); + if (pos2) + { + pos2[0] = '\0'; + pos2++; + while (pos2[0] == ' ') + pos2++; + if (pos2[0] == ':') + pos2++; + + ptr_channel = channel_search (server, pos); + if (ptr_channel) + { + + /* display users on channel */ + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _("Nicks ")); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s", ptr_channel->name); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, ": "); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "["); + + for (ptr_nick = ptr_channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + { + irc_display_nick (ptr_channel->window, ptr_nick, + MSG_TYPE_INFO, 0, 0, 1); + if (ptr_nick != ptr_channel->last_nick) + gui_printf (ptr_channel->window, " "); + } + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "]\n"); + + /* display number of nicks, ops, halfops & voices on the channel */ + nick_count (ptr_channel, &num_nicks, &num_op, &num_halfop, &num_voice, + &num_normal); + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _("Channel ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%s", ptr_channel->name); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, ": "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_nicks); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_nicks > 1) ? _("nicks") : _("nick")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, " ("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_op); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_op > 1) ? _("ops") : _("op")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_halfop); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_halfop > 1) ? _("halfops") : _("halfop")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_voice); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_voice > 1) ? _("voices") : _("voice")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_normal); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + _("normal")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")\n"); + } + else + { + irc_display_prefix (gui_current_window, PREFIX_INFO); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_CHANNEL, pos); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, ": %s\n", pos2); + return 0; + } + } + } + return 0; +} + +/* + * irc_cmd_recv_433: '433' command received (nickname already in use) + */ + +int +irc_cmd_recv_433 (t_irc_server *server, char *host, char *arguments) +{ + char hostname[128]; + + if (!server->is_connected) + { + if (strcmp (server->nick, server->nick1) == 0) + { + gui_printf (server->window, + _(WEECHAT_NAME + ": nickname \"%s\" is already in use, " + "trying 2nd nickname \"%s\"\n"), + server->nick, server->nick2); + free (server->nick); + server->nick = strdup (server->nick2); + } + else + { + if (strcmp (server->nick, server->nick2) == 0) + { + gui_printf (server->window, + _(WEECHAT_NAME + ": nickname \"%s\" is already in use, " + "trying 3rd nickname \"%s\"\n"), + server->nick, server->nick3); + free (server->nick); + server->nick = strdup (server->nick3); + } + else + { + gui_printf (server->window, + _(WEECHAT_NAME + ": all declared nicknames are already in use, " + "closing connection with server!\n")); + server_disconnect (server); + return 0; + } + } + + gethostname (hostname, sizeof (hostname) - 1); + hostname[sizeof (hostname) - 1] = '\0'; + if (!hostname[0]) + strcpy (hostname, _("unknown")); + server_sendf (server, + "NICK %s\r\n", + server->nick); + } + else + return irc_cmd_recv_error (server, host, arguments); + return 0; +} diff --git a/src/irc/irc-display.c b/src/irc/irc-display.c new file mode 100644 index 000000000..2f2f9931b --- /dev/null +++ b/src/irc/irc-display.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-display.c: display functions for IRC */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat.h" +#include "irc.h" +#include "../config.h" +#include "../gui/gui.h" + + +/* + * irc_display_prefix: display prefix for action or info message + * prefix must be 3 chars length + */ + +void +irc_display_prefix (t_gui_window *window, char *prefix) +{ + if (prefix[0] == prefix[2]) + { + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c", prefix[0]); + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX2, "%c", prefix[1]); + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c ", prefix[2]); + } + else + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%s ", prefix); +} + +/* + * irc_display_nick: display nick in chat window + */ + +void +irc_display_nick (t_gui_window *window, t_irc_nick *nick, int message_type, + int display_around, int color_nick, int no_nickmode) +{ + if (display_around) + gui_printf_color_type (window, + message_type, COLOR_WIN_CHAT_DARK, "<"); + if (cfg_look_nickmode) + { + if (nick->is_op) + gui_printf_color_type (window, + message_type, + COLOR_WIN_NICK_OP, "@"); + else + { + if (nick->is_halfop) + gui_printf_color_type (window, + message_type, + COLOR_WIN_NICK_HALFOP, "%%"); + else + { + if (nick->has_voice) + gui_printf_color_type (window, + message_type, + COLOR_WIN_NICK_VOICE, "+"); + else + if (cfg_look_nickmode_empty && !no_nickmode) + gui_printf_color_type (window, + message_type, + COLOR_WIN_CHAT, " "); + } + } + } + gui_printf_color_type (window, + message_type, + (color_nick) ? + ((cfg_look_color_nicks) ? + nick->color : COLOR_WIN_CHAT) : + COLOR_WIN_CHAT, + "%s", nick->nick); + + if (display_around) + gui_printf_color_type (window, + message_type, COLOR_WIN_CHAT_DARK, "> "); +} + +/* + * irc_display_mode: display IRC message for mode change + */ + +void +irc_display_mode (t_gui_window *window, char *channel_name, char set_flag, + char *symbol, char *nick_host, char *message, char *param) +{ + irc_display_prefix (window, PREFIX_INFO); + gui_printf_color (window, COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%s", channel_name); + gui_printf_color (window, COLOR_WIN_CHAT, "/"); + gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%c%s", set_flag, symbol); + gui_printf_color (window, COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s", nick_host); + if (param) + { + gui_printf_color (window, COLOR_WIN_CHAT, " %s ", message); + gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s\n", param); + } + else + gui_printf_color (window, COLOR_WIN_CHAT, " %s\n", message); +} diff --git a/src/irc/irc-nick.c b/src/irc/irc-nick.c new file mode 100644 index 000000000..1f9faf3b3 --- /dev/null +++ b/src/irc/irc-nick.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-nick.c: manages nick list for channels */ + + +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "../weechat.h" +#include "irc.h" + + +/* + * nick_find_color: find a color for a nick (less used will be better!) + */ + +int +nick_find_color (t_irc_channel *channel) +{ + int i, color_less_used, min_used; + int count_used[COLOR_WIN_NICK_NUMBER]; + t_irc_nick *ptr_nick; + + /* initialize array for counting usage of color */ + for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++) + count_used[i] = 0; + + /* summarize each color usage */ + for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + count_used[ptr_nick->color - COLOR_WIN_NICK_FIRST]++; + + /* look for color less used on channel */ + color_less_used = -1; + min_used = INT_MAX; + for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++) + { + if (count_used[i] < min_used) + { + color_less_used = i; + min_used = count_used[i]; + } + } + + return (color_less_used < 0) ? + COLOR_WIN_NICK_FIRST : COLOR_WIN_NICK_FIRST + color_less_used; +} + +/* + * nick_compare: compare two nicks + * return: -1 is nick1 < nick2 + * 0 if nick1 = nick2 + * +1 if nick1 > nick2 + * status sort: operator > voice > normal nick + */ + +int +nick_compare (t_irc_nick *nick1, t_irc_nick *nick2) +{ + int score1, score2, comp; + + score1 = - ( (nick1->is_op * 3) + (nick1->is_halfop * 2) + nick1->has_voice ); + score2 = - ( (nick2->is_op * 3) + (nick2->is_halfop * 2) + nick2->has_voice ); + + comp = strcasecmp(nick1->nick, nick2->nick); + if (comp > 0) + score1++; + else + if (comp < 0) + score2++; + + /* nick1 > nick2 */ + if (score1 > score2) + return 1; + /* nick1 < nick2 */ + if (score1 < score2) + return -1; + /* nick1 == nick2 */ + return 0; +} + +/* + * nick_find_pos: find position for a nick (for sorting nick list) + */ + +t_irc_nick * +nick_find_pos (t_irc_channel *channel, t_irc_nick *nick) +{ + t_irc_nick *ptr_nick; + + for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + { + if (nick_compare (nick, ptr_nick) < 0) + return ptr_nick; + } + return NULL; +} + +/* + * nick_insert_sorted: insert nick into sorted list + */ + +void +nick_insert_sorted (t_irc_channel *channel, t_irc_nick *nick) +{ + t_irc_nick *pos_nick; + + if (channel->nicks) + { + pos_nick = nick_find_pos (channel, nick); + + if (pos_nick) + { + /* insert nick into the list (before nick found) */ + nick->prev_nick = pos_nick->prev_nick; + nick->next_nick = pos_nick; + if (pos_nick->prev_nick) + pos_nick->prev_nick->next_nick = nick; + else + channel->nicks = nick; + pos_nick->prev_nick = nick; + } + else + { + /* add nick to the end */ + nick->prev_nick = channel->last_nick; + nick->next_nick = NULL; + channel->last_nick->next_nick = nick; + channel->last_nick = nick; + } + } + else + { + nick->prev_nick = NULL; + nick->next_nick = NULL; + channel->nicks = nick; + channel->last_nick = nick; + } +} + +/* + * nick_new: allocate a new nick for a channel and add it to the nick list + */ + +t_irc_nick * +nick_new (t_irc_channel *channel, char *nick_name, + int is_op, int is_halfop, int has_voice) +{ + t_irc_nick *new_nick; + + /* nick already exists on this channel? */ + if ((new_nick = nick_search (channel, nick_name))) + { + /* update nick */ + new_nick->is_op = is_op; + new_nick->is_halfop = is_halfop; + new_nick->has_voice = has_voice; + return new_nick; + } + + /* alloc memory for new nick */ + if ((new_nick = (t_irc_nick *) malloc (sizeof (t_irc_nick))) == NULL) + { + gui_printf (channel->window, + _("%s cannot allocate new nick\n"), WEECHAT_ERROR); + return NULL; + } + + /* initialize new nick */ + new_nick->nick = strdup (nick_name); + new_nick->is_op = is_op; + new_nick->is_halfop = is_halfop; + new_nick->has_voice = has_voice; + if (strcasecmp (new_nick->nick, SERVER(channel->window)->nick) == 0) + new_nick->color = COLOR_WIN_NICK_SELF; + else + new_nick->color = nick_find_color (channel); + + nick_insert_sorted (channel, new_nick); + + /* all is ok, return address of new nick */ + return new_nick; +} + +/* + * nick_resort: resort nick in the list + */ + +void +nick_resort (t_irc_channel *channel, t_irc_nick *nick) +{ + /* temporarly remove nick from list */ + if (nick == channel->nicks) + channel->nicks = nick->next_nick; + else + nick->prev_nick->next_nick = nick->next_nick; + if (nick->next_nick) + nick->next_nick->prev_nick = nick->prev_nick; + if (nick == channel->last_nick) + channel->last_nick = nick->prev_nick; + + /* insert again nick into sorted list */ + nick_insert_sorted (channel, nick); +} + +/* + * nick_change: change nickname and move it if necessary (list is sorted) + */ + +void +nick_change (t_irc_channel *channel, t_irc_nick *nick, char *new_nick) +{ + /* change nickname */ + if (nick->nick) + free (nick->nick); + nick->nick = strdup (new_nick); + + /* insert again nick into sorted list */ + nick_resort (channel, nick); +} + +/* + * nick_free: free a nick and remove it from nicks queue + */ + +void +nick_free (t_irc_channel *channel, t_irc_nick *nick) +{ + t_irc_nick *new_nicks; + + /* remove nick from queue */ + if (channel->last_nick == nick) + channel->last_nick = nick->prev_nick; + if (nick->prev_nick) + { + (nick->prev_nick)->next_nick = nick->next_nick; + new_nicks = channel->nicks; + } + else + new_nicks = nick->next_nick; + + if (nick->next_nick) + (nick->next_nick)->prev_nick = nick->prev_nick; + + /* free data */ + if (nick->nick) + free (nick->nick); + free (nick); + channel->nicks = new_nicks; +} + +/* + * nick_free_all: free all allocated nicks for a channel + */ + +void +nick_free_all (t_irc_channel *channel) +{ + /* remove all nicks for the channel */ + while (channel->nicks) + nick_free (channel, channel->nicks); +} + +/* + * nick_search: returns pointer on a nick + */ + +t_irc_nick * +nick_search (t_irc_channel *channel, char *nickname) +{ + t_irc_nick *ptr_nick; + + for (ptr_nick = channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + if (strcasecmp (ptr_nick->nick, nickname) == 0) + return ptr_nick; + } + return NULL; +} + +/* + * nick_count: returns number of nicks (total, op, halfop, voice) on a channel + */ + +void +nick_count (t_irc_channel *channel, int *total, int *count_op, + int *count_halfop, int *count_voice, int *count_normal) +{ + t_irc_nick *ptr_nick; + + (*total) = 0; + (*count_op) = 0; + (*count_halfop) = 0; + (*count_voice) = 0; + (*count_normal) = 0; + for (ptr_nick = channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + (*total)++; + if (ptr_nick->is_op) + (*count_op)++; + else + { + if (ptr_nick->is_halfop) + (*count_halfop)++; + else + { + if (ptr_nick->has_voice) + (*count_voice)++; + else + (*count_normal)++; + } + } + } +} + +/* + * nick_get_max_length: returns longer nickname on a channel + */ + +int +nick_get_max_length (t_irc_channel *channel) +{ + int length, max_length; + t_irc_nick *ptr_nick; + + max_length = 0; + for (ptr_nick = channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + length = strlen (ptr_nick->nick); + if (length > max_length) + max_length = length; + } + return max_length; +} diff --git a/src/irc/irc-server.c b/src/irc/irc-server.c new file mode 100644 index 000000000..b8bacc303 --- /dev/null +++ b/src/irc/irc-server.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-server.c: (dis)connection and communication with irc server */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include "../weechat.h" +#include "irc.h" +#include "../gui/gui.h" + + +t_irc_server *irc_servers = NULL; +t_irc_server *last_irc_server = NULL; +t_irc_server *current_irc_server = NULL; + +t_irc_message *recv_msgq, *msgq_last_msg; + +/* buffer containing beginning of message if not ending with \r\n */ +char *unterminated_message = NULL; + + +/* + * server_alloc: allocate a new server and add it to the servers queue + */ + +t_irc_server * +server_alloc () +{ + t_irc_server *new_server; + + #if DEBUG >= 1 + log_printf ("allocating new server\n"); + #endif + + /* alloc memory for new server */ + if ((new_server = (t_irc_server *) malloc (sizeof (t_irc_server))) == NULL) + { + fprintf (stderr, _("%s cannot allocate new server"), WEECHAT_ERROR); + return NULL; + } + + /* initialize new server */ + new_server->name = NULL; + new_server->address = NULL; + new_server->password = NULL; + new_server->nick1 = NULL; + new_server->nick2 = NULL; + new_server->nick3 = NULL; + new_server->username = NULL; + new_server->realname = NULL; + new_server->nick = NULL; + new_server->is_connected = 0; + new_server->sock4 = -1; + new_server->is_away = 0; + new_server->server_read = -1; + new_server->server_write = -1; + new_server->window = NULL; + new_server->channels = NULL; + new_server->last_channel = NULL; + + /* add new server to queue */ + new_server->prev_server = last_irc_server; + new_server->next_server = NULL; + if (irc_servers) + last_irc_server->next_server = new_server; + else + irc_servers = new_server; + last_irc_server = new_server; + + /* all is ok, return address of new server */ + return new_server; +} + +/* + * server_create_window: create windows for a server + */ + +void +server_create_window (t_irc_server *server) +{ + if (!SERVER(gui_windows)) + { + server->window = gui_windows; + SERVER(gui_windows) = server; + } + else + gui_window_new (server, NULL); +} + +/* + * server_free: free a server and remove it from servers queue + */ + +void +server_free (t_irc_server *server) +{ + t_irc_server *new_irc_servers; + + /* remove server from queue */ + if (server->prev_server) + { + (server->prev_server)->next_server = server->next_server; + new_irc_servers = irc_servers; + } + else + new_irc_servers = server->next_server; + + if (server->next_server) + (server->next_server)->prev_server = server->prev_server; + + /* free data */ + if (server->name) + free (server->name); + if (server->address) + free (server->address); + if (server->password) + free (server->password); + if (server->nick1) + free (server->nick1); + if (server->nick2) + free (server->nick2); + if (server->nick3) + free (server->nick3); + if (server->username) + free (server->username); + if (server->realname) + free (server->realname); + if (server->nick) + free (server->nick); + if (server->channels) + channel_free_all (server); + /* TODO: free weechat window (???) */ + /* (...) */ + free (server); + irc_servers = new_irc_servers; +} + +/* + * server_free_all: free all allocated servers + */ + +void +server_free_all () +{ + /* for each server in memory, remove it */ + while (irc_servers) + server_free (irc_servers); +} + +/* + * server_new: creates a new server, and initialize it + */ + +t_irc_server * +server_new (char *name, char *address, int port, char *password, + char *nick1, char *nick2, char *nick3, + char *username, char *realname) +{ + t_irc_server *new_server; + + if (!name || !address || (port < 0) || !nick1 || !nick2 || !nick3 + || !username || !realname) + return NULL; + + #if DEBUG >= 1 + log_printf ("creating new server (name:%s, address:%s, port:%d, pwd:%s, " + "nick1:%s, nick2:%s, nick3:%s, username:%s, realname:%s)\n", + name, address, port, password, nick1, nick2, nick3, + username, realname); + #endif + + if ((new_server = server_alloc ())) + { + new_server->name = strdup (name); + new_server->address = strdup (address); + new_server->port = port; + new_server->password = (password) ? strdup (password) : strdup (""); + new_server->nick1 = (nick1) ? strdup (nick1) : strdup ("weechat_user"); + new_server->nick2 = (nick2) ? strdup (nick2) : strdup ("weechat2"); + new_server->nick3 = (nick3) ? strdup (nick3) : strdup ("weechat3"); + new_server->username = + (username) ? strdup (username) : strdup ("weechat"); + new_server->realname = + (realname) ? strdup (realname) : strdup ("realname"); + new_server->nick = strdup (new_server->nick1); + } + else + return NULL; + return new_server; +} + +/* + * server_send: send data to irc server + */ + +int +server_send (t_irc_server * server, char *buffer, int size_buf) +{ + if (!server) + return -1; + + return send (server->sock4, buffer, size_buf, 0); +} + +/* + * server_sendf: send formatted data to irc server + */ + +int +server_sendf (t_irc_server * server, char *fmt, ...) +{ + va_list args; + static char buffer[1024]; + int size_buf; + + if (!server) + return -1; + + va_start (args, fmt); + size_buf = vsnprintf (buffer, sizeof (buffer) - 1, fmt, args); + va_end (args); + + if ((size_buf == 0) || (strcmp (buffer, "\r\n") == 0)) + return 0; + + buffer[sizeof (buffer) - 1] = '\0'; + if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1))) + size_buf = strlen (buffer); + buffer[size_buf - 2] = '\0'; + #if DEBUG >= 2 + gui_printf (server->window, "[DEBUG] Sending to server >>> %s\n", buffer); + #endif + buffer[size_buf - 2] = '\r'; + return server_send (server, buffer, size_buf); +} + +/* + * server_msgq_add_msg: add a message to received messages queue (at the end) + */ + +void +server_msgq_add_msg (t_irc_server * server, char *msg) +{ + t_irc_message *message; + + message = (t_irc_message *) malloc (sizeof (t_irc_message)); + message->server = server; + if (unterminated_message) + { + message->data = (char *) malloc (strlen (unterminated_message) + + strlen (msg) + 1); + strcpy (message->data, unterminated_message); + strcat (message->data, msg); + free (unterminated_message); + unterminated_message = NULL; + } + else + message->data = strdup (msg); + message->next_message = NULL; + + if (msgq_last_msg) + { + msgq_last_msg->next_message = message; + msgq_last_msg = message; + } + else + { + recv_msgq = message; + msgq_last_msg = message; + } +} + +/* + * server_msgq_add_buffer: explode received buffer, creating queued messages + */ + +void +server_msgq_add_buffer (t_irc_server * server, char *buffer) +{ + char *pos; + + while (buffer[0]) + { + pos = strstr (buffer, "\r\n"); + if (pos) + { + pos[0] = '\0'; + server_msgq_add_msg (server, buffer); + buffer = pos + 2; + } + else + { + pos = strchr (buffer, '\0'); + if (pos) + { + unterminated_message = + (char *) realloc (unterminated_message, + strlen (buffer) + 1); + strcpy (unterminated_message, buffer); + return; + } + gui_printf (server->window, + _("%s unable to explode received buffer\n"), + WEECHAT_ERROR); + } + } +} + +/* + * server_msgq_flush: flush message queue + */ + +void +server_msgq_flush () +{ + t_irc_message *next; + /*char **argv; + int argc;*/ + char *ptr_data, *pos, *pos2; + char *host, *command, *args; + + /* TODO: optimize this function, parse only a few messages (for low CPU time!) */ + while (recv_msgq) + { + #if DEBUG >= 2 + gui_printf (gui_current_window, "[DEBUG] %s\n", recv_msgq->data); + #endif + + ptr_data = recv_msgq->data; + + while (ptr_data[0] == ' ') + ptr_data++; + + if (ptr_data) + { + #if DEBUG >= 2 + gui_printf (NULL, "[DEBUG] data received from server: %s\n", ptr_data); + #endif + + host = NULL; + command = NULL; + args = ptr_data; + + if (ptr_data[0] == ':') + { + pos = strchr(ptr_data, ' '); + pos[0] = '\0'; + host = ptr_data+1; + pos++; + } + else + pos = ptr_data; + + if (pos != NULL) + { + while (pos[0] == ' ') + pos++; + pos2 = strchr(pos, ' '); + if (pos2 != NULL) + { + pos2[0] = '\0'; + command = strdup(pos); + pos2++; + while (pos2[0] == ' ') + pos2++; + args = (pos2[0] == ':') ? pos2+1 : pos2; + } + } + + switch (irc_recv_command (recv_msgq->server, host, command, args)) + { + case -1: + gui_printf (recv_msgq->server->window, + _("Command '%s' failed!\n"), command); + break; + case -2: + gui_printf (recv_msgq->server->window, + _("No command to execute!\n")); + break; + case -3: + gui_printf (recv_msgq->server->window, + _("Unknown command: cmd=%s, args=%s\n"), + command, args); + break; + } + } + + free (recv_msgq->data); + next = recv_msgq->next_message; + free (recv_msgq); + recv_msgq = next; + if (recv_msgq == NULL) + msgq_last_msg = NULL; + } +} + +/* + * server_recv: receive data from an irc server + */ + +void +server_recv (t_irc_server *server) +{ + static char buffer[4096 + 2]; + int num_read; + + num_read = recv (server->sock4, buffer, sizeof (buffer) - 2, 0); + if (num_read > 0) + { + buffer[num_read] = '\0'; + server_msgq_add_buffer (server, buffer); + server_msgq_flush (); + } +} + +/* + * server_connect: connect to an irc server + */ + +int +server_connect (t_irc_server *server) +{ + int set; + struct hostent *ip4_hostent; + struct sockaddr_in addr; + char *ip_address; + int error; + int server_pipe[2]; + + gui_printf (server->window, + _(WEECHAT_NAME ": connecting to %s:%d...\n"), + server->address, server->port); + log_printf ("connecting to server %s:%d...\n", + server->address, server->port); + server->is_connected = 0; + + /* create pipe */ + if (pipe (server_pipe) < 0) + { + gui_printf (server->window, + _("%s cannot create pipe\n"), WEECHAT_ERROR); + server_free (server); + return 0; + } + server->server_read = server_pipe[0]; + server->server_write = server_pipe[1]; + + /* create socket and set options */ + server->sock4 = socket (AF_INET, SOCK_STREAM, 0); + set = 1; + if (setsockopt + (server->sock4, SOL_SOCKET, SO_REUSEADDR, (char *) &set, + sizeof (set)) == -1) + gui_printf (server->window, + _("%s cannot set socket option 'SO_REUSEADDR'\n"), + WEECHAT_ERROR); + set = 1; + if (setsockopt + (server->sock4, SOL_SOCKET, SO_KEEPALIVE, (char *) &set, + sizeof (set)) == -1) + gui_printf (server->window, + _("%s cannot set socket option \"SO_KEEPALIVE\"\n"), + WEECHAT_ERROR); + + /* bind to hostname */ + ip4_hostent = gethostbyname (server->address); + if (!ip4_hostent) + { + gui_printf (server->window, + _("%s address \"%s\" not found\n"), + WEECHAT_ERROR, server->address); + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->sock4 = -1; + return 0; + } + memset (&addr, 0, sizeof (addr)); + memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length); + addr.sin_port = htons (server->port); + addr.sin_family = AF_INET; + /*error = bind(server->sock4, (struct sockaddr *)(&addr), sizeof(addr)); + if (error != 0) + { + gui_printf (server->window, + WEECHAT_ERORR "server_connect: can't bind to hostname\n"); + return 0; + } */ + ip_address = inet_ntoa (addr.sin_addr); + if (!ip_address) + { + gui_printf (server->window, + _("%s IP address not found\n"), WEECHAT_ERROR); + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->sock4 = -1; + return 0; + } + + /* connection to server */ + gui_printf (server->window, + _(WEECHAT_NAME ": server IP is: %s\n"), ip_address); + + error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr)); + if (error != 0) + { + gui_printf (server->window, + _("%s cannot connect to irc server\n"), WEECHAT_ERROR); + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->sock4 = -1; + return 0; + } + + current_irc_server = server; + return 1; +} + +/* + * server_disconnect: disconnect from an irc server + */ + +void +server_disconnect (t_irc_server *server) +{ + if (server->is_connected) + { + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->is_connected = 0; + } +} + +/* + * server_disconnect_all: disconnect from all irc servers + */ + +void +server_disconnect_all () +{ + t_irc_server *ptr_server; + + for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) + server_disconnect (ptr_server); +} + +/* + * server_get_number_connected: returns number of connected server + */ + +int +server_get_number_connected () +{ + t_irc_server *ptr_server; + int number; + + number = 0; + for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) + { + if (ptr_server->is_connected) + number++; + } + return number; +} + +/* + * server_name_already_exists: return 1 if server name already exists + * otherwise return 0 + */ + +int +server_name_already_exists (char *name) +{ + t_irc_server *ptr_server; + + for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) + { + if (strcmp (ptr_server->name, name) == 0) + return 1; + } + return 0; +} diff --git a/src/irc/irc.h b/src/irc/irc.h new file mode 100644 index 000000000..f1f3698be --- /dev/null +++ b/src/irc/irc.h @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_IRC_H +#define __WEECHAT_IRC_H 1 + +#include "../gui/gui.h" + +#define PREFIX_SERVER "-@-" +#define PREFIX_INFO "-=-" +#define PREFIX_ACTION_ME "-*-" +#define PREFIX_JOIN "-->" +#define PREFIX_PART "<--" +#define PREFIX_QUIT "<--" +#define PREFIX_ERROR "=!=" + +#define CHANNEL_PREFIX "#&+!" + +/* nick types */ + +typedef struct t_irc_nick t_irc_nick; + +struct t_irc_nick +{ + char *nick; /* nickname */ + int is_op; /* operator privileges? */ + int is_halfop; /* half operaor privileges? */ + int has_voice; /* nick has voice? */ + int color; /* color for nickname */ + t_irc_nick *prev_nick; /* link to previous nick on the channel */ + t_irc_nick *next_nick; /* link to next nick on the channel */ +}; + +/* channel types */ + +typedef struct t_irc_channel t_irc_channel; + +#define CHAT_UNKNOWN -1 +#define CHAT_CHANNEL 0 +#define CHAT_PRIVATE 1 + +struct t_irc_channel +{ + int type; /* channel type */ + char *name; /* name of channel (exemple: "#abc") */ + char *topic; /* topic of channel (host for private) */ + t_irc_nick *nicks; /* nicks on the channel */ + t_irc_nick *last_nick; /* last nick on the channel */ + t_gui_window *window; /* GUI window allocated for channel */ + t_irc_channel *prev_channel; /* link to previous channel */ + t_irc_channel *next_channel; /* link to next channel */ +}; + +/* server types */ + +typedef struct t_irc_server t_irc_server; + +struct t_irc_server +{ + /* user choices */ + char *name; /* name of server (only for display) */ + char *address; /* address of server (IP or name) */ + int port; /* port for server (6667 by default) */ + char *password; /* password for server */ + char *nick1; /* first nickname for the server */ + char *nick2; /* alternate nickname */ + char *nick3; /* 2nd alternate nickname */ + char *username; /* user name */ + char *realname; /* real name */ + + /* internal vars */ + char *nick; /* current nickname */ + int is_connected; /* 1 if WeeChat is connected to server */ + int sock4; /* socket for server */ + int is_away; /* 1 is user is marker as away */ + int server_read; /* pipe for reading server data */ + int server_write; /* pipe for sending data to server */ + t_gui_window *window; /* GUI window allocated for server */ + t_irc_channel *channels; /* opened channels on server */ + t_irc_channel *last_channel; /* last opened channal on server */ + t_irc_server *prev_server; /* link to previous server */ + t_irc_server *next_server; /* link to next server */ +}; + +/* irc commands */ + +typedef struct t_irc_command t_irc_command; + +struct t_irc_command +{ + char *command_name; /* command name (internal or IRC cmd) */ + char *command_description; /* command description */ + char *arguments; /* command parameters */ + char *arguments_description; /* parameters description */ + int min_arg, max_arg; /* min & max number of parameters */ + int need_connection; /* = 1 if cmd needs server connection */ + int (*cmd_function_args)(t_irc_server *, int, char **); + /* function called when user enters cmd */ + int (*cmd_function_1arg)(t_irc_server *, char *); + /* function called when user enters cmd */ + int (*recv_function)(t_irc_server *, char *, char *); + /* function called when cmd is received */ +}; + +typedef struct t_irc_message t_irc_message; + +struct t_irc_message +{ + t_irc_server *server; /* server pointer for received msg */ + char *data; /* message content */ + t_irc_message *next_message; /* link to next message */ +}; + +extern t_irc_command irc_commands[]; +extern t_irc_server *irc_servers, *current_irc_server; +extern t_irc_message *recv_msgq, *msgq_last_msg; +extern t_irc_channel *current_channel; + +/* server functions (irc-server.c) */ + +extern t_irc_server *server_alloc (); +extern void server_create_window (t_irc_server *); +extern void server_free (t_irc_server *); +extern void server_free_all (); +extern t_irc_server *server_new (char *, char *, int, char *, char *, char *, + char *, char *, char *); +extern int server_send (t_irc_server *, char *, int); +extern int server_sendf (t_irc_server *, char *, ...); +extern void server_recv (t_irc_server *); +extern int server_connect (); +extern void server_disconnect (t_irc_server *); +extern void server_disconnect_all (); +extern int server_get_number_connected (); +extern int server_name_already_exists (char *); + +/* channel functions (irc-channel.c) */ + +extern t_irc_channel *channel_new (t_irc_server *, int, char *); +extern void channel_free (t_irc_server *, t_irc_channel *); +extern void channel_free_all (t_irc_server *); +extern t_irc_channel *channel_search (t_irc_server *, char *); +extern int string_is_channel (char *); + +/* nick functions (irc-nick.c) */ + +extern t_irc_nick *nick_new (t_irc_channel *, char *, int, int, int); +extern void nick_resort (t_irc_channel *, t_irc_nick *); +extern void nick_change (t_irc_channel *, t_irc_nick *, char *); +extern void nick_free (t_irc_channel *, t_irc_nick *); +extern void nick_free_all (t_irc_channel *); +extern t_irc_nick *nick_search (t_irc_channel *, char *); +extern void nick_count (t_irc_channel *, int *, int *, int *, int *, int *); +extern int nick_get_max_length (t_irc_channel *); + +/* IRC display (irc-diplay.c) */ + +extern void irc_display_prefix (t_gui_window *, char *); +extern void irc_display_nick (t_gui_window *, t_irc_nick *, int, int, int, int); +extern void irc_display_mode (t_gui_window *, char *, char, char *, char *, + char *, char *); + +/* IRC protocol (irc-commands.c) */ + +extern int irc_recv_command (t_irc_server *, char *, char *, char *); +extern void irc_login (t_irc_server *); +/* IRC commands issued by user */ +extern int irc_cmd_send_away (t_irc_server *, char *); +extern int irc_cmd_send_ctcp (t_irc_server *, char *); +extern int irc_cmd_send_deop (t_irc_server *, int, char **); +extern int irc_cmd_send_devoice (t_irc_server *, int, char **); +extern int irc_cmd_send_invite (t_irc_server *, char *); +extern int irc_cmd_send_join (t_irc_server *, char *); +extern int irc_cmd_send_kick (t_irc_server *, char *); +extern int irc_cmd_send_kill (t_irc_server *, char *); +extern int irc_cmd_send_list (t_irc_server *, char *); +extern int irc_cmd_send_me (t_irc_server *, char *); +extern int irc_cmd_send_mode (t_irc_server *, char *); +extern int irc_cmd_send_msg (t_irc_server *, char *); +extern int irc_cmd_send_names (t_irc_server *, char *); +extern int irc_cmd_send_nick (t_irc_server *, int, char **); +extern int irc_cmd_send_notice (t_irc_server *, char *); +extern int irc_cmd_send_op (t_irc_server *, int, char **); +extern int irc_cmd_send_oper (t_irc_server *, int, char **); +extern int irc_cmd_send_part (t_irc_server *, char *); +extern int irc_cmd_send_ping (t_irc_server *, int, char **); +extern int irc_cmd_send_pong (t_irc_server *, int, char **); +extern int irc_cmd_send_quit (t_irc_server *, char *); +extern int irc_cmd_send_quote (t_irc_server *, char *); +extern int irc_cmd_send_topic (t_irc_server *, char *); +extern int irc_cmd_send_version (t_irc_server *, char *); +extern int irc_cmd_send_voice (t_irc_server *, int, char **); +extern int irc_cmd_send_whois (t_irc_server *, char *); +/* IRC commands executed when received from server */ +extern int irc_cmd_recv_error (t_irc_server *, char *, char *); +extern int irc_cmd_recv_join (t_irc_server *, char *, char *); +extern int irc_cmd_recv_kick (t_irc_server *, char *, char *); +extern int irc_cmd_recv_mode (t_irc_server *, char *, char *); +extern int irc_cmd_recv_nick (t_irc_server *, char *, char *); +extern int irc_cmd_recv_notice (t_irc_server *, char *, char *); +extern int irc_cmd_recv_part (t_irc_server *, char *, char *); +extern int irc_cmd_recv_ping (t_irc_server *, char *, char *); +extern int irc_cmd_recv_privmsg (t_irc_server *, char *, char *); +extern int irc_cmd_recv_quit (t_irc_server *, char *, char *); +extern int irc_cmd_recv_server_msg (t_irc_server *, char *, char *); +extern int irc_cmd_recv_server_reply (t_irc_server *, char *, char *); +extern int irc_cmd_recv_topic (t_irc_server *, char *, char *); +extern int irc_cmd_recv_001 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_004 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_301 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_311 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_312 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_313 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_317 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_318 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_319 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_320 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_321 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_322 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_323 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_331 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_332 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_333 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_351 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_353 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_366 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_433 (t_irc_server *, char *, char *); + +#endif /* irc.h */ diff --git a/src/plugins/README b/src/plugins/README new file mode 100644 index 000000000..978e37655 --- /dev/null +++ b/src/plugins/README @@ -0,0 +1,9 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +This is plugins directory for WeeChat. +In the future, you'll find there interfaces with many famous languages for +writing extensions to WeeChat: +- Perl interface, +- Python interface, +- Ruby interface. diff --git a/src/weechat.c b/src/weechat.c new file mode 100644 index 000000000..25f7a34d6 --- /dev/null +++ b/src/weechat.c @@ -0,0 +1,311 @@ +/* ############################################################################ + * ### ___ __ ______________ _____ ### + * ### __ | / /___________ ____/__ /_______ __ /_ ### + * ### __ | /| / /_ _ \ _ \ / __ __ \ __ `/ __/ ### + * ### __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ ### + * ### ____/|__/ \___/\___/\____/ /_/ /_/\__,_/ \__/ ### + * ### ### + * ### WeeChat - Wee Enhanced Environment for Chat ### + * ### Fast & light environment for Chat ### + * ### ### + * ### By: FlashCode <flashcode@flashtux.org> ### + * ### Bounga <bounga@altern.org> ### + * ### Xahlexx <xahlexx@tuxisland.org> ### + * ### ### + * ### http://weechat.flashtux.org ### + * ### ### + * ############################################################################ + * + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* weechat.c: core functions for WeeChat */ + + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> + +#include "weechat.h" +#include "config.h" +#include "command.h" +#include "irc/irc.h" +#include "gui/gui.h" + + +/* char *display_name; */ +int quit_weechat; /* = 1 if quit request from user... why ? :'( */ + +FILE *log_file; /* WeeChat log file (~/.weechat/weechat.log */ + + +/* + * log_printf: displays a message in WeeChat log (~/.weechat/weechat.log) + */ + +void +log_printf (char *message, ...) +{ + static char buffer[4096]; + va_list argptr; + static time_t seconds; + struct tm *date_tmp; + + if (!log_file) + return; + + va_start (argptr, message); + vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); + va_end (argptr); + + seconds = time (NULL); + date_tmp = localtime (&seconds); + fprintf (log_file, "[%04d-%02d-%02d %02d:%02d:%02d] %s", + date_tmp->tm_year + 1900, date_tmp->tm_mon + 1, date_tmp->tm_mday, + date_tmp->tm_hour, date_tmp->tm_min, date_tmp->tm_sec, + buffer); + fflush (log_file); +} + +/* + * wee_parse_args: parse command line args + */ + +void +wee_parse_args (int argc, char *argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + { + if ((strcmp (argv[i], "-h") == 0) + || (strcmp (argv[i], "--help") == 0)) + { + printf ("\n%s%s", WEE_USAGE); + exit (0); + } + else if ((strcmp (argv[i], "-l") == 0) + || (strcmp (argv[i], "--license") == 0)) + { + printf ("\n%s%s", WEE_LICENSE); + exit (0); + } + /*else if ((strcmp (argv[i], "-d") == 0) + || (strcmp (argv[i], "--display") == 0)) + { + if (i == (argc - 1)) + fprintf (stderr, + _("%s no display specified (parameter '%s'), ignored\n"), + WEECHAT_WARNING, argv[i]); + else + { + display_name = argv[i + 1]; + i++; + } + }*/ + else if ((strcmp (argv[i], "-v") == 0) + || (strcmp (argv[i], "--version") == 0)) + { + printf (WEECHAT_VERSION "\n"); + exit (0); + } + else + { + fprintf (stderr, + _("%s unknown parameter '%s', ignored\n"), + WEECHAT_WARNING, argv[i]); + } + } +} + +/* + * wee_create_home_dir: create weechat home directory (if not found) + */ + +void +wee_create_home_dir () +{ + char *weechat_home_dir; + int return_code; + + weechat_home_dir = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (weechat_home_dir, "%s/.weechat", getenv ("HOME")); + return_code = mkdir (weechat_home_dir, 0755); + if (return_code < 0) + { + if (errno != EEXIST) + { + fprintf (stderr, _("%s cannot create directory \"%s\"\n"), + WEECHAT_ERROR, weechat_home_dir); + free (weechat_home_dir); + exit (1); + } + } + free (weechat_home_dir); +} + +/* + * wee_init_vars: initialize some variables + */ + +void +wee_init_vars () +{ + /* GUI not yet initialized */ + gui_ready = 0; + + /* init received messages queue */ + recv_msgq = NULL; + msgq_last_msg = NULL; +} + +/* + * wee_init_log: initialize log file + */ + +void +wee_init_log () +{ + char *filename; + + filename = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (filename, "%s/.weechat/" WEECHAT_LOG_NAME, getenv ("HOME")); + if ((log_file = fopen (filename, "wt")) == NULL) + { + free (filename); + fprintf (stderr, + _("%s unable to create/append to log file (~/.weechat/" + WEECHAT_LOG_NAME), WEECHAT_ERROR); + } + free (filename); +} + +/* + * wee_shutdown: shutdown WeeChat + */ + +void +wee_shutdown () +{ + gui_end (); + server_free_all (); + if (log_file) + fclose (log_file); + exit (0); +} + +/* + * main: WeeChat startup + */ + +int +main (int argc, char *argv[]) +{ + t_irc_server *ptr_server; + + /* initialize variables */ + wee_init_vars (); + + /* parse command line args */ + wee_parse_args (argc, argv); + + /* create weechat home directory */ + wee_create_home_dir (); + + /* init log file */ + wee_init_log (); + + /* read configuration */ + switch (config_read ()) + { + case 0: /* success */ + break; + case -1: /* config file not found */ + config_create_default (); + config_read (); + break; + default: /* other error (fatal) */ + server_free_all (); + return 1; + } + + /* init gui */ + gui_init (); + + /* build commands index (sorted), for completion */ + index_command_build (); + + /* Welcome message - yeah! */ + if (cfg_look_startup_logo) + { + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1, + " ___ __ ______________ _____ \n" + " __ | / /___________ ____/__ /_______ __ /_\n" + " __ | /| / /_ _ \\ _ \\ / __ __ \\ __ `/ __/\n" + " __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ \n" + " ____/|__/ \\___/\\___/\\____/ /_/ /_/\\__,_/ \\__/ \n"); + } + if (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0]) + { + gui_printf_color (NULL, COLOR_WIN_CHAT, _("%sWelcome to "), + (cfg_look_startup_logo) ? " " : ""); + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2, WEECHAT_NAME); + gui_printf_color (NULL, COLOR_WIN_CHAT, + ", %s\n", cfg_look_weechat_slogan); + } + if (cfg_look_startup_version) + { + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2, + "%s" WEECHAT_NAME_AND_VERSION, + (cfg_look_startup_logo) ? " " : ""); + gui_printf_color (NULL, COLOR_WIN_CHAT, + ", %s %s %s\n", + _("compiled on"), __DATE__, __TIME__); + } + if (cfg_look_startup_logo || + (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0]) || + cfg_look_startup_version) + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1, + "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + + /* connect to all servers */ + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + server_create_window (ptr_server); + if (server_connect (ptr_server)) + irc_login (ptr_server); + } + gui_main_loop (); + server_disconnect_all (); + + /* program ending */ + wee_shutdown (); + + /* make gcc happy (statement never executed) */ + return 0; +} diff --git a/src/weechat.h b/src/weechat.h new file mode 100644 index 000000000..027d4e743 --- /dev/null +++ b/src/weechat.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_H +#define __WEECHAT_H 1 + +#include <stdio.h> +#include <libintl.h> + +#define _(string) gettext(string) +#define N_(string) (string) + +#define WEECHAT_NAME "WeeChat" +#define WEECHAT_VERSION "0.0.1" + +#define WEECHAT_NAME_AND_VERSION WEECHAT_NAME " " WEECHAT_VERSION +#define WEECHAT_COPYRIGHT WEECHAT_NAME " (c) 2003 by Wee Team" +#define WEECHAT_WEBSITE "http://weechat.flashtux.org" + +#define WEECHAT_ERROR _(WEECHAT_NAME " Error:") +#define WEECHAT_WARNING _(WEECHAT_NAME " Warning:") + +/* debug mode, 0=normal use, 1=some debug msg, 2=full debug (developers only) */ +#define DEBUG 0 + +/* log file */ + +#define WEECHAT_LOG_NAME "weechat.log" + +/* license */ + +#define WEE_LICENSE \ + WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \ + "Developed by FlashCode <flashcode@flashtux.org>\n" \ + " Bounga <bounga@altern.org>\n" \ + " Xahlexx <xahlexx@tuxisland.org>\n\n" \ + "This program is free software; you can redistribute it and/or modify\n" \ + "it under the terms of the GNU General Public License as published by\n" \ + "the Free Software Foundation; either version 2 of the License, or\n" \ + "(at your option) any later version.\n" \ + "\n", \ + \ + "This program is distributed in the hope that it will be useful,\n" \ + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \ + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \ + "GNU General Public License for more details.\n" \ + "\n" \ + "You should have received a copy of the GNU General Public License\n" \ + "along with this program; if not, write to the Free Software\n" \ + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n" + +#define WEE_USAGE \ + WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \ + "Developed by FlashCode <flashcode@flashtux.org>\n" \ + " Bounga <bounga@altern.org>\n" \ + " Xahlexx <xahlexx@tuxisland.org>\n\n" \ + " Bounga <bounga@altern.org>\n" \ + " Xahlexx <xahlexx@tuxisland.org>\n\n" \ + " -h, --help this help screen\n", \ + " -l, --license display WeeChat license\n" \ + " -v, --version display WeeChat version\n\n" + +/* " -d, --display choose X display\n" \*/ + + +/*#define DEFAULT_DISPLAY ":0" */ + + +/*extern char *display_name; */ +int quit_weechat; + +extern int quit_weechat; + +extern void log_printf (char *, ...); +extern void wee_shutdown (); + +#endif /* weechat.h */ diff --git a/weechat.1 b/weechat.1 new file mode 100644 index 000000000..4d03e5cd0 --- /dev/null +++ b/weechat.1 @@ -0,0 +1,44 @@ +.TH WEECHAT 1 "September 2003" "FlashCode" + +.SH NAME +weechat \- wee enhanced environment for chat + +.SH SYNOPSIS +.B weechat +.RI [ options ] +.br + +.SH DESCRIPTION +Fast, light and extensible IRC client for many operating systems. Everything can be +done with a keyboard. It is customizable and extensible with scripts. + +.SH OPTIONS +.TP +.B \-h, \-\-help +.br +display summary of options +.TP +.B \-l, \-\-license +.br +display program license +.TP +.B \-v, \-\-version +.br +display WeeChat version + +.SH FILES +.TP +.B $HOME/.weechat/weechat.rc +configuration file for WeeChat + +.SH AUTHOR +WeeChat is written by: +.br + - FlashCode <flashcode@flashtux.org> + - Bounga <bounga@altern.org> + - Xahlexx <xahlexx@tuxisland.org> +.br +WeeChat on the web: +.UR +http://weechat.flashtux.org +.UE diff --git a/weechat.spec b/weechat.spec new file mode 100644 index 000000000..6bf1a5f61 --- /dev/null +++ b/weechat.spec @@ -0,0 +1,41 @@ +%define name weechat +%define version 0.0.1 +%define release 1 + +Name: %{name} +Summary: portable, fast, light and extensible IRC client +Version: %{version} +Release: %{release} +Source: http://weechat.flashtux.org/download/%{name}-%{version}.tar.gz +URL: http://weechat.flashtux.org +Group: Networking/IRC +BuildRoot: %{_tmppath}/%{name}-buildroot +License: GPL + +%description +WeeChat (Wee Enhanced Environment for Chat) is a portable, fast, light and +extensible IRC client. Everything can be done with a keyboard. +It is customizable and extensible with scripts. + +%prep +rm -rf $RPM_BUILD_ROOT +%setup + +%build +make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local" + +%install +make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local" install + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,0755) +%doc AUTHORS BUGS ChangeLog COPYING FAQ INSTALL NEWS README TODO +/usr/share/man/man1/weechat.1* +/usr/local/bin/weechat + +%changelog +* Thu Sep 27 2003 FlashCode <flashcode@flashtux.org> 0.0.1-1 +- Released version 0.0.1 diff --git a/weechat/AUTHORS b/weechat/AUTHORS new file mode 100644 index 000000000..dcb0ba274 --- /dev/null +++ b/weechat/AUTHORS @@ -0,0 +1,29 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +Developers: +---------- + +All developers are connected to IRC: +server: irc.freenode.net, channel: #weechat + +FlashCode <flashcode@flashtux.org> + Web : http://www.flashtux.org + IRC : nick is "FlashCode" + Jabber: flashcode@jabber.org + ICQ : 160677660 + AIM : FlashCode AIM + Yahoo : FlashCode_Y + +Bounga <bounga@altern.org> + Web : http://bounga.ath.cx + IRC : nick is "Bounga" + Jabber: Bounga@jabber.org + ICQ : 178297842 + +Xahlexx <xahlexx@tuxisland.org> + Web : http://www.tuxisland.org + IRC : nick is "xahlexx" + + +See README file for licence detail. diff --git a/weechat/BUGS b/weechat/BUGS new file mode 100644 index 000000000..0a6a5f3f3 --- /dev/null +++ b/weechat/BUGS @@ -0,0 +1,17 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +WeeChat known bugs, 2003-09-27 + +- too much nicks in the channel (> height of window) => display bug +- some IRC commands are marked as 'unknown' when received + (irc protocol is under dev!) +- bug in nicklist resize (sometimes resize doesn't work and there is display + problem) +- alias/unalias commands doesn't work +- config is not saved (to ~/.weechat/weechatrc) +- intercept Ctrl-C (do not quit immediately if Ctrl-C pressed!) +- program is stopped when bad option in config file (it should not, only display + warning) +- too much opened channel => display bug +- when kicked, channel is not prefixed by '(' and sufixed by ')' diff --git a/weechat/COPYING b/weechat/COPYING new file mode 100644 index 000000000..5b6e7c66c --- /dev/null +++ b/weechat/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/weechat/ChangeLog b/weechat/ChangeLog new file mode 100644 index 000000000..2bc1255bd --- /dev/null +++ b/weechat/ChangeLog @@ -0,0 +1,88 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +ChangeLog - 2003-09-27 + +* 2003-09-27: + - WeeChat 0.0.1 released! + +* 2003-09-26: + - added completor prefix (in config: look_nick_completor) + - fixef log_printf command (bug with year & month) + - added "/kill" command + - fixed /version and /ctcp commands (missing ":" before message) + +* 2003-09-25: + - added "/kick" command + - added IRC errors 402 to 407 + - added "/invite" command + +* 2003-09-24: + - "ctcp version" received is now correctly displayed + - "/version" command is ok + +* 2003-09-23: + - log file (~/.weechat/weechat.log) + - renamed config file (~/.weechat/weechatrc to ~/.weechat/weechat.rc) + +* 2003-09-21: + - "demi-highlight": 2 types of windows highlight: lightred for windows with + unread messages (from other users), lightmagenta for windows with other + unread data (join, part, quit, away, ...) + - "320" IRC message management + - "/clear" command + +* 2003-09-19: + - préparation des sources pour l'internationalisation avec gettext + - "301" IRC command (away message) + - functions renamed in rc-commands.c, irc-server.c, + command.c and config.c (all functions are beginning with a prefix: + irc_cmd_recv_xxx, irc_cmd_send_xxx, server_xxx, weechat_cmd_xxx and + config_xxx). Moreover, all commands (sent and received) return a value + (success or not) + - "/quote" command + - "/whois" command (and colored display of /whois result in server window) + +* 2003-09-18: + - use of alternate nickname (and 2nd alternate) if nick is already used + on server (changed/added in config file: options "nick1", "nick2", "nick3" + for a server, all are mandatory) + - "433" IRC error management (nickname already in use) + - "mode" command received correctly for "channel flags" and + op/deop/voice/devoice actions for a nick + - "401" IRC error management (no such nick/channel) + - private windows management (when received and opened, with /privmsg), + "/privmsg" completed consequently + +* 2003-09-17: + - nickmode display ((half)op/voice) before nicks (as option, look at config + options beginning with "look_nickmode") + - windows history is now ok (pgup/pgdn on any window type) + - "/me" command (and OK when received) + - display nicks count when joining channel or with "/names" command + (total, ops, halfops, voices et normaux) + +* 2003-09-16: + - added and normalized chat window colors + (new colors in config file) + - "/topic" command + - nicklist can be moved on top, bottom, left or right of window + +* 2003-09-15: + - auto-resize of nicklist, according to nick max length + - IRC multi-servers is OK + +* 2003-09-14: + - no hangup if "/part" command is executed on server window + - continue if no server is declared in config file + (empty window will be opened for executing WeeChat commands) + - string array for strings in config file + example: cfg_look_nicklist_position can take values "left", "right", + "top", "bottom", which are converted to int (from 0 for "left" to 3 for + "bottom") + - messages are aligned under time (server window) or under time + nick + (channel window) + +* 2003-09-13: + - sources exploded in many directories: ./irc, ./gui/curses, ./gui/gtk, + ./gui/qt and ./gui/text diff --git a/weechat/FAQ b/weechat/FAQ new file mode 100644 index 000000000..f949ac4e8 --- /dev/null +++ b/weechat/FAQ @@ -0,0 +1,6 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +WeeChat FAQ, 2003-09-19 + +<<< TO DO ! >>> diff --git a/weechat/INSTALL b/weechat/INSTALL new file mode 100644 index 000000000..8ef31434c --- /dev/null +++ b/weechat/INSTALL @@ -0,0 +1,10 @@ +WeeChat - Installation instructions +=================================== + +1) Run 'make' + +2) As root, run 'make install' + +3) Enjoy ! :-) + +See AUTHORS for any support, feel free to contact us for any problem ;) diff --git a/weechat/Makefile b/weechat/Makefile new file mode 100644 index 000000000..22b2a4ec1 --- /dev/null +++ b/weechat/Makefile @@ -0,0 +1,31 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +OUTPUT=weechat + +all: + cd src && make + +install: + @mkdir -v -p $(DESTDIR)/usr/$(LOCALRPM)/bin + @cp -v src/$(OUTPUT) $(DESTDIR)/usr/$(LOCALRPM)/bin/ + @mkdir -v -p $(DESTDIR)/usr/share/man/man1 + @cp -v weechat.1 $(DESTDIR)/usr/share/man/man1/ + @echo -e "\n=== WeeChat installed!\n" + +clean: + cd src && make clean diff --git a/weechat/NEWS b/weechat/NEWS new file mode 100644 index 000000000..fb7c6bbb8 --- /dev/null +++ b/weechat/NEWS @@ -0,0 +1,6 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +FlashCode, 2003-09-27 + +WeeChat 0.0.1 released. diff --git a/weechat/README b/weechat/README new file mode 100644 index 000000000..bca3871dc --- /dev/null +++ b/weechat/README @@ -0,0 +1,50 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + + +WeeChat (Wee Enhanced Environment for Chat) is a fast and light chat +environment for many operating systems. Everything can be done with a keyboard. +It is customizable and extensible with scripts. + + +Features +-------- + * IRC chat client with multi-server connection + * many GUI (curses, text, Gtk, QT) (1) + * small, fast and very light + * customizable and extensible with scripts (Perl, Python, Ruby) (2) + * compliant with RFC 1459,2810,2811,2812,2813 + * multi-platform (GNU/Linux, *BSD, Windows & other) (3) + * 100% GPL & free + + +Copyright +--------- + +WeeChat (c) Copyright 2003 + by: FlashCode <flashcode@flashtux.org> + Xahlexx <xahlex@tuxisland.org> + Bounga <bounga@altern.org> +(see AUTHORS file if you want to contact authors) + +WeeChat is distributed under GPL licence (see COPYING file for complete license): + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +--- +(1) only curses & text interfaces are available today +(2) plugin interfaces are not yet developed +(3) only GNU/Linux version is available today diff --git a/weechat/TODO b/weechat/TODO new file mode 100644 index 000000000..e65f0a957 --- /dev/null +++ b/weechat/TODO @@ -0,0 +1,130 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +TODO - 2003-09-27 + +Legend: + # done + + currently in development + - pending + ? is this really necessary? + + +v0.0.1: + + * IRC protocol: + # "/quote" command: send a raw string to the server without parsing it + # "/me" command (for user actions description) + # "/away" command (to toggle the away status) + # "/op", "/deop", "/voice", "/devoice" commands + # "/invite" command + # "/kick", "/ban", "/unban" commands + # "/kill" command + # "/list" command: list of channels + # "/names" command: view who is on a given channel without being + on it (for example /names #weechat gives all the nicks present on + #weechat, except those who have the +i flag (server side)) + # "/oper" command: become operator on the irc network + # "/topic" command: change the topic of a channel + # "/version" command: give the irc client version (CTCP VERSION) + of a given nick/channel (without parameter: gives WeeChat version) + # "/whois" command + + * WeeChat commands: + # "/clear": to clear window content + + * Interface: + # "demi-highlight" when joins/quits etc + # log messages/warning/errors to ~/.weechat/log file + # improve editing zone (left arrow <> backspace) + # sort nick list + # choose nick list position (top, left, right (default), bottom) + # auto-resize nicklist (when nick too long) + # do pretty cutting of long lines (align on the nick or after hour for server) + # keep history of commands and call them again with up/down arrow + # text GUI + # ncurses GUI: + # one window for each channel + # color display + # private windows + # redraw window when term size is modified + # chat history (pgup/pgdn for displaying history) + # switch to other channel window + + * TCP/IP communication: + # IPv4 protocol implementation + + * Configuration: + # write default config file + + +Future versions: + + * IRC protocol: + - implement RFC 2812 + + "/mode" command: change the user/channels modes + - "/dcc" command (for chat and sending/receiving files) + - manage "halfop" status + - complete "/list" command: add regexp search, display only channels that + match regexp + - "/connect" and "/disconnect" commands (for multiservers use) + - "/ignore" and "/unignore" commands: hide all that is write by a given + nick/host + - when we're away, WeeChat should log all the lines begenning by our nick. + When we come back from our away it should print it to the current window + - "/rehash" command: tell the server to reload its config file + - "/restart" command: tell the server to restart itself + - "/notify" and "/unnotify" command to be warn by WeeChat when a given + nick/host connect to the given irc network + - "/wallops" command: write the same string to all the + persons with the flag +w enable + + * WeeChat commands: + - "/completion" command: do shortcuts (for example when we type "u" + in the text bar it send it to the server as "you") + - "/exec" command: execute a command as if we was in shell + and show us the output on the current window. An option to exec + like -o could send the output to the server, on the current + channel/private + - "/reload" command: reload the WeeChat's config file + - "/set" command: allow the user to set the WeeChat variables + under WeeChat without editing the config file (colours, time + format, etc) + - "/highlight" command: highlight a given word when it appears on + channels/privates + + * Interface: + - display current channel modes (example : #weechat(+nt)) + - interpret ^B in messages (this means bold text) + - internationalization (traduce WeeChat in many languages) + - many channel windows in one window/term (window split) + - add lag indicator + - log chats to file + - forget some old lines that were displayed long time ago (now all is saved, + if WeeChat is running for long time, a lot of memory is used!) + - improve completion (for example complete command parameters when possible) + - understand incomplete commands if unambigous (for example: /he for /help is ok) + - add clock (in status bar?) + - Gtk GUI + ? Qt GUI + + * TCP/IP communication: + - IPv6 protocol implementation + + * Configuration: + - add key bindings to config file + - add missing options for config file + - write config file + - add an option for each server in order to run commands on join + (example: /msg nickserv identify password) + - channel list for auto-join (for each server) + - do not stop program if problem with options in config file + - load config file after GUI (so init values by default (colors, ...) before + loading config) + + * Plugins: + - add Perl plugin + - add Python plugin + - add Ruby plugin + - "/load" and "/unload" commands to (un)load extension scripts + (perl, python, ruby, ...) diff --git a/weechat/debian/changelog b/weechat/debian/changelog new file mode 100644 index 000000000..7ab78b78a --- /dev/null +++ b/weechat/debian/changelog @@ -0,0 +1,5 @@ +weechat (0.0.1-1) unstable; urgency=low + + * First version. + + -- FlashCode <flashcode@flashtux.org> Sat, 27 Jun 2003 12:00:00 +0200 diff --git a/weechat/debian/compat b/weechat/debian/compat new file mode 100644 index 000000000..b8626c4cf --- /dev/null +++ b/weechat/debian/compat @@ -0,0 +1 @@ +4 diff --git a/weechat/debian/control b/weechat/debian/control new file mode 100644 index 000000000..0a4844738 --- /dev/null +++ b/weechat/debian/control @@ -0,0 +1,14 @@ +Source: weechat +Section: net +Priority: optional +Maintainer: FlashCode <flashcode@flashtux.org> +Build-Depends: debhelper (>> 4.0.0) +Standards-Version: 3.5.8 + +Package: weechat +Architecture: any +Depends: ${shlibs:Depends} +Description: Fast, light and extensible IRC client + WeeChat (Wee Enhanced Environment for Chat) is a fast and light IRC client + for many operating systems. Everything can be done with a keyboard. + It is customizable and extensible with scripts. diff --git a/weechat/debian/copyright b/weechat/debian/copyright new file mode 100644 index 000000000..1a1dbdde6 --- /dev/null +++ b/weechat/debian/copyright @@ -0,0 +1,17 @@ +This package was debianized by FlashCode <flashcode@flashtux.org> on +Sat, 27 Sep 2003 10:00:00 +0200. + +It was downloaded from http://weechat.flashtux.org/download + +Upstream Author(s): FlashCode <flashcode@flashtux.org> + +Copyright: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +On Debian systems, the complete text of the GNU General Public +License, Version 2 can be found in the file +/usr/share/common-licenses/GPL diff --git a/weechat/debian/dirs b/weechat/debian/dirs new file mode 100644 index 000000000..e77248175 --- /dev/null +++ b/weechat/debian/dirs @@ -0,0 +1 @@ +usr/bin diff --git a/weechat/debian/docs b/weechat/debian/docs new file mode 100644 index 000000000..a204c4610 --- /dev/null +++ b/weechat/debian/docs @@ -0,0 +1,9 @@ +AUTHORS +BUGS +ChangeLog +COPYING +FAQ +INSTALL +NEWS +README +TODO diff --git a/weechat/debian/files b/weechat/debian/files new file mode 100644 index 000000000..48f4dc400 --- /dev/null +++ b/weechat/debian/files @@ -0,0 +1 @@ +weechat_0.0.1-1_i386.deb net optional diff --git a/weechat/debian/rules b/weechat/debian/rules new file mode 100755 index 000000000..db43ab7e6 --- /dev/null +++ b/weechat/debian/rules @@ -0,0 +1,97 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + + + + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + #/usr/bin/docbook-to-man debian/weechat.sgml > weechat.1 + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) clean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/weechat. + $(MAKE) install DESTDIR=$(CURDIR)/debian/weechat + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples +# dh_install +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman weechat.1 + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_perl +# dh_python +# dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/weechat/debian/weechat.substvars b/weechat/debian/weechat.substvars new file mode 100644 index 000000000..0e328c3d3 --- /dev/null +++ b/weechat/debian/weechat.substvars @@ -0,0 +1 @@ +shlibs:Depends=libc6 (>= 2.3.2-1), libncurses5 (>= 5.3.20030510-1) diff --git a/weechat/src/Makefile b/weechat/src/Makefile new file mode 100644 index 000000000..575773bb1 --- /dev/null +++ b/weechat/src/Makefile @@ -0,0 +1,91 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=weechat + +OBJS=weechat.o config.o command.o completion.o history.o +OBJS_IRC=irc/irc.a +OBJS_GUI=gui/gui.a + + +# WeeChat with Curses interface +ifeq ($(GUI), curses) +LIBS_CURSES=-lcurses +DEFINES=WEE_CURSES + +curses: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_CURSES) +endif + +# WeeChat with Gtk+ interface +ifeq ($(GUI), gtk) +OBJS_GTK=gui-gtk.o +LIBS_GTK= +DEFINES=WEE_GTK +gtk: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_GTK) +endif + +# WeeChat with Qt interface +ifeq ($(GUI), qt) +OBJS_QT=gui-qt.o +LIBS_QT= +DEFINES=WEE_QT +qt: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_QT) +endif + +# WeeChat with Text interface +ifeq ($(GUI), text) +OBJS_TEXT=gui-text.o +LIBS_TEXT= +DEFINES=WEE_TEXT +text: $(OBJS) $(OBJS_IRC) $(OBJS_GUI) + $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_TEXT) +endif + + +all: + make curses GUI=curses + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +irc/irc.a: + cd irc && make + +gui/gui.a: + cd gui && make $(GUI) GUI=$(GUI) + +clean: + rm -f *.o *.a *~ core $(OUTPUT) + cd irc && make clean + cd gui && make clean + +command.o: command.c weechat.h command.h irc/irc.h gui/gui.h completion.h \ + history.h config.h +completion.o: completion.c weechat.h completion.h irc/irc.h gui/gui.h \ + history.h command.h +config.o: config.c weechat.h config.h irc/irc.h gui/gui.h completion.h \ + history.h +history.o: history.c weechat.h history.h gui/gui.h completion.h +weechat.o: weechat.c weechat.h config.h command.h irc/irc.h gui/gui.h \ + completion.h history.h diff --git a/weechat/src/command.c b/weechat/src/command.c new file mode 100644 index 000000000..ddd3ce202 --- /dev/null +++ b/weechat/src/command.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* command.c: WeeChat internal commands */ + + +#include <stdlib.h> +#include <string.h> + +#include "weechat.h" +#include "command.h" +#include "irc/irc.h" +#include "config.h" +#include "gui/gui.h" + + +/* WeeChat internal commands */ + +t_weechat_command weechat_commands[] = +{ { "alias", N_("create an alias for a command"), + N_("[alias_name [command [arguments]]"), + N_("alias_name: name of alias\ncommand: command name (" WEECHAT_NAME + " or IRC command)\n" "arguments: arguments for command"), + 0, MAX_ARGS, weechat_cmd_alias, NULL }, + { "clear", N_("clear window(s)"), + N_("[-all]"), + N_("-all: clear all windows"), + 0, 1, weechat_cmd_clear, NULL }, + { "help", N_("display help about commands"), + N_("[command]"), N_("command: name of a " WEECHAT_NAME " or IRC command"), + 0, 1, weechat_cmd_help, NULL }, + { "set", N_("set config parameters"), + N_("[option [value]]"), N_("option: name of an option\nvalue: value for option"), + 0, 2, weechat_cmd_set, NULL }, + { "unalias", N_("remove an alias"), + N_("alias_name"), N_("alias_name: name of alias to remove"), + 1, 1, weechat_cmd_unalias, NULL }, + { NULL, NULL, NULL, NULL, 0, 0, NULL, NULL } +}; + +t_index_command *index_commands; +t_index_command *last_index_command; + + +/* + * index_find_pos: find position for a command index (for sorting index) + */ + +t_index_command * +index_command_find_pos (char *command) +{ + t_index_command *ptr_index; + + for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index) + { + if (strcasecmp (command, ptr_index->command_name) < 0) + return ptr_index; + } + return NULL; +} + +/* + * index_command_insert_sorted: insert index into sorted list + */ + +void +index_command_insert_sorted (t_index_command *index) +{ + t_index_command *pos_index; + + pos_index = index_command_find_pos (index->command_name); + + if (index_commands) + { + if (pos_index) + { + /* insert index into the list (before index found) */ + index->prev_index = pos_index->prev_index; + index->next_index = pos_index; + if (pos_index->prev_index) + pos_index->prev_index->next_index = index; + else + index_commands = index; + pos_index->prev_index = index; + } + else + { + /* add index to the end */ + index->prev_index = last_index_command; + index->next_index = NULL; + last_index_command->next_index = index; + last_index_command = index; + } + } + else + { + index->prev_index = NULL; + index->next_index = NULL; + index_commands = index; + last_index_command = index; + } + return; +} + +/* + * index_command_build: build an index of commands (internal, irc and alias) + * This list will be sorted, and used for completion + */ + +void +index_command_build () +{ + int i; + t_index_command *new_index; + + index_commands = NULL; + last_index_command = NULL; + i = 0; + while (weechat_commands[i].command_name) + { + if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command))))) + { + new_index->command_name = strdup (weechat_commands[i].command_name); + index_command_insert_sorted (new_index); + } + i++; + } + i = 0; + while (irc_commands[i].command_name) + { + if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg) + { + if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command))))) + { + new_index->command_name = strdup (irc_commands[i].command_name); + index_command_insert_sorted (new_index); + } + } + i++; + } +} + +/* + * explode_string: explode a string according to separators + */ + +char ** +explode_string (char *string, char *separators, int num_items_max, + int *num_items) +{ + int i, n_items; + char **array; + char *ptr, *ptr1, *ptr2; + + if (num_items != NULL) + *num_items = 0; + + n_items = num_items_max; + + if (string == NULL) + return NULL; + + if (num_items_max == 0) + { + /* calculate number of items */ + ptr = string; + i = 1; + while ((ptr = strpbrk (ptr, separators))) + { + while (strchr (separators, ptr[0]) != NULL) + ptr++; + i++; + } + n_items = i; + } + + array = + (char **) malloc ((num_items_max ? n_items : n_items + 1) * + sizeof (char *)); + + ptr1 = string; + ptr2 = string; + + for (i = 0; i < n_items; i++) + { + while (strchr (separators, ptr1[0]) != NULL) + ptr1++; + if (i == (n_items - 1) || (ptr2 = strpbrk (ptr1, separators)) == NULL) + if ((ptr2 = strchr (ptr1, '\r')) == NULL) + if ((ptr2 = strchr (ptr1, '\n')) == NULL) + ptr2 = strchr (ptr1, '\0'); + + if ((ptr1 == NULL) || (ptr2 == NULL)) + { + array[i] = NULL; + } + else + { + if (ptr2 - ptr1 > 0) + { + array[i] = + (char *) malloc ((ptr2 - ptr1 + 1) * sizeof (char)); + array[i] = strncpy (array[i], ptr1, ptr2 - ptr1); + array[i][ptr2 - ptr1] = '\0'; + ptr1 = ++ptr2; + } + else + { + array[i] = NULL; + } + } + } + if (num_items_max == 0) + { + array[i] = NULL; + if (num_items != NULL) + *num_items = i; + } + else + { + if (num_items != NULL) + *num_items = num_items_max; + } + + return array; +} + +/* + * exec_weechat_command: executes a command (WeeChat internal or IRC) + * returns: 1 if command was executed succesfully + * 0 if error (command not executed) + */ + +int +exec_weechat_command (t_irc_server *server, char *string) +{ + int i, j, argc, return_code; + char *pos, *ptr_args, **argv; + + if ((!string[0]) || (string[0] != '/')) + return 0; + + /* look for end of command */ + ptr_args = NULL; + pos = strchr (string, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + ptr_args = pos; + if (!ptr_args[0]) + ptr_args = NULL; + } + + argv = explode_string (ptr_args, " ", 0, &argc); + + for (i = 0; weechat_commands[i].command_name; i++) + { + if (strcasecmp (weechat_commands[i].command_name, string + 1) == 0) + { + if ((argc < weechat_commands[i].min_arg) + || (argc > weechat_commands[i].max_arg)) + { + if (weechat_commands[i].min_arg == + weechat_commands[i].max_arg) + gui_printf (NULL, + _("%s wrong argument count for " + WEECHAT_NAME " command '%s' " + "(expected: %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + weechat_commands[i].max_arg, + (weechat_commands[i].max_arg > + 1) ? "s" : ""); + else + gui_printf (NULL, + _("%s wrong argument count for " + WEECHAT_NAME " command '%s' " + "(expected: between %d and %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + weechat_commands[i].min_arg, + weechat_commands[i].max_arg, + (weechat_commands[i].max_arg > + 1) ? "s" : ""); + } + else + { + if (weechat_commands[i].cmd_function_args != NULL) + return_code = (int) (weechat_commands[i].cmd_function_args) + (argc, argv); + else + return_code = (int) (weechat_commands[i].cmd_function_1arg) + (ptr_args); + if (return_code < 0) + gui_printf (NULL, + _("%s " WEECHAT_NAME " command \"%s\" failed\n"), + WEECHAT_ERROR, string + 1); + } + if (argv) + { + for (j = 0; argv[j]; j++) + free (argv[j]); + free (argv); + } + return 1; + } + } + for (i = 0; irc_commands[i].command_name; i++) + { + if (strcasecmp (irc_commands[i].command_name, string + 1) == 0) + { + if ((argc < irc_commands[i].min_arg) + || (argc > irc_commands[i].max_arg)) + { + if (irc_commands[i].min_arg == irc_commands[i].max_arg) + gui_printf + (NULL, + _("%s wrong argument count for IRC command '%s' " + "(expected: %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + irc_commands[i].max_arg, + (irc_commands[i].max_arg > 1) ? "s" : ""); + else + gui_printf + (NULL, + _("%s wrong argument count for IRC command '%s' " + "(expected: between %d and %d arg%s)\n"), + WEECHAT_ERROR, + string + 1, + irc_commands[i].min_arg, irc_commands[i].max_arg, + (irc_commands[i].max_arg > 1) ? "s" : ""); + } + else + { + if ((irc_commands[i].need_connection) && + ((!server) || (!server->is_connected))) + { + gui_printf (NULL, + _("%s command '%s' needs a server connection!\n"), + WEECHAT_ERROR, irc_commands[i].command_name); + return 0; + } + if (irc_commands[i].cmd_function_args != NULL) + return_code = (int) (irc_commands[i].cmd_function_args) + (server, argc, argv); + else + return_code = (int) (irc_commands[i].cmd_function_1arg) + (server, ptr_args); + if (return_code < 0) + gui_printf (NULL, + _("%s IRC command \"%s\" failed\n"), + WEECHAT_ERROR, string + 1); + } + if (argv) + { + for (j = 0; argv[j]; j++) + free (argv[j]); + free (argv); + } + return 1; + } + } + gui_printf (server->window, + _("%s unknown command '%s' (type /help for help)\n"), + WEECHAT_ERROR, + string + 1); + if (argv) + { + for (j = 0; argv[j]; j++) + free (argv[j]); + free (argv); + } + return 0; +} + +/* + * user_command: interprets user command (if beginning with '/') + * any other text is sent to the server, if connected + */ + +void +user_command (t_irc_server *server, char *command) +{ + t_irc_nick *ptr_nick; + + if ((!command) || (command[0] == '\r') || (command[0] == '\n')) + return; + if ((command[0] == '/') && (command[1] != '/')) + { + /* WeeChat internal command (or IRC command) */ + exec_weechat_command (server, command); + } + else + { + if ((command[0] == '/') && (command[1] == '/')) + command++; + if (!WIN_IS_SERVER(gui_current_window)) + { + server_sendf (server, "PRIVMSG %s :%s\r\n", + CHANNEL(gui_current_window)->name, + command); + + if (WIN_IS_PRIVATE(gui_current_window)) + { + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "<"); + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_NICK, + COLOR_WIN_NICK_SELF, + "%s", server->nick); + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "> "); + gui_printf_color_type (CHANNEL(gui_current_window)->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", command); + } + else + { + ptr_nick = nick_search (CHANNEL(gui_current_window), server->nick); + if (ptr_nick) + { + irc_display_nick (CHANNEL(gui_current_window)->window, ptr_nick, + MSG_TYPE_NICK, 1, 1, 0); + gui_printf_color (CHANNEL(gui_current_window)->window, + COLOR_WIN_CHAT, "%s\n", command); + } + else + gui_printf (server->window, + _("%s cannot find nick for sending message\n"), + WEECHAT_ERROR); + } + } + else + gui_printf (server->window, _("This window is not a channel!\n")); + } +} + +/* + * weechat_cmd_alias: display or create alias + */ + +int +weechat_cmd_alias (int argc, char **argv) +{ + if (argc == 0) + { + /* List all aliases */ + } + argv = NULL; + gui_printf (NULL, _("(TODO) \"/alias\" command not developed!\n")); + return 0; +} + +/* + * weechat_cmd_clear: display or create alias + */ + +int +weechat_cmd_clear (int argc, char **argv) +{ + if (argc == 1) + { + if (strcmp (argv[0], "-all") == 0) + gui_window_clear_all (); + else + { + gui_printf (NULL, + _("unknown parameter \"%s\" for /clear command\n"), + argv[0]); + return -1; + } + } + else + gui_window_clear (gui_current_window); + return 0; +} + +/* + * weechat_cmd_help: display help + */ + +int +weechat_cmd_help (int argc, char **argv) +{ + int i; + + if (argc == 0) + { + gui_printf (NULL, + _("> List of " WEECHAT_NAME " internal commands:\n")); + for (i = 0; weechat_commands[i].command_name; i++) + gui_printf (NULL, " %s - %s\n", + weechat_commands[i].command_name, + weechat_commands[i].command_description); + gui_printf (NULL, _("> List of IRC commands:\n")); + for (i = 0; irc_commands[i].command_name; i++) + if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg) + gui_printf (NULL, " %s - %s\n", + irc_commands[i].command_name, + irc_commands[i].command_description); + } + if (argc == 1) + { + for (i = 0; weechat_commands[i].command_name; i++) + { + if (strcasecmp (weechat_commands[i].command_name, argv[0]) == 0) + { + gui_printf + (NULL, + _("> Help on " WEECHAT_NAME " internal command '%s':\n"), + weechat_commands[i].command_name); + gui_printf (NULL, + _("Syntax: /%s %s\n"), + weechat_commands[i].command_name, + (weechat_commands[i]. + arguments) ? weechat_commands[i]. + arguments : ""); + if (weechat_commands[i].arguments_description) + { + gui_printf (NULL, "%s\n", + weechat_commands[i]. + arguments_description); + } + return 0; + } + } + for (i = 0; irc_commands[i].command_name; i++) + { + if (strcasecmp (irc_commands[i].command_name, argv[0]) == 0) + { + gui_printf (NULL, + _("> Help on IRC command '%s':\n"), + irc_commands[i].command_name); + gui_printf (NULL, _("Syntax: /%s %s\n"), + irc_commands[i].command_name, + (irc_commands[i].arguments) ? + irc_commands[i].arguments : ""); + if (irc_commands[i].arguments_description) + { + gui_printf (NULL, "%s\n", + irc_commands[i]. + arguments_description); + } + return 0; + } + } + gui_printf (NULL, + _("No help available, \"%s\" is an unknown command\n"), + argv[0]); + } + return 0; +} + +/* + * weechat_cmd_set: set options + */ + +int +weechat_cmd_set (int argc, char **argv) +{ + int i, j, section_displayed; + char *color_name; + + /* TODO: complete /set command */ + for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + section_displayed = 0; + if (i != CONFIG_SECTION_SERVER) + { + for (j = 0; weechat_options[i][j].option_name; j++) + { + if ((argc == 0) || + ((argc > 0) + && (strstr (weechat_options[i][j].option_name, argv[0]) + != NULL))) + { + if (!section_displayed) + { + gui_printf (NULL, "[%s]\n", + config_sections[i].section_name); + section_displayed = 1; + } + switch (weechat_options[i][j].option_type) + { + case OPTION_TYPE_BOOLEAN: + gui_printf (NULL, " %s = %s\n", + weechat_options[i][j].option_name, + (*weechat_options[i][j].ptr_int) ? + "ON" : "OFF"); + break; + case OPTION_TYPE_INT: + gui_printf (NULL, + " %s = %d\n", + weechat_options[i][j].option_name, + *weechat_options[i][j].ptr_int); + break; + case OPTION_TYPE_INT_WITH_STRING: + gui_printf (NULL, + " %s = %s\n", + weechat_options[i][j].option_name, + weechat_options[i][j].array_values[*weechat_options[i][j].ptr_int]); + break; + case OPTION_TYPE_COLOR: + color_name = gui_get_color_by_value (*weechat_options[i][j].ptr_int); + gui_printf (NULL, + " %s = %s\n", + weechat_options[i][j].option_name, + (color_name) ? color_name : _("(unknown)")); + break; + case OPTION_TYPE_STRING: + gui_printf (NULL, " %s = %s\n", + weechat_options[i][j]. + option_name, + (*weechat_options[i][j]. + ptr_string) ? + *weechat_options[i][j]. + ptr_string : ""); + break; + } + } + } + } + } + gui_printf (NULL, _("(TODO) \"/set\" command not developed!\n")); + return 0; +} + +/* + * cmd_unalias: remove an alias + */ + +int +weechat_cmd_unalias (int argc, char **argv) +{ + if (argc != 1) + { + gui_printf + (NULL, + _("Wrong argument count for unalias function (expexted: 1 arg)\n")); + return -1; + } + argv = NULL; + gui_printf (NULL, _("(TODO) \"/unalias\" not developed!\n")); + return 0; +} diff --git a/weechat/src/command.h b/weechat/src/command.h new file mode 100644 index 000000000..5bec6c92e --- /dev/null +++ b/weechat/src/command.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_COMMAND_H +#define __WEECHAT_COMMAND_H 1 + +#include "irc/irc.h" + +#define MAX_ARGS 8192 + +typedef struct t_weechat_command t_weechat_command; + +struct t_weechat_command +{ + char *command_name; + char *command_description; + char *arguments; + char *arguments_description; + int min_arg, max_arg; + int (*cmd_function_args)(int, char **); + int (*cmd_function_1arg)(char *); +}; + +typedef struct t_index_command t_index_command; + +struct t_index_command +{ + char *command_name; + t_index_command *prev_index; + t_index_command *next_index; +}; + +extern t_index_command *index_commands; + +extern void index_command_build (); +extern int exec_weechat_command (t_irc_server *, char *); +extern void user_command (t_irc_server *, char *); +extern int weechat_cmd_alias(int, char **); +extern int weechat_cmd_clear(int, char **); +extern int weechat_cmd_help (int, char **); +extern int weechat_cmd_set (int, char **); +extern int weechat_cmd_unalias (int, char **); + +#endif /* command.h */ diff --git a/weechat/src/completion.c b/weechat/src/completion.c new file mode 100644 index 000000000..6809d8100 --- /dev/null +++ b/weechat/src/completion.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* completion.c: completes words according to context (cmd/nick) */ + + +#include <stdlib.h> +#include <string.h> + +#include "weechat.h" +#include "completion.h" +#include "irc/irc.h" +#include "command.h" + + +/* + * completion_init: init completion + */ + +void +completion_init (t_completion *completion) +{ + completion->position = -1; + completion->base_word = NULL; +} + +/* + * completion_command: complete a command + */ + +void +completion_command (t_completion *completion) +{ + int length, word_found_seen; + t_index_command *ptr_index; + + length = strlen (completion->base_word) - 1; + word_found_seen = 0; + for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index) + { + if (strncasecmp (ptr_index->command_name, completion->base_word + 1, length) == 0) + { + if ((!completion->word_found) || word_found_seen) + { + completion->word_found = ptr_index->command_name; + return; + } + } + if (completion->word_found && + (strcasecmp (ptr_index->command_name, completion->word_found) == 0)) + word_found_seen = 1; + } + if (completion->word_found) + { + completion->word_found = NULL; + completion_command (completion); + } +} + +/* + * completion_nick: complete a nick + */ + +void +completion_nick (t_completion *completion, t_irc_channel *channel) +{ + int length, word_found_seen; + t_irc_nick *ptr_nick; + + length = strlen (completion->base_word); + word_found_seen = 0; + for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + { + if (strncasecmp (ptr_nick->nick, completion->base_word, length) == 0) + { + if ((!completion->word_found) || word_found_seen) + { + completion->word_found = ptr_nick->nick; + return; + } + } + if (completion->word_found && + (strcasecmp (ptr_nick->nick, completion->word_found) == 0)) + word_found_seen = 1; + } + if (completion->word_found) + { + completion->word_found = NULL; + completion_nick (completion, channel); + } +} + +/* + * completion_search: complete word according to context + */ + +void +completion_search (t_completion *completion, void *channel, + char *buffer, int size, int pos) +{ + int i, pos_start, pos_end; + char *old_word_found; + + /* TODO: complete when no word is there with command according to context */ + if (size == 0) + { + completion->word_found = NULL; + return; + } + + /* if new complation => look for base word */ + if (pos != completion->position) + { + completion->word_found = NULL; + + if ((pos == size) || (buffer[pos-1] != ' ')) + pos--; + if ((pos > 0) && (buffer[pos] == ' ')) + return; + + i = pos; + while ((i >= 0) && (buffer[i] != ' ')) + i--; + pos_start = i + 1; + i = pos; + while ((i < size) && (buffer[i] != ' ')) + i++; + pos_end = i - 1; + + if (pos_start > pos_end) + return; + + completion->base_word_pos = pos_start; + + if (completion->base_word) + free (completion->base_word); + completion->base_word = (char *) malloc (pos_end - pos_start + 2); + + for (i = pos_start; i <= pos_end; i++) + completion->base_word[i - pos_start] = buffer[i]; + completion->base_word[pos_end - pos_start + 1] = '\0'; + + if (completion->base_word[0] == '/') + completion->position_replace = pos_start + 1; + else + completion->position_replace = pos_start; + } + + /* completion */ + old_word_found = completion->word_found; + if (completion->base_word[0] == '/') + { + completion_command (completion); + if (completion->word_found) + { + if (old_word_found) + completion->diff_size = strlen (completion->word_found) - + strlen (old_word_found); + else + completion->diff_size = strlen (completion->word_found) - + strlen (completion->base_word) + 1; + } + } + else + { + if (channel) + { + completion_nick (completion, (t_irc_channel *)channel); + if (completion->word_found) + { + if (old_word_found) + completion->diff_size = strlen (completion->word_found) - + strlen (old_word_found); + else + completion->diff_size = strlen (completion->word_found) - + strlen (completion->base_word); + } + } + } +} diff --git a/weechat/src/completion.h b/weechat/src/completion.h new file mode 100644 index 000000000..f07d4a1f7 --- /dev/null +++ b/weechat/src/completion.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_COMPLETION_H +#define __WEECHAT_COMPLETION_H 1 + +typedef struct t_completion t_completion; + +struct t_completion +{ + char *base_word; /* word to complete (when Tab was pressed) */ + int base_word_pos; /* beggining of base word */ + int position; /* position where we shoud complete */ + char *word_found; /* word found (to replace base word) */ + int position_replace; /* position where word should be replaced */ + int diff_size; /* size difference (< 0 = char(s) deleted) */ +}; + +extern void completion_init (t_completion *); +extern void completion_search (t_completion *, void *, char *, int, int); + +#endif /* completion.h */ diff --git a/weechat/src/config.c b/weechat/src/config.c new file mode 100644 index 000000000..ad93695b9 --- /dev/null +++ b/weechat/src/config.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* config.c: WeeChat configuration */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <time.h> + +#include "weechat.h" +#include "config.h" +#include "irc/irc.h" +#include "gui/gui.h" + + +/* config sections */ + +t_config_section config_sections[CONFIG_NUMBER_SECTIONS] = +{ { CONFIG_SECTION_LOOK, "look" }, + { CONFIG_SECTION_COLORS, "colors" }, + { CONFIG_SECTION_HISTORY, "history" }, + { CONFIG_SECTION_LOG, "log" }, + { CONFIG_SECTION_DCC, "dcc" }, + { CONFIG_SECTION_PROXY, "proxy" }, + { CONFIG_SECTION_SERVER, "server" } +}; + +/* config, look & feel section */ + +int cfg_look_startup_logo; +int cfg_look_startup_version; +char *cfg_look_weechat_slogan; +int cfg_look_color_nicks; +int cfg_look_color_actions; +int cfg_look_remove_colors_from_msgs; +int cfg_look_nicklist; +int cfg_look_nicklist_position; +char *cfg_look_nicklist_position_values[] = +{ "left", "right", "top", "bottom", NULL }; +int cfg_look_nicklist_min_size; +int cfg_look_nicklist_max_size; +int cfg_look_nickmode; +int cfg_look_nickmode_empty; +char *cfg_look_no_nickname; +char *cfg_look_completor; + +t_config_option weechat_options_look[] = +{ { "look_startup_logo", N_("display " WEECHAT_NAME " logo at startup"), + N_("display " WEECHAT_NAME " logo at startup"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_startup_logo, NULL, NULL }, + { "look_startup_version", N_("display " WEECHAT_NAME " version at startup"), + N_("display " WEECHAT_NAME " version at startup"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_startup_version, NULL, NULL }, + { "look_weechat_slogan", N_(WEECHAT_NAME "slogan"), + N_(WEECHAT_NAME "slogan (if empty, slogan is not used)"), + OPTION_TYPE_STRING, 0, 0, 0, + "the geekest IRC client!", NULL, NULL, &cfg_look_weechat_slogan, NULL }, + { "look_color_nicks", N_("display nick names with different colors"), + N_("display nick names with different colors"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_color_nicks, NULL, NULL }, + { "look_color_actions", N_("display actions with different colors"), + N_("display actions with different colors"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_color_actions, NULL, NULL }, + { "look_remove_colors_from_msgs", N_("remove colors from incoming messages"), + N_("remove colors from incoming messages"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_remove_colors_from_msgs, NULL, NULL }, + { "look_nicklist", N_("display nicklist window"), + N_("display nicklist window (for channel windows)"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_nicklist, NULL, NULL }, + { "look_nicklist_position", N_("nicklist position"), + N_("nicklist position (top, left, right (default), bottom)"), + OPTION_TYPE_INT_WITH_STRING, 0, 0, 0, + "right", cfg_look_nicklist_position_values, &cfg_look_nicklist_position, NULL, NULL }, + { "look_nicklist_min_size", N_("min size for nicklist"), + N_("min size for nicklist (width or height, depending on look_nicklist_position " + "(0 = no min size))"), + OPTION_TYPE_INT, 0, 100, 0, + NULL, NULL, &cfg_look_nicklist_min_size, NULL, NULL }, + { "look_nicklist_max_size", N_("max size for nicklist"), + N_("max size for nicklist (width or height, depending on look_nicklist_position " + "(0 = no max size; if min == max and > 0, then size is fixed))"), + OPTION_TYPE_INT, 0, 100, 0, + NULL, NULL, &cfg_look_nicklist_max_size, NULL, NULL }, + { "look_no_nickname", N_("text to display instead of nick when not connected"), + N_("text to display instead of nick when not connected"), + OPTION_TYPE_STRING, 0, 0, 0, + "-cmd-", NULL, NULL, &cfg_look_no_nickname, NULL }, + { "look_nickmode", N_("display nick mode ((half)op/voice) before each nick"), + N_("display nick mode ((half)op/voice) before each nick"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_look_nickmode, NULL, NULL }, + { "look_nickmode_empty", N_("display space if nick mode is not (half)op/voice"), + N_("display space if nick mode is not (half)op/voice"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE, + NULL, NULL, &cfg_look_nickmode_empty, NULL, NULL }, + { "look_nick_completor", N_("the string inserted after nick completion"), + N_("the string inserted after nick completion"), + OPTION_TYPE_STRING, 0, 0, 0, + ":", NULL, NULL, &cfg_look_completor, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, colors section */ + +int cfg_col_title; +int cfg_col_title_bg; +int cfg_col_chat; +int cfg_col_chat_time; +int cfg_col_chat_time_sep; +int cfg_col_chat_prefix1; +int cfg_col_chat_prefix2; +int cfg_col_chat_nick; +int cfg_col_chat_host; +int cfg_col_chat_channel; +int cfg_col_chat_dark; +int cfg_col_chat_bg; +int cfg_col_status; +int cfg_col_status_active; +int cfg_col_status_data_msg; +int cfg_col_status_data_other; +int cfg_col_status_more; +int cfg_col_status_bg; +int cfg_col_input; +int cfg_col_input_channel; +int cfg_col_input_nick; +int cfg_col_input_bg; +int cfg_col_nick; +int cfg_col_nick_op; +int cfg_col_nick_halfop; +int cfg_col_nick_voice; +int cfg_col_nick_sep; +int cfg_col_nick_self; +int cfg_col_nick_private; +int cfg_col_nick_bg; + +t_config_option weechat_options_colors[] = +{ /* title window */ + { "col_title", N_("color for title bar"), + N_("color for title bar"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_title, NULL, NULL }, + { "col_title_bg", N_("background for title bar"), + N_("background for title bar"), + OPTION_TYPE_COLOR, 0, 0, 0, + "blue", NULL, &cfg_col_title_bg, NULL, NULL }, + + /* chat window */ + { "col_chat", N_("color for chat text"), + N_("color for chat text"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_chat, NULL, NULL }, + { "col_chat_time", N_("color for time"), + N_("color for time in chat window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_chat_time, NULL, NULL }, + { "col_chat_time_sep", N_("color for time separator"), + N_("color for time separator (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "brown", NULL, &cfg_col_chat_time_sep, NULL, NULL }, + { "col_chat_prefix1", N_("color for 1st and 3rd char of prefix"), + N_("color for 1st and 3rd char of prefix"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightcyan", NULL, &cfg_col_chat_prefix1, NULL, NULL }, + { "col_chat_prefix2", N_("color for middle char of prefix"), + N_("color for middle char of prefix"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_chat_prefix2, NULL, NULL }, + { "col_chat_nick", N_("color for nicks in actions"), + N_("color for nicks in actions (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightcyan", NULL, &cfg_col_chat_nick, NULL, NULL }, + { "col_chat_host", N_("color for hostnames"), + N_("color for hostnames (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "cyan", NULL, &cfg_col_chat_host, NULL, NULL }, + { "col_chat_channel", N_("color for channel names in actions"), + N_("color for channel names in actions (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_chat_channel, NULL, NULL }, + { "col_chat_dark", N_("color for dark separators"), + N_("color for dark separators (chat window)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "green", NULL, &cfg_col_chat_dark, NULL, NULL }, + { "col_chat_bg", N_("background for chat"), + N_("background for chat window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "default", NULL, &cfg_col_chat_bg, NULL, NULL }, + + /* status window */ + { "col_status", N_("color for status bar"), + N_("color for status bar"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_status, NULL, NULL }, + { "col_status_active", N_("color for active window"), + N_("color for active window (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "yellow", NULL, &cfg_col_status_active, NULL, NULL }, + { "col_status_data_msg", N_("color for window with new messages"), + N_("color for window with new messages (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightred", NULL, &cfg_col_status_data_msg, NULL, NULL }, + { "col_status_data_other", N_("color for window with new data (not messages)"), + N_("color for window with new data (not messages) (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightmagenta", NULL, &cfg_col_status_data_other, NULL, NULL }, + { "col_status_more", N_("color for \"*MORE*\" text"), + N_("color for window with new data (status bar)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_status_more, NULL, NULL }, + { "col_status_bg", N_("background for status window"), + N_("background for status window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "blue", NULL, &cfg_col_status_bg, NULL, NULL }, + + /* input window */ + { "col_input", N_("color for input text"), + N_("color for input text"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_input, NULL, NULL }, + { "col_input_channel", N_("color for input text (channel name)"), + N_("color for input text (channel name)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_input_channel, NULL, NULL }, + { "col_input_nick", N_("color for input text (nick name)"), + N_("color for input text (nick name)"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightgreen", NULL, &cfg_col_input_nick, NULL, NULL }, + { "col_input_bg", N_("background for input window"), + N_("background for input window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "default", NULL, &cfg_col_input_bg, NULL, NULL }, + + /* nick window */ + { "col_nick", N_("color for nicknames"), + N_("color for nicknames"), + OPTION_TYPE_COLOR, 0, 0, 0, + "gray", NULL, &cfg_col_nick, NULL, NULL }, + { "col_nick_op", N_("color for operator symbol"), + N_("color for operator symbol"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightgreen", NULL, &cfg_col_nick_op, NULL, NULL }, + { "col_nick_halfop", N_("color for half-operator symbol"), + N_("color for half-operator symbol"), + OPTION_TYPE_COLOR, 0, 0, 0, + "lightmagenta", NULL, &cfg_col_nick_halfop, NULL, NULL }, + { "col_nick_voice", N_("color for voice symbol"), + N_("color for voice symbol"), + OPTION_TYPE_COLOR, 0, 0, 0, + "yellow", NULL, &cfg_col_nick_voice, NULL, NULL }, + { "col_nick_sep", N_("color for nick separator"), + N_("color for nick separator"), + OPTION_TYPE_COLOR, 0, 0, 0, + "blue", NULL, &cfg_col_nick_sep, NULL, NULL }, + { "col_nick_self", N_("color for local nick"), + N_("color for local nick"), + OPTION_TYPE_COLOR, 0, 0, 0, + "white", NULL, &cfg_col_nick_self, NULL, NULL }, + { "col_nick_private", N_("color for other nick in private window"), + N_("color for other nick in private window"), + OPTION_TYPE_COLOR, 0, 0, 0, + "brown", NULL, &cfg_col_nick_private, NULL, NULL }, + { "col_nick_bg", N_("background for nicknames"), + N_("background for nicknames"), + OPTION_TYPE_COLOR, 0, 0, 0, + "default", NULL, &cfg_col_nick_bg, NULL, NULL }, + + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, history section */ + +int cfg_history_max_lines; +int cfg_history_max_commands; + +t_config_option weechat_options_history[] = +{ { "history_max_lines", N_("max lines in history (per window)"), + N_("maximum number of lines in history " + "for one server/channel/private window (0 = unlimited)"), + OPTION_TYPE_INT, 0, INT_MAX, 4096, + NULL, NULL, &cfg_history_max_lines, NULL, NULL }, + { "history_max_commands", N_("max user commands in history"), + N_("maximum number of user commands in history (0 = unlimited)"), + OPTION_TYPE_INT, 0, INT_MAX, 100, + NULL, NULL, &cfg_history_max_commands, NULL, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, log section */ + +int cfg_log_auto_channels; +int cfg_log_auto_private; +char *cfg_log_path; +char *cfg_log_name; +char *cfg_log_timestamp; +char *cfg_log_start_string; +char *cfg_log_end_string; + +t_config_option weechat_options_log[] = +{ { "log_auto_channels", N_("automatically log channel chats"), + N_("automatically log channel chats"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_log_auto_channels, NULL, NULL }, + { "log_auto_private", N_("automatically log private chats"), + N_("automatically log private chats"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_log_auto_private, NULL, NULL }, + { "log_path", N_("path for log files"), + N_("path for " WEECHAT_NAME " log files"), + OPTION_TYPE_STRING, 0, 0, 0, + "~/.weechat/logs/", NULL, NULL, &cfg_log_path, NULL }, + { "log_name", N_("name for log files"), + N_("name for log files (%S == irc server name, " + "%N == channel name (or nickname if private chat)"), + OPTION_TYPE_STRING, 0, 0, 0, + "%S,%N.weechatlog", NULL, NULL, &cfg_log_name, NULL }, + { "log_timestamp", N_("timestamp for log"), + N_("timestamp for log (see man strftime for date/time specifiers)"), + OPTION_TYPE_STRING, 0, 0, 0, + "~", NULL, NULL, &cfg_log_timestamp, NULL }, + { "log_start_string", N_("start string for log files"), + N_("text writed when starting new log file " + "(see man strftime for date/time specifiers)"), + OPTION_TYPE_STRING, 0, 0, 0, + "--- Log started %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_start_string, NULL }, + { "log_end_string", N_("end string for log files"), + N_("text writed when ending log file " + "(see man strftime for date/time specifiers)"), + OPTION_TYPE_STRING, 0, 0, 0, + "--- Log ended %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_end_string, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, dcc section */ + +int cfg_dcc_auto_accept_files; +int cfg_dcc_auto_accept_max_size; +int cfg_dcc_auto_accept_chats; +int cfg_dcc_timeout; +char *cfg_dcc_download_path; +char *cfg_dcc_upload_path; +int cfg_dcc_auto_rename; +int cfg_dcc_auto_resume; + +t_config_option weechat_options_dcc[] = +{ { "dcc_auto_accept_files", N_("automatically accept dcc files"), + N_("automatically accept incoming dcc files"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_accept_files, NULL, NULL }, + { "dcc_auto_accept_max_size", N_("max size when auto accepting file"), + N_("maximum size for incoming file when automatically accepted"), + OPTION_TYPE_INT, 0, INT_MAX, 0, + NULL, NULL, &cfg_dcc_auto_accept_max_size, NULL, NULL }, + { "dcc_auto_accept_chats", N_("automatically accept dcc chats"), + N_("automatically accept dcc chats (use carefully!)"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_accept_chats, NULL, NULL }, + { "dcc_timeout", N_("timeout for dcc request"), + N_("timeout for dcc request (in seconds)"), + OPTION_TYPE_INT, 1, INT_MAX, 300, + NULL, NULL, &cfg_dcc_timeout, NULL, NULL }, + { "dcc_download_path", N_("path for incoming files with dcc"), + N_("path for writing incoming files with dcc (default: user home)"), + OPTION_TYPE_STRING, 0, 0, 0, "~", + NULL, NULL, &cfg_dcc_download_path, NULL }, + { "dcc_upload_path", N_("default path for sending files with dcc"), + N_("path for reading files when sending thru dcc (when no path is specified)"), + OPTION_TYPE_STRING, 0, 0, 0, "~", + NULL, NULL, &cfg_dcc_upload_path, NULL }, + { "dcc_auto_rename", N_("automatically rename dcc files if already exists"), + N_("rename incoming files if already exists (add '.1', '.2', ...)"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_rename, NULL, NULL }, + { "dcc_auto_resume", N_("automatically resume aborted transfers"), + N_("automatically resume dcc trsnafer if connection with remote host is loosed"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE, + NULL, NULL, &cfg_dcc_auto_resume, NULL, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, proxy section */ + +int cfg_proxy_use; +char *cfg_proxy_address; +int cfg_proxy_port; +char *cfg_proxy_password; + +t_config_option weechat_options_proxy[] = +{ { "proxy_use", N_("use proxy"), + N_("use a proxy server to connect to irc server"), + OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE, + NULL, NULL, &cfg_proxy_use, NULL, NULL }, + { "proxy_address", N_("proxy address"), + N_("proxy server address (IP or hostname)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &cfg_proxy_address, NULL }, + { "proxy_port", N_("port for proxy"), + N_("port for connecting to proxy server"), + OPTION_TYPE_INT, 0, 65535, 1080, + NULL, NULL, &cfg_proxy_port, NULL, NULL }, + { "proxy_password", N_("proxy password"), + N_("password for proxy server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &cfg_proxy_password, NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* config, server section */ + +static t_irc_server cfg_server; + +t_config_option weechat_options_server[] = +{ { "server_name", N_("server name"), + N_("name associated to IRC server (for display only)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.name), NULL }, + { "server_address", N_("server address or hostname"), + N_("IP address or hostname of IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.address), NULL }, + { "server_port", N_("port for IRC server"), + N_("port for connecting to server"), + OPTION_TYPE_INT, 0, 65535, 6667, + NULL, NULL, &(cfg_server.port), NULL, NULL }, + { "server_password", N_("server password"), + N_("password for IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.password), NULL }, + { "server_nick1", N_("nickname for server"), + N_("nickname to use on IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.nick1), NULL }, + { "server_nick2", N_("alternate nickname for server"), + N_("alternate nickname to use on IRC server (if nickname is already used)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.nick2), NULL }, + { "server_nick3", N_("2nd alternate nickname for server"), + N_("2nd alternate nickname to use on IRC server (if alternate nickname is already used)"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.nick3), NULL }, + { "server_username", N_("user name for server"), + N_("user name to use on IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.username), NULL }, + { "server_realname", N_("real name for server"), + N_("real name to use on IRC server"), + OPTION_TYPE_STRING, 0, 0, 0, + "", NULL, NULL, &(cfg_server.realname), NULL }, + { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + +/* all weechat options */ + +t_config_option *weechat_options[CONFIG_NUMBER_SECTIONS] = +{ weechat_options_look, weechat_options_colors, weechat_options_history, + weechat_options_log, weechat_options_dcc, weechat_options_proxy, + weechat_options_server +}; + + +/* + * get_pos_array_values: returns position of a string in an array of values + * returns -1 if not found, otherwise position + */ + +int +get_pos_array_values (char **array, char *string) +{ + int i; + + i = 0; + while (array[i]) + { + if (strcasecmp (array[i], string) == 0) + return i; + i++; + } + /* string not found in array */ + return -1; +} + +/* + * config_init_server: init server struct + */ + +void +config_init_server () +{ + cfg_server.name = NULL; + cfg_server.address = NULL; + cfg_server.port = -1; + cfg_server.password = NULL; + cfg_server.nick1 = NULL; + cfg_server.nick2 = NULL; + cfg_server.nick3 = NULL; + cfg_server.username = NULL; + cfg_server.realname = NULL; +} + +/* + * config_allocate_server: allocate a new server + */ + +int +config_allocate_server (char *filename, int line_number) +{ + if (!cfg_server.name + || !cfg_server.address + || cfg_server.port < 0 + || !cfg_server.nick1 + || !cfg_server.nick2 + || !cfg_server.nick3 + || !cfg_server.username + || !cfg_server.realname) + { + server_free_all (); + gui_printf (NULL, + _("%s %s, line %d: new server, but previous was incomplete\n"), + WEECHAT_WARNING, filename, line_number); + return 0; + + } + if (server_name_already_exists (cfg_server.name)) + { + server_free_all (); + gui_printf (NULL, + _("%s %s, line %d: server '%s' already exists\n"), + WEECHAT_WARNING, filename, line_number, cfg_server.name); + return 0; + } + if (!server_new (cfg_server.name, + cfg_server.address, cfg_server.port, cfg_server.password, + cfg_server.nick1, cfg_server.nick2, cfg_server.nick3, + cfg_server.username, cfg_server.realname)) + { + server_free_all (); + gui_printf (NULL, + _("%s %s, line %d: unable to create server\n"), + WEECHAT_WARNING, filename, line_number); + return 0; + } + if (cfg_server.name) + free (cfg_server.name); + if (cfg_server.address) + free (cfg_server.address); + if (cfg_server.password) + free (cfg_server.password); + if (cfg_server.nick1) + free (cfg_server.nick1); + if (cfg_server.nick2) + free (cfg_server.nick2); + if (cfg_server.nick3) + free (cfg_server.nick3); + if (cfg_server.username) + free (cfg_server.username); + if (cfg_server.realname) + free (cfg_server.realname); + if (cfg_server.nick) + free (cfg_server.nick); + + config_init_server (); + + return 1; +} + +/* + * config_default_values: initialize config variables with default values + */ + +void +config_default_values () +{ + int i, j, int_value; + + for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + if (i != CONFIG_SECTION_SERVER) + { + for (j = 0; weechat_options[i][j].option_name; j++) + { + switch (weechat_options[i][j].option_type) + { + case OPTION_TYPE_BOOLEAN: + case OPTION_TYPE_INT: + *weechat_options[i][j].ptr_int = + weechat_options[i][j].default_int; + break; + case OPTION_TYPE_INT_WITH_STRING: + int_value = get_pos_array_values ( + weechat_options[i][j].array_values, + weechat_options[i][j].default_string); + if (int_value < 0) + gui_printf (NULL, + _("%s unable to assign default int with string (\"%s\")\n"), + weechat_options[i][j].default_string); + else + *weechat_options[i][j].ptr_int = + int_value; + break; + case OPTION_TYPE_COLOR: + if (!gui_assign_color ( + weechat_options[i][j].ptr_int, + weechat_options[i][j].default_string)) + gui_printf (NULL, + _("%s unable to assign default color (\"%s\")\n"), + weechat_options[i][j].default_string); + break; + case OPTION_TYPE_STRING: + *weechat_options[i][j].ptr_string = + strdup (weechat_options[i][j].default_string); + break; + } + } + } + } +} + +/* + * config_read: read WeeChat configuration + * returns: 0 = successful + * -1 = config file file not found + * < -1 = other error (fatal) + */ + +int +config_read () +{ + char *filename; + FILE *file; + int section, line_number, i, option_number, int_value; + int server_found; + char line[1024], *ptr_line, *pos, *pos2; + + filename = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME")); + if ((file = fopen (filename, "rt")) == NULL) + { + gui_printf (NULL, _("%s config file \"%s\" not found.\n"), + WEECHAT_WARNING, filename); + free (filename); + return -1; + } + + config_default_values (); + config_init_server (); + + /* read config file */ + section = CONFIG_SECTION_NONE; + server_found = 0; + line_number = 0; + while (!feof (file)) + { + ptr_line = fgets (line, sizeof (line) - 1, file); + line_number++; + if (ptr_line) + { + /* skip spaces */ + while (ptr_line[0] == ' ') + ptr_line++; + /* not a comment and not an empty line */ + if ((ptr_line[0] != '#') && (ptr_line[0] != '\r') + && (ptr_line[0] != '\n')) + { + /* beginning of section */ + if (ptr_line[0] == '[') + { + pos = strchr (line, ']'); + if (pos == NULL) + { + gui_printf (NULL, + _("%s %s, line %d: invalid syntax, missing \"]\"\n"), + WEECHAT_WARNING, filename, line_number); + fclose (file); + free (filename); + return -2; + } + pos[0] = '\0'; + pos = ptr_line + 1; + section = CONFIG_SECTION_NONE; + for (i = 0; config_sections[i].section_name; i++) + { + if (strcmp (config_sections[i].section_name, pos) == 0) + { + section = i; + break; + } + } + if (section == CONFIG_SECTION_NONE) + { + gui_printf (NULL, + _("%s %s, line %d: unknown section identifier (\"%s\")\n"), + WEECHAT_WARNING, filename, line_number, pos); + fclose (file); + free (filename); + return -2; + } + if (server_found) + { + /* if server already started => create it */ + if (!config_allocate_server (filename, line_number)) + { + fclose (file); + free (filename); + return -2; + } + } + server_found = (section == CONFIG_SECTION_SERVER) ? 1 : 0; + } + else + { + pos = strchr (line, '='); + if (pos == NULL) + { + gui_printf (NULL, + _("%s %s, line %d: invalid syntax, missing \"=\"\n"), + WEECHAT_WARNING, filename, line_number); + fclose (file); + free (filename); + return -2; + } + else + { + pos[0] = '\0'; + pos++; + pos2 = strchr (pos, '\r'); + if (pos2 != NULL) + pos2[0] = '\0'; + pos2 = strchr (pos, '\n'); + if (pos2 != NULL) + pos2[0] = '\0'; + option_number = -1; + for (i = 0; + weechat_options[section][i].option_name; i++) + { + if (strcmp + (weechat_options[section][i].option_name, + ptr_line) == 0) + { + option_number = i; + break; + } + } + if (option_number < 0) + { + gui_printf (NULL, + _("%s %s, line %d: invalid option \"%s\"\n"), + WEECHAT_WARNING, filename, line_number, ptr_line); + fclose (file); + free (filename); + return -2; + } + else + { + switch (weechat_options[section] + [option_number].option_type) + { + case OPTION_TYPE_BOOLEAN: + if (strcasecmp (pos, "on") == 0) + *weechat_options[section] + [option_number].ptr_int = BOOL_TRUE; + else if (strcasecmp (pos, "off") == 0) + *weechat_options[section] + [option_number].ptr_int = BOOL_FALSE; + else + { + gui_printf (NULL, + _("%s %s, line %d: invalid value for" + "option '%s'\n" + "Expected: boolean value: " + "'off' or 'on'\n"), + WEECHAT_WARNING, filename, + line_number, ptr_line); + fclose (file); + free (filename); + return -2; + } + break; + case OPTION_TYPE_INT: + int_value = atoi (pos); + if ((int_value < + weechat_options[section] + [option_number].min) + || (int_value > + weechat_options[section] + [option_number].max)) + { + gui_printf (NULL, + _("%s %s, line %d: invalid value for" + "option '%s'\n" + "Expected: integer between %d " + "and %d\n"), + WEECHAT_WARNING, filename, + line_number, ptr_line, + weechat_options[section][option_number].min, + weechat_options[section][option_number].max); + fclose (file); + free (filename); + return -2; + } + *weechat_options[section][option_number].ptr_int = + int_value; + break; + case OPTION_TYPE_INT_WITH_STRING: + int_value = get_pos_array_values ( + weechat_options[section][option_number].array_values, + pos); + if (int_value < 0) + { + gui_printf (NULL, + _("%s %s, line %d: invalid value for" + "option '%s'\n" + "Expected: one of these strings: "), + WEECHAT_WARNING, filename, + line_number, ptr_line); + i = 0; + while (weechat_options[section][option_number].array_values[i]) + { + gui_printf (NULL, "\"%s\" ", + weechat_options[section][option_number].array_values[i]); + i++; + } + gui_printf (NULL, "\n"); + fclose (file); + free (filename); + return -2; + } + *weechat_options[section][option_number].ptr_int = + int_value; + break; + case OPTION_TYPE_COLOR: + if (!gui_assign_color ( + weechat_options[section][option_number].ptr_int, + pos)) + { + gui_printf (NULL, + _("%s %s, line %d: invalid color " + "name for option '%s'\n"), + WEECHAT_WARNING, filename, + line_number, + ptr_line); + fclose (file); + free (filename); + return -2; + } + break; + case OPTION_TYPE_STRING: + if (*weechat_options[section] + [option_number].ptr_string) + free (*weechat_options[section][option_number].ptr_string); + *weechat_options[section][option_number].ptr_string = + strdup (pos); + break; + } + } + } + } + } + } + } + + if (server_found) + { + if (!config_allocate_server (filename, line_number)) + { + fclose (file); + free (filename); + return -2; + } + } + + /* set default colors for colors not set */ + /*for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + if (i != CONFIG_SECTION_SERVER) + { + for (j = 0; weechat_options[i][j].option_name; j++) + { + if ((weechat_options[i][j].option_type == OPTION_TYPE_COLOR) && + (*weechat_options[i][j].ptr_int == COLOR_NOT_SET)) + *weechat_options[i][j].ptr_int = + gui_get_color_by_name (weechat_options[i][j].default_string); + } + } + }*/ + + fclose (file); + free (filename); + + return 0; +} + + +/* + * config_create_default: create default WeeChat config + */ + +int +config_create_default () +{ + char *filename; + char line[1024]; + FILE *file; + int i, j; + time_t current_time; + + filename = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME")); + if ((file = fopen (filename, "wt")) == NULL) + { + free (filename); + gui_printf (NULL, _("%s cannot create file \"%s\"\n"), + WEECHAT_ERROR, filename); + return -1; + } + + printf (_(WEECHAT_NAME ": creating default config file...\n")); + + current_time = time (NULL); + sprintf (line, _("#\n# " WEECHAT_NAME " configuration file, generated by " + WEECHAT_NAME " " WEECHAT_VERSION " on %s"), ctime (¤t_time)); + fputs (line, file); + fputs (_("# This file may be edited by user. Invalid syntax will prevent " + WEECHAT_NAME " from running!\n#\n"), file); + + for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++) + { + if (i != CONFIG_SECTION_SERVER) + { + sprintf (line, "\n[%s]\n", config_sections[i].section_name); + fputs (line, file); + if ((i == CONFIG_SECTION_HISTORY) || (i == CONFIG_SECTION_LOG) || + (i == CONFIG_SECTION_DCC) || (i == CONFIG_SECTION_PROXY)) + { + sprintf (line, + "# WARNING!!! Options for section \"%s\" are not developed!\n", + config_sections[i].section_name); + fputs (line, file); + } + for (j = 0; weechat_options[i][j].option_name; j++) + { + switch (weechat_options[i][j].option_type) + { + case OPTION_TYPE_BOOLEAN: + sprintf (line, "%s=%s\n", + weechat_options[i][j].option_name, + (weechat_options[i][j]. + default_int) ? "on" : "off"); + break; + case OPTION_TYPE_INT: + sprintf (line, "%s=%d\n", + weechat_options[i][j].option_name, + weechat_options[i][j].default_int); + break; + case OPTION_TYPE_INT_WITH_STRING: + case OPTION_TYPE_COLOR: + case OPTION_TYPE_STRING: + sprintf (line, "%s=%s\n", + weechat_options[i][j].option_name, + weechat_options[i][j].default_string); + break; + } + fputs (line, file); + } + } + } + + /* default server is freenode */ + fputs ("\n[server]\n", file); + fputs ("server_name=freenode\n", file); + fputs ("server_address=irc.freenode.net\n", file); + fputs ("server_port=6667\n", file); + fputs ("server_password=\n", file); + fputs ("server_nick1=weechat_user\n", file); + fputs ("server_nick2=weechat2\n", file); + fputs ("server_nick3=weechat3\n", file); + fputs ("server_username=weechat\n", file); + fputs ("server_realname=WeeChat default realname\n", file); + + fclose (file); + free (filename); + return 0; +} + +/* + * config_write: write WeeChat configurtion + */ + +void +config_write () +{ + /* TODO: write "config_write" function! */ +} diff --git a/weechat/src/config.h b/weechat/src/config.h new file mode 100644 index 000000000..cc84eaab6 --- /dev/null +++ b/weechat/src/config.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_CONFIG_H +#define __WEECHAT_CONFIG_H 1 + +#define WEECHAT_CONFIG_NAME "weechat.rc" + +#define CONFIG_SECTION_NONE -1 +#define CONFIG_SECTION_LOOK 0 +#define CONFIG_SECTION_COLORS 1 +#define CONFIG_SECTION_HISTORY 2 +#define CONFIG_SECTION_LOG 3 +#define CONFIG_SECTION_DCC 4 +#define CONFIG_SECTION_PROXY 5 +#define CONFIG_SECTION_SERVER 6 +#define CONFIG_NUMBER_SECTIONS 7 + +#define OPTION_TYPE_BOOLEAN 1 /* values: on/off */ +#define OPTION_TYPE_INT 2 /* values: from min to max */ +#define OPTION_TYPE_INT_WITH_STRING 3 /* values: one from **array_values */ +#define OPTION_TYPE_COLOR 4 /* values: a color name */ +#define OPTION_TYPE_STRING 5 /* values: any string, may be empty */ + +#define BOOL_FALSE 0 +#define BOOL_TRUE 1 + +#define CFG_LOOK_NICKLIST_LEFT 0 +#define CFG_LOOK_NICKLIST_RIGHT 1 +#define CFG_LOOK_NICKLIST_TOP 2 +#define CFG_LOOK_NICKLIST_BOTTOM 3 + +typedef struct t_config_section t_config_section; + +struct t_config_section +{ + int section_number; + char *section_name; +}; + +typedef struct t_config_option t_config_option; + +struct t_config_option +{ + char *option_name; + char *short_description; + char *long_description; + int option_type; + int min, max; + int default_int; + char *default_string; + char **array_values; + int *ptr_int; + char **ptr_string; + int (*handler_change)(int *, char **); +}; + +extern int cfg_look_startup_logo; +extern int cfg_look_startup_version; +extern char *cfg_look_weechat_slogan; +extern int cfg_look_color_nicks; +extern int cfg_look_color_actions; +extern int cfg_look_remove_colors_from_msgs; +extern int cfg_look_nicklist; +extern int cfg_look_nicklist_position; +extern int cfg_look_nicklist_min_size; +extern int cfg_look_nicklist_max_size; +extern int cfg_look_nickmode; +extern int cfg_look_nickmode_empty; +extern char *cfg_look_no_nickname; +extern char *cfg_look_completor; + +extern int cfg_col_title; +extern int cfg_col_title_bg; +extern int cfg_col_chat; +extern int cfg_col_chat_time; +extern int cfg_col_chat_time_sep; +extern int cfg_col_chat_prefix1; +extern int cfg_col_chat_prefix2; +extern int cfg_col_chat_nick; +extern int cfg_col_chat_host; +extern int cfg_col_chat_channel; +extern int cfg_col_chat_dark; +extern int cfg_col_chat_bg; +extern int cfg_col_status; +extern int cfg_col_status_active; +extern int cfg_col_status_data_msg; +extern int cfg_col_status_data_other; +extern int cfg_col_status_more; +extern int cfg_col_status_bg; +extern int cfg_col_input; +extern int cfg_col_input_channel; +extern int cfg_col_input_nick; +extern int cfg_col_input_bg; +extern int cfg_col_nick; +extern int cfg_col_nick_op; +extern int cfg_col_nick_halfop; +extern int cfg_col_nick_voice; +extern int cfg_col_nick_sep; +extern int cfg_col_nick_self; +extern int cfg_col_nick_private; +extern int cfg_col_nick_bg; + +extern int cfg_history_max_lines; +extern int cfg_history_max_commands; + +extern int cfg_log_auto_channels; +extern int cfg_log_auto_private; +extern char *cfg_log_path; +extern char *cfg_log_name; +extern char *cfg_log_timestamp; +extern char *cfg_log_start_string; +extern char *cfg_log_end_string; + +extern int cfg_dcc_auto_accept_files; +extern int cfg_dcc_auto_accept_max_size; +extern int cfg_dcc_auto_accept_chats; +extern int cfg_dcc_timeout; +extern char *cfg_dcc_download_path; +extern char *cfg_dcc_upload_path; +extern int cfg_dcc_auto_rename; +extern int cfg_dcc_auto_resume; + +extern int cfg_proxy_use; +extern char *cfg_proxy_address; +extern int cfg_proxy_port; +extern char *cfg_proxy_password; + +extern t_config_section config_sections [CONFIG_NUMBER_SECTIONS]; +extern t_config_option * weechat_options [CONFIG_NUMBER_SECTIONS]; + +extern int config_read (); +extern int config_create_default (); +extern void config_write (); + +#endif /* config.h */ diff --git a/weechat/src/gui/Makefile b/weechat/src/gui/Makefile new file mode 100644 index 000000000..77d66bea7 --- /dev/null +++ b/weechat/src/gui/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# WeeChat with Curses interface +ifeq ($(GUI), curses) +curses: curses/gui.a +curses/gui.a: + cd curses && make +endif + +# WeeChat with Gtk+ interface +ifeq ($(GUI), gtk) +gtk: gtk/gui.a +gtk/gui.a: + cd gtk && make +endif + +# WeeChat with Qt interface +ifeq ($(GUI), qt) +qt: qt/gui.a +qt/gui.a: + cd qt && make +endif + +# WeeChat with Text interface +ifeq ($(GUI), text) +text: text/gui.a +text/gui.a: + cd text && make +endif + + +all: + make curses GUI=curses + +clean: + rm -f *.o *.a *~ core + cd curses && make clean + cd gtk && make clean + cd qt && make clean + cd text && make clean diff --git a/weechat/src/gui/curses/Makefile b/weechat/src/gui/curses/Makefile new file mode 100644 index 000000000..80f800dd9 --- /dev/null +++ b/weechat/src/gui/curses/Makefile @@ -0,0 +1,38 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_CURSES + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../completion.h \ + ../../history.h ../../config.h ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h ../../completion.h \ + ../../history.h ../../command.h ../../irc/irc.h ../../gui/gui.h diff --git a/weechat/src/gui/curses/gui-display.c b/weechat/src/gui/curses/gui-display.c new file mode 100644 index 000000000..9ad67edac --- /dev/null +++ b/weechat/src/gui/curses/gui-display.c @@ -0,0 +1,1730 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-display.c: display functions for Curses GUI */ + + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <time.h> +#include <sys/socket.h> +#include <curses.h> + +#include "../../weechat.h" +#include "../gui.h" +#include "../../config.h" +#include "../../irc/irc.h" + + +int gui_ready; /* = 1 if GUI is initialized */ + +t_gui_window *gui_windows = NULL; /* pointer to first window */ +t_gui_window *last_gui_window = NULL; /* pointer to last window */ +t_gui_window *gui_current_window = NULL; /* pointer to current window */ + +t_gui_color gui_colors[] = +{ { "default", -1 | A_NORMAL }, + { "black", COLOR_BLACK | A_NORMAL }, + { "red", COLOR_RED | A_NORMAL }, + { "lightred", COLOR_RED | A_BOLD }, + { "green", COLOR_GREEN | A_NORMAL }, + { "lightgreen", COLOR_GREEN | A_BOLD }, + { "brown", COLOR_YELLOW | A_NORMAL }, + { "yellow", COLOR_YELLOW | A_BOLD }, + { "blue", COLOR_BLUE | A_NORMAL }, + { "lightblue", COLOR_BLUE | A_BOLD }, + { "magenta", COLOR_MAGENTA | A_NORMAL }, + { "lightmagenta", COLOR_MAGENTA | A_BOLD }, + { "cyan", COLOR_CYAN | A_NORMAL }, + { "lightcyan", COLOR_CYAN | A_BOLD }, + { "gray", COLOR_WHITE }, + { "white", COLOR_WHITE | A_BOLD }, + { NULL, 0 } +}; + +char *nicks_colors[COLOR_WIN_NICK_NUMBER] = +{ "cyan", "magenta", "green", "brown", "lightblue", "gray", + "lightcyan", "lightmagenta", "lightgreen", "blue" }; + +int color_attr[NUM_COLORS]; + +/* + * gui_assign_color: assign a color (read from config) + */ + +int +gui_assign_color (int *color, char *color_name) +{ + int i; + + /* look for curses colors in table */ + i = 0; + while (gui_colors[i].name) + { + if (strcasecmp (gui_colors[i].name, color_name) == 0) + { + *color = gui_colors[i].color; + return 1; + } + i++; + } + + /* color not found */ + return 0; +} + +/* + * gui_get_color_by_name: get color by name + */ + +int +gui_get_color_by_name (char *color_name) +{ + int i; + + /* look for curses colors in table */ + i = 0; + while (gui_colors[i].name) + { + if (strcasecmp (gui_colors[i].name, color_name) == 0) + return gui_colors[i].color; + i++; + } + + /* color not found */ + return -1; +} + +/* + * gui_get_color_by_value: get color name by value + */ + +char * +gui_get_color_by_value (int color_value) +{ + int i; + + /* look for curses colors in table */ + i = 0; + while (gui_colors[i].name) + { + if (gui_colors[i].color == color_value) + return gui_colors[i].name; + i++; + } + + /* color not found */ + return NULL; +} + +/* + * gui_window_set_color: set color for window + */ + +void +gui_window_set_color (WINDOW *window, int num_color) +{ + if (has_colors) + { + if (color_attr[num_color - 1] & A_BOLD) + wattron (window, COLOR_PAIR (num_color) | A_BOLD); + else + { + wattroff (window, A_BOLD); + wattron (window, COLOR_PAIR (num_color)); + } + } +} + +/* + * gui_calculate_pos_size: calculate position and size for a window & sub-win + */ + +void +gui_calculate_pos_size (t_gui_window *window) +{ + int max_length, lines; + int num_nicks, num_op, num_halfop, num_voice, num_normal; + + /* global position & size */ + /* TODO: get values from function parameters */ + window->win_x = 0; + window->win_y = 0; + window->win_width = COLS; + window->win_height = LINES; + + /* init chat & nicklist settings */ + /* TODO: calculate values from function parameters */ + if (WIN_IS_CHANNEL(window)) + { + max_length = nick_get_max_length (CHANNEL(window)); + + switch (cfg_look_nicklist_position) + { + case CFG_LOOK_NICKLIST_LEFT: + window->win_chat_x = max_length + 2; + window->win_chat_y = 1; + window->win_chat_width = COLS - max_length - 2; + window->win_chat_height = LINES - 3; + window->win_nick_x = 0; + window->win_nick_y = 1; + window->win_nick_width = max_length + 2; + window->win_nick_height = LINES - 3; + break; + case CFG_LOOK_NICKLIST_RIGHT: + window->win_chat_x = 0; + window->win_chat_y = 1; + window->win_chat_width = COLS - max_length - 2; + window->win_chat_height = LINES - 3; + window->win_nick_x = COLS - max_length - 2; + window->win_nick_y = 1; + window->win_nick_width = max_length + 2; + window->win_nick_height = LINES - 3; + break; + case CFG_LOOK_NICKLIST_TOP: + nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop, + &num_voice, &num_normal); + if (((max_length + 1) * num_nicks) % COLS == 0) + lines = ((max_length + 1) * num_nicks) / COLS; + else + lines = (((max_length + 1) * num_nicks) / COLS) + 1; + window->win_chat_x = 0; + window->win_chat_y = 1 + (lines + 1); + window->win_chat_width = COLS; + window->win_chat_height = LINES - 3 - (lines + 1); + window->win_nick_x = 0; + window->win_nick_y = 1; + window->win_nick_width = COLS; + window->win_nick_height = lines + 1; + break; + case CFG_LOOK_NICKLIST_BOTTOM: + nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop, + &num_voice, &num_normal); + if (((max_length + 1) * num_nicks) % COLS == 0) + lines = ((max_length + 1) * num_nicks) / COLS; + else + lines = (((max_length + 1) * num_nicks) / COLS) + 1; + window->win_chat_x = 0; + window->win_chat_y = 1; + window->win_chat_width = COLS; + window->win_chat_height = LINES - 3 - (lines + 1); + window->win_nick_x = 0; + window->win_nick_y = LINES - 2 - (lines + 1); + window->win_nick_width = COLS; + window->win_nick_height = lines + 1; + break; + } + + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = 0; + } + else + { + window->win_chat_x = 0; + window->win_chat_y = 1; + window->win_chat_width = COLS; + window->win_chat_height = LINES - 3; + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = 0; + window->win_nick_x = -1; + window->win_nick_y = -1; + window->win_nick_width = -1; + window->win_nick_height = -1; + } +} + +/* + * gui_curses_window_clear: clear a window + */ + +void +gui_curses_window_clear (WINDOW *window) +{ + werase (window); + wmove (window, 0, 0); + //wrefresh (window); +} + +/* + * gui_draw_window_title: draw title window + */ + +void +gui_draw_window_title (t_gui_window *window) +{ + char format[32]; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_title, COLOR_WIN_TITLE); + wborder (window->win_title, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_title); + refresh (); + } + if (CHANNEL(window)) + { + sprintf (format, "%%-%ds", window->win_width); + if (CHANNEL(window)->topic) + mvwprintw (window->win_title, 0, 0, format, + CHANNEL(window)->topic); + } + else + { + /* TODO: change this copyright as title? */ + mvwprintw (window->win_title, 0, 0, + "%s", WEECHAT_NAME_AND_VERSION " - " WEECHAT_WEBSITE); + mvwprintw (window->win_title, 0, COLS - strlen (WEECHAT_COPYRIGHT), + "%s", WEECHAT_COPYRIGHT); + } + wrefresh (window->win_title); + refresh (); +} + +/* + * gui_redraw_window_title: redraw title window + */ + +void +gui_redraw_window_title (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_title); + gui_draw_window_title (window); +} + +/* + * gui_get_line_num_splits: returns number of lines on window + * (depending on window width and type (server/channel) + * for alignment) + */ + +int +gui_get_line_num_splits (t_gui_window *window, t_gui_line *line) +{ + int length, width; + + /* TODO: modify arbitraty value for non aligning messages on time/nick? */ + if (line->length_align >= window->win_chat_width - 5) + { + length = line->length; + width = window->win_chat_width; + } + else + { + length = line->length - line->length_align; + width = window->win_chat_width - line->length_align; + } + + return (length % width == 0) ? (length / width) : ((length / width) + 1); +} + +/* + * gui_display_end_of_line: display end of a line in the chat window + */ + +void +gui_display_end_of_line (t_gui_window *window, t_gui_line *line, int count) +{ + int lines_displayed, num_lines, offset, remainder, num_displayed; + t_gui_message *ptr_message; + char saved_char, format_align[32]; + + sprintf (format_align, "%%-%ds", line->length_align); + num_lines = gui_get_line_num_splits (window, line); + ptr_message = line->messages; + offset = 0; + lines_displayed = 0; + while (ptr_message) + { + /* set text color if beginning of message */ + if (offset == 0) + gui_window_set_color (window->win_chat, ptr_message->color); + + /* insert spaces for align text under time/nick */ + if ((lines_displayed > 0) && (window->win_chat_cursor_x == 0)) + { + if (lines_displayed >= num_lines - count) + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + format_align, " "); + window->win_chat_cursor_x += line->length_align; + } + + remainder = strlen (ptr_message->message + offset); + if (window->win_chat_cursor_x + remainder > + window->win_chat_width - 1) + { + num_displayed = window->win_chat_width - + window->win_chat_cursor_x; + saved_char = ptr_message->message[offset + num_displayed]; + ptr_message->message[offset + num_displayed] = '\0'; + if (lines_displayed >= num_lines - count) + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + ptr_message->message[offset + num_displayed] = saved_char; + offset += num_displayed; + } + else + { + num_displayed = remainder; + if (lines_displayed >= num_lines - count) + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + ptr_message = ptr_message->next_message; + offset = 0; + } + window->win_chat_cursor_x += num_displayed; + if (!ptr_message || + (window->win_chat_cursor_x > (window->win_chat_width - 1))) + { + window->win_chat_cursor_x = 0; + if (lines_displayed >= num_lines - count) + { + window->win_chat_cursor_y++; + } + lines_displayed++; + } + } +} + +/* + * gui_display_line: display a line in the chat window + * if stop_at_end == 1, screen will not scroll and then we + * exit since chat window is full + * returns: 1 if stop_at_end == 0 or screen not full + * 0 if screen is full and if stop_at_end == 1 + */ + +int +gui_display_line (t_gui_window *window, t_gui_line *line, int stop_at_end) +{ + int offset, remainder, num_displayed; + t_gui_message *ptr_message; + char saved_char, format_align[32]; + + sprintf (format_align, "%%-%ds", line->length_align); + ptr_message = line->messages; + offset = 0; + while (ptr_message) + { + /* cursor is below end line of chat window */ + if (window->win_chat_cursor_y > window->win_chat_height - 1) + { + /*if (!stop_at_end) + wscrl (window->win_chat, +1);*/ + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = window->win_chat_height - 1; + if (stop_at_end) + return 0; + window->first_line_displayed = 0; + } + + /* set text color if beginning of message */ + if (offset == 0) + gui_window_set_color (window->win_chat, ptr_message->color); + + /* insert spaces for align text under time/nick */ + if ((window->win_chat_cursor_x == 0) && + (ptr_message->type != MSG_TYPE_TIME) && + (ptr_message->type != MSG_TYPE_NICK) && + (line->length_align > 0) && + /* TODO: modify arbitraty value for non aligning messages on time/nick? */ + (line->length_align < (window->win_chat_width - 5))) + { + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + format_align, " "); + window->win_chat_cursor_x += line->length_align; + } + + remainder = strlen (ptr_message->message + offset); + if (window->win_chat_cursor_x + remainder > window->win_chat_width) + { + num_displayed = window->win_chat_width - + window->win_chat_cursor_x; + saved_char = ptr_message->message[offset + num_displayed]; + ptr_message->message[offset + num_displayed] = '\0'; + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + ptr_message->message[offset + num_displayed] = saved_char; + offset += num_displayed; + } + else + { + num_displayed = remainder; + mvwprintw (window->win_chat, + window->win_chat_cursor_y, + window->win_chat_cursor_x, + "%s", ptr_message->message + offset); + offset = 0; + ptr_message = ptr_message->next_message; + } + window->win_chat_cursor_x += num_displayed; + if (!ptr_message || + (window->win_chat_cursor_x > (window->win_chat_width - 1))) + { + if (!ptr_message || + ((window->win_chat_cursor_y <= window->win_chat_height - 1) && + (window->win_chat_cursor_x > window->win_chat_width - 1))) + window->win_chat_cursor_y++; + window->win_chat_cursor_x = 0; + } + } + return 1; +} + +/* + * gui_draw_window_chat: draw chat window + */ + +void +gui_draw_window_chat (t_gui_window *window) +{ + t_gui_line *ptr_line; + int lines_used; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_chat, COLOR_WIN_CHAT); + wborder (window->win_chat, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_chat); + } + + ptr_line = window->last_line; + lines_used = 0; + while (ptr_line + && (lines_used < (window->win_chat_height + window->sub_lines))) + { + lines_used += gui_get_line_num_splits (window, ptr_line); + ptr_line = ptr_line->prev_line; + } + window->win_chat_cursor_x = 0; + window->win_chat_cursor_y = 0; + if (lines_used > (window->win_chat_height + window->sub_lines)) + { + /* screen will be full (we'll display only end of 1st line) */ + ptr_line = (ptr_line) ? ptr_line->next_line : window->lines; + gui_display_end_of_line (window, ptr_line, + gui_get_line_num_splits (window, ptr_line) - + (lines_used - (window->win_chat_height + window->sub_lines))); + ptr_line = ptr_line->next_line; + window->first_line_displayed = 0; + } + else + { + /* all lines are displayed */ + if (!ptr_line) + { + window->first_line_displayed = 1; + ptr_line = window->lines; + } + else + { + window->first_line_displayed = 0; + ptr_line = ptr_line->next_line; + } + } + while (ptr_line) + { + if (!gui_display_line (window, ptr_line, 1)) + break; + + ptr_line = ptr_line->next_line; + } + /*if (window->win_chat_cursor_y <= window->win_chat_height - 1) + window->sub_lines = 0;*/ + wrefresh (window->win_chat); + refresh (); +} + +/* + * gui_redraw_window_chat: redraw chat window + */ + +void +gui_redraw_window_chat (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_chat); + gui_draw_window_chat (window); +} + +/* + * gui_draw_window_nick: draw nick window + */ + +void +gui_draw_window_nick (t_gui_window *window) +{ + int i, x, y, column, max_length; + char format[32]; + t_irc_nick *ptr_nick; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (CHANNEL(window) && CHANNEL(window)->nicks) + { + max_length = nick_get_max_length (CHANNEL(window)); + if ((max_length + 2) != window->win_nick_width) + { + gui_calculate_pos_size (window); + delwin (window->win_chat); + delwin (window->win_nick); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + window->win_nick = newwin (window->win_nick_height, + window->win_nick_width, + window->win_nick_y, + window->win_nick_x); + //scrollok (window->win_chat, TRUE); + gui_redraw_window_chat (window); + } + sprintf (format, "%%-%ds", max_length); + + if (has_colors ()) + { + switch (cfg_look_nicklist_position) + { + case CFG_LOOK_NICKLIST_LEFT: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP); + for (i = 0; i < window->win_chat_height; i++) + mvwprintw (window->win_nick, + i, window->win_nick_width - 1, " "); + break; + case CFG_LOOK_NICKLIST_RIGHT: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP); + for (i = 0; i < window->win_chat_height; i++) + mvwprintw (window->win_nick, + i, 0, " "); + break; + case CFG_LOOK_NICKLIST_TOP: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + for (i = 0; i < window->win_chat_width; i += 2) + mvwprintw (window->win_nick, + window->win_nick_height - 1, i, "-"); + break; + case CFG_LOOK_NICKLIST_BOTTOM: + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + for (i = 0; i < window->win_chat_width; i += 2) + mvwprintw (window->win_nick, + 0, i, "-"); + break; + } + } + + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + x = 0; + y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM) ? 1 : 0; + column = 0; + for (ptr_nick = CHANNEL(window)->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + switch (cfg_look_nicklist_position) + { + case CFG_LOOK_NICKLIST_LEFT: + x = 0; + break; + case CFG_LOOK_NICKLIST_RIGHT: + x = 1; + break; + case CFG_LOOK_NICKLIST_TOP: + case CFG_LOOK_NICKLIST_BOTTOM: + x = column; + break; + } + if (ptr_nick->is_op) + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_OP); + mvwprintw (window->win_nick, y, x, "@"); + x++; + } + else + { + if (ptr_nick->is_halfop) + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_HALFOP); + mvwprintw (window->win_nick, y, x, "%%"); + x++; + } + else + { + if (ptr_nick->has_voice) + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK_VOICE); + mvwprintw (window->win_nick, y, x, "+"); + x++; + } + else + { + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + mvwprintw (window->win_nick, y, x, " "); + x++; + } + } + } + gui_window_set_color (window->win_nick, COLOR_WIN_NICK); + mvwprintw (window->win_nick, y, x, format, ptr_nick->nick); + y++; + if ((cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) || + (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM)) + { + if (y >= window->win_nick_height - 1) + { + column += max_length + 1; + y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) ? + 0 : 1; + } + } + } + } + wrefresh (window->win_nick); + refresh (); +} + +/* + * gui_redraw_window_nick: redraw nick window + */ + +void +gui_redraw_window_nick (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_nick); + gui_draw_window_nick (window); +} + +/* + * gui_draw_window_status: draw status window + */ + +void +gui_draw_window_status (t_gui_window *window) +{ + t_gui_window *ptr_win; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_status, COLOR_WIN_STATUS); + wborder (window->win_status, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_status); + } + //refresh (); + wmove (window->win_status, 0, 0); + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + if (SERVER(ptr_win) && !CHANNEL(ptr_win)) + { + if (gui_current_window == SERVER(ptr_win)->window) + { + if (ptr_win->unread_data) + { + if (ptr_win->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_ACTIVE); + } + else + { + if (SERVER(ptr_win)->window && + ((SERVER(ptr_win)->window)->unread_data)) + { + if (SERVER(ptr_win)->window->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS); + } + if (SERVER(ptr_win)->is_connected) + wprintw (window->win_status, "[%s] ", + SERVER(ptr_win)->name); + else + wprintw (window->win_status, "(%s) ", + SERVER(ptr_win)->name); + } + if (SERVER(ptr_win) && CHANNEL(ptr_win)) + { + if (gui_current_window == CHANNEL(ptr_win)->window) + { + if ((CHANNEL(ptr_win)->window) && + (CHANNEL(ptr_win)->window->unread_data)) + { + if (CHANNEL(ptr_win)->window->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_ACTIVE); + } + else + { + if ((CHANNEL(ptr_win)->window) && + (CHANNEL(ptr_win)->window->unread_data)) + { + if (CHANNEL(ptr_win)->window->unread_data > 1) + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_MSG); + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS_DATA_OTHER); + } + else + gui_window_set_color (window->win_status, + COLOR_WIN_STATUS); + } + wprintw (window->win_status, "%s ", CHANNEL(ptr_win)->name); + } + if (!SERVER(ptr_win)) + { + gui_window_set_color (window->win_status, COLOR_WIN_STATUS); + wprintw (window->win_status, _("[not connected] ")); + } + } + + /* display "*MORE*" if last line is not displayed */ + gui_window_set_color (window->win_status, COLOR_WIN_STATUS_MORE); + if (window->sub_lines > 0) + mvwprintw (window->win_status, 0, COLS - 7, "-MORE-"); + else + mvwprintw (window->win_status, 0, COLS - 7, " "); + + wrefresh (window->win_status); + refresh (); +} + +/* + * gui_redraw_window_status: redraw status window + */ + +void +gui_redraw_window_status (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_status); + gui_draw_window_status (window); +} + +/* + * gui_get_input_width: return input width (max # chars displayed) + */ + +int +gui_get_input_width (t_gui_window *window) +{ + if (CHANNEL(window)) + return (COLS - strlen (CHANNEL(window)->name) - + strlen (SERVER(window)->nick) - 3); + else + { + if (SERVER(window) && (SERVER(window)->is_connected)) + return (COLS - strlen (SERVER(window)->nick) - 2); + else + return (COLS - strlen (cfg_look_no_nickname) - 2); + } +} + +/* + * gui_draw_window_input: draw input window + */ + +void +gui_draw_window_input (t_gui_window *window) +{ + char format[32]; + char *ptr_nickname; + int input_width; + + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + if (has_colors ()) + { + gui_window_set_color (window->win_input, COLOR_WIN_INPUT); + wborder (window->win_input, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wrefresh (window->win_input); + } + //refresh (); + + if (window->input_buffer_size == 0) + window->input_buffer[0] = '\0'; + + input_width = gui_get_input_width (window); + + if (window->input_buffer_pos - window->input_buffer_1st_display + 1 > + input_width) + window->input_buffer_1st_display = window->input_buffer_pos - + input_width + 1; + else + { + if (window->input_buffer_pos < window->input_buffer_1st_display) + window->input_buffer_1st_display = window->input_buffer_pos; + else + { + if ((window->input_buffer_1st_display > 0) && + (window->input_buffer_pos - + window->input_buffer_1st_display + 1) < input_width) + { + window->input_buffer_1st_display = + window->input_buffer_pos - input_width + 1; + if (window->input_buffer_1st_display < 0) + window->input_buffer_1st_display = 0; + } + } + } + if (CHANNEL(window)) + { + sprintf (format, "%%s %%s> %%-%ds", input_width); + mvwprintw (window->win_input, 0, 0, format, + CHANNEL(window)->name, + SERVER(window)->nick, + window->input_buffer + window->input_buffer_1st_display); + wclrtoeol (window->win_input); + move (LINES - 1, strlen (CHANNEL(window)->name) + + strlen (SERVER(window)->nick) + 3 + + (window->input_buffer_pos - window->input_buffer_1st_display)); + } + else + { + sprintf (format, "%%s> %%-%ds", input_width); + if (SERVER(window) && (SERVER(window)->is_connected)) + ptr_nickname = SERVER(window)->nick; + else + ptr_nickname = cfg_look_no_nickname; + mvwprintw (window->win_input, 0, 0, format, + ptr_nickname, + window->input_buffer + window->input_buffer_1st_display); + wclrtoeol (window->win_input); + move (LINES - 1, strlen (ptr_nickname) + 2 + + (window->input_buffer_pos - window->input_buffer_1st_display)); + } + + wrefresh (window->win_input); + refresh (); +} + +/* + * gui_redraw_window_input: redraw input window + */ + +void +gui_redraw_window_input (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_curses_window_clear (window->win_input); + gui_draw_window_input (window); +} + +/* + * gui_redraw_window: redraw a window + */ + +void +gui_redraw_window (t_gui_window *window) +{ + /* TODO: manage splitted windows! */ + if (window != gui_current_window) + return; + + gui_redraw_window_title (window); + gui_redraw_window_chat (window); + if (window->win_nick) + gui_redraw_window_nick (window); + gui_redraw_window_status (window); + gui_redraw_window_input (window); +} + +/* + * gui_window_clear: clear window content + */ + +void +gui_window_clear (t_gui_window *window) +{ + t_gui_line *ptr_line; + t_gui_message *ptr_message; + + while (window->lines) + { + ptr_line = window->lines->next_line; + while (window->lines->messages) + { + ptr_message = window->lines->messages->next_message; + if (window->lines->messages->message) + free (window->lines->messages->message); + free (window->lines->messages); + window->lines->messages = ptr_message; + } + free (window->lines); + window->lines = ptr_line; + } + + window->lines = NULL; + window->last_line = NULL; + window->first_line_displayed = 1; + window->sub_lines = 0; + window->line_complete = 1; + window->unread_data = 0; + + if (window == gui_current_window) + gui_redraw_window_chat (window); +} + +/* + * gui_window_clear_all: clear all windows content + */ + +void +gui_window_clear_all () +{ + t_gui_window *ptr_win; + + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + gui_window_clear (ptr_win); +} + +/* + * gui_switch_to_window: switch to another window + */ + +void +gui_switch_to_window (t_gui_window *window) +{ + int another_window; + t_gui_window *ptr_win; + + another_window = 0; + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + if (ptr_win->win_title) + { + /* TODO: manage splitted windows */ + another_window = 1; + window->win_title = ptr_win->win_title; + window->win_chat = ptr_win->win_chat; + window->win_nick = ptr_win->win_nick; + window->win_status = ptr_win->win_status; + window->win_input = ptr_win->win_input; + ptr_win->win_title = NULL; + ptr_win->win_chat = NULL; + ptr_win->win_nick = NULL; + ptr_win->win_status = NULL; + ptr_win->win_input = NULL; + break; + } + } + + /* first time creation for windows */ + if (!another_window) + { + /* create new windows */ + gui_calculate_pos_size (window); + window->win_title = newwin (1, COLS, 0, 0); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + //scrollok (window->win_chat, TRUE); + if (CHANNEL(window)) + window->win_nick = newwin (window->win_nick_height, + window->win_nick_width, + window->win_nick_y, + window->win_nick_x); + else + window->win_nick = NULL; + window->win_status = newwin (1, COLS, LINES - 2, 0); + window->win_input = newwin (1, COLS, LINES - 1, 0); + } + else + { + gui_calculate_pos_size (window); + + /* create chat & nick windows */ + if (WIN_IS_CHANNEL(window) && !(window->win_nick)) + { + /* add nick list window */ + delwin (window->win_chat); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + //scrollok (window->win_chat, TRUE); + window->win_nick = newwin (window->win_nick_height, + window->win_nick_width, + window->win_nick_y, + window->win_nick_x); + } + if (!(WIN_IS_CHANNEL(window)) && window->win_nick) + { + /* remove nick list window */ + delwin (window->win_nick); + window->win_nick = NULL; + delwin (window->win_chat); + window->win_chat = newwin (window->win_chat_height, + window->win_chat_width, + window->win_chat_y, + window->win_chat_x); + //scrollok (window->win_chat, TRUE); + } + } + + /* change current window to the new window */ + gui_current_window = window; + + window->unread_data = 0; +} + +/* + * gui_switch_to_previous_window: switch to previous window + */ + +void +gui_switch_to_previous_window () +{ + /* if only one windows then return */ + if (gui_windows == last_gui_window) + return; + + if (gui_current_window->prev_window) + gui_switch_to_window (gui_current_window->prev_window); + else + gui_switch_to_window (last_gui_window); + gui_redraw_window (gui_current_window); +} + +/* + * gui_switch_to_next_window: switch to next window + */ + +void +gui_switch_to_next_window () +{ + /* if only one windows then return */ + if (gui_windows == last_gui_window) + return; + + if (gui_current_window->next_window) + gui_switch_to_window (gui_current_window->next_window); + else + gui_switch_to_window (gui_windows); + gui_redraw_window (gui_current_window); +} + +/* + * gui_move_page_up: display previous page on window + */ + +void +gui_move_page_up () +{ + if (!gui_current_window->first_line_displayed) + { + gui_current_window->sub_lines += gui_current_window->win_chat_height - 1; + gui_redraw_window_chat (gui_current_window); + gui_redraw_window_status (gui_current_window); + } +} + +/* + * gui_move_page_down: display next page on window + */ + +void +gui_move_page_down () +{ + if (gui_current_window->sub_lines > 0) + { + gui_current_window->sub_lines -= gui_current_window->win_chat_height - 1; + if (gui_current_window->sub_lines < 0) + gui_current_window->sub_lines = 0; + if (gui_current_window->sub_lines == 0) + gui_current_window->unread_data = 0; + gui_redraw_window_chat (gui_current_window); + gui_redraw_window_status (gui_current_window); + } +} + +/* + * gui_window_new: create a new window + * (TODO: add coordinates and size, for splited windows) + */ + +t_gui_window * +gui_window_new (void *server, void *channel + /*int x, int y, int width, int height*/) +{ + t_gui_window *new_window; + + if ((new_window = (t_gui_window *)(malloc (sizeof (t_gui_window))))) + { + /* assign server and channel to window */ + SERVER(new_window) = server; + CHANNEL(new_window) = channel; + /* assign window to server and channel */ + if (server && !channel) + SERVER(new_window)->window = new_window; + if (channel) + CHANNEL(new_window)->window = new_window; + + gui_calculate_pos_size (new_window); + + /* init windows */ + new_window->win_title = NULL; + new_window->win_chat = NULL; + new_window->win_nick = NULL; + new_window->win_status = NULL; + new_window->win_input = NULL; + + /* init lines */ + new_window->lines = NULL; + new_window->last_line = NULL; + new_window->first_line_displayed = 1; + new_window->sub_lines = 0; + new_window->line_complete = 1; + new_window->unread_data = 0; + + /* init input buffer */ + new_window->input_buffer_alloc = INPUT_BUFFER_BLOCK_SIZE; + new_window->input_buffer = (char *) malloc (INPUT_BUFFER_BLOCK_SIZE); + new_window->input_buffer[0] = '\0'; + new_window->input_buffer_size = 0; + new_window->input_buffer_pos = 0; + new_window->input_buffer_1st_display = 0; + + /* init completion */ + completion_init (&(new_window->completion)); + + /* init history */ + new_window->history = NULL; + new_window->ptr_history = NULL; + + /* switch to new window */ + gui_switch_to_window (new_window); + + /* add window to windows queue */ + new_window->prev_window = last_gui_window; + if (gui_windows) + last_gui_window->next_window = new_window; + else + gui_windows = new_window; + last_gui_window = new_window; + new_window->next_window = NULL; + + /* redraw whole screen */ + gui_redraw_window (new_window); + } + else + return NULL; + return new_window; +} + +/* + * gui_window_free: delete a window + */ + +void +gui_window_free (t_gui_window *window) +{ + t_gui_line *ptr_line; + t_gui_message *ptr_message; + + /* TODO: manage splitted windows! */ + if (window == gui_current_window) + gui_switch_to_previous_window (); + + /* free lines and messages */ + while (window->lines) + { + ptr_line = window->lines->next_line; + while (window->lines->messages) + { + ptr_message = window->lines->messages->next_message; + if (window->lines->messages->message) + free (window->lines->messages->message); + free (window->lines->messages); + window->lines->messages = ptr_message; + } + free (window->lines); + window->lines = ptr_line; + } + if (window->input_buffer) + free (window->input_buffer); + + /* TODO: free completion struct */ + /* there... */ + + /* remove window from windows list */ + if (window->prev_window) + window->prev_window->next_window = window->next_window; + if (window->next_window) + window->next_window->prev_window = window->prev_window; + if (gui_windows == window) + gui_windows = window->next_window; + if (last_gui_window == window) + last_gui_window = window->prev_window; + + free (window); +} + +/* + * gui_resize_term_handler: called when term size is modified + */ + +void +gui_resize_term_handler () +{ + t_gui_window *ptr_win; + int width, height; + + endwin (); + refresh (); + + getmaxyx (stdscr, height, width); + + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + gui_calculate_pos_size (ptr_win); + // TODO: manage splitted windows! + if (ptr_win->win_title) + { + if (ptr_win->win_title) + delwin (ptr_win->win_title); + if (ptr_win->win_chat) + delwin (ptr_win->win_chat); + if (ptr_win->win_nick) + delwin (ptr_win->win_nick); + if (ptr_win->win_status) + delwin (ptr_win->win_status); + if (ptr_win->win_input) + delwin (ptr_win->win_input); + ptr_win->win_title = NULL; + ptr_win->win_chat = NULL; + ptr_win->win_nick = NULL; + ptr_win->win_status = NULL; + ptr_win->win_input = NULL; + gui_switch_to_window (ptr_win); + } + } +} + +/* + * gui_init_colors: init GUI colors + */ + +void +gui_init_colors () +{ + int i, color; + + if (has_colors ()) + { + start_color (); + use_default_colors (); + + init_pair (COLOR_WIN_TITLE, + cfg_col_title & A_CHARTEXT, cfg_col_title_bg); + init_pair (COLOR_WIN_CHAT, + cfg_col_chat & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_TIME, + cfg_col_chat_time & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_TIME_SEP, + cfg_col_chat_time_sep & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_PREFIX1, + cfg_col_chat_prefix1 & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_PREFIX2, + cfg_col_chat_prefix2 & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_NICK, + cfg_col_chat_nick & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_HOST, + cfg_col_chat_host & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_CHANNEL, + cfg_col_chat_channel & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_CHAT_DARK, + cfg_col_chat_dark & A_CHARTEXT, cfg_col_chat_bg); + init_pair (COLOR_WIN_STATUS, + cfg_col_status & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_ACTIVE, + cfg_col_status_active & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_DATA_MSG, + cfg_col_status_data_msg & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_DATA_OTHER, + cfg_col_status_data_other & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_STATUS_MORE, + cfg_col_status_more & A_CHARTEXT, cfg_col_status_bg); + init_pair (COLOR_WIN_INPUT, + cfg_col_input & A_CHARTEXT, cfg_col_input_bg); + init_pair (COLOR_WIN_INPUT_CHANNEL, + cfg_col_input_channel & A_CHARTEXT, cfg_col_input_bg); + init_pair (COLOR_WIN_INPUT_NICK, + cfg_col_input_nick & A_CHARTEXT, cfg_col_input_bg); + init_pair (COLOR_WIN_NICK, + cfg_col_nick & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_OP, + cfg_col_nick_op & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_HALFOP, + cfg_col_nick_halfop & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_VOICE, + cfg_col_nick_voice & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_SEP, + COLOR_BLACK & A_CHARTEXT, cfg_col_nick_sep); + init_pair (COLOR_WIN_NICK_SELF, + cfg_col_nick_self & A_CHARTEXT, cfg_col_nick_bg); + init_pair (COLOR_WIN_NICK_PRIVATE, + cfg_col_nick_private & A_CHARTEXT, cfg_col_nick_bg); + + for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++) + { + gui_assign_color (&color, nicks_colors[i]); + init_pair (COLOR_WIN_NICK_FIRST + i, color & A_CHARTEXT, cfg_col_chat_bg); + color_attr[COLOR_WIN_NICK_FIRST + i - 1] = + (color & A_BOLD) ? A_BOLD : 0; + } + + color_attr[COLOR_WIN_TITLE - 1] = cfg_col_title & A_BOLD; + color_attr[COLOR_WIN_CHAT - 1] = cfg_col_chat & A_BOLD; + color_attr[COLOR_WIN_CHAT_TIME - 1] = cfg_col_chat_time & A_BOLD; + color_attr[COLOR_WIN_CHAT_TIME_SEP - 1] = cfg_col_chat_time_sep & A_BOLD; + color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD; + color_attr[COLOR_WIN_CHAT_PREFIX1 - 1] = cfg_col_chat_prefix1 & A_BOLD; + color_attr[COLOR_WIN_CHAT_PREFIX2 - 1] = cfg_col_chat_prefix2 & A_BOLD; + color_attr[COLOR_WIN_CHAT_NICK - 1] = cfg_col_chat_nick & A_BOLD; + color_attr[COLOR_WIN_CHAT_HOST - 1] = cfg_col_chat_host & A_BOLD; + color_attr[COLOR_WIN_CHAT_CHANNEL - 1] = cfg_col_chat_channel & A_BOLD; + color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD; + color_attr[COLOR_WIN_STATUS - 1] = cfg_col_status & A_BOLD; + color_attr[COLOR_WIN_STATUS_ACTIVE - 1] = cfg_col_status_active & A_BOLD; + color_attr[COLOR_WIN_STATUS_DATA_MSG - 1] = cfg_col_status_data_msg & A_BOLD; + color_attr[COLOR_WIN_STATUS_DATA_OTHER - 1] = cfg_col_status_data_other & A_BOLD; + color_attr[COLOR_WIN_STATUS_MORE - 1] = cfg_col_status_more & A_BOLD; + color_attr[COLOR_WIN_INPUT - 1] = cfg_col_input & A_BOLD; + color_attr[COLOR_WIN_INPUT_CHANNEL - 1] = cfg_col_input_channel & A_BOLD; + color_attr[COLOR_WIN_INPUT_NICK - 1] = cfg_col_input_nick & A_BOLD; + color_attr[COLOR_WIN_NICK - 1] = cfg_col_nick & A_BOLD; + color_attr[COLOR_WIN_NICK_OP - 1] = cfg_col_nick_op & A_BOLD; + color_attr[COLOR_WIN_NICK_HALFOP - 1] = cfg_col_nick_halfop & A_BOLD; + color_attr[COLOR_WIN_NICK_VOICE - 1] = cfg_col_nick_voice & A_BOLD; + color_attr[COLOR_WIN_NICK_SEP - 1] = 0; + color_attr[COLOR_WIN_NICK_SELF - 1] = cfg_col_nick_self & A_BOLD; + color_attr[COLOR_WIN_NICK_PRIVATE - 1] = cfg_col_nick_private & A_BOLD; + } +} + +/* + * gui_init: init GUI + */ + +void +gui_init () +{ + initscr (); + + curs_set (1); + keypad (stdscr, TRUE); + noecho (); + /*nonl();*/ + nodelay (stdscr, TRUE); + + gui_init_colors (); + + /* create windows */ + gui_current_window = gui_window_new (NULL, NULL /*0, 0, COLS, LINES*/); + + signal (SIGWINCH, gui_resize_term_handler); + + gui_ready = 1; +} + +/* + * gui_end: GUI end + */ + +void +gui_end () +{ + t_gui_window *ptr_win; + + /* delete all windows */ + for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window) + { + if (ptr_win->win_title) + delwin (ptr_win->win_title); + if (ptr_win->win_chat) + delwin (ptr_win->win_chat); + if (ptr_win->win_nick) + delwin (ptr_win->win_nick); + if (ptr_win->win_status) + delwin (ptr_win->win_status); + if (ptr_win->win_input) + delwin (ptr_win->win_input); + /* TODO: free input buffer, lines, messages, completion */ + } + + /* end of ncurses output */ + refresh (); + endwin (); +} + +/* + * gui_new_line: create new line for a window + */ + +t_gui_line * +gui_new_line (t_gui_window *window) +{ + t_gui_line *new_line; + + if ((new_line = (t_gui_line *) malloc (sizeof (struct t_gui_line)))) + { + new_line->length = 0; + new_line->length_align = 0; + new_line->line_with_message = 0; + new_line->messages = NULL; + new_line->last_message = NULL; + if (!window->lines) + window->lines = new_line; + else + window->last_line->next_line = new_line; + new_line->prev_line = window->last_line; + new_line->next_line = NULL; + window->last_line = new_line; + } + else + { + wprintw (window->win_chat, + _("%s not enough memory for new line!\n"), + WEECHAT_ERROR); + return NULL; + } + return new_line; +} + +/* + * gui_new_message: create a new message for last line of window + */ + +t_gui_message * +gui_new_message (t_gui_window *window) +{ + t_gui_message *new_message; + + if ((new_message = (t_gui_message *) malloc (sizeof (struct t_gui_message)))) + { + if (!window->last_line->messages) + window->last_line->messages = new_message; + else + window->last_line->last_message->next_message = new_message; + new_message->prev_message = window->last_line->last_message; + new_message->next_message = NULL; + window->last_line->last_message = new_message; + } + else + { + log_printf ("not enough memory!\n"); + return NULL; + } + return new_message; +} + +/* + * gui_add_message: add a message to a window + */ + +void +gui_add_message (t_gui_window *window, int type, int color, char *message) +{ + char *pos; + int length; + + /* create new line if previous was ending by '\n' (or if 1st line) */ + if (window->line_complete) + { + window->line_complete = 0; + if (!gui_new_line (window)) + return; + } + if (!gui_new_message (window)) + return; + + window->last_line->last_message->type = type; + window->last_line->last_message->color = color; + pos = strchr (message, '\n'); + if (pos) + { + pos[0] = '\0'; + window->line_complete = 1; + } + window->last_line->last_message->message = strdup (message); + length = strlen (message); + window->last_line->length += length; + if (type == MSG_TYPE_MSG) + window->last_line->line_with_message = 1; + if ((type == MSG_TYPE_TIME) || (type == MSG_TYPE_NICK)) + window->last_line->length_align += length; + if (pos) + { + pos[0] = '\n'; + if ((window == gui_current_window) && (window->sub_lines == 0)) + { + if ((window->win_chat_cursor_y + + gui_get_line_num_splits (window, window->last_line)) > + (window->win_chat_height - 1)) + gui_redraw_window_chat (window); + else + gui_display_line (window, window->last_line, 1); + } + if ((window != gui_current_window) || (window->sub_lines > 0)) + { + window->unread_data = 1 + window->last_line->line_with_message; + gui_redraw_window_status (gui_current_window); + } + } +} + +/* + * gui_printf_color_type: display a message in a window + */ + +void +gui_printf_color_type (t_gui_window *window, int type, int color, char *message, ...) +{ + static char buffer[8192]; + char timestamp[16]; + char *pos; + va_list argptr; + static time_t seconds; + struct tm *date_tmp; + + if (gui_ready) + { + if (color == -1) + color = COLOR_WIN_CHAT; + + if (window == NULL) + { + if (SERVER(gui_current_window)) + window = SERVER(gui_current_window)->window; + else + window = gui_current_window; + } + + if (window == NULL) + { + log_printf ("gui_printf without window! this is a bug, please send to developers - thanks\n"); + return; + } + } + + va_start (argptr, message); + vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); + va_end (argptr); + + if (gui_ready) + { + seconds = time (NULL); + date_tmp = localtime (&seconds); + + pos = buffer - 1; + while (pos) + { + /* TODO: read timestamp format from config! */ + if ((!window->last_line) || (window->line_complete)) + { + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "["); + sprintf (timestamp, "%02d", date_tmp->tm_hour); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":"); + sprintf (timestamp, "%02d", date_tmp->tm_min); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":"); + sprintf (timestamp, "%02d", date_tmp->tm_sec); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp); + gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "] "); + } + gui_add_message (window, type, color, pos+1); + pos = strchr (pos+1, '\n'); + if (pos) + if (pos[1] == '\0') + pos = NULL; + } + + wrefresh (window->win_chat); + refresh (); + } + else + printf ("%s", buffer); +} diff --git a/weechat/src/gui/curses/gui-input.c b/weechat/src/gui/curses/gui-input.c new file mode 100644 index 000000000..2717d3dab --- /dev/null +++ b/weechat/src/gui/curses/gui-input.c @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-input: user input functions for Curses GUI */ + + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <time.h> +#include <sys/socket.h> +#include <curses.h> + +#include "../../weechat.h" +#include "../gui.h" +#include "../../config.h" +#include "../../command.h" +#include "../../irc/irc.h" + + +/* + * gui_optimize_input_buffer_size: optimize input buffer size by adding + * or deleting data block (predefined size) + */ + +void +gui_optimize_input_buffer_size (t_gui_window *window) +{ + int optimal_size; + + optimal_size = ((window->input_buffer_size / INPUT_BUFFER_BLOCK_SIZE) * + INPUT_BUFFER_BLOCK_SIZE) + INPUT_BUFFER_BLOCK_SIZE; + if (window->input_buffer_alloc != optimal_size) + { + window->input_buffer_alloc = optimal_size; + window->input_buffer = realloc (window->input_buffer, optimal_size); + } +} + +/* + * gui_delete_previous_word: delete previous word + */ + +void +gui_delete_previous_word () +{ + int i, j, num_char_deleted, num_char_end; + + if (gui_current_window->input_buffer_pos > 0) + { + i = gui_current_window->input_buffer_pos - 1; + while ((i >= 0) && + (gui_current_window->input_buffer[i] == ' ')) + i--; + if (i >= 0) + { + while ((i >= 0) && + (gui_current_window->input_buffer[i] != ' ')) + i--; + if (i >= 0) + { + while ((i >= 0) && + (gui_current_window->input_buffer[i] == ' ')) + i--; + } + } + + if (i >= 0) + i++; + i++; + num_char_deleted = gui_current_window->input_buffer_pos - i; + num_char_end = gui_current_window->input_buffer_size - + gui_current_window->input_buffer_pos; + + for (j = 0; j < num_char_end; j++) + gui_current_window->input_buffer[i + j] = + gui_current_window->input_buffer[gui_current_window->input_buffer_pos + j]; + + gui_current_window->input_buffer_size -= num_char_deleted; + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + gui_current_window->input_buffer_pos = i; + gui_draw_window_input (gui_current_window); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->completion.position = -1; + } +} + +/* + * gui_move_previous_word: move to beginning of previous word + */ + +void +gui_move_previous_word () +{ + int i; + + if (gui_current_window->input_buffer_pos > 0) + { + i = gui_current_window->input_buffer_pos - 1; + while ((i >= 0) && + (gui_current_window->input_buffer[i] == ' ')) + i--; + if (i < 0) + gui_current_window->input_buffer_pos = 0; + else + { + while ((i >= 0) && + (gui_current_window->input_buffer[i] != ' ')) + i--; + gui_current_window->input_buffer_pos = i + 1; + } + gui_draw_window_input (gui_current_window); + } +} + +/* + * gui_move_next_word: move to the end of next + */ + +void +gui_move_next_word () +{ + int i; + + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size + 1) + { + i = gui_current_window->input_buffer_pos; + while ((i <= gui_current_window->input_buffer_size) && + (gui_current_window->input_buffer[i] == ' ')) + i++; + if (i > gui_current_window->input_buffer_size) + gui_current_window->input_buffer_pos = i - 1; + else + { + while ((i <= gui_current_window->input_buffer_size) && + (gui_current_window->input_buffer[i] != ' ')) + i++; + if (i > gui_current_window->input_buffer_size) + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + else + gui_current_window->input_buffer_pos = i; + + } + gui_draw_window_input (gui_current_window); + } +} + +/* + * gui_buffer_insert_string: insert a string into the input buffer + */ + +void +gui_buffer_insert_string (char *string, int pos) +{ + int i, start, end, length; + + length = strlen (string); + + /* increase buffer size */ + gui_current_window->input_buffer_size += length; + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + + /* move end of string to the right */ + start = pos + length; + end = gui_current_window->input_buffer_size - 1; + for (i = end; i >= start; i--) + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i - length]; + + /* insert new string */ + strncpy (gui_current_window->input_buffer + pos, string, length); +} + +/* + * gui_read_keyb: read keyboard line + */ + +void +gui_read_keyb () +{ + int key, i; + t_gui_window *ptr_window; + char new_char[2]; + + key = getch (); + if (key != ERR) + { + switch (key) + { + /* resize event: do nothing */ + case KEY_RESIZE: + gui_redraw_window (gui_current_window); + break; + case KEY_F(6): + gui_switch_to_previous_window (); + break; + /* next window */ + case KEY_F(7): + gui_switch_to_next_window (); + break; + /* cursor up */ + case KEY_UP: + if (gui_current_window->ptr_history) + { + gui_current_window->ptr_history = + gui_current_window->ptr_history->next_history; + if (!gui_current_window->ptr_history) + gui_current_window->ptr_history = + gui_current_window->history; + } + else + gui_current_window->ptr_history = + gui_current_window->history; + if (gui_current_window->ptr_history) + { + gui_current_window->input_buffer_size = + strlen (gui_current_window->ptr_history->text); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + strcpy (gui_current_window->input_buffer, + gui_current_window->ptr_history->text); + gui_draw_window_input (gui_current_window); + } + break; + /* cursor down */ + case KEY_DOWN: + if (gui_current_window->ptr_history) + { + gui_current_window->ptr_history = + gui_current_window->ptr_history->prev_history; + if (gui_current_window->ptr_history) + gui_current_window->input_buffer_size = + strlen (gui_current_window->ptr_history->text); + else + gui_current_window->input_buffer_size = 0; + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + if (gui_current_window->ptr_history) + strcpy (gui_current_window->input_buffer, + gui_current_window->ptr_history->text); + gui_draw_window_input (gui_current_window); + } + break; + /* cursor left */ + case KEY_LEFT: + if (gui_current_window->input_buffer_pos > 0) + { + gui_current_window->input_buffer_pos--; + gui_draw_window_input (gui_current_window); + } + break; + /* cursor right */ + case KEY_RIGHT: + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size) + { + gui_current_window->input_buffer_pos++; + gui_draw_window_input (gui_current_window); + } + break; + /* home key */ + case KEY_HOME: + if (gui_current_window->input_buffer_pos > 0) + { + gui_current_window->input_buffer_pos = 0; + gui_draw_window_input (gui_current_window); + } + break; + /* end key */ + case KEY_END: + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size) + { + gui_current_window->input_buffer_pos = + gui_current_window->input_buffer_size; + gui_draw_window_input (gui_current_window); + } + break; + /* page up */ + case KEY_PPAGE: + gui_move_page_up (); + break; + /* page down */ + case KEY_NPAGE: + gui_move_page_down (); + break; + /* erase before cursor and move cursor to the left */ + case 127: + case KEY_BACKSPACE: + if (gui_current_window->input_buffer_pos > 0) + { + i = gui_current_window->input_buffer_pos-1; + while (gui_current_window->input_buffer[i]) + { + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i+1]; + i++; + } + gui_current_window->input_buffer_size--; + gui_current_window->input_buffer_pos--; + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + gui_draw_window_input (gui_current_window); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->completion.position = -1; + } + break; + /* Control + Backspace */ + case 0x08: + gui_delete_previous_word (); + break; + /* erase char under cursor */ + case KEY_DC: + if (gui_current_window->input_buffer_pos < + gui_current_window->input_buffer_size) + { + i = gui_current_window->input_buffer_pos; + while (gui_current_window->input_buffer[i]) + { + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i+1]; + i++; + } + gui_current_window->input_buffer_size--; + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + gui_draw_window_input (gui_current_window); + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->completion.position = -1; + } + break; + /* Tab : completion */ + case '\t': + completion_search (&(gui_current_window->completion), + CHANNEL(gui_current_window), + gui_current_window->input_buffer, + gui_current_window->input_buffer_size, + gui_current_window->input_buffer_pos); + if (gui_current_window->completion.word_found) + { + // replace word with new completed word into input buffer + gui_current_window->input_buffer_size += + gui_current_window->completion.diff_size; + gui_optimize_input_buffer_size (gui_current_window); + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + + if (gui_current_window->completion.diff_size > 0) + { + for (i = gui_current_window->input_buffer_size - 1; + i >= gui_current_window->completion.position_replace + + (int)strlen (gui_current_window->completion.word_found); i--) + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i - + gui_current_window->completion.diff_size]; + } + else + { + for (i = gui_current_window->completion.position_replace + + strlen (gui_current_window->completion.word_found); + i < gui_current_window->input_buffer_size; i++) + gui_current_window->input_buffer[i] = + gui_current_window->input_buffer[i - + gui_current_window->completion.diff_size]; + } + + strncpy (gui_current_window->input_buffer + gui_current_window->completion.position_replace, + gui_current_window->completion.word_found, + strlen (gui_current_window->completion.word_found)); + gui_current_window->input_buffer_pos = + gui_current_window->completion.position_replace + + strlen (gui_current_window->completion.word_found); + gui_current_window->completion.position = + gui_current_window->input_buffer_pos; + + /* add space or completor to the end of completion, if needed */ + if (gui_current_window->completion.base_word[0] == '/') + { + if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ') + gui_buffer_insert_string (" ", + gui_current_window->input_buffer_pos); + gui_current_window->completion.position++; + gui_current_window->input_buffer_pos++; + } + else + { + if (gui_current_window->completion.base_word_pos == 0) + { + if (strncmp (gui_current_window->input_buffer + gui_current_window->input_buffer_pos, + cfg_look_completor, strlen (cfg_look_completor)) != 0) + gui_buffer_insert_string (cfg_look_completor, + gui_current_window->input_buffer_pos); + gui_current_window->completion.position += strlen (cfg_look_completor); + gui_current_window->input_buffer_pos += strlen (cfg_look_completor); + if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ') + gui_buffer_insert_string (" ", + gui_current_window->input_buffer_pos); + gui_current_window->completion.position++; + gui_current_window->input_buffer_pos++; + } + } + gui_draw_window_input (gui_current_window); + } + break; + /* escape code (for control-key) */ + case KEY_ESCAPE: + if ((key = getch()) != ERR) + { + switch (key) + { + case KEY_LEFT: + gui_switch_to_previous_window (); + break; + case KEY_RIGHT: + gui_switch_to_next_window (); + break; + case 79: + /* TODO: replace 79 by constant name! */ + if (key == 79) + { + if ((key = getch()) != ERR) + { + switch (key) + { + /* Control + Right */ + case 99: + gui_move_next_word (); + break; + /* Control + Left */ + case 100: + gui_move_previous_word (); + break; + } + } + } + break; + } + } + break; + /* send command/message */ + case '\n': + if (gui_current_window->input_buffer_size > 0) + { + gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0'; + history_add (gui_current_window, gui_current_window->input_buffer); + gui_current_window->input_buffer_size = 0; + gui_current_window->input_buffer_pos = 0; + gui_current_window->input_buffer_1st_display = 0; + gui_current_window->completion.position = -1; + gui_current_window->ptr_history = NULL; + ptr_window = gui_current_window; + user_command (SERVER(gui_current_window), + gui_current_window->input_buffer); + if (ptr_window == gui_current_window) + gui_draw_window_input (ptr_window); + if (ptr_window) + ptr_window->input_buffer[0] = '\0'; + } + break; + /* other key => add to input buffer */ + default: + /*gui_printf (gui_current_window, + "[Debug] key pressed = %d, as octal: %o\n", key, key);*/ + new_char[0] = key; + new_char[1] = '\0'; + gui_buffer_insert_string (new_char, + gui_current_window->input_buffer_pos); + gui_current_window->input_buffer_pos++; + gui_draw_window_input (gui_current_window); + gui_current_window->completion.position = -1; + break; + } + } +} + +/* + * gui_main_loop: main loop for WeeChat with ncurses GUI + */ + +void +gui_main_loop () +{ + fd_set read_fd; + static struct timeval timeout; + t_irc_server *ptr_server; + + quit_weechat = 0; + while (!quit_weechat) + { + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + FD_ZERO (&read_fd); + FD_SET (STDIN_FILENO, &read_fd); + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->sock4 >= 0) + FD_SET (ptr_server->sock4, &read_fd); + } + if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout)) + { + if (FD_ISSET (STDIN_FILENO, &read_fd)) + { + gui_read_keyb (); + } + else + { + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if ((ptr_server->sock4 >= 0) && + (FD_ISSET (ptr_server->sock4, &read_fd))) + server_recv (ptr_server); + } + } + } + } +} diff --git a/weechat/src/gui/gtk/Makefile b/weechat/src/gui/gtk/Makefile new file mode 100644 index 000000000..6d2de6eba --- /dev/null +++ b/weechat/src/gui/gtk/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_GTK + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \ + ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h diff --git a/weechat/src/gui/gtk/gui-gtk.c b/weechat/src/gui/gtk/gui-gtk.c new file mode 100644 index 000000000..8e9aa5db3 --- /dev/null +++ b/weechat/src/gui/gtk/gui-gtk.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-gtk.c: Gtk+ GUI for WeeChat */ + + +/* ***** Gtk+ GUI for WeeChat, NOT developed! ***** */ diff --git a/weechat/src/gui/gtk/gui-gtk.h b/weechat/src/gui/gtk/gui-gtk.h new file mode 100644 index 000000000..889f75e60 --- /dev/null +++ b/weechat/src/gui/gtk/gui-gtk.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_GTK_H +#define __WEECHAT_GUI_GTK_H 1 + +#endif /* gui-gtk.h */ diff --git a/weechat/src/gui/gui.h b/weechat/src/gui/gui.h new file mode 100644 index 000000000..d8e3aca99 --- /dev/null +++ b/weechat/src/gui/gui.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_H +#define __WEECHAT_GUI_H 1 + +#ifdef WEE_CURSES +#include <curses.h> +#endif + +#include "../completion.h" +#include "../history.h" + +#ifdef WEE_CURSES +#define KEY_ESCAPE 27 +#endif + +#define INPUT_BUFFER_BLOCK_SIZE 256 + +#define NUM_COLORS 35 +#define COLOR_WIN_TITLE 1 +#define COLOR_WIN_CHAT 2 +#define COLOR_WIN_CHAT_TIME 3 +#define COLOR_WIN_CHAT_TIME_SEP 4 +#define COLOR_WIN_CHAT_PREFIX1 5 +#define COLOR_WIN_CHAT_PREFIX2 6 +#define COLOR_WIN_CHAT_NICK 7 +#define COLOR_WIN_CHAT_HOST 8 +#define COLOR_WIN_CHAT_CHANNEL 9 +#define COLOR_WIN_CHAT_DARK 10 +#define COLOR_WIN_STATUS 11 +#define COLOR_WIN_STATUS_ACTIVE 12 +#define COLOR_WIN_STATUS_DATA_MSG 13 +#define COLOR_WIN_STATUS_DATA_OTHER 14 +#define COLOR_WIN_STATUS_MORE 15 +#define COLOR_WIN_INPUT 16 +#define COLOR_WIN_INPUT_CHANNEL 17 +#define COLOR_WIN_INPUT_NICK 18 +#define COLOR_WIN_NICK 19 +#define COLOR_WIN_NICK_OP 20 +#define COLOR_WIN_NICK_HALFOP 21 +#define COLOR_WIN_NICK_VOICE 22 +#define COLOR_WIN_NICK_SEP 23 +#define COLOR_WIN_NICK_SELF 24 +#define COLOR_WIN_NICK_PRIVATE 25 +#define COLOR_WIN_NICK_FIRST 26 +#define COLOR_WIN_NICK_LAST 35 +#define COLOR_WIN_NICK_NUMBER (COLOR_WIN_NICK_LAST - COLOR_WIN_NICK_FIRST + 1) + +#define SERVER(window) ((t_irc_server *)(window->server)) +#define CHANNEL(window) ((t_irc_channel *)(window->channel)) + +#define WIN_IS_SERVER(window) (SERVER(window) && !CHANNEL(window)) +#define WIN_IS_CHANNEL(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_CHANNEL)) +#define WIN_IS_PRIVATE(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_PRIVATE)) + +#define MSG_TYPE_TIME 0 +#define MSG_TYPE_NICK 1 +#define MSG_TYPE_INFO 2 +#define MSG_TYPE_MSG 3 + +#define gui_printf_color(window, color, fmt, argz...) \ + gui_printf_color_type(window, MSG_TYPE_INFO, color, fmt, ##argz) + +#define gui_printf(window, fmt, argz...) \ + gui_printf_color_type(window, MSG_TYPE_INFO, -1, fmt, ##argz) + +typedef struct t_gui_message t_gui_message; + +struct t_gui_message +{ + int type; /* type of message (time, nick, other) */ + int color; /* color of message */ + char *message; /* message content */ + t_gui_message *prev_message; /* link to previous message for line */ + t_gui_message *next_message; /* link to next message for line */ +}; + +typedef struct t_gui_line t_gui_line; + +struct t_gui_line +{ + int length; /* length of the line (in char) */ + int length_align; /* alignment length (time or time/nick) */ + int line_with_message; /* line contains a message from a user? */ + t_gui_message *messages; /* messages for the line */ + t_gui_message *last_message; /* last message of the line */ + t_gui_line *prev_line; /* link to previous line */ + t_gui_line *next_line; /* link to next line */ +}; + +typedef struct t_gui_color t_gui_color; + +struct t_gui_color +{ + char *name; + int color; +}; + +typedef struct t_gui_window t_gui_window; + +struct t_gui_window +{ + /* server/channel */ + void *server; /* window's server */ + void *channel; /* window's channel */ + + /* global position & size */ + int win_x, win_y; /* position of window */ + int win_width, win_height; /* window geometry */ + + /* chat window settings */ + int win_chat_x, win_chat_y; /* chat window position */ + int win_chat_width; /* width of chat window */ + int win_chat_height; /* height of chat window */ + int win_chat_cursor_x; /* position of cursor in chat window */ + int win_chat_cursor_y; /* position of cursor in chat window */ + + /* nicklist window settings */ + int win_nick_x, win_nick_y; /* chat window position */ + int win_nick_width; /* width of chat window */ + int win_nick_height; /* height of chat window */ + + /* windows */ + #ifdef WEE_CURSES + WINDOW *win_title; /* title window */ + WINDOW *win_chat; /* chat window (exemple: channel) */ + WINDOW *win_nick; /* nick window */ + WINDOW *win_status; /* status window */ + WINDOW *win_input; /* input window */ + #endif + #ifdef WEE_GTK + /* TODO: declare Gtk+ window */ + #endif + #ifdef WEE_QT + /* TODO: declare Qt window */ + #endif + + /* chat content (lines, line is composed by many messages) */ + t_gui_line *lines; /* lines of chat window */ + t_gui_line *last_line; /* last line of chat window */ + int first_line_displayed; /* = 1 if first line is displayed */ + int sub_lines; /* if > 0 then do not display until end */ + int line_complete; /* current line complete ? (\n ending) */ + int unread_data; /* highlight windows with unread data */ + + /* inupt buffer */ + char *input_buffer; /* input buffer */ + int input_buffer_alloc; /* input buffer: allocated size in mem */ + int input_buffer_size; /* buffer size (user input length) */ + int input_buffer_pos; /* position into buffer */ + int input_buffer_1st_display; /* first char displayed on screen */ + + /* completion */ + t_completion completion; /* for cmds/nicks completion */ + + /* history */ + t_history *history; /* commands history */ + t_history *ptr_history; /* current command in history */ + + /* link to next window */ + t_gui_window *prev_window; /* link to previous window */ + t_gui_window *next_window; /* link to next window */ +}; + +/* variables */ + +extern int gui_ready; +extern t_gui_window *gui_windows; +extern t_gui_window *gui_current_window; + +/* prototypes */ + +extern int gui_assign_color (int *, char *); +extern int gui_get_color_by_name (char *); +extern char *gui_get_color_by_value (int); + +extern void gui_draw_window_title (t_gui_window *); +extern void gui_redraw_window_title (t_gui_window *); +extern void gui_draw_window_chat (t_gui_window *); +extern void gui_redraw_window_chat (t_gui_window *); +extern void gui_draw_window_nick (t_gui_window *); +extern void gui_redraw_window_nick (t_gui_window *); +extern void gui_draw_window_status (t_gui_window *); +extern void gui_redraw_window_status (t_gui_window *); +extern void gui_draw_window_input (t_gui_window *); +extern void gui_redraw_window_input (t_gui_window *); +extern void gui_redraw_window (t_gui_window *); + +extern void gui_window_clear (t_gui_window *); +extern void gui_window_clear_all (); + +extern void gui_switch_to_window (t_gui_window *); +extern void gui_switch_to_previous_window (); +extern void gui_switch_to_next_window (); + +extern void gui_move_page_up (); +extern void gui_move_page_down (); + +extern void gui_init (); +/* TODO: add coordinates and size */ +extern t_gui_window *gui_window_new (void *, void * /*int, int, int, int*/); +extern void gui_window_free (t_gui_window *); +extern void gui_end (); +extern void gui_printf_color_type (t_gui_window *, int, int, char *, ...); +extern void gui_display_nick (t_gui_window *, void *, int, int, int, int); + +extern void gui_main_loop (); + +#endif /* gui.h */ diff --git a/weechat/src/gui/qt/Makefile b/weechat/src/gui/qt/Makefile new file mode 100644 index 000000000..f0695d3a3 --- /dev/null +++ b/weechat/src/gui/qt/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_QT + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \ + ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h diff --git a/weechat/src/gui/qt/gui-qt.c b/weechat/src/gui/qt/gui-qt.c new file mode 100644 index 000000000..e8dffab14 --- /dev/null +++ b/weechat/src/gui/qt/gui-qt.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-qt.c: Qt GUI for WeeChat */ + + +/* ***** Qt GUI for WeeChat, NOT developed! ***** */ diff --git a/weechat/src/gui/qt/gui-qt.h b/weechat/src/gui/qt/gui-qt.h new file mode 100644 index 000000000..b07167d88 --- /dev/null +++ b/weechat/src/gui/qt/gui-qt.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_QT_H +#define __WEECHAT_GUI_QT_H 1 + +#endif /* gui-qt.h */ diff --git a/weechat/src/gui/text/Makefile b/weechat/src/gui/text/Makefile new file mode 100644 index 000000000..538d760a3 --- /dev/null +++ b/weechat/src/gui/text/Makefile @@ -0,0 +1,37 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=../gui.a +OBJS=gui-display.o gui-input.o +DEFINES=WEE_TEXT + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \ + ../../irc/irc.h ../../gui/gui.h +gui-input.o: gui-input.c ../../weechat.h ../gui.h diff --git a/weechat/src/gui/text/gui-text.c b/weechat/src/gui/text/gui-text.c new file mode 100644 index 000000000..7121e11e5 --- /dev/null +++ b/weechat/src/gui/text/gui-text.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* gui-text.c: text GUI - display functions */ + + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> + +#include "weechat.h" +#include "gui-text.h" +#include "command.h" +#include "irc.h" + + +/* + * gui_init: init GUI + */ + +void +gui_init () +{ +} + + +/* + * gui_init_irc_window: allocates a window for a channel or server + */ + +void +gui_init_irc_window (t_irc_window * window) +{ + /* no window in text GUI */ + window->text = NULL; + window->window = NULL; +} + + +/* + * gui_free_irc_window: free a GUI window + */ + +void +gui_free_irc_window (t_irc_window * window) +{ + /* no window in text GUI */ +} + + +/* + * gui_end: GUI end + */ + +void +gui_end () +{ +} + + +/* + * read_keyb: read keyboard line + */ + +void +read_keyb () +{ + int num_read; + static char buffer[4096]; + static int pos_buffer = 0; + char buffer_tmp[1024]; + int pos_buffer_tmp; + + num_read = read (STDIN_FILENO, buffer_tmp, sizeof (buffer_tmp) - 1); + pos_buffer_tmp = 0; + while (pos_buffer_tmp < num_read) + { + switch (buffer_tmp[pos_buffer_tmp]) + { + case '\r': + break; + case '\n': + buffer[pos_buffer] = '\0'; + pos_buffer = 0; + user_command (buffer); + break; + default: + buffer[pos_buffer] = buffer_tmp[pos_buffer_tmp]; + if (pos_buffer < (int) (sizeof (buffer) - 2)) + pos_buffer++; + } + pos_buffer_tmp++; + } +} + + +/* + * gui_main_loop: main loop for WeeChat with text GUI + */ + +void +gui_main_loop () +{ + struct timeval timeout; + fd_set read_fd; + t_irc_server *ptr_server; + + quit_weechat = 0; + while (!quit_weechat) + { + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + FD_ZERO (&read_fd); + FD_SET (STDIN_FILENO, &read_fd); + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + FD_SET (ptr_server->sock4, &read_fd); + } + select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout); + if (FD_ISSET (STDIN_FILENO, &read_fd)) + { + read_keyb (); + } + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (FD_ISSET (ptr_server->sock4, &read_fd)) + recv_from_server (ptr_server); + } + } +} + + +/* + * gui_display_message: display a message on the screen + */ + +void +gui_display_message (char *message) +{ + printf ("%s\n", message); +} diff --git a/weechat/src/gui/text/gui-text.h b/weechat/src/gui/text/gui-text.h new file mode 100644 index 000000000..2e62d1a55 --- /dev/null +++ b/weechat/src/gui/text/gui-text.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_GUI_TEXT_H +#define __WEECHAT_GUI_TEXT_H 1 + +#endif /* gui-text.h */ diff --git a/weechat/src/history.c b/weechat/src/history.c new file mode 100644 index 000000000..9e13e6935 --- /dev/null +++ b/weechat/src/history.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* history.c: memorize and call again commands or text */ + + +#include <stdlib.h> +#include <string.h> + +#include "weechat.h" +#include "history.h" +#include "gui/gui.h" + + +t_history *history_general = NULL; +t_history *history_general_ptr = NULL; + + +/* + * history_add: add a text/command to history + */ + +void +history_add (void *window, char *string) +{ + t_history *new_history; + + new_history = (t_history *)malloc (sizeof (t_history)); + if (new_history) + { + new_history->text = strdup (string); + + /* add history to general history */ + if (history_general) + history_general->prev_history = new_history; + new_history->next_history = history_general; + new_history->prev_history = NULL; + history_general = new_history; + + /* add history to local history */ + if (((t_gui_window *)(window))->history) + ((t_gui_window *)(window))->history->prev_history = new_history; + new_history->next_history = ((t_gui_window *)(window))->history; + new_history->prev_history = NULL; + ((t_gui_window *)window)->history = new_history; + } +} diff --git a/weechat/src/history.h b/weechat/src/history.h new file mode 100644 index 000000000..946f2e792 --- /dev/null +++ b/weechat/src/history.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_HISTORY_H +#define __WEECHAT_HISTORY_H 1 + +typedef struct t_history t_history; + +struct t_history +{ + char *text; /* text or command (as entered by user) */ + t_history *next_history; /* link to next text/command */ + t_history *prev_history; /* link to previous text/command */ +}; + +extern void history_add (void *, char *); + +#endif /* history.h */ diff --git a/weechat/src/irc/Makefile b/weechat/src/irc/Makefile new file mode 100644 index 000000000..d22617bda --- /dev/null +++ b/weechat/src/irc/Makefile @@ -0,0 +1,44 @@ +# Copyright (c) 2003 FlashCode <flashcode@flashtux.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC=gcc + +OPTIONS=-Wall -W -pipe -O2 + +OUTPUT=irc.a +OBJS=irc-commands.o irc-display.o irc-server.o irc-channel.o irc-nick.o +DEFINES=WEE_CURSES + +all: $(OBJS) + ar r $(OUTPUT) $(OBJS) + +$(OBJS): + $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES) + +clean: + rm -f *.o *.a *~ core + +irc-channel.o: irc-channel.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h +irc-commands.o: irc-commands.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h ../command.h ../irc/irc.h ../config.h +irc-display.o: irc-display.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h +irc-nick.o: irc-nick.c ../weechat.h irc.h ../gui/gui.h ../completion.h \ + ../history.h +irc-server.o: irc-server.c ../weechat.h irc.h ../gui/gui.h \ + ../completion.h ../history.h diff --git a/weechat/src/irc/irc-channel.c b/weechat/src/irc/irc-channel.c new file mode 100644 index 000000000..bdad12265 --- /dev/null +++ b/weechat/src/irc/irc-channel.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-channel.c: manages a chat (channel or private chat) */ + + +#include <stdlib.h> +#include <string.h> + +#include "../weechat.h" +#include "irc.h" + + +t_irc_channel *current_channel = NULL; + + +/* + * channel_new: allocate a new channel for a server and add it to the server queue + */ + +t_irc_channel * +channel_new (t_irc_server *server, int channel_type, char *channel_name) +{ + t_irc_channel *new_channel; + + #if DEBUG >= 1 + log_printf ("joining channel %s\n", channel_name); + #endif + + /* alloc memory for new channel */ + if ((new_channel = (t_irc_channel *) malloc (sizeof (t_irc_channel))) == NULL) + { + fprintf (stderr, _("%s cannot allocate new channel"), WEECHAT_ERROR); + return NULL; + } + + /* initialize new channel */ + new_channel->type = channel_type; + new_channel->name = strdup (channel_name); + new_channel->topic = NULL; + new_channel->nicks = NULL; + new_channel->last_nick = NULL; + + /* add new channel to queue */ + new_channel->prev_channel = server->last_channel; + new_channel->next_channel = NULL; + if (server->channels) + server->last_channel->next_channel = new_channel; + else + server->channels = new_channel; + server->last_channel = new_channel; + + gui_window_new (server, new_channel); + + /* all is ok, return address of new channel */ + return new_channel; +} + +/* + * channel_free: free a channel and remove it from channels queue + */ + +void +channel_free (t_irc_server *server, t_irc_channel *channel) +{ + t_irc_channel *new_channels; + + /* remove channel from queue */ + if (server->last_channel == channel) + server->last_channel = channel->prev_channel; + if (channel->prev_channel) + { + (channel->prev_channel)->next_channel = channel->next_channel; + new_channels = server->channels; + } + else + new_channels = channel->next_channel; + + if (channel->next_channel) + (channel->next_channel)->prev_channel = channel->prev_channel; + + /* free data */ + if (channel->name) + free (channel->name); + if (channel->topic) + free (channel->topic); + nick_free_all (channel); + free (channel); + server->channels = new_channels; +} + +/* + * channel_free_all: free all allocated channels + */ + +void +channel_free_all (t_irc_server *server) +{ + /* remove all channels for the server */ + while (server->channels) + channel_free (server, server->channels); +} + +/* + * channel_search: returns pointer on a channel with name + */ + +t_irc_channel * +channel_search (t_irc_server *server, char *channel_name) +{ + t_irc_channel *ptr_channel; + + for (ptr_channel = server->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + if (strcasecmp (ptr_channel->name, channel_name) == 0) + return ptr_channel; + } + return NULL; +} + +/* + * string_is_channel: returns 1 if string is channel + */ + +int +string_is_channel (char *string) +{ + char first_char[2]; + + first_char[0] = string[0]; + first_char[1] = '\0'; + return (strpbrk (first_char, CHANNEL_PREFIX)) ? 1 : 0; +} diff --git a/weechat/src/irc/irc-commands.c b/weechat/src/irc/irc-commands.c new file mode 100644 index 000000000..2b4cf33ec --- /dev/null +++ b/weechat/src/irc/irc-commands.c @@ -0,0 +1,3064 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-commands.c: implementation of IRC commands, according to + RFC 1459,2810,2811,2812 */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "../weechat.h" +#include "irc.h" +#include "../command.h" +#include "../config.h" +#include "../gui/gui.h" + + +t_irc_command irc_commands[] = +{ { "away", N_("toggle away status"), + N_("[-all] [message]"), + N_("-all: toggle away status on all connected servers\n" + "message: message for away (if no message is given, away status is removed)"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_away, NULL }, + { "ctcp", N_("send a ctcp message"), + N_("nickname type"), + N_("nickname: user to send ctcp to\ntype: \"action\" or \"version\""), + 2, MAX_ARGS, 1, NULL, irc_cmd_send_ctcp, NULL }, + { "deop", N_("removes channel operator status from nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_deop, NULL, NULL }, + { "devoice", N_("removes voice from nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_devoice, NULL, NULL }, + { "error", N_("error received from IRC server"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_error }, + { "invite", N_("invite a nick on a channel"), + N_("nickname channel"), + N_("nickname: nick to invite\nchannel: channel to invite"), + 2, 2, 1, NULL, irc_cmd_send_invite, NULL }, + { "join", N_("join a channel"), + N_("channel[,channel] [key[,key]]"), + N_("channel: channel name to join\nkey: key to join the channel"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_join, irc_cmd_recv_join }, + { "kick", N_("forcibly remove a user from a channel"), + N_("[channel] nickname [comment]"), + N_("channel: channel where user is\nnickname: nickname to kick\ncomment: comment for kick"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_kick, irc_cmd_recv_kick }, + { "kill", N_("close client-server connection"), + N_("nickname comment"), + N_("nickname: nickname\ncomment: comment for kill"), + 2, MAX_ARGS, 1, NULL, irc_cmd_send_kill, NULL }, + { "list", N_("list channels and their topic"), + N_("[channel[,channel] [server]]"), + N_("channel: channel to list\nserver: server name"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_list, NULL }, + { "me", N_("send a ctcp action to the current channel"), + N_("message"), + N_("message: message to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_me, NULL }, + { "mode", N_("change channel or user mode"), + N_("{ channel {[+|-]|o|p|s|i|t|n|b|v} [limit] [user] [ban mask] } | " + "{ nickname {[+|-]|i|w|s|o}"), + N_("channel modes:\n" + " channel: channel name to modify\n" + " o: give/take channel operator privileges\n" + " p: private channel flag\n" + " s: secret channel flag\n" + " i: invite-only channel flag\n" + " t: topic settable by channel operator only flag\n" + " n: no messages to channel from clients on the outside\n" + " m: moderated channel\n" + " l: set the user limit to channel\n" + " b: set a ban mask to keep users out\n" + " v: give/take the ability to speak on a moderated channel\n" + " k: set a channel key (password)\n" + "user modes:\n" + " nickname: nickname to modify\n" + " i: mark a user as invisible\n" + " s: mark a user for receive server notices\n" + " w: user receives wallops\n" + " o: operator flag\n"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_mode, irc_cmd_recv_mode }, + { "msg", N_("send message to a nick or channel"), + N_("receiver[,receiver] text"), N_("receiver: nick or channel (may be mask)" + "\ntext: text to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_msg, NULL }, + { "names", N_("list nicknames on channels"), + N_("[channel[,channel]]"), N_("channel: channel name"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_names, NULL }, + { "nick", N_("change current nickname"), + N_("nickname"), N_("nickname: new nickname for current IRC server"), + 1, 1, 1, irc_cmd_send_nick, NULL, irc_cmd_recv_nick }, + { "notice", N_("send notice message to user"), + N_("nickname text"), N_("nickname: user to send notice to\ntext: text to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_notice, irc_cmd_recv_notice }, + { "op", N_("gives channel operator status to nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_op, NULL, NULL }, + { "oper", N_("get operator privileges"), + N_("user password"), + N_("user/password: used to get privileges on current IRC server"), + 2, 2, 1, irc_cmd_send_oper, NULL, NULL }, + { "part", N_("leave a channel"), + N_("[channel[,channel]]"), N_("channel: channel name to join"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_part, irc_cmd_recv_part }, + { "ping", N_("ping server"), + N_("server1 [server2]"), + N_("server1: server to ping\nserver2: forward ping to this server"), + 1, 2, 1, irc_cmd_send_ping, NULL, irc_cmd_recv_ping }, + { "pong", N_("answer to a ping message"), + N_("daemon [daemon2]"), N_("daemon: daemon who has responded to Ping message\n" + "daemon2: forward message to this daemon"), + 1, 2, 1, irc_cmd_send_pong, NULL, NULL }, + { "privmsg", N_("message received"), + "", "", + 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_privmsg }, + { "quit", N_("close all connections & quit " WEECHAT_NAME), + N_("[quit_message]"), + N_("quit_message: quit message (displayed to other users)"), + 0, MAX_ARGS, 0, NULL, irc_cmd_send_quit, irc_cmd_recv_quit }, + { "quote", N_("send raw data to server without parsing"), + N_("data"), + N_("data: raw data to send"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_quote, NULL }, + { "topic", N_("get/set channel topic"), + N_("[channel] [topic]"), N_("channel: channel name\ntopic: new topic for channel " + "(if topic is \"-delete\" then topic is deleted)"), + 0, MAX_ARGS, 1, NULL, irc_cmd_send_topic, irc_cmd_recv_topic }, + { "version", N_("gives the version info of nick or server (current or specified)"), + N_("[server | nickname]"), N_("server: server name\nnickname: nickname"), + 0, 1, 1, NULL, irc_cmd_send_version, NULL }, + { "voice", N_("gives voice to nickname(s)"), + N_("nickname [nickname]"), "", + 1, 1, 1, irc_cmd_send_voice, NULL, NULL }, + { "whois", N_("query information about user(s)"), + N_("[server] nickname[,nickname]"), N_("server: server name\n" + "nickname: nickname (may be a mask)"), + 1, MAX_ARGS, 1, NULL, irc_cmd_send_whois, NULL }, + { "001", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "002", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "003", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "004", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_004 }, + { "005", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "250", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "251", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "252", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "253", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "254", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "255", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "256", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "257", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "258", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "259", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "260", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "261", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "262", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "263", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "264", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "265", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "266", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "267", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "268", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "269", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "301", N_("away message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_301 }, + { "305", N_("unaway"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply }, + { "306", N_("now away"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply }, + { "311", N_("whois (user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_311 }, + { "312", N_("whois (server)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_312 }, + { "313", N_("whois (operator)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_313 }, + { "317", N_("whois (idle)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_317 }, + { "318", N_("whois (end)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_318 }, + { "319", N_("whois (channels)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_319 }, + { "320", N_("whois (identified user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_320 }, + { "321", N_("/list start"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_321 }, + { "322", N_("channel (for /list)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_322 }, + { "323", N_("/list end"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_323 }, + { "331", N_("no topic for channel"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_331 }, + { "332", N_("topic of channel"), + N_("channel :topic"), + N_("channel: name of channel\ntopic: topic of the channel"), + 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_332 }, + { "333", N_("infos about topic (nick & date changed)"), + "", "", + 0, 0, 1, NULL, NULL, irc_cmd_recv_333 }, + { "351", N_("server version"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_351 }, + { "353", N_("list of nicks on channel"), + N_("channel :[[@|+]nick ...]"), + N_("channel: name of channel\nnick: nick on the channel"), + 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_353 }, + { "366", N_("end of /names list"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_366 }, + { "371", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "372", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "373", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "374", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "375", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "376", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg }, + { "401", N_("no such nick/channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "402", N_("no such server"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "403", N_("no such channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "404", N_("cannot send to channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "405", N_("too many channels"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "406", N_("was no such nick"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "406", N_("was no such nick"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "407", N_("was no such nick"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "409", N_("no origin"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "411", N_("no recipient"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "412", N_("no text to send"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "413", N_("no toplevel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "414", N_("wilcard in toplevel domain"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "421", N_("unknown command"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "422", N_("MOTD is missing"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "423", N_("no administrative info"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "424", N_("file error"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "431", N_("no nickname given"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "432", N_("erroneus nickname"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "433", N_("nickname already in use"), + "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_433 }, + { "436", N_("nickname collision"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "441", N_("user not in channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "442", N_("not on channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "443", N_("user already on channel"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "444", N_("user not logged in"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "445", N_("summon has been disabled"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "446", N_("users has been disabled"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "451", N_("you are not registered"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "461", N_("not enough parameters"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "462", N_("you may not register"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "463", N_("your host isn't among the privileged"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "464", N_("password incorrect"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "465", N_("you are banned from this server"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "467", N_("channel key already set"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "471", N_("channel is already full"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "472", N_("unknown mode char to me"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "473", N_("cannot join channel (invite only)"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "474", N_("cannot join channel (banned from channel)"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "475", N_("cannot join channel (bad channel key)"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "481", N_("you're not an IRC operator"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "482", N_("you're not channel operator"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "483", N_("you can't kill a server!"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "491", N_("no O-lines for your host"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "501", N_("unknown mode flag"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { "502", N_("can't change mode for other users"), + "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error }, + { NULL, NULL, NULL, NULL, 0, 0, 1, NULL, NULL, NULL } +}; + + +/* + * irc_recv_command: executes action when receiving IRC command + * returns: 0 = all ok, command executed + * -1 = command failed + * -2 = no command to execute + * -3 = command not found + */ + +int +irc_recv_command (t_irc_server *server, + char *host, char *command, char *arguments) +{ + int i, cmd_found; + + #if DEBUG >= 2 + gui_printf (server->window, "recv_irc_command: cmd=%s args=%s\n", + command, arguments); + #endif + + if (command == NULL) + return -2; + + /* looks for irc command */ + cmd_found = -1; + for (i = 0; irc_commands[i].command_name; i++) + if (strcasecmp (irc_commands[i].command_name, command) == 0) + { + cmd_found = i; + break; + } + + /* command not found */ + if (cmd_found < 0) + return -3; + + if (irc_commands[i].recv_function != NULL) + return (int) (irc_commands[i].recv_function) (server, host, arguments); + + return 0; +} + +/* + * irc_login: login to irc server + */ + +void +irc_login (t_irc_server *server) +{ + char hostname[128]; + + if ((server->password) && (server->password[0])) + server_sendf (server, "PASS %s\r\n", server->password); + + gethostname (hostname, sizeof (hostname) - 1); + hostname[sizeof (hostname) - 1] = '\0'; + if (!hostname[0]) + strcpy (hostname, _("unknown")); + gui_printf (server->window, + _(WEECHAT_NAME ": using local hostname \"%s\"\n"), + hostname); + server_sendf (server, + "NICK %s\r\n" + "USER %s %s %s :%s\r\n", + server->nick, server->username, hostname, "servername", + server->realname); +} + +/* + * irc_cmd_send_away: toggle away status + */ + +int +irc_cmd_send_away (t_irc_server *server, char *arguments) +{ + char *pos; + t_irc_server *ptr_server; + + if (arguments && (strncmp (arguments, "-all", 4) == 0)) + { + pos = arguments + 4; + while (pos[0] == ' ') + pos++; + if (!pos[0]) + pos = NULL; + + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (server->is_connected) + { + if (pos) + server_sendf (ptr_server, "AWAY :%s\r\n", pos); + else + server_sendf (ptr_server, "AWAY\r\n"); + } + } + } + else + { + if (arguments) + server_sendf (server, "AWAY :%s\r\n", arguments); + else + server_sendf (server, "AWAY\r\n"); + } + return 0; +} + +/* + * irc_cmd_send_ctcp: send a ctcp message + */ + +int +irc_cmd_send_ctcp (t_irc_server *server, char *arguments) +{ + char *pos, *pos2; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + pos2 = strchr (pos, ' '); + if (pos2) + { + pos2[0] = '\0'; + pos2++; + while (pos2[0] == ' ') + pos2++; + } + else + pos2 = NULL; + + if (strcasecmp (pos, "version") == 0) + { + if (pos2) + server_sendf (server, "PRIVMSG %s :\01VERSION %s\01\r\n", + arguments, pos2); + else + server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n", + arguments); + } + if (strcasecmp (pos, "action") == 0) + { + if (pos2) + server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n", + arguments, pos2); + else + server_sendf (server, "PRIVMSG %s :\01ACTION\01\r\n", + arguments); + } + + } + return 0; +} + +/* + * irc_cmd_send_deop: remove operator privileges from nickname(s) + */ + +int +irc_cmd_send_deop (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s -o %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + gui_printf (server->window, + _("%s \"deop\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return 0; +} + +/* + * irc_cmd_send_devoice: remove voice from nickname(s) + */ + +int +irc_cmd_send_devoice (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s -v %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + { + gui_printf (server->window, + _("%s \"devoice\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_send_invite: invite a nick on a channel + */ + +int +irc_cmd_send_invite (t_irc_server *server, char *arguments) +{ + server_sendf (server, "INVITE %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_join: join a new channel + */ + +int +irc_cmd_send_join (t_irc_server *server, char *arguments) +{ + server_sendf (server, "JOIN %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_kick: forcibly remove a user from a channel + */ + +int +irc_cmd_send_kick (t_irc_server *server, char *arguments) +{ + if (string_is_channel (arguments)) + server_sendf (server, "KICK %s\r\n", arguments); + else + { + if (WIN_IS_CHANNEL (gui_current_window)) + { + server_sendf (server, + "KICK %s %s\r\n", + CHANNEL(gui_current_window)->name, arguments); + } + else + { + gui_printf (server->window, + _("%s \"kick\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + } + return 0; +} + +/* + * irc_cmd_send_kill: close client-server connection + */ + +int +irc_cmd_send_kill (t_irc_server *server, char *arguments) +{ + server_sendf (server, "KILL %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_list: close client-server connection + */ + +int +irc_cmd_send_list (t_irc_server *server, char *arguments) +{ + if (arguments) + server_sendf (server, "LIST %s\r\n", arguments); + else + server_sendf (server, "LIST\r\n"); + return 0; +} + +/* + * irc_cmd_send_me: send a ctcp action to the current channel + */ + +int +irc_cmd_send_me (t_irc_server *server, char *arguments) +{ + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"me\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n", + CHANNEL(gui_current_window)->name, arguments); + irc_display_prefix (gui_current_window, PREFIX_ACTION_ME); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_NICK, "%s", server->nick); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, " %s\n", arguments); + return 0; +} + +/* + * irc_cmd_send_mode: change mode for channel/nickname + */ + +int +irc_cmd_send_mode (t_irc_server *server, char *arguments) +{ + server_sendf (server, "MODE %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_msg: send a message to a nick or channel + */ + +int +irc_cmd_send_msg (t_irc_server *server, char *arguments) +{ + char *pos, *pos_comma; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + + while (arguments && arguments[0]) + { + pos_comma = strchr (arguments, ','); + if (pos_comma) + { + pos_comma[0] = '\0'; + pos_comma++; + } + if (string_is_channel (arguments)) + { + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + ptr_nick = nick_search (ptr_channel, server->nick); + if (ptr_nick) + { + irc_display_nick (ptr_channel->window, ptr_nick, + MSG_TYPE_NICK, 1, 1, 0); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + } + else + gui_printf (server->window, + _("%s nick not found for \"privmsg\" command\n"), + WEECHAT_ERROR); + } + server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos); + } + else + { + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + { + ptr_channel = channel_new (server, CHAT_PRIVATE, arguments); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s cannot create new private window \"%s\"\n"), + WEECHAT_ERROR, + arguments); + return -1; + } + gui_redraw_window_title (ptr_channel->window); + } + + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "<"); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_NICK_SELF, + "%s", server->nick); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "> "); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos); + } + arguments = pos_comma; + } + } + else + gui_printf (server->window, + _("%s wrong number of args for \"privmsg\" command\n"), + WEECHAT_ERROR); + return 0; +} + +/* + * irc_cmd_send_names: list nicknames on channels + */ + +int +irc_cmd_send_names (t_irc_server *server, char *arguments) +{ + if (arguments) + server_sendf (server, "NAMES %s\r\n", arguments); + else + { + if (!WIN_IS_CHANNEL(gui_current_window)) + { + gui_printf (server->window, + _("%s \"names\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + else + server_sendf (server, "NAMES %s\r\n", + CHANNEL(gui_current_window)->name); + } + return 0; +} + +/* + * irc_cmd_send_nick: change nickname + */ + +int +irc_cmd_send_nick (t_irc_server *server, int argc, char **argv) +{ + if (argc != 1) + return -1; + server_sendf (server, "NICK %s\r\n", argv[0]); + return 0; +} + +/* + * irc_cmd_send_notice: send notice message + */ + +int +irc_cmd_send_notice (t_irc_server *server, char *arguments) +{ + server_sendf (server, "NOTICE %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_op: give operator privileges to nickname(s) + */ + +int +irc_cmd_send_op (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s +o %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + { + gui_printf (server->window, + _("%s \"op\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_send_oper: get oper privileges + */ + +int +irc_cmd_send_oper (t_irc_server *server, int argc, char **argv) +{ + if (argc != 2) + return -1; + server_sendf (server, "OPER %s %s\r\n", argv[0], argv[1]); + return 0; +} + +/* + * irc_cmd_send_part: leave a channel or close a private window + */ + +int +irc_cmd_send_part (t_irc_server *server, char *arguments) +{ + char *channel_name, *pos_args; + t_irc_channel *ptr_channel; + + if (arguments) + { + if (string_is_channel (arguments)) + { + channel_name = arguments; + pos_args = strchr (arguments, ' '); + if (pos_args) + { + pos_args[0] = '\0'; + pos_args++; + while (pos_args[0] == ' ') + pos_args++; + } + } + else + { + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"part\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + channel_name = CHANNEL(gui_current_window)->name; + pos_args = arguments; + } + } + else + { + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"part\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + if (WIN_IS_PRIVATE(gui_current_window)) + { + ptr_channel = CHANNEL(gui_current_window); + gui_window_free (ptr_channel->window); + channel_free (server, ptr_channel); + gui_redraw_window_status (gui_current_window); + gui_redraw_window_input (gui_current_window); + return 0; + } + channel_name = CHANNEL(gui_current_window)->name; + pos_args = NULL; + } + + if (pos_args) + server_sendf (server, "PART %s :%s\r\n", channel_name, pos_args); + else + server_sendf (server, "PART %s\r\n", channel_name); + return 0; +} + +/* + * irc_cmd_send_ping: ping a server + */ + +int +irc_cmd_send_ping (t_irc_server *server, int argc, char **argv) +{ + if (argc == 1) + server_sendf (server, "PING %s\r\n", argv[0]); + if (argc == 2) + server_sendf (server, "PING %s %s\r\n", argv[0], + argv[1]); + return 0; +} + +/* + * irc_cmd_send_pong: send pong answer to a daemon + */ + +int +irc_cmd_send_pong (t_irc_server *server, int argc, char **argv) +{ + if (argc == 1) + server_sendf (server, "PONG %s\r\n", argv[0]); + if (argc == 2) + server_sendf (server, "PONG %s %s\r\n", argv[0], + argv[1]); + return 0; +} + +/* + * irc_cmd_send_quit: disconnect from all servers and quit WeeChat + */ + +int +irc_cmd_send_quit (t_irc_server *server, char *arguments) +{ + if (server && server->is_connected) + { + if (arguments) + server_sendf (server, "QUIT :%s\r\n", arguments); + else + server_sendf (server, "QUIT\r\n"); + } + quit_weechat = 1; + return 0; +} + +/* + * irc_cmd_send_quote: send raw data to server + */ + +int +irc_cmd_send_quote (t_irc_server *server, char *arguments) +{ + server_sendf (server, "%s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_send_topic: get/set topic for a channel + */ + +int +irc_cmd_send_topic (t_irc_server *server, char *arguments) +{ + char *channel_name, *new_topic, *pos; + + channel_name = NULL; + new_topic = NULL; + + if (arguments) + { + if (string_is_channel (arguments)) + { + channel_name = arguments; + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + new_topic = (pos[0]) ? pos : NULL; + } + } + else + new_topic = arguments; + } + + /* look for current channel if not specified */ + if (!channel_name) + { + if (WIN_IS_SERVER(gui_current_window)) + { + gui_printf (server->window, + _("%s \"topic\" command can not be executed on a server window\n"), + WEECHAT_ERROR); + return -1; + } + channel_name = CHANNEL(gui_current_window)->name; + } + + if (new_topic) + { + if (strcmp (new_topic, "-delete") == 0) + server_sendf (server, "TOPIC %s :\r\n", channel_name); + else + server_sendf (server, "TOPIC %s :%s\r\n", channel_name, new_topic); + } + else + server_sendf (server, "TOPIC %s\r\n", channel_name); + return 0; +} + +/* + * irc_cmd_send_version: gives the version info of nick or server (current or specified) + */ + +int +irc_cmd_send_version (t_irc_server *server, char *arguments) +{ + if (arguments) + { + if (WIN_IS_CHANNEL(gui_current_window) && + nick_search (CHANNEL(gui_current_window), arguments)) + server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n", + arguments); + else + server_sendf (server, "VERSION %s\r\n", + arguments); + } + else + { + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s, compiled on %s %s\n", + WEECHAT_NAME_AND_VERSION, + __DATE__, __TIME__); + server_sendf (server, "VERSION\r\n"); + } + return 0; +} + +/* + * irc_cmd_send_voice: give voice to nickname(s) + */ + +int +irc_cmd_send_voice (t_irc_server *server, int argc, char **argv) +{ + int i; + + if (WIN_IS_CHANNEL(gui_current_window)) + { + for (i = 0; i < argc; i++) + server_sendf (server, "MODE %s +v %s\r\n", + CHANNEL(gui_current_window)->name, + argv[i]); + } + else + { + gui_printf (server->window, + _("%s \"voice\" command can only be executed in a channel window\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_send_whois: query information about user(s) + */ + +int +irc_cmd_send_whois (t_irc_server *server, char *arguments) +{ + server_sendf (server, "WHOIS %s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_error: error received from server + */ + +int +irc_cmd_recv_error (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + int first; + + /* make gcc happy */ + (void) server; + (void) host; + + if (strncmp (arguments, "Closing Link", 12) == 0) + { + server_disconnect (server); + return 0; + } + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_ERROR); + first = 1; + + while (pos && pos[0]) + { + pos2 = strchr (pos, ' '); + if ((pos[0] == ':') || (!pos2)) + { + if (pos[0] == ':') + pos++; + gui_printf_color (server->window, + COLOR_WIN_CHAT, + "%s%s\n", (first) ? "" : ": ", pos); + pos = NULL; + } + else + { + pos2[0] = '\0'; + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s%s", + (first) ? "" : " ", pos); + first = 0; + pos = pos2 + 1; + } + } + return 0; +} + +/* + * irc_cmd_recv_join: 'join' message received + */ + +int +irc_cmd_recv_join (t_irc_server *server, char *host, char *arguments) +{ + t_irc_channel *ptr_channel; + char *pos; + + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + { + ptr_channel = channel_new (server, CHAT_CHANNEL, arguments); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s cannot create new channel \"%s\"\n"), + WEECHAT_ERROR, arguments); + return -1; + } + } + + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + irc_display_prefix (ptr_channel->window, PREFIX_JOIN); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK, + "%s ", host); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + "("); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_HOST, + "%s", pos + 1); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + ")"); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _(" has joined ")); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s\n", arguments); + nick_new (ptr_channel, host, 0, 0, 0); + gui_redraw_window_nick (gui_current_window); + return 0; +} + +/* + * irc_cmd_recv_kick: 'kick' message received + */ + +int +irc_cmd_recv_kick (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos_nick, *pos_comment; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + pos_nick[0] = '\0'; + pos_nick++; + while (pos_nick[0] == ' ') + pos_nick++; + + pos_comment = strchr (pos_nick, ' '); + if (pos_comment) + { + pos_comment[0] = '\0'; + pos_comment++; + while (pos_comment[0] == ' ') + pos_comment++; + if (pos_comment[0] == ':') + pos_comment++; + } + + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s channel not found for \"kick\" command\n"), + WEECHAT_ERROR); + return -1; + } + + irc_display_prefix (ptr_channel->window, PREFIX_PART); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK, + "%s", host); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _(" has kicked ")); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK, + "%s", pos_nick); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _(" from ")); + if (pos_comment) + { + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s ", arguments); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + "("); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + "%s", pos_comment); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, + ")\n"); + } + else + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s\n", arguments); + } + else + { + gui_printf (server->window, + _("%s nick not found for \"kick\" command\n"), + WEECHAT_ERROR); + return -1; + } + ptr_nick = nick_search (ptr_channel, pos_nick); + if (ptr_nick) + { + nick_free (ptr_channel, ptr_nick); + gui_redraw_window_nick (gui_current_window); + } + return 0; +} + +/* + * irc_cmd_recv_mode: 'mode' message received + */ + +int +irc_cmd_recv_mode (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2, *pos_parm; + char set_flag; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"mode\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + pos = strchr (arguments, ' '); + if (!pos) + { + gui_printf (server->window, + _("%s \"mode\" command received without channel or nickname\n"), + WEECHAT_ERROR); + return -1; + } + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + + pos_parm = strchr (pos, ' '); + if (pos_parm) + { + pos_parm[0] = '\0'; + pos_parm++; + while (pos_parm[0] == ' ') + pos_parm++; + pos2 = strchr (pos_parm, ' '); + if (pos2) + pos2[0] = '\0'; + } + + set_flag = '+'; + + if (string_is_channel (arguments)) + { + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + /* channel modes */ + while (pos && pos[0]) + { + switch (pos[0]) + { + case '+': + set_flag = '+'; + break; + case '-': + set_flag = '-'; + break; + case 'b': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "b", host, + (set_flag == '+') ? + _("sets ban on") : + _("removes ban on"), + pos_parm); + /* TODO: change & redraw channel modes */ + break; + case 'i': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "i", host, + (set_flag == '+') ? + _("sets invite-only channel flag") : + _("removes invite-only channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 'l': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "l", host, + (set_flag == '+') ? + _("sets the user limit to") : + _("removes user limit"), + (set_flag == '+') ? pos_parm : NULL); + /* TODO: change & redraw channel modes */ + break; + case 'm': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "m", host, + (set_flag == '+') ? + _("sets moderated channel flag") : + _("removes moderated channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 'o': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "o", host, + (set_flag == '+') ? + _("gives channel operator status to") : + _("removes channel operator status from"), + pos_parm); + ptr_nick = nick_search (ptr_channel, pos_parm); + if (ptr_nick) + { + ptr_nick->is_op = (set_flag == '+') ? 1 : 0; + nick_resort (ptr_channel, ptr_nick); + gui_redraw_window_nick (ptr_channel->window); + } + break; + /* TODO: remove this obsolete (?) channel flag? */ + case 'p': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "p", host, + (set_flag == '+') ? + _("sets private channel flag") : + _("removes private channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 's': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "s", host, + (set_flag == '+') ? + _("sets secret channel flag") : + _("removes secret channel flag"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 't': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "t", host, + (set_flag == '+') ? + _("sets topic protection") : + _("removes topic protection"), + NULL); + /* TODO: change & redraw channel modes */ + break; + case 'v': + irc_display_mode (ptr_channel->window, + arguments, set_flag, "v", host, + (set_flag == '+') ? + _("gives voice to") : + _("removes voice from"), + pos_parm); + + ptr_nick = nick_search (ptr_channel, pos_parm); + if (ptr_nick) + { + ptr_nick->has_voice = (set_flag == '+') ? 1 : 0; + nick_resort (ptr_channel, ptr_nick); + gui_redraw_window_nick (ptr_channel->window); + } + break; + } + pos++; + } + } + else + { + gui_printf (server->window, + _("%s channel not found for \"mode\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + /* nickname modes */ + gui_printf (server->window, "(TODO!) nickname modes: channel=%s, args=%s\n", arguments, pos); + } + return 0; +} + +/* + * irc_cmd_recv_nick: 'nick' message received + */ + +int +irc_cmd_recv_nick (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + int nick_is_me; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"nick\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + for (ptr_channel = server->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + ptr_nick = nick_search (ptr_channel, host); + if (ptr_nick) + { + nick_is_me = (strcmp (ptr_nick->nick, server->nick) == 0); + nick_change (ptr_channel, ptr_nick, arguments); + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + if (nick_is_me) + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + _("You are ")); + else + { + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, + "%s", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, " is "); + } + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + _("now known as ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, + "%s\n", + arguments); + if (ptr_channel->window->win_nick) + gui_redraw_window_nick (ptr_channel->window); + } + } + + if (strcmp (server->nick, host) == 0) + { + free (server->nick); + server->nick = strdup (arguments); + } + gui_redraw_window_input (gui_current_window); + + return 0; +} + +/* + * irc_cmd_recv_notice: 'notice' message received + */ + +int +irc_cmd_recv_notice (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + + if (host) + { + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + } + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + } + else + { + gui_printf (server->window, + _("%s nickname not found for \"notice\" command\n"), + WEECHAT_ERROR); + return -1; + } + irc_display_prefix (server->window, PREFIX_SERVER); + if (strncmp (pos, "\01VERSION", 8) == 0) + { + pos += 9; + pos2 = strchr (pos, '\01'); + if (pos2) + pos2[0] = '\0'; + gui_printf_color (server->window, COLOR_WIN_CHAT, "CTCP "); + gui_printf_color (server->window, COLOR_WIN_CHAT_CHANNEL, "VERSION"); + gui_printf_color (server->window, COLOR_WIN_CHAT, " reply from "); + gui_printf_color (server->window, COLOR_WIN_CHAT_NICK, "%s", host); + gui_printf_color (server->window, COLOR_WIN_CHAT, ": %s\n", pos); + } + else + gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_part: 'part' message received + */ + +int +irc_cmd_recv_part (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos_args; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (!host || !arguments) + { + gui_printf (server->window, + _("%s \"part\" command received without host or channel\n"), + WEECHAT_ERROR); + return -1; + } + + pos_args = strchr (arguments, ' '); + if (pos_args) + { + pos_args[0] = '\0'; + pos_args++; + while (pos_args[0] == ' ') + pos_args++; + if (pos_args[0] == ':') + pos_args++; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + ptr_nick = nick_search (ptr_channel, host); + if (ptr_nick) + { + if (strcmp (ptr_nick->nick, server->nick) == 0) + { + /* part request was issued by local client */ + gui_window_free (ptr_channel->window); + channel_free (server, ptr_channel); + gui_redraw_window_status (gui_current_window); + gui_redraw_window_input (gui_current_window); + } + else + { + + /* remove nick from nick list and display message */ + nick_free (ptr_channel, ptr_nick); + irc_display_prefix (ptr_channel->window, PREFIX_PART); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s ", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_HOST, "%s", pos+1); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")"); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _(" has left ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%s", ptr_channel->name); + if (pos_args && pos_args[0]) + { + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, " ("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, "%s", pos_args); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")"); + } + gui_printf (ptr_channel->window, "\n"); + + /* redraw nick list if this is current window */ + if (ptr_channel->window->win_nick) + gui_redraw_window_nick (ptr_channel->window); + } + } + } + else + { + gui_printf (server->window, + _("%s channel not found for \"part\" command\n"), + WEECHAT_ERROR); + return -1; + } + + return 0; +} + +/* + * irc_cmd_recv_ping: 'ping' command received + */ + +int +irc_cmd_recv_ping (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + (void)host; + pos = strrchr (arguments, ' '); + if (pos) + pos[0] = '\0'; + server_sendf (server, "PONG :%s\r\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_privmsg: 'privmsg' command received + */ + +int +irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2, *host2; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"privmsg\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + { + pos[0] = '\0'; + host2 = pos+1; + } + else + host2 = host; + + /* receiver is a channel ? */ + if (string_is_channel (arguments)) + { + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + + ptr_channel = channel_search (server, arguments); + if (ptr_channel) + { + if (strncmp (pos, "\01ACTION ", 8) == 0) + { + pos += 8; + pos2 = strchr (pos, '\01'); + if (pos2) + pos2[0] = '\0'; + irc_display_prefix (ptr_channel->window, PREFIX_ACTION_ME); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, " %s\n", pos); + } + else + { + ptr_nick = nick_search (ptr_channel, host); + if (ptr_nick) + { + irc_display_nick (ptr_channel->window, ptr_nick, + MSG_TYPE_NICK, 1, 1, 0); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + } + else + { + gui_printf (server->window, + _("%s nick not found for \"privmsg\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + } + else + { + gui_printf (server->window, + _("%s channel not found for \"privmsg\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + } + else + { + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + + if (strcmp (pos, "\01VERSION\01") == 0) + server_sendf (server, + "NOTICE %s :\01VERSION " + WEECHAT_NAME " v" + WEECHAT_VERSION ", compiled on " __DATE__ "\01\r\n", + host); + else + { + /* private message received */ + ptr_channel = channel_search (server, host); + if (!ptr_channel) + { + ptr_channel = channel_new (server, CHAT_PRIVATE, host); + if (!ptr_channel) + { + gui_printf (server->window, + _("%s cannot create new private window \"%s\"\n"), + WEECHAT_ERROR, host); + return -1; + } + } + if (!ptr_channel->topic) + { + ptr_channel->topic = strdup (host2); + gui_redraw_window_title (ptr_channel->window); + } + + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "<"); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_NICK_PRIVATE, + "%s", host); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_NICK, + COLOR_WIN_CHAT_DARK, "> "); + gui_printf_color_type (ptr_channel->window, + MSG_TYPE_MSG, + COLOR_WIN_CHAT, "%s\n", pos); + } + } + else + { + gui_printf (server->window, + _("%s cannot parse \"privmsg\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + return 0; +} + +/* + * irc_cmd_recv_quit: 'quit' command received + */ + +int +irc_cmd_recv_quit (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + + /* no host => we can't identify sender of message! */ + if (host == NULL) + { + gui_printf (server->window, + _("%s \"quit\" command received without host\n"), + WEECHAT_ERROR); + return -1; + } + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + for (ptr_channel = server->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + if (ptr_channel->type == CHAT_PRIVATE) + ptr_nick = NULL; + else + ptr_nick = nick_search (ptr_channel, host); + + if (ptr_nick || (strcmp (ptr_channel->name, host) == 0)) + { + if (ptr_nick) + nick_free (ptr_channel, ptr_nick); + irc_display_prefix (ptr_channel->window, PREFIX_QUIT); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s ", host); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_HOST, "%s", pos + 1); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")"); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _(" has quit ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, "%s", + arguments); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")\n"); + if ((ptr_channel->window == gui_current_window) && + (ptr_channel->window->win_nick)) + gui_redraw_window_nick (ptr_channel->window); + } + } + + return 0; +} + +/* + * irc_cmd_recv_server_msg: command received from server (numeric) + */ + +int +irc_cmd_recv_server_msg (t_irc_server *server, char *host, char *arguments) +{ + /* make gcc happy */ + (void) host; + + /* skip nickname if at beginning of server message */ + if (strncmp (server->nick, arguments, strlen (server->nick)) == 0) + { + arguments += strlen (server->nick) + 1; + while (arguments[0] == ' ') + arguments++; + } + + if (arguments[0] == ':') + arguments++; + + /* display server message */ + irc_display_prefix (server->window, PREFIX_SERVER); + gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_server_reply: server reply + */ + +int +irc_cmd_recv_server_reply (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + int first; + + /* make gcc happy */ + (void) server; + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_ERROR); + first = 1; + + while (pos && pos[0]) + { + pos2 = strchr (pos, ' '); + if ((pos[0] == ':') || (!pos2)) + { + if (pos[0] == ':') + pos++; + gui_printf_color (server->window, + COLOR_WIN_CHAT, + "%s%s\n", (first) ? "" : ": ", pos); + pos = NULL; + } + else + { + pos2[0] = '\0'; + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s%s", + (first) ? "" : " ", pos); + first = 0; + pos = pos2 + 1; + } + } + return 0; +} + +/* + * irc_cmd_recv_topic: 'topic' command received + */ + +int +irc_cmd_recv_topic (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + t_irc_channel *ptr_channel; + t_gui_window *window; + + /* make gcc happy */ + (void) host; + + /* keep only nick name from host */ + pos = strchr (host, '!'); + if (pos) + pos[0] = '\0'; + + if (string_is_channel (arguments)) + { + gui_printf (server->window, + _("%s \"topic\" command received without channel\n"), + WEECHAT_ERROR); + return -1; + } + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] == ':') + pos++; + if (!pos[0]) + pos = NULL; + } + + ptr_channel = channel_search (server, arguments); + window = (ptr_channel) ? ptr_channel->window : server->window; + + irc_display_prefix (window, PREFIX_INFO); + gui_printf_color (window, + COLOR_WIN_CHAT_NICK, "%s", + host); + if (pos) + { + gui_printf_color (window, + COLOR_WIN_CHAT, _(" has changed topic for ")); + gui_printf_color (window, + COLOR_WIN_CHAT_CHANNEL, "%s", + arguments); + gui_printf_color (window, + COLOR_WIN_CHAT, _(" to: \"%s\"\n"), + pos); + } + else + { + gui_printf_color (window, + COLOR_WIN_CHAT, _(" has unset topic for ")); + gui_printf_color (window, + COLOR_WIN_CHAT_CHANNEL, "%s\n", + arguments); + } + + if (ptr_channel) + { + if (ptr_channel->topic) + free (ptr_channel->topic); + if (pos) + ptr_channel->topic = strdup (pos); + else + ptr_channel->topic = strdup (""); + gui_redraw_window_title (ptr_channel->window); + } + + return 0; +} + +/* + * irc_cmd_recv_004: '004' command (connected to irc server ?????) + */ + +int +irc_cmd_recv_004 (t_irc_server *server, char *host, char *arguments) +{ + /* make gcc happy */ + (void) host; + (void) arguments; + + irc_cmd_recv_server_msg (server, host, arguments); + + /* connection to IRC server is ok! */ + server->is_connected = 1; + gui_redraw_window_status (server->window); + gui_redraw_window_input (server->window); + return 0; +} + +/* + * irc_cmd_recv_311: '311' command (away message) + */ + +int +irc_cmd_recv_301 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) server; + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (gui_current_window, PREFIX_INFO); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, _(" is away: %s\n"), pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_311: '311' command (whois, user) + */ + +int +irc_cmd_recv_311 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_user, *pos_host, *pos_realname; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_user = strchr (pos_nick, ' '); + if (pos_user) + { + pos_user[0] = '\0'; + pos_user++; + while (pos_user[0] == ' ') + pos_user++; + pos_host = strchr (pos_user, ' '); + if (pos_host) + { + pos_host[0] = '\0'; + pos_host++; + while (pos_host[0] == ' ') + pos_host++; + pos_realname = strchr (pos_host, ' '); + if (pos_realname) + { + pos_realname[0] = '\0'; + pos_realname++; + while (pos_realname[0] == ' ') + pos_realname++; + if (pos_realname[0] == '*') + pos_realname++; + while (pos_realname[0] == ' ') + pos_realname++; + if (pos_realname[0] == ':') + pos_realname++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] ("); + gui_printf_color (server->window, + COLOR_WIN_CHAT_HOST, "%s@%s", + pos_user, pos_host); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, ")"); + gui_printf_color (server->window, + COLOR_WIN_CHAT, ": %s\n", pos_realname); + } + } + } + } + return 0; +} + +/* + * irc_cmd_recv_312: '312' command (whois, server) + */ + +int +irc_cmd_recv_312 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_server, *pos_serverinfo; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_server = strchr (pos_nick, ' '); + if (pos_server) + { + pos_server[0] = '\0'; + pos_server++; + while (pos_server[0] == ' ') + pos_server++; + pos_serverinfo = strchr (pos_server, ' '); + if (pos_serverinfo) + { + pos_serverinfo[0] = '\0'; + pos_serverinfo++; + while (pos_serverinfo[0] == ' ') + pos_serverinfo++; + if (pos_serverinfo[0] == ':') + pos_serverinfo++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s ", pos_server); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "("); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s", pos_serverinfo); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, ")\n"); + } + } + } + return 0; +} + +/* + * irc_cmd_recv_313: '313' command (whois, operator) + */ + +int +irc_cmd_recv_313 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s\n", pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_317: '317' command (whois, idle) + */ + +int +irc_cmd_recv_317 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_idle, *pos_signon, *pos_message; + int idle_time, day, hour, min, sec; + time_t datetime; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_idle = strchr (pos_nick, ' '); + if (pos_idle) + { + pos_idle[0] = '\0'; + pos_idle++; + while (pos_idle[0] == ' ') + pos_idle++; + pos_signon = strchr (pos_idle, ' '); + if (pos_signon) + { + pos_signon[0] = '\0'; + pos_signon++; + while (pos_signon[0] == ' ') + pos_signon++; + pos_message = strchr (pos_signon, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + + idle_time = atoi (pos_idle); + day = idle_time / (60 * 60 * 24); + hour = (idle_time % (60 * 60 * 24)) / (60 * 60); + min = ((idle_time % (60 * 60 * 24)) % (60 * 60)) / 60; + sec = ((idle_time % (60 * 60 * 24)) % (60 * 60)) % 60; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, _("idle: ")); + if (day > 0) + { + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", day); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (day > 1) ? _("days") : _("day")); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + ", "); + } + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%02d ", hour); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (hour > 1) ? _("hours") : _("hour")); + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + " %02d ", min); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (min > 1) ? _("minutes") : _("minute")); + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + " %02d ", sec); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + (sec > 1) ? _("seconds") : _("second")); + gui_printf_color (server->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, _("signon at: ")); + datetime = (time_t)(atol (pos_signon)); + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s", ctime (&datetime)); + } + } + } + } + return 0; +} + +/* + * irc_cmd_recv_318: '318' command (whois, end) + */ + +int +irc_cmd_recv_318 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s\n", pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_319: '319' command (whois, end) + */ + +int +irc_cmd_recv_319 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_channel, *pos; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_channel = strchr (pos_nick, ' '); + if (pos_channel) + { + pos_channel[0] = '\0'; + pos_channel++; + while (pos_channel[0] == ' ') + pos_channel++; + if (pos_channel[0] == ':') + pos_channel++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, _("Channels: ")); + + while (pos_channel && pos_channel[0]) + { + if (pos_channel[0] == '@') + { + gui_printf_color (server->window, + COLOR_WIN_NICK_OP, "@"); + pos_channel++; + } + else + { + if (pos_channel[0] == '%') + { + gui_printf_color (server->window, + COLOR_WIN_NICK_HALFOP, "%"); + pos_channel++; + } + else + if (pos_channel[0] == '+') + { + gui_printf_color (server->window, + COLOR_WIN_NICK_VOICE, "+"); + pos_channel++; + } + } + pos = strchr (pos_channel, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + gui_printf_color (server->window, + COLOR_WIN_CHAT_CHANNEL, + "%s%s", + pos_channel, + (pos && pos[0]) ? " " : "\n"); + pos_channel = pos; + } + } + } + return 0; +} + +/* + * irc_cmd_recv_320: '320' command (whois, identified user) + */ + +int +irc_cmd_recv_320 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_nick, *pos_message; + + /* make gcc happy */ + (void) host; + + pos_nick = strchr (arguments, ' '); + if (pos_nick) + { + while (pos_nick[0] == ' ') + pos_nick++; + pos_message = strchr (pos_nick, ' '); + if (pos_message) + { + pos_message[0] = '\0'; + pos_message++; + while (pos_message[0] == ' ') + pos_message++; + if (pos_message[0] == ':') + pos_message++; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (server->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + gui_printf_color (server->window, + COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (server->window, + COLOR_WIN_CHAT, "%s\n", pos_message); + } + } + return 0; +} + +/* + * irc_cmd_recv_321: '321' command (/list start) + */ + +int +irc_cmd_recv_321 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_322: '322' command (channel for /list) + */ + +int +irc_cmd_recv_322 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_323: '323' command (/list end) + */ + +int +irc_cmd_recv_323 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + while (pos[0] == ' ') + pos++; + } + else + pos = arguments; + + irc_display_prefix (server->window, PREFIX_INFO); + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_331: '331' command received (no topic for channel) + */ + +int +irc_cmd_recv_331 (t_irc_server *server, char *host, char *arguments) +{ + char *pos; + + /* make gcc happy */ + (void) server; + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + pos[0] = '\0'; + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, _("No topic set for ")); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_CHANNEL, "%s\n", arguments); + return 0; +} + +/* + * irc_cmd_recv_332: '332' command received (topic of channel) + */ + +int +irc_cmd_recv_332 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + t_irc_channel *ptr_channel; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + while (pos[0] == ' ') + pos++; + pos2 = strchr (pos, ' '); + if (pos2) + { + pos2[0] = '\0'; + ptr_channel = channel_search (server, pos); + if (ptr_channel) + { + pos2++; + while (pos2[0] == ' ') + pos2++; + if (pos2[0] == ':') + pos2++; + if (ptr_channel->topic) + free (ptr_channel->topic); + ptr_channel->topic = strdup (pos2); + + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _("Topic for ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, "%s", pos); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _(" is: \"%s\"\n"), pos2); + + gui_redraw_window_title (ptr_channel->window); + } + else + { + gui_printf (server->window, + _("%s channel not found for \"332\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + } + else + { + gui_printf (server->window, + _("%s cannot identify channel for \"332\" command\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_recv_333: '333' command received (infos about topic (nick / date) + */ + +int +irc_cmd_recv_333 (t_irc_server *server, char *host, char *arguments) +{ + char *pos_channel, *pos_nick, *pos_date; + t_irc_channel *ptr_channel; + time_t datetime; + + /* make gcc happy */ + (void) host; + + pos_channel = strchr (arguments, ' '); + if (pos_channel) + { + while (pos_channel[0] == ' ') + pos_channel++; + pos_nick = strchr (pos_channel, ' '); + if (pos_nick) + { + pos_nick[0] = '\0'; + pos_nick++; + while (pos_nick[0] == ' ') + pos_nick++; + pos_date = strchr (pos_nick, ' '); + if (pos_date) + { + pos_date[0] = '\0'; + pos_date++; + while (pos_date[0] == ' ') + pos_date++; + + ptr_channel = channel_search (server, pos_channel); + if (ptr_channel) + { + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _("Topic set by ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_NICK, "%s", pos_nick); + datetime = (time_t)(atol (pos_date)); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, ", %s", ctime (&datetime)); + } + else + { + gui_printf (server->window, + _("%s channel not found for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + gui_printf (server->window, + _("%s cannot identify date/time for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + gui_printf (server->window, + _("%s cannot identify nickname for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + } + else + { + gui_printf (server->window, + _("%s cannot identify channel for \"333\" command\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_recv_351: '351' command received (server version) + */ + +int +irc_cmd_recv_351 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + + /* make gcc happy */ + (void) server; + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + } + else + pos = arguments; + + pos2 = strstr (pos, " :"); + if (pos2) + { + pos2[0] = '\0'; + pos2 += 2; + } + + irc_display_prefix (server->window, PREFIX_SERVER); + if (pos2) + gui_printf (server->window, "%s %s\n", pos, pos2); + else + gui_printf (server->window, "%s\n", pos); + return 0; +} + +/* + * irc_cmd_recv_353: '353' command received (list of users on a channel) + */ + +int +irc_cmd_recv_353 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos_nick; + int is_op, is_halfop, has_voice; + t_irc_channel *ptr_channel; + + /* make gcc happy */ + (void) host; + + pos = strstr (arguments, " = "); + if (pos) + arguments = pos + 3; + pos = strchr (arguments, ' '); + if (pos) + { + pos[0] = '\0'; + + ptr_channel = channel_search (server, arguments); + if (!ptr_channel) + return 0; + + pos++; + while (pos[0] == ' ') + pos++; + if (pos[0] != ':') + { + gui_printf (server->window, + _("%s cannot parse \"353\" command\n"), + WEECHAT_ERROR); + return -1; + } + pos++; + if (pos[0]) + { + while (pos && pos[0]) + { + is_op = 0; + is_halfop = 0; + has_voice = 0; + while ((pos[0] == '@') || (pos[0] == '%') || (pos[0] == '+')) + { + if (pos[0] == '@') + is_op = 1; + if (pos[0] == '%') + is_halfop = 1; + if (pos[0] == '+') + has_voice = 1; + pos++; + } + pos_nick = pos; + pos = strchr (pos, ' '); + if (pos) + { + pos[0] = '\0'; + pos++; + } + if (!nick_new (ptr_channel, pos_nick, is_op, is_halfop, has_voice)) + gui_printf (server->window, + _("%s cannot create nick \"%s\" for channel \"%s\"\n"), + WEECHAT_ERROR, pos_nick, ptr_channel->name); + } + } + gui_redraw_window_nick (ptr_channel->window); + } + else + { + gui_printf (server->window, + _("%s cannot parse \"353\" command\n"), + WEECHAT_ERROR); + return -1; + } + return 0; +} + +/* + * irc_cmd_recv_366: '366' command received (end of /names list) + */ + +int +irc_cmd_recv_366 (t_irc_server *server, char *host, char *arguments) +{ + char *pos, *pos2; + t_irc_channel *ptr_channel; + t_irc_nick *ptr_nick; + int num_nicks, num_op, num_halfop, num_voice, num_normal; + + /* make gcc happy */ + (void) host; + + pos = strchr (arguments, ' '); + if (pos) + { + while (pos[0] == ' ') + pos++; + pos2 = strchr (pos, ' '); + if (pos2) + { + pos2[0] = '\0'; + pos2++; + while (pos2[0] == ' ') + pos2++; + if (pos2[0] == ':') + pos2++; + + ptr_channel = channel_search (server, pos); + if (ptr_channel) + { + + /* display users on channel */ + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, + _("Nicks ")); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL, + "%s", ptr_channel->name); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, ": "); + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "["); + + for (ptr_nick = ptr_channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + { + irc_display_nick (ptr_channel->window, ptr_nick, + MSG_TYPE_INFO, 0, 0, 1); + if (ptr_nick != ptr_channel->last_nick) + gui_printf (ptr_channel->window, " "); + } + gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "]\n"); + + /* display number of nicks, ops, halfops & voices on the channel */ + nick_count (ptr_channel, &num_nicks, &num_op, &num_halfop, &num_voice, + &num_normal); + irc_display_prefix (ptr_channel->window, PREFIX_INFO); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, _("Channel ")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%s", ptr_channel->name); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, ": "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_nicks); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_nicks > 1) ? _("nicks") : _("nick")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, " ("); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_op); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_op > 1) ? _("ops") : _("op")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_halfop); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_halfop > 1) ? _("halfops") : _("halfop")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_voice); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + (num_voice > 1) ? _("voices") : _("voice")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + ", "); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_CHANNEL, + "%d ", num_normal); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT, + _("normal")); + gui_printf_color (ptr_channel->window, + COLOR_WIN_CHAT_DARK, ")\n"); + } + else + { + irc_display_prefix (gui_current_window, PREFIX_INFO); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT_CHANNEL, pos); + gui_printf_color (gui_current_window, + COLOR_WIN_CHAT, ": %s\n", pos2); + return 0; + } + } + } + return 0; +} + +/* + * irc_cmd_recv_433: '433' command received (nickname already in use) + */ + +int +irc_cmd_recv_433 (t_irc_server *server, char *host, char *arguments) +{ + char hostname[128]; + + if (!server->is_connected) + { + if (strcmp (server->nick, server->nick1) == 0) + { + gui_printf (server->window, + _(WEECHAT_NAME + ": nickname \"%s\" is already in use, " + "trying 2nd nickname \"%s\"\n"), + server->nick, server->nick2); + free (server->nick); + server->nick = strdup (server->nick2); + } + else + { + if (strcmp (server->nick, server->nick2) == 0) + { + gui_printf (server->window, + _(WEECHAT_NAME + ": nickname \"%s\" is already in use, " + "trying 3rd nickname \"%s\"\n"), + server->nick, server->nick3); + free (server->nick); + server->nick = strdup (server->nick3); + } + else + { + gui_printf (server->window, + _(WEECHAT_NAME + ": all declared nicknames are already in use, " + "closing connection with server!\n")); + server_disconnect (server); + return 0; + } + } + + gethostname (hostname, sizeof (hostname) - 1); + hostname[sizeof (hostname) - 1] = '\0'; + if (!hostname[0]) + strcpy (hostname, _("unknown")); + server_sendf (server, + "NICK %s\r\n", + server->nick); + } + else + return irc_cmd_recv_error (server, host, arguments); + return 0; +} diff --git a/weechat/src/irc/irc-display.c b/weechat/src/irc/irc-display.c new file mode 100644 index 000000000..2f2f9931b --- /dev/null +++ b/weechat/src/irc/irc-display.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-display.c: display functions for IRC */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat.h" +#include "irc.h" +#include "../config.h" +#include "../gui/gui.h" + + +/* + * irc_display_prefix: display prefix for action or info message + * prefix must be 3 chars length + */ + +void +irc_display_prefix (t_gui_window *window, char *prefix) +{ + if (prefix[0] == prefix[2]) + { + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c", prefix[0]); + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX2, "%c", prefix[1]); + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c ", prefix[2]); + } + else + gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%s ", prefix); +} + +/* + * irc_display_nick: display nick in chat window + */ + +void +irc_display_nick (t_gui_window *window, t_irc_nick *nick, int message_type, + int display_around, int color_nick, int no_nickmode) +{ + if (display_around) + gui_printf_color_type (window, + message_type, COLOR_WIN_CHAT_DARK, "<"); + if (cfg_look_nickmode) + { + if (nick->is_op) + gui_printf_color_type (window, + message_type, + COLOR_WIN_NICK_OP, "@"); + else + { + if (nick->is_halfop) + gui_printf_color_type (window, + message_type, + COLOR_WIN_NICK_HALFOP, "%%"); + else + { + if (nick->has_voice) + gui_printf_color_type (window, + message_type, + COLOR_WIN_NICK_VOICE, "+"); + else + if (cfg_look_nickmode_empty && !no_nickmode) + gui_printf_color_type (window, + message_type, + COLOR_WIN_CHAT, " "); + } + } + } + gui_printf_color_type (window, + message_type, + (color_nick) ? + ((cfg_look_color_nicks) ? + nick->color : COLOR_WIN_CHAT) : + COLOR_WIN_CHAT, + "%s", nick->nick); + + if (display_around) + gui_printf_color_type (window, + message_type, COLOR_WIN_CHAT_DARK, "> "); +} + +/* + * irc_display_mode: display IRC message for mode change + */ + +void +irc_display_mode (t_gui_window *window, char *channel_name, char set_flag, + char *symbol, char *nick_host, char *message, char *param) +{ + irc_display_prefix (window, PREFIX_INFO); + gui_printf_color (window, COLOR_WIN_CHAT_DARK, "["); + gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%s", channel_name); + gui_printf_color (window, COLOR_WIN_CHAT, "/"); + gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%c%s", set_flag, symbol); + gui_printf_color (window, COLOR_WIN_CHAT_DARK, "] "); + gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s", nick_host); + if (param) + { + gui_printf_color (window, COLOR_WIN_CHAT, " %s ", message); + gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s\n", param); + } + else + gui_printf_color (window, COLOR_WIN_CHAT, " %s\n", message); +} diff --git a/weechat/src/irc/irc-nick.c b/weechat/src/irc/irc-nick.c new file mode 100644 index 000000000..1f9faf3b3 --- /dev/null +++ b/weechat/src/irc/irc-nick.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-nick.c: manages nick list for channels */ + + +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "../weechat.h" +#include "irc.h" + + +/* + * nick_find_color: find a color for a nick (less used will be better!) + */ + +int +nick_find_color (t_irc_channel *channel) +{ + int i, color_less_used, min_used; + int count_used[COLOR_WIN_NICK_NUMBER]; + t_irc_nick *ptr_nick; + + /* initialize array for counting usage of color */ + for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++) + count_used[i] = 0; + + /* summarize each color usage */ + for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + count_used[ptr_nick->color - COLOR_WIN_NICK_FIRST]++; + + /* look for color less used on channel */ + color_less_used = -1; + min_used = INT_MAX; + for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++) + { + if (count_used[i] < min_used) + { + color_less_used = i; + min_used = count_used[i]; + } + } + + return (color_less_used < 0) ? + COLOR_WIN_NICK_FIRST : COLOR_WIN_NICK_FIRST + color_less_used; +} + +/* + * nick_compare: compare two nicks + * return: -1 is nick1 < nick2 + * 0 if nick1 = nick2 + * +1 if nick1 > nick2 + * status sort: operator > voice > normal nick + */ + +int +nick_compare (t_irc_nick *nick1, t_irc_nick *nick2) +{ + int score1, score2, comp; + + score1 = - ( (nick1->is_op * 3) + (nick1->is_halfop * 2) + nick1->has_voice ); + score2 = - ( (nick2->is_op * 3) + (nick2->is_halfop * 2) + nick2->has_voice ); + + comp = strcasecmp(nick1->nick, nick2->nick); + if (comp > 0) + score1++; + else + if (comp < 0) + score2++; + + /* nick1 > nick2 */ + if (score1 > score2) + return 1; + /* nick1 < nick2 */ + if (score1 < score2) + return -1; + /* nick1 == nick2 */ + return 0; +} + +/* + * nick_find_pos: find position for a nick (for sorting nick list) + */ + +t_irc_nick * +nick_find_pos (t_irc_channel *channel, t_irc_nick *nick) +{ + t_irc_nick *ptr_nick; + + for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) + { + if (nick_compare (nick, ptr_nick) < 0) + return ptr_nick; + } + return NULL; +} + +/* + * nick_insert_sorted: insert nick into sorted list + */ + +void +nick_insert_sorted (t_irc_channel *channel, t_irc_nick *nick) +{ + t_irc_nick *pos_nick; + + if (channel->nicks) + { + pos_nick = nick_find_pos (channel, nick); + + if (pos_nick) + { + /* insert nick into the list (before nick found) */ + nick->prev_nick = pos_nick->prev_nick; + nick->next_nick = pos_nick; + if (pos_nick->prev_nick) + pos_nick->prev_nick->next_nick = nick; + else + channel->nicks = nick; + pos_nick->prev_nick = nick; + } + else + { + /* add nick to the end */ + nick->prev_nick = channel->last_nick; + nick->next_nick = NULL; + channel->last_nick->next_nick = nick; + channel->last_nick = nick; + } + } + else + { + nick->prev_nick = NULL; + nick->next_nick = NULL; + channel->nicks = nick; + channel->last_nick = nick; + } +} + +/* + * nick_new: allocate a new nick for a channel and add it to the nick list + */ + +t_irc_nick * +nick_new (t_irc_channel *channel, char *nick_name, + int is_op, int is_halfop, int has_voice) +{ + t_irc_nick *new_nick; + + /* nick already exists on this channel? */ + if ((new_nick = nick_search (channel, nick_name))) + { + /* update nick */ + new_nick->is_op = is_op; + new_nick->is_halfop = is_halfop; + new_nick->has_voice = has_voice; + return new_nick; + } + + /* alloc memory for new nick */ + if ((new_nick = (t_irc_nick *) malloc (sizeof (t_irc_nick))) == NULL) + { + gui_printf (channel->window, + _("%s cannot allocate new nick\n"), WEECHAT_ERROR); + return NULL; + } + + /* initialize new nick */ + new_nick->nick = strdup (nick_name); + new_nick->is_op = is_op; + new_nick->is_halfop = is_halfop; + new_nick->has_voice = has_voice; + if (strcasecmp (new_nick->nick, SERVER(channel->window)->nick) == 0) + new_nick->color = COLOR_WIN_NICK_SELF; + else + new_nick->color = nick_find_color (channel); + + nick_insert_sorted (channel, new_nick); + + /* all is ok, return address of new nick */ + return new_nick; +} + +/* + * nick_resort: resort nick in the list + */ + +void +nick_resort (t_irc_channel *channel, t_irc_nick *nick) +{ + /* temporarly remove nick from list */ + if (nick == channel->nicks) + channel->nicks = nick->next_nick; + else + nick->prev_nick->next_nick = nick->next_nick; + if (nick->next_nick) + nick->next_nick->prev_nick = nick->prev_nick; + if (nick == channel->last_nick) + channel->last_nick = nick->prev_nick; + + /* insert again nick into sorted list */ + nick_insert_sorted (channel, nick); +} + +/* + * nick_change: change nickname and move it if necessary (list is sorted) + */ + +void +nick_change (t_irc_channel *channel, t_irc_nick *nick, char *new_nick) +{ + /* change nickname */ + if (nick->nick) + free (nick->nick); + nick->nick = strdup (new_nick); + + /* insert again nick into sorted list */ + nick_resort (channel, nick); +} + +/* + * nick_free: free a nick and remove it from nicks queue + */ + +void +nick_free (t_irc_channel *channel, t_irc_nick *nick) +{ + t_irc_nick *new_nicks; + + /* remove nick from queue */ + if (channel->last_nick == nick) + channel->last_nick = nick->prev_nick; + if (nick->prev_nick) + { + (nick->prev_nick)->next_nick = nick->next_nick; + new_nicks = channel->nicks; + } + else + new_nicks = nick->next_nick; + + if (nick->next_nick) + (nick->next_nick)->prev_nick = nick->prev_nick; + + /* free data */ + if (nick->nick) + free (nick->nick); + free (nick); + channel->nicks = new_nicks; +} + +/* + * nick_free_all: free all allocated nicks for a channel + */ + +void +nick_free_all (t_irc_channel *channel) +{ + /* remove all nicks for the channel */ + while (channel->nicks) + nick_free (channel, channel->nicks); +} + +/* + * nick_search: returns pointer on a nick + */ + +t_irc_nick * +nick_search (t_irc_channel *channel, char *nickname) +{ + t_irc_nick *ptr_nick; + + for (ptr_nick = channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + if (strcasecmp (ptr_nick->nick, nickname) == 0) + return ptr_nick; + } + return NULL; +} + +/* + * nick_count: returns number of nicks (total, op, halfop, voice) on a channel + */ + +void +nick_count (t_irc_channel *channel, int *total, int *count_op, + int *count_halfop, int *count_voice, int *count_normal) +{ + t_irc_nick *ptr_nick; + + (*total) = 0; + (*count_op) = 0; + (*count_halfop) = 0; + (*count_voice) = 0; + (*count_normal) = 0; + for (ptr_nick = channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + (*total)++; + if (ptr_nick->is_op) + (*count_op)++; + else + { + if (ptr_nick->is_halfop) + (*count_halfop)++; + else + { + if (ptr_nick->has_voice) + (*count_voice)++; + else + (*count_normal)++; + } + } + } +} + +/* + * nick_get_max_length: returns longer nickname on a channel + */ + +int +nick_get_max_length (t_irc_channel *channel) +{ + int length, max_length; + t_irc_nick *ptr_nick; + + max_length = 0; + for (ptr_nick = channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + length = strlen (ptr_nick->nick); + if (length > max_length) + max_length = length; + } + return max_length; +} diff --git a/weechat/src/irc/irc-server.c b/weechat/src/irc/irc-server.c new file mode 100644 index 000000000..b8bacc303 --- /dev/null +++ b/weechat/src/irc/irc-server.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* irc-server.c: (dis)connection and communication with irc server */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include "../weechat.h" +#include "irc.h" +#include "../gui/gui.h" + + +t_irc_server *irc_servers = NULL; +t_irc_server *last_irc_server = NULL; +t_irc_server *current_irc_server = NULL; + +t_irc_message *recv_msgq, *msgq_last_msg; + +/* buffer containing beginning of message if not ending with \r\n */ +char *unterminated_message = NULL; + + +/* + * server_alloc: allocate a new server and add it to the servers queue + */ + +t_irc_server * +server_alloc () +{ + t_irc_server *new_server; + + #if DEBUG >= 1 + log_printf ("allocating new server\n"); + #endif + + /* alloc memory for new server */ + if ((new_server = (t_irc_server *) malloc (sizeof (t_irc_server))) == NULL) + { + fprintf (stderr, _("%s cannot allocate new server"), WEECHAT_ERROR); + return NULL; + } + + /* initialize new server */ + new_server->name = NULL; + new_server->address = NULL; + new_server->password = NULL; + new_server->nick1 = NULL; + new_server->nick2 = NULL; + new_server->nick3 = NULL; + new_server->username = NULL; + new_server->realname = NULL; + new_server->nick = NULL; + new_server->is_connected = 0; + new_server->sock4 = -1; + new_server->is_away = 0; + new_server->server_read = -1; + new_server->server_write = -1; + new_server->window = NULL; + new_server->channels = NULL; + new_server->last_channel = NULL; + + /* add new server to queue */ + new_server->prev_server = last_irc_server; + new_server->next_server = NULL; + if (irc_servers) + last_irc_server->next_server = new_server; + else + irc_servers = new_server; + last_irc_server = new_server; + + /* all is ok, return address of new server */ + return new_server; +} + +/* + * server_create_window: create windows for a server + */ + +void +server_create_window (t_irc_server *server) +{ + if (!SERVER(gui_windows)) + { + server->window = gui_windows; + SERVER(gui_windows) = server; + } + else + gui_window_new (server, NULL); +} + +/* + * server_free: free a server and remove it from servers queue + */ + +void +server_free (t_irc_server *server) +{ + t_irc_server *new_irc_servers; + + /* remove server from queue */ + if (server->prev_server) + { + (server->prev_server)->next_server = server->next_server; + new_irc_servers = irc_servers; + } + else + new_irc_servers = server->next_server; + + if (server->next_server) + (server->next_server)->prev_server = server->prev_server; + + /* free data */ + if (server->name) + free (server->name); + if (server->address) + free (server->address); + if (server->password) + free (server->password); + if (server->nick1) + free (server->nick1); + if (server->nick2) + free (server->nick2); + if (server->nick3) + free (server->nick3); + if (server->username) + free (server->username); + if (server->realname) + free (server->realname); + if (server->nick) + free (server->nick); + if (server->channels) + channel_free_all (server); + /* TODO: free weechat window (???) */ + /* (...) */ + free (server); + irc_servers = new_irc_servers; +} + +/* + * server_free_all: free all allocated servers + */ + +void +server_free_all () +{ + /* for each server in memory, remove it */ + while (irc_servers) + server_free (irc_servers); +} + +/* + * server_new: creates a new server, and initialize it + */ + +t_irc_server * +server_new (char *name, char *address, int port, char *password, + char *nick1, char *nick2, char *nick3, + char *username, char *realname) +{ + t_irc_server *new_server; + + if (!name || !address || (port < 0) || !nick1 || !nick2 || !nick3 + || !username || !realname) + return NULL; + + #if DEBUG >= 1 + log_printf ("creating new server (name:%s, address:%s, port:%d, pwd:%s, " + "nick1:%s, nick2:%s, nick3:%s, username:%s, realname:%s)\n", + name, address, port, password, nick1, nick2, nick3, + username, realname); + #endif + + if ((new_server = server_alloc ())) + { + new_server->name = strdup (name); + new_server->address = strdup (address); + new_server->port = port; + new_server->password = (password) ? strdup (password) : strdup (""); + new_server->nick1 = (nick1) ? strdup (nick1) : strdup ("weechat_user"); + new_server->nick2 = (nick2) ? strdup (nick2) : strdup ("weechat2"); + new_server->nick3 = (nick3) ? strdup (nick3) : strdup ("weechat3"); + new_server->username = + (username) ? strdup (username) : strdup ("weechat"); + new_server->realname = + (realname) ? strdup (realname) : strdup ("realname"); + new_server->nick = strdup (new_server->nick1); + } + else + return NULL; + return new_server; +} + +/* + * server_send: send data to irc server + */ + +int +server_send (t_irc_server * server, char *buffer, int size_buf) +{ + if (!server) + return -1; + + return send (server->sock4, buffer, size_buf, 0); +} + +/* + * server_sendf: send formatted data to irc server + */ + +int +server_sendf (t_irc_server * server, char *fmt, ...) +{ + va_list args; + static char buffer[1024]; + int size_buf; + + if (!server) + return -1; + + va_start (args, fmt); + size_buf = vsnprintf (buffer, sizeof (buffer) - 1, fmt, args); + va_end (args); + + if ((size_buf == 0) || (strcmp (buffer, "\r\n") == 0)) + return 0; + + buffer[sizeof (buffer) - 1] = '\0'; + if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1))) + size_buf = strlen (buffer); + buffer[size_buf - 2] = '\0'; + #if DEBUG >= 2 + gui_printf (server->window, "[DEBUG] Sending to server >>> %s\n", buffer); + #endif + buffer[size_buf - 2] = '\r'; + return server_send (server, buffer, size_buf); +} + +/* + * server_msgq_add_msg: add a message to received messages queue (at the end) + */ + +void +server_msgq_add_msg (t_irc_server * server, char *msg) +{ + t_irc_message *message; + + message = (t_irc_message *) malloc (sizeof (t_irc_message)); + message->server = server; + if (unterminated_message) + { + message->data = (char *) malloc (strlen (unterminated_message) + + strlen (msg) + 1); + strcpy (message->data, unterminated_message); + strcat (message->data, msg); + free (unterminated_message); + unterminated_message = NULL; + } + else + message->data = strdup (msg); + message->next_message = NULL; + + if (msgq_last_msg) + { + msgq_last_msg->next_message = message; + msgq_last_msg = message; + } + else + { + recv_msgq = message; + msgq_last_msg = message; + } +} + +/* + * server_msgq_add_buffer: explode received buffer, creating queued messages + */ + +void +server_msgq_add_buffer (t_irc_server * server, char *buffer) +{ + char *pos; + + while (buffer[0]) + { + pos = strstr (buffer, "\r\n"); + if (pos) + { + pos[0] = '\0'; + server_msgq_add_msg (server, buffer); + buffer = pos + 2; + } + else + { + pos = strchr (buffer, '\0'); + if (pos) + { + unterminated_message = + (char *) realloc (unterminated_message, + strlen (buffer) + 1); + strcpy (unterminated_message, buffer); + return; + } + gui_printf (server->window, + _("%s unable to explode received buffer\n"), + WEECHAT_ERROR); + } + } +} + +/* + * server_msgq_flush: flush message queue + */ + +void +server_msgq_flush () +{ + t_irc_message *next; + /*char **argv; + int argc;*/ + char *ptr_data, *pos, *pos2; + char *host, *command, *args; + + /* TODO: optimize this function, parse only a few messages (for low CPU time!) */ + while (recv_msgq) + { + #if DEBUG >= 2 + gui_printf (gui_current_window, "[DEBUG] %s\n", recv_msgq->data); + #endif + + ptr_data = recv_msgq->data; + + while (ptr_data[0] == ' ') + ptr_data++; + + if (ptr_data) + { + #if DEBUG >= 2 + gui_printf (NULL, "[DEBUG] data received from server: %s\n", ptr_data); + #endif + + host = NULL; + command = NULL; + args = ptr_data; + + if (ptr_data[0] == ':') + { + pos = strchr(ptr_data, ' '); + pos[0] = '\0'; + host = ptr_data+1; + pos++; + } + else + pos = ptr_data; + + if (pos != NULL) + { + while (pos[0] == ' ') + pos++; + pos2 = strchr(pos, ' '); + if (pos2 != NULL) + { + pos2[0] = '\0'; + command = strdup(pos); + pos2++; + while (pos2[0] == ' ') + pos2++; + args = (pos2[0] == ':') ? pos2+1 : pos2; + } + } + + switch (irc_recv_command (recv_msgq->server, host, command, args)) + { + case -1: + gui_printf (recv_msgq->server->window, + _("Command '%s' failed!\n"), command); + break; + case -2: + gui_printf (recv_msgq->server->window, + _("No command to execute!\n")); + break; + case -3: + gui_printf (recv_msgq->server->window, + _("Unknown command: cmd=%s, args=%s\n"), + command, args); + break; + } + } + + free (recv_msgq->data); + next = recv_msgq->next_message; + free (recv_msgq); + recv_msgq = next; + if (recv_msgq == NULL) + msgq_last_msg = NULL; + } +} + +/* + * server_recv: receive data from an irc server + */ + +void +server_recv (t_irc_server *server) +{ + static char buffer[4096 + 2]; + int num_read; + + num_read = recv (server->sock4, buffer, sizeof (buffer) - 2, 0); + if (num_read > 0) + { + buffer[num_read] = '\0'; + server_msgq_add_buffer (server, buffer); + server_msgq_flush (); + } +} + +/* + * server_connect: connect to an irc server + */ + +int +server_connect (t_irc_server *server) +{ + int set; + struct hostent *ip4_hostent; + struct sockaddr_in addr; + char *ip_address; + int error; + int server_pipe[2]; + + gui_printf (server->window, + _(WEECHAT_NAME ": connecting to %s:%d...\n"), + server->address, server->port); + log_printf ("connecting to server %s:%d...\n", + server->address, server->port); + server->is_connected = 0; + + /* create pipe */ + if (pipe (server_pipe) < 0) + { + gui_printf (server->window, + _("%s cannot create pipe\n"), WEECHAT_ERROR); + server_free (server); + return 0; + } + server->server_read = server_pipe[0]; + server->server_write = server_pipe[1]; + + /* create socket and set options */ + server->sock4 = socket (AF_INET, SOCK_STREAM, 0); + set = 1; + if (setsockopt + (server->sock4, SOL_SOCKET, SO_REUSEADDR, (char *) &set, + sizeof (set)) == -1) + gui_printf (server->window, + _("%s cannot set socket option 'SO_REUSEADDR'\n"), + WEECHAT_ERROR); + set = 1; + if (setsockopt + (server->sock4, SOL_SOCKET, SO_KEEPALIVE, (char *) &set, + sizeof (set)) == -1) + gui_printf (server->window, + _("%s cannot set socket option \"SO_KEEPALIVE\"\n"), + WEECHAT_ERROR); + + /* bind to hostname */ + ip4_hostent = gethostbyname (server->address); + if (!ip4_hostent) + { + gui_printf (server->window, + _("%s address \"%s\" not found\n"), + WEECHAT_ERROR, server->address); + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->sock4 = -1; + return 0; + } + memset (&addr, 0, sizeof (addr)); + memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length); + addr.sin_port = htons (server->port); + addr.sin_family = AF_INET; + /*error = bind(server->sock4, (struct sockaddr *)(&addr), sizeof(addr)); + if (error != 0) + { + gui_printf (server->window, + WEECHAT_ERORR "server_connect: can't bind to hostname\n"); + return 0; + } */ + ip_address = inet_ntoa (addr.sin_addr); + if (!ip_address) + { + gui_printf (server->window, + _("%s IP address not found\n"), WEECHAT_ERROR); + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->sock4 = -1; + return 0; + } + + /* connection to server */ + gui_printf (server->window, + _(WEECHAT_NAME ": server IP is: %s\n"), ip_address); + + error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr)); + if (error != 0) + { + gui_printf (server->window, + _("%s cannot connect to irc server\n"), WEECHAT_ERROR); + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->sock4 = -1; + return 0; + } + + current_irc_server = server; + return 1; +} + +/* + * server_disconnect: disconnect from an irc server + */ + +void +server_disconnect (t_irc_server *server) +{ + if (server->is_connected) + { + close (server->server_read); + close (server->server_write); + close (server->sock4); + server->is_connected = 0; + } +} + +/* + * server_disconnect_all: disconnect from all irc servers + */ + +void +server_disconnect_all () +{ + t_irc_server *ptr_server; + + for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) + server_disconnect (ptr_server); +} + +/* + * server_get_number_connected: returns number of connected server + */ + +int +server_get_number_connected () +{ + t_irc_server *ptr_server; + int number; + + number = 0; + for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) + { + if (ptr_server->is_connected) + number++; + } + return number; +} + +/* + * server_name_already_exists: return 1 if server name already exists + * otherwise return 0 + */ + +int +server_name_already_exists (char *name) +{ + t_irc_server *ptr_server; + + for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) + { + if (strcmp (ptr_server->name, name) == 0) + return 1; + } + return 0; +} diff --git a/weechat/src/irc/irc.h b/weechat/src/irc/irc.h new file mode 100644 index 000000000..f1f3698be --- /dev/null +++ b/weechat/src/irc/irc.h @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_IRC_H +#define __WEECHAT_IRC_H 1 + +#include "../gui/gui.h" + +#define PREFIX_SERVER "-@-" +#define PREFIX_INFO "-=-" +#define PREFIX_ACTION_ME "-*-" +#define PREFIX_JOIN "-->" +#define PREFIX_PART "<--" +#define PREFIX_QUIT "<--" +#define PREFIX_ERROR "=!=" + +#define CHANNEL_PREFIX "#&+!" + +/* nick types */ + +typedef struct t_irc_nick t_irc_nick; + +struct t_irc_nick +{ + char *nick; /* nickname */ + int is_op; /* operator privileges? */ + int is_halfop; /* half operaor privileges? */ + int has_voice; /* nick has voice? */ + int color; /* color for nickname */ + t_irc_nick *prev_nick; /* link to previous nick on the channel */ + t_irc_nick *next_nick; /* link to next nick on the channel */ +}; + +/* channel types */ + +typedef struct t_irc_channel t_irc_channel; + +#define CHAT_UNKNOWN -1 +#define CHAT_CHANNEL 0 +#define CHAT_PRIVATE 1 + +struct t_irc_channel +{ + int type; /* channel type */ + char *name; /* name of channel (exemple: "#abc") */ + char *topic; /* topic of channel (host for private) */ + t_irc_nick *nicks; /* nicks on the channel */ + t_irc_nick *last_nick; /* last nick on the channel */ + t_gui_window *window; /* GUI window allocated for channel */ + t_irc_channel *prev_channel; /* link to previous channel */ + t_irc_channel *next_channel; /* link to next channel */ +}; + +/* server types */ + +typedef struct t_irc_server t_irc_server; + +struct t_irc_server +{ + /* user choices */ + char *name; /* name of server (only for display) */ + char *address; /* address of server (IP or name) */ + int port; /* port for server (6667 by default) */ + char *password; /* password for server */ + char *nick1; /* first nickname for the server */ + char *nick2; /* alternate nickname */ + char *nick3; /* 2nd alternate nickname */ + char *username; /* user name */ + char *realname; /* real name */ + + /* internal vars */ + char *nick; /* current nickname */ + int is_connected; /* 1 if WeeChat is connected to server */ + int sock4; /* socket for server */ + int is_away; /* 1 is user is marker as away */ + int server_read; /* pipe for reading server data */ + int server_write; /* pipe for sending data to server */ + t_gui_window *window; /* GUI window allocated for server */ + t_irc_channel *channels; /* opened channels on server */ + t_irc_channel *last_channel; /* last opened channal on server */ + t_irc_server *prev_server; /* link to previous server */ + t_irc_server *next_server; /* link to next server */ +}; + +/* irc commands */ + +typedef struct t_irc_command t_irc_command; + +struct t_irc_command +{ + char *command_name; /* command name (internal or IRC cmd) */ + char *command_description; /* command description */ + char *arguments; /* command parameters */ + char *arguments_description; /* parameters description */ + int min_arg, max_arg; /* min & max number of parameters */ + int need_connection; /* = 1 if cmd needs server connection */ + int (*cmd_function_args)(t_irc_server *, int, char **); + /* function called when user enters cmd */ + int (*cmd_function_1arg)(t_irc_server *, char *); + /* function called when user enters cmd */ + int (*recv_function)(t_irc_server *, char *, char *); + /* function called when cmd is received */ +}; + +typedef struct t_irc_message t_irc_message; + +struct t_irc_message +{ + t_irc_server *server; /* server pointer for received msg */ + char *data; /* message content */ + t_irc_message *next_message; /* link to next message */ +}; + +extern t_irc_command irc_commands[]; +extern t_irc_server *irc_servers, *current_irc_server; +extern t_irc_message *recv_msgq, *msgq_last_msg; +extern t_irc_channel *current_channel; + +/* server functions (irc-server.c) */ + +extern t_irc_server *server_alloc (); +extern void server_create_window (t_irc_server *); +extern void server_free (t_irc_server *); +extern void server_free_all (); +extern t_irc_server *server_new (char *, char *, int, char *, char *, char *, + char *, char *, char *); +extern int server_send (t_irc_server *, char *, int); +extern int server_sendf (t_irc_server *, char *, ...); +extern void server_recv (t_irc_server *); +extern int server_connect (); +extern void server_disconnect (t_irc_server *); +extern void server_disconnect_all (); +extern int server_get_number_connected (); +extern int server_name_already_exists (char *); + +/* channel functions (irc-channel.c) */ + +extern t_irc_channel *channel_new (t_irc_server *, int, char *); +extern void channel_free (t_irc_server *, t_irc_channel *); +extern void channel_free_all (t_irc_server *); +extern t_irc_channel *channel_search (t_irc_server *, char *); +extern int string_is_channel (char *); + +/* nick functions (irc-nick.c) */ + +extern t_irc_nick *nick_new (t_irc_channel *, char *, int, int, int); +extern void nick_resort (t_irc_channel *, t_irc_nick *); +extern void nick_change (t_irc_channel *, t_irc_nick *, char *); +extern void nick_free (t_irc_channel *, t_irc_nick *); +extern void nick_free_all (t_irc_channel *); +extern t_irc_nick *nick_search (t_irc_channel *, char *); +extern void nick_count (t_irc_channel *, int *, int *, int *, int *, int *); +extern int nick_get_max_length (t_irc_channel *); + +/* IRC display (irc-diplay.c) */ + +extern void irc_display_prefix (t_gui_window *, char *); +extern void irc_display_nick (t_gui_window *, t_irc_nick *, int, int, int, int); +extern void irc_display_mode (t_gui_window *, char *, char, char *, char *, + char *, char *); + +/* IRC protocol (irc-commands.c) */ + +extern int irc_recv_command (t_irc_server *, char *, char *, char *); +extern void irc_login (t_irc_server *); +/* IRC commands issued by user */ +extern int irc_cmd_send_away (t_irc_server *, char *); +extern int irc_cmd_send_ctcp (t_irc_server *, char *); +extern int irc_cmd_send_deop (t_irc_server *, int, char **); +extern int irc_cmd_send_devoice (t_irc_server *, int, char **); +extern int irc_cmd_send_invite (t_irc_server *, char *); +extern int irc_cmd_send_join (t_irc_server *, char *); +extern int irc_cmd_send_kick (t_irc_server *, char *); +extern int irc_cmd_send_kill (t_irc_server *, char *); +extern int irc_cmd_send_list (t_irc_server *, char *); +extern int irc_cmd_send_me (t_irc_server *, char *); +extern int irc_cmd_send_mode (t_irc_server *, char *); +extern int irc_cmd_send_msg (t_irc_server *, char *); +extern int irc_cmd_send_names (t_irc_server *, char *); +extern int irc_cmd_send_nick (t_irc_server *, int, char **); +extern int irc_cmd_send_notice (t_irc_server *, char *); +extern int irc_cmd_send_op (t_irc_server *, int, char **); +extern int irc_cmd_send_oper (t_irc_server *, int, char **); +extern int irc_cmd_send_part (t_irc_server *, char *); +extern int irc_cmd_send_ping (t_irc_server *, int, char **); +extern int irc_cmd_send_pong (t_irc_server *, int, char **); +extern int irc_cmd_send_quit (t_irc_server *, char *); +extern int irc_cmd_send_quote (t_irc_server *, char *); +extern int irc_cmd_send_topic (t_irc_server *, char *); +extern int irc_cmd_send_version (t_irc_server *, char *); +extern int irc_cmd_send_voice (t_irc_server *, int, char **); +extern int irc_cmd_send_whois (t_irc_server *, char *); +/* IRC commands executed when received from server */ +extern int irc_cmd_recv_error (t_irc_server *, char *, char *); +extern int irc_cmd_recv_join (t_irc_server *, char *, char *); +extern int irc_cmd_recv_kick (t_irc_server *, char *, char *); +extern int irc_cmd_recv_mode (t_irc_server *, char *, char *); +extern int irc_cmd_recv_nick (t_irc_server *, char *, char *); +extern int irc_cmd_recv_notice (t_irc_server *, char *, char *); +extern int irc_cmd_recv_part (t_irc_server *, char *, char *); +extern int irc_cmd_recv_ping (t_irc_server *, char *, char *); +extern int irc_cmd_recv_privmsg (t_irc_server *, char *, char *); +extern int irc_cmd_recv_quit (t_irc_server *, char *, char *); +extern int irc_cmd_recv_server_msg (t_irc_server *, char *, char *); +extern int irc_cmd_recv_server_reply (t_irc_server *, char *, char *); +extern int irc_cmd_recv_topic (t_irc_server *, char *, char *); +extern int irc_cmd_recv_001 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_004 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_301 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_311 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_312 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_313 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_317 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_318 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_319 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_320 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_321 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_322 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_323 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_331 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_332 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_333 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_351 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_353 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_366 (t_irc_server *, char *, char *); +extern int irc_cmd_recv_433 (t_irc_server *, char *, char *); + +#endif /* irc.h */ diff --git a/weechat/src/plugins/README b/weechat/src/plugins/README new file mode 100644 index 000000000..978e37655 --- /dev/null +++ b/weechat/src/plugins/README @@ -0,0 +1,9 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +This is plugins directory for WeeChat. +In the future, you'll find there interfaces with many famous languages for +writing extensions to WeeChat: +- Perl interface, +- Python interface, +- Ruby interface. diff --git a/weechat/src/weechat.c b/weechat/src/weechat.c new file mode 100644 index 000000000..25f7a34d6 --- /dev/null +++ b/weechat/src/weechat.c @@ -0,0 +1,311 @@ +/* ############################################################################ + * ### ___ __ ______________ _____ ### + * ### __ | / /___________ ____/__ /_______ __ /_ ### + * ### __ | /| / /_ _ \ _ \ / __ __ \ __ `/ __/ ### + * ### __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ ### + * ### ____/|__/ \___/\___/\____/ /_/ /_/\__,_/ \__/ ### + * ### ### + * ### WeeChat - Wee Enhanced Environment for Chat ### + * ### Fast & light environment for Chat ### + * ### ### + * ### By: FlashCode <flashcode@flashtux.org> ### + * ### Bounga <bounga@altern.org> ### + * ### Xahlexx <xahlexx@tuxisland.org> ### + * ### ### + * ### http://weechat.flashtux.org ### + * ### ### + * ############################################################################ + * + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* weechat.c: core functions for WeeChat */ + + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> + +#include "weechat.h" +#include "config.h" +#include "command.h" +#include "irc/irc.h" +#include "gui/gui.h" + + +/* char *display_name; */ +int quit_weechat; /* = 1 if quit request from user... why ? :'( */ + +FILE *log_file; /* WeeChat log file (~/.weechat/weechat.log */ + + +/* + * log_printf: displays a message in WeeChat log (~/.weechat/weechat.log) + */ + +void +log_printf (char *message, ...) +{ + static char buffer[4096]; + va_list argptr; + static time_t seconds; + struct tm *date_tmp; + + if (!log_file) + return; + + va_start (argptr, message); + vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); + va_end (argptr); + + seconds = time (NULL); + date_tmp = localtime (&seconds); + fprintf (log_file, "[%04d-%02d-%02d %02d:%02d:%02d] %s", + date_tmp->tm_year + 1900, date_tmp->tm_mon + 1, date_tmp->tm_mday, + date_tmp->tm_hour, date_tmp->tm_min, date_tmp->tm_sec, + buffer); + fflush (log_file); +} + +/* + * wee_parse_args: parse command line args + */ + +void +wee_parse_args (int argc, char *argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + { + if ((strcmp (argv[i], "-h") == 0) + || (strcmp (argv[i], "--help") == 0)) + { + printf ("\n%s%s", WEE_USAGE); + exit (0); + } + else if ((strcmp (argv[i], "-l") == 0) + || (strcmp (argv[i], "--license") == 0)) + { + printf ("\n%s%s", WEE_LICENSE); + exit (0); + } + /*else if ((strcmp (argv[i], "-d") == 0) + || (strcmp (argv[i], "--display") == 0)) + { + if (i == (argc - 1)) + fprintf (stderr, + _("%s no display specified (parameter '%s'), ignored\n"), + WEECHAT_WARNING, argv[i]); + else + { + display_name = argv[i + 1]; + i++; + } + }*/ + else if ((strcmp (argv[i], "-v") == 0) + || (strcmp (argv[i], "--version") == 0)) + { + printf (WEECHAT_VERSION "\n"); + exit (0); + } + else + { + fprintf (stderr, + _("%s unknown parameter '%s', ignored\n"), + WEECHAT_WARNING, argv[i]); + } + } +} + +/* + * wee_create_home_dir: create weechat home directory (if not found) + */ + +void +wee_create_home_dir () +{ + char *weechat_home_dir; + int return_code; + + weechat_home_dir = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (weechat_home_dir, "%s/.weechat", getenv ("HOME")); + return_code = mkdir (weechat_home_dir, 0755); + if (return_code < 0) + { + if (errno != EEXIST) + { + fprintf (stderr, _("%s cannot create directory \"%s\"\n"), + WEECHAT_ERROR, weechat_home_dir); + free (weechat_home_dir); + exit (1); + } + } + free (weechat_home_dir); +} + +/* + * wee_init_vars: initialize some variables + */ + +void +wee_init_vars () +{ + /* GUI not yet initialized */ + gui_ready = 0; + + /* init received messages queue */ + recv_msgq = NULL; + msgq_last_msg = NULL; +} + +/* + * wee_init_log: initialize log file + */ + +void +wee_init_log () +{ + char *filename; + + filename = + (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char)); + sprintf (filename, "%s/.weechat/" WEECHAT_LOG_NAME, getenv ("HOME")); + if ((log_file = fopen (filename, "wt")) == NULL) + { + free (filename); + fprintf (stderr, + _("%s unable to create/append to log file (~/.weechat/" + WEECHAT_LOG_NAME), WEECHAT_ERROR); + } + free (filename); +} + +/* + * wee_shutdown: shutdown WeeChat + */ + +void +wee_shutdown () +{ + gui_end (); + server_free_all (); + if (log_file) + fclose (log_file); + exit (0); +} + +/* + * main: WeeChat startup + */ + +int +main (int argc, char *argv[]) +{ + t_irc_server *ptr_server; + + /* initialize variables */ + wee_init_vars (); + + /* parse command line args */ + wee_parse_args (argc, argv); + + /* create weechat home directory */ + wee_create_home_dir (); + + /* init log file */ + wee_init_log (); + + /* read configuration */ + switch (config_read ()) + { + case 0: /* success */ + break; + case -1: /* config file not found */ + config_create_default (); + config_read (); + break; + default: /* other error (fatal) */ + server_free_all (); + return 1; + } + + /* init gui */ + gui_init (); + + /* build commands index (sorted), for completion */ + index_command_build (); + + /* Welcome message - yeah! */ + if (cfg_look_startup_logo) + { + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1, + " ___ __ ______________ _____ \n" + " __ | / /___________ ____/__ /_______ __ /_\n" + " __ | /| / /_ _ \\ _ \\ / __ __ \\ __ `/ __/\n" + " __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ \n" + " ____/|__/ \\___/\\___/\\____/ /_/ /_/\\__,_/ \\__/ \n"); + } + if (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0]) + { + gui_printf_color (NULL, COLOR_WIN_CHAT, _("%sWelcome to "), + (cfg_look_startup_logo) ? " " : ""); + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2, WEECHAT_NAME); + gui_printf_color (NULL, COLOR_WIN_CHAT, + ", %s\n", cfg_look_weechat_slogan); + } + if (cfg_look_startup_version) + { + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2, + "%s" WEECHAT_NAME_AND_VERSION, + (cfg_look_startup_logo) ? " " : ""); + gui_printf_color (NULL, COLOR_WIN_CHAT, + ", %s %s %s\n", + _("compiled on"), __DATE__, __TIME__); + } + if (cfg_look_startup_logo || + (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0]) || + cfg_look_startup_version) + gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1, + "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + + /* connect to all servers */ + for (ptr_server = irc_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + server_create_window (ptr_server); + if (server_connect (ptr_server)) + irc_login (ptr_server); + } + gui_main_loop (); + server_disconnect_all (); + + /* program ending */ + wee_shutdown (); + + /* make gcc happy (statement never executed) */ + return 0; +} diff --git a/weechat/src/weechat.h b/weechat/src/weechat.h new file mode 100644 index 000000000..027d4e743 --- /dev/null +++ b/weechat/src/weechat.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org> + * Bounga <bounga@altern.org> + * Xahlexx <xahlexx@tuxisland.org> + * See README for License detail. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __WEECHAT_H +#define __WEECHAT_H 1 + +#include <stdio.h> +#include <libintl.h> + +#define _(string) gettext(string) +#define N_(string) (string) + +#define WEECHAT_NAME "WeeChat" +#define WEECHAT_VERSION "0.0.1" + +#define WEECHAT_NAME_AND_VERSION WEECHAT_NAME " " WEECHAT_VERSION +#define WEECHAT_COPYRIGHT WEECHAT_NAME " (c) 2003 by Wee Team" +#define WEECHAT_WEBSITE "http://weechat.flashtux.org" + +#define WEECHAT_ERROR _(WEECHAT_NAME " Error:") +#define WEECHAT_WARNING _(WEECHAT_NAME " Warning:") + +/* debug mode, 0=normal use, 1=some debug msg, 2=full debug (developers only) */ +#define DEBUG 0 + +/* log file */ + +#define WEECHAT_LOG_NAME "weechat.log" + +/* license */ + +#define WEE_LICENSE \ + WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \ + "Developed by FlashCode <flashcode@flashtux.org>\n" \ + " Bounga <bounga@altern.org>\n" \ + " Xahlexx <xahlexx@tuxisland.org>\n\n" \ + "This program is free software; you can redistribute it and/or modify\n" \ + "it under the terms of the GNU General Public License as published by\n" \ + "the Free Software Foundation; either version 2 of the License, or\n" \ + "(at your option) any later version.\n" \ + "\n", \ + \ + "This program is distributed in the hope that it will be useful,\n" \ + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \ + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \ + "GNU General Public License for more details.\n" \ + "\n" \ + "You should have received a copy of the GNU General Public License\n" \ + "along with this program; if not, write to the Free Software\n" \ + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n" + +#define WEE_USAGE \ + WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \ + "Developed by FlashCode <flashcode@flashtux.org>\n" \ + " Bounga <bounga@altern.org>\n" \ + " Xahlexx <xahlexx@tuxisland.org>\n\n" \ + " Bounga <bounga@altern.org>\n" \ + " Xahlexx <xahlexx@tuxisland.org>\n\n" \ + " -h, --help this help screen\n", \ + " -l, --license display WeeChat license\n" \ + " -v, --version display WeeChat version\n\n" + +/* " -d, --display choose X display\n" \*/ + + +/*#define DEFAULT_DISPLAY ":0" */ + + +/*extern char *display_name; */ +int quit_weechat; + +extern int quit_weechat; + +extern void log_printf (char *, ...); +extern void wee_shutdown (); + +#endif /* weechat.h */ diff --git a/weechat/weechat.1 b/weechat/weechat.1 new file mode 100644 index 000000000..4d03e5cd0 --- /dev/null +++ b/weechat/weechat.1 @@ -0,0 +1,44 @@ +.TH WEECHAT 1 "September 2003" "FlashCode" + +.SH NAME +weechat \- wee enhanced environment for chat + +.SH SYNOPSIS +.B weechat +.RI [ options ] +.br + +.SH DESCRIPTION +Fast, light and extensible IRC client for many operating systems. Everything can be +done with a keyboard. It is customizable and extensible with scripts. + +.SH OPTIONS +.TP +.B \-h, \-\-help +.br +display summary of options +.TP +.B \-l, \-\-license +.br +display program license +.TP +.B \-v, \-\-version +.br +display WeeChat version + +.SH FILES +.TP +.B $HOME/.weechat/weechat.rc +configuration file for WeeChat + +.SH AUTHOR +WeeChat is written by: +.br + - FlashCode <flashcode@flashtux.org> + - Bounga <bounga@altern.org> + - Xahlexx <xahlexx@tuxisland.org> +.br +WeeChat on the web: +.UR +http://weechat.flashtux.org +.UE diff --git a/weechat/weechat.spec b/weechat/weechat.spec new file mode 100644 index 000000000..6bf1a5f61 --- /dev/null +++ b/weechat/weechat.spec @@ -0,0 +1,41 @@ +%define name weechat +%define version 0.0.1 +%define release 1 + +Name: %{name} +Summary: portable, fast, light and extensible IRC client +Version: %{version} +Release: %{release} +Source: http://weechat.flashtux.org/download/%{name}-%{version}.tar.gz +URL: http://weechat.flashtux.org +Group: Networking/IRC +BuildRoot: %{_tmppath}/%{name}-buildroot +License: GPL + +%description +WeeChat (Wee Enhanced Environment for Chat) is a portable, fast, light and +extensible IRC client. Everything can be done with a keyboard. +It is customizable and extensible with scripts. + +%prep +rm -rf $RPM_BUILD_ROOT +%setup + +%build +make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local" + +%install +make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local" install + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,0755) +%doc AUTHORS BUGS ChangeLog COPYING FAQ INSTALL NEWS README TODO +/usr/share/man/man1/weechat.1* +/usr/local/bin/weechat + +%changelog +* Thu Sep 27 2003 FlashCode <flashcode@flashtux.org> 0.0.1-1 +- Released version 0.0.1 |