From 109101faebaa56cc93916803898608328016bf46 Mon Sep 17 00:00:00 2001 From: Sebastien Helleu Date: Sat, 27 Sep 2003 10:01:11 +0000 Subject: [PATCH] First CVS upload. --- AUTHORS | 29 + BUGS | 17 + COPYING | 340 +++ ChangeLog | 88 + FAQ | 6 + INSTALL | 10 + Makefile | 31 + NEWS | 6 + README | 50 + TODO | 130 ++ debian/changelog | 5 + debian/compat | 1 + debian/control | 14 + debian/copyright | 17 + debian/dirs | 1 + debian/docs | 9 + debian/files | 1 + debian/rules | 97 + debian/weechat.substvars | 1 + src/Makefile | 91 + src/command.c | 670 ++++++ src/command.h | 63 + src/completion.c | 199 ++ src/completion.h | 41 + src/config.c | 1021 +++++++++ src/config.h | 155 ++ src/gui/Makefile | 55 + src/gui/curses/Makefile | 38 + src/gui/curses/gui-display.c | 1730 +++++++++++++++ src/gui/curses/gui-input.c | 541 +++++ src/gui/gtk/Makefile | 37 + src/gui/gtk/gui-gtk.c | 26 + src/gui/gtk/gui-gtk.h | 26 + src/gui/gui.h | 229 ++ src/gui/qt/Makefile | 37 + src/gui/qt/gui-qt.c | 26 + src/gui/qt/gui-qt.h | 26 + src/gui/text/Makefile | 37 + src/gui/text/gui-text.c | 164 ++ src/gui/text/gui-text.h | 26 + src/history.c | 66 + src/history.h | 37 + src/irc/Makefile | 44 + src/irc/irc-channel.c | 153 ++ src/irc/irc-commands.c | 3064 ++++++++++++++++++++++++++ src/irc/irc-display.c | 127 ++ src/irc/irc-nick.c | 357 +++ src/irc/irc-server.c | 615 ++++++ src/irc/irc.h | 247 +++ src/plugins/README | 9 + src/weechat.c | 311 +++ src/weechat.h | 96 + weechat.1 | 44 + weechat.spec | 41 + weechat/AUTHORS | 29 + weechat/BUGS | 17 + weechat/COPYING | 340 +++ weechat/ChangeLog | 88 + weechat/FAQ | 6 + weechat/INSTALL | 10 + weechat/Makefile | 31 + weechat/NEWS | 6 + weechat/README | 50 + weechat/TODO | 130 ++ weechat/debian/changelog | 5 + weechat/debian/compat | 1 + weechat/debian/control | 14 + weechat/debian/copyright | 17 + weechat/debian/dirs | 1 + weechat/debian/docs | 9 + weechat/debian/files | 1 + weechat/debian/rules | 97 + weechat/debian/weechat.substvars | 1 + weechat/src/Makefile | 91 + weechat/src/command.c | 670 ++++++ weechat/src/command.h | 63 + weechat/src/completion.c | 199 ++ weechat/src/completion.h | 41 + weechat/src/config.c | 1021 +++++++++ weechat/src/config.h | 155 ++ weechat/src/gui/Makefile | 55 + weechat/src/gui/curses/Makefile | 38 + weechat/src/gui/curses/gui-display.c | 1730 +++++++++++++++ weechat/src/gui/curses/gui-input.c | 541 +++++ weechat/src/gui/gtk/Makefile | 37 + weechat/src/gui/gtk/gui-gtk.c | 26 + weechat/src/gui/gtk/gui-gtk.h | 26 + weechat/src/gui/gui.h | 229 ++ weechat/src/gui/qt/Makefile | 37 + weechat/src/gui/qt/gui-qt.c | 26 + weechat/src/gui/qt/gui-qt.h | 26 + weechat/src/gui/text/Makefile | 37 + weechat/src/gui/text/gui-text.c | 164 ++ weechat/src/gui/text/gui-text.h | 26 + weechat/src/history.c | 66 + weechat/src/history.h | 37 + weechat/src/irc/Makefile | 44 + weechat/src/irc/irc-channel.c | 153 ++ weechat/src/irc/irc-commands.c | 3064 ++++++++++++++++++++++++++ weechat/src/irc/irc-display.c | 127 ++ weechat/src/irc/irc-nick.c | 357 +++ weechat/src/irc/irc-server.c | 615 ++++++ weechat/src/irc/irc.h | 247 +++ weechat/src/plugins/README | 9 + weechat/src/weechat.c | 311 +++ weechat/src/weechat.h | 96 + weechat/weechat.1 | 44 + weechat/weechat.spec | 41 + 108 files changed, 22604 insertions(+) create mode 100644 AUTHORS create mode 100644 BUGS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 FAQ create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/files create mode 100755 debian/rules create mode 100644 debian/weechat.substvars create mode 100644 src/Makefile create mode 100644 src/command.c create mode 100644 src/command.h create mode 100644 src/completion.c create mode 100644 src/completion.h create mode 100644 src/config.c create mode 100644 src/config.h create mode 100644 src/gui/Makefile create mode 100644 src/gui/curses/Makefile create mode 100644 src/gui/curses/gui-display.c create mode 100644 src/gui/curses/gui-input.c create mode 100644 src/gui/gtk/Makefile create mode 100644 src/gui/gtk/gui-gtk.c create mode 100644 src/gui/gtk/gui-gtk.h create mode 100644 src/gui/gui.h create mode 100644 src/gui/qt/Makefile create mode 100644 src/gui/qt/gui-qt.c create mode 100644 src/gui/qt/gui-qt.h create mode 100644 src/gui/text/Makefile create mode 100644 src/gui/text/gui-text.c create mode 100644 src/gui/text/gui-text.h create mode 100644 src/history.c create mode 100644 src/history.h create mode 100644 src/irc/Makefile create mode 100644 src/irc/irc-channel.c create mode 100644 src/irc/irc-commands.c create mode 100644 src/irc/irc-display.c create mode 100644 src/irc/irc-nick.c create mode 100644 src/irc/irc-server.c create mode 100644 src/irc/irc.h create mode 100644 src/plugins/README create mode 100644 src/weechat.c create mode 100644 src/weechat.h create mode 100644 weechat.1 create mode 100644 weechat.spec create mode 100644 weechat/AUTHORS create mode 100644 weechat/BUGS create mode 100644 weechat/COPYING create mode 100644 weechat/ChangeLog create mode 100644 weechat/FAQ create mode 100644 weechat/INSTALL create mode 100644 weechat/Makefile create mode 100644 weechat/NEWS create mode 100644 weechat/README create mode 100644 weechat/TODO create mode 100644 weechat/debian/changelog create mode 100644 weechat/debian/compat create mode 100644 weechat/debian/control create mode 100644 weechat/debian/copyright create mode 100644 weechat/debian/dirs create mode 100644 weechat/debian/docs create mode 100644 weechat/debian/files create mode 100755 weechat/debian/rules create mode 100644 weechat/debian/weechat.substvars create mode 100644 weechat/src/Makefile create mode 100644 weechat/src/command.c create mode 100644 weechat/src/command.h create mode 100644 weechat/src/completion.c create mode 100644 weechat/src/completion.h create mode 100644 weechat/src/config.c create mode 100644 weechat/src/config.h create mode 100644 weechat/src/gui/Makefile create mode 100644 weechat/src/gui/curses/Makefile create mode 100644 weechat/src/gui/curses/gui-display.c create mode 100644 weechat/src/gui/curses/gui-input.c create mode 100644 weechat/src/gui/gtk/Makefile create mode 100644 weechat/src/gui/gtk/gui-gtk.c create mode 100644 weechat/src/gui/gtk/gui-gtk.h create mode 100644 weechat/src/gui/gui.h create mode 100644 weechat/src/gui/qt/Makefile create mode 100644 weechat/src/gui/qt/gui-qt.c create mode 100644 weechat/src/gui/qt/gui-qt.h create mode 100644 weechat/src/gui/text/Makefile create mode 100644 weechat/src/gui/text/gui-text.c create mode 100644 weechat/src/gui/text/gui-text.h create mode 100644 weechat/src/history.c create mode 100644 weechat/src/history.h create mode 100644 weechat/src/irc/Makefile create mode 100644 weechat/src/irc/irc-channel.c create mode 100644 weechat/src/irc/irc-commands.c create mode 100644 weechat/src/irc/irc-display.c create mode 100644 weechat/src/irc/irc-nick.c create mode 100644 weechat/src/irc/irc-server.c create mode 100644 weechat/src/irc/irc.h create mode 100644 weechat/src/plugins/README create mode 100644 weechat/src/weechat.c create mode 100644 weechat/src/weechat.h create mode 100644 weechat/weechat.1 create mode 100644 weechat/weechat.spec 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 + Web : http://www.flashtux.org + IRC : nick is "FlashCode" + Jabber: flashcode@jabber.org + ICQ : 160677660 + AIM : FlashCode AIM + Yahoo : FlashCode_Y + +Bounga + Web : http://bounga.ath.cx + IRC : nick is "Bounga" + Jabber: Bounga@jabber.org + ICQ : 178297842 + +Xahlexx + Web : http://www.tuxisland.org + IRC : nick is "xahlexx" + + +See README file for licence detail. diff --git a/BUGS b/BUGS new file mode 100644 index 000000000..0a6a5f3f3 --- /dev/null +++ b/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/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. + + + Copyright (C) + + 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. + + , 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 diff --git a/FAQ b/FAQ new file mode 100644 index 000000000..f949ac4e8 --- /dev/null +++ b/FAQ @@ -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 +# +# 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/NEWS b/NEWS new file mode 100644 index 000000000..fb7c6bbb8 --- /dev/null +++ b/NEWS @@ -0,0 +1,6 @@ +WeeChat - Wee Enhanced Environment for Chat +=========================================== + +FlashCode, 2003-09-27 + +WeeChat 0.0.1 released. diff --git a/README b/README new file mode 100644 index 000000000..bca3871dc --- /dev/null +++ b/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 + Xahlexx + Bounga +(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/TODO b/TODO new file mode 100644 index 000000000..e65f0a957 --- /dev/null +++ b/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/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 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 +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 on +Sat, 27 Sep 2003 10:00:00 +0200. + +It was downloaded from http://weechat.flashtux.org/download + +Upstream Author(s): FlashCode + +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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +# +# 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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +# +# 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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#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 +# +# 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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 ### + * ### Bounga ### + * ### Xahlexx ### + * ### ### + * ### http://weechat.flashtux.org ### + * ### ### + * ############################################################################ + * + * Copyright (c) 2003 by FlashCode + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include + +#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 \n" \ + " Bounga \n" \ + " Xahlexx \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 \n" \ + " Bounga \n" \ + " Xahlexx \n\n" \ + " Bounga \n" \ + " Xahlexx \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 + - Bounga + - Xahlexx +.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 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 + Web : http://www.flashtux.org + IRC : nick is "FlashCode" + Jabber: flashcode@jabber.org + ICQ : 160677660 + AIM : FlashCode AIM + Yahoo : FlashCode_Y + +Bounga + Web : http://bounga.ath.cx + IRC : nick is "Bounga" + Jabber: Bounga@jabber.org + ICQ : 178297842 + +Xahlexx + 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. + + + Copyright (C) + + 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. + + , 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 +# +# 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 + Xahlexx + Bounga +(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 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 +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 on +Sat, 27 Sep 2003 10:00:00 +0200. + +It was downloaded from http://weechat.flashtux.org/download + +Upstream Author(s): FlashCode + +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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +# +# 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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +# +# 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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#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 +# +# 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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 +# +# 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 + * Bounga + * Xahlexx + * 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 +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 ### + * ### Bounga ### + * ### Xahlexx ### + * ### ### + * ### http://weechat.flashtux.org ### + * ### ### + * ############################################################################ + * + * Copyright (c) 2003 by FlashCode + * Bounga + * Xahlexx + * 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 +#include +#include +#include +#include +#include +#include + +#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 + * Bounga + * Xahlexx + * 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 +#include + +#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 \n" \ + " Bounga \n" \ + " Xahlexx \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 \n" \ + " Bounga \n" \ + " Xahlexx \n\n" \ + " Bounga \n" \ + " Xahlexx \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 + - Bounga + - Xahlexx +.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 0.0.1-1 +- Released version 0.0.1