aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2003-09-27 10:01:11 +0000
committerSebastien Helleu <flashcode@flashtux.org>2003-09-27 10:01:11 +0000
commit109101faebaa56cc93916803898608328016bf46 (patch)
tree476e7ab1951995c0a980954d7a271cf272e4a835
downloadweechat-109101faebaa56cc93916803898608328016bf46.tar.xz
weechat-109101faebaa56cc93916803898608328016bf46.zip
First CVS upload.v0.0.1release-0-0-1
-rw-r--r--AUTHORS29
-rw-r--r--BUGS17
-rw-r--r--COPYING340
-rw-r--r--ChangeLog88
-rw-r--r--FAQ6
-rw-r--r--INSTALL10
-rw-r--r--Makefile31
-rw-r--r--NEWS6
-rw-r--r--README50
-rw-r--r--TODO130
-rw-r--r--debian/changelog5
-rw-r--r--debian/compat1
-rw-r--r--debian/control14
-rw-r--r--debian/copyright17
-rw-r--r--debian/dirs1
-rw-r--r--debian/docs9
-rw-r--r--debian/files1
-rwxr-xr-xdebian/rules97
-rw-r--r--debian/weechat.substvars1
-rw-r--r--src/Makefile91
-rw-r--r--src/command.c670
-rw-r--r--src/command.h63
-rw-r--r--src/completion.c199
-rw-r--r--src/completion.h41
-rw-r--r--src/config.c1021
-rw-r--r--src/config.h155
-rw-r--r--src/gui/Makefile55
-rw-r--r--src/gui/curses/Makefile38
-rw-r--r--src/gui/curses/gui-display.c1730
-rw-r--r--src/gui/curses/gui-input.c541
-rw-r--r--src/gui/gtk/Makefile37
-rw-r--r--src/gui/gtk/gui-gtk.c26
-rw-r--r--src/gui/gtk/gui-gtk.h26
-rw-r--r--src/gui/gui.h229
-rw-r--r--src/gui/qt/Makefile37
-rw-r--r--src/gui/qt/gui-qt.c26
-rw-r--r--src/gui/qt/gui-qt.h26
-rw-r--r--src/gui/text/Makefile37
-rw-r--r--src/gui/text/gui-text.c164
-rw-r--r--src/gui/text/gui-text.h26
-rw-r--r--src/history.c66
-rw-r--r--src/history.h37
-rw-r--r--src/irc/Makefile44
-rw-r--r--src/irc/irc-channel.c153
-rw-r--r--src/irc/irc-commands.c3064
-rw-r--r--src/irc/irc-display.c127
-rw-r--r--src/irc/irc-nick.c357
-rw-r--r--src/irc/irc-server.c615
-rw-r--r--src/irc/irc.h247
-rw-r--r--src/plugins/README9
-rw-r--r--src/weechat.c311
-rw-r--r--src/weechat.h96
-rw-r--r--weechat.144
-rw-r--r--weechat.spec41
-rw-r--r--weechat/AUTHORS29
-rw-r--r--weechat/BUGS17
-rw-r--r--weechat/COPYING340
-rw-r--r--weechat/ChangeLog88
-rw-r--r--weechat/FAQ6
-rw-r--r--weechat/INSTALL10
-rw-r--r--weechat/Makefile31
-rw-r--r--weechat/NEWS6
-rw-r--r--weechat/README50
-rw-r--r--weechat/TODO130
-rw-r--r--weechat/debian/changelog5
-rw-r--r--weechat/debian/compat1
-rw-r--r--weechat/debian/control14
-rw-r--r--weechat/debian/copyright17
-rw-r--r--weechat/debian/dirs1
-rw-r--r--weechat/debian/docs9
-rw-r--r--weechat/debian/files1
-rwxr-xr-xweechat/debian/rules97
-rw-r--r--weechat/debian/weechat.substvars1
-rw-r--r--weechat/src/Makefile91
-rw-r--r--weechat/src/command.c670
-rw-r--r--weechat/src/command.h63
-rw-r--r--weechat/src/completion.c199
-rw-r--r--weechat/src/completion.h41
-rw-r--r--weechat/src/config.c1021
-rw-r--r--weechat/src/config.h155
-rw-r--r--weechat/src/gui/Makefile55
-rw-r--r--weechat/src/gui/curses/Makefile38
-rw-r--r--weechat/src/gui/curses/gui-display.c1730
-rw-r--r--weechat/src/gui/curses/gui-input.c541
-rw-r--r--weechat/src/gui/gtk/Makefile37
-rw-r--r--weechat/src/gui/gtk/gui-gtk.c26
-rw-r--r--weechat/src/gui/gtk/gui-gtk.h26
-rw-r--r--weechat/src/gui/gui.h229
-rw-r--r--weechat/src/gui/qt/Makefile37
-rw-r--r--weechat/src/gui/qt/gui-qt.c26
-rw-r--r--weechat/src/gui/qt/gui-qt.h26
-rw-r--r--weechat/src/gui/text/Makefile37
-rw-r--r--weechat/src/gui/text/gui-text.c164
-rw-r--r--weechat/src/gui/text/gui-text.h26
-rw-r--r--weechat/src/history.c66
-rw-r--r--weechat/src/history.h37
-rw-r--r--weechat/src/irc/Makefile44
-rw-r--r--weechat/src/irc/irc-channel.c153
-rw-r--r--weechat/src/irc/irc-commands.c3064
-rw-r--r--weechat/src/irc/irc-display.c127
-rw-r--r--weechat/src/irc/irc-nick.c357
-rw-r--r--weechat/src/irc/irc-server.c615
-rw-r--r--weechat/src/irc/irc.h247
-rw-r--r--weechat/src/plugins/README9
-rw-r--r--weechat/src/weechat.c311
-rw-r--r--weechat/src/weechat.h96
-rw-r--r--weechat/weechat.144
-rw-r--r--weechat/weechat.spec41
108 files changed, 22604 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 000000000..dcb0ba274
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,29 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+Developers:
+----------
+
+All developers are connected to IRC:
+server: irc.freenode.net, channel: #weechat
+
+FlashCode <flashcode@flashtux.org>
+ Web : http://www.flashtux.org
+ IRC : nick is "FlashCode"
+ Jabber: flashcode@jabber.org
+ ICQ : 160677660
+ AIM : FlashCode AIM
+ Yahoo : FlashCode_Y
+
+Bounga <bounga@altern.org>
+ Web : http://bounga.ath.cx
+ IRC : nick is "Bounga"
+ Jabber: Bounga@jabber.org
+ ICQ : 178297842
+
+Xahlexx <xahlexx@tuxisland.org>
+ Web : http://www.tuxisland.org
+ IRC : nick is "xahlexx"
+
+
+See README file for licence detail.
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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 000000000..2bc1255bd
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,88 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+ChangeLog - 2003-09-27
+
+* 2003-09-27:
+ - WeeChat 0.0.1 released!
+
+* 2003-09-26:
+ - added completor prefix (in config: look_nick_completor)
+ - fixef log_printf command (bug with year & month)
+ - added "/kill" command
+ - fixed /version and /ctcp commands (missing ":" before message)
+
+* 2003-09-25:
+ - added "/kick" command
+ - added IRC errors 402 to 407
+ - added "/invite" command
+
+* 2003-09-24:
+ - "ctcp version" received is now correctly displayed
+ - "/version" command is ok
+
+* 2003-09-23:
+ - log file (~/.weechat/weechat.log)
+ - renamed config file (~/.weechat/weechatrc to ~/.weechat/weechat.rc)
+
+* 2003-09-21:
+ - "demi-highlight": 2 types of windows highlight: lightred for windows with
+ unread messages (from other users), lightmagenta for windows with other
+ unread data (join, part, quit, away, ...)
+ - "320" IRC message management
+ - "/clear" command
+
+* 2003-09-19:
+ - préparation des sources pour l'internationalisation avec gettext
+ - "301" IRC command (away message)
+ - functions renamed in rc-commands.c, irc-server.c,
+ command.c and config.c (all functions are beginning with a prefix:
+ irc_cmd_recv_xxx, irc_cmd_send_xxx, server_xxx, weechat_cmd_xxx and
+ config_xxx). Moreover, all commands (sent and received) return a value
+ (success or not)
+ - "/quote" command
+ - "/whois" command (and colored display of /whois result in server window)
+
+* 2003-09-18:
+ - use of alternate nickname (and 2nd alternate) if nick is already used
+ on server (changed/added in config file: options "nick1", "nick2", "nick3"
+ for a server, all are mandatory)
+ - "433" IRC error management (nickname already in use)
+ - "mode" command received correctly for "channel flags" and
+ op/deop/voice/devoice actions for a nick
+ - "401" IRC error management (no such nick/channel)
+ - private windows management (when received and opened, with /privmsg),
+ "/privmsg" completed consequently
+
+* 2003-09-17:
+ - nickmode display ((half)op/voice) before nicks (as option, look at config
+ options beginning with "look_nickmode")
+ - windows history is now ok (pgup/pgdn on any window type)
+ - "/me" command (and OK when received)
+ - display nicks count when joining channel or with "/names" command
+ (total, ops, halfops, voices et normaux)
+
+* 2003-09-16:
+ - added and normalized chat window colors
+ (new colors in config file)
+ - "/topic" command
+ - nicklist can be moved on top, bottom, left or right of window
+
+* 2003-09-15:
+ - auto-resize of nicklist, according to nick max length
+ - IRC multi-servers is OK
+
+* 2003-09-14:
+ - no hangup if "/part" command is executed on server window
+ - continue if no server is declared in config file
+ (empty window will be opened for executing WeeChat commands)
+ - string array for strings in config file
+ example: cfg_look_nicklist_position can take values "left", "right",
+ "top", "bottom", which are converted to int (from 0 for "left" to 3 for
+ "bottom")
+ - messages are aligned under time (server window) or under time + nick
+ (channel window)
+
+* 2003-09-13:
+ - sources exploded in many directories: ./irc, ./gui/curses, ./gui/gtk,
+ ./gui/qt and ./gui/text
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 <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+OUTPUT=weechat
+
+all:
+ cd src && make
+
+install:
+ @mkdir -v -p $(DESTDIR)/usr/$(LOCALRPM)/bin
+ @cp -v src/$(OUTPUT) $(DESTDIR)/usr/$(LOCALRPM)/bin/
+ @mkdir -v -p $(DESTDIR)/usr/share/man/man1
+ @cp -v weechat.1 $(DESTDIR)/usr/share/man/man1/
+ @echo -e "\n=== WeeChat installed!\n"
+
+clean:
+ cd src && make clean
diff --git a/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 <flashcode@flashtux.org>
+ Xahlexx <xahlex@tuxisland.org>
+ Bounga <bounga@altern.org>
+(see AUTHORS file if you want to contact authors)
+
+WeeChat is distributed under GPL licence (see COPYING file for complete license):
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+---
+(1) only curses & text interfaces are available today
+(2) plugin interfaces are not yet developed
+(3) only GNU/Linux version is available today
diff --git a/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 <flashcode@flashtux.org> Sat, 27 Jun 2003 12:00:00 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 000000000..b8626c4cf
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+4
diff --git a/debian/control b/debian/control
new file mode 100644
index 000000000..0a4844738
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,14 @@
+Source: weechat
+Section: net
+Priority: optional
+Maintainer: FlashCode <flashcode@flashtux.org>
+Build-Depends: debhelper (>> 4.0.0)
+Standards-Version: 3.5.8
+
+Package: weechat
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Fast, light and extensible IRC client
+ WeeChat (Wee Enhanced Environment for Chat) is a fast and light IRC client
+ for many operating systems. Everything can be done with a keyboard.
+ It is customizable and extensible with scripts.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 000000000..1a1dbdde6
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,17 @@
+This package was debianized by FlashCode <flashcode@flashtux.org> on
+Sat, 27 Sep 2003 10:00:00 +0200.
+
+It was downloaded from http://weechat.flashtux.org/download
+
+Upstream Author(s): FlashCode <flashcode@flashtux.org>
+
+Copyright:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+On Debian systems, the complete text of the GNU General Public
+License, Version 2 can be found in the file
+/usr/share/common-licenses/GPL
diff --git a/debian/dirs b/debian/dirs
new file mode 100644
index 000000000..e77248175
--- /dev/null
+++ b/debian/dirs
@@ -0,0 +1 @@
+usr/bin
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 000000000..a204c4610
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,9 @@
+AUTHORS
+BUGS
+ChangeLog
+COPYING
+FAQ
+INSTALL
+NEWS
+README
+TODO
diff --git a/debian/files b/debian/files
new file mode 100644
index 000000000..48f4dc400
--- /dev/null
+++ b/debian/files
@@ -0,0 +1 @@
+weechat_0.0.1-1_i386.deb net optional
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 000000000..db43ab7e6
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,97 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ # Add here commands to configure the package.
+
+ touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+ dh_testdir
+
+ # Add here commands to compile the package.
+ $(MAKE)
+ #/usr/bin/docbook-to-man debian/weechat.sgml > weechat.1
+
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+
+ # Add here commands to clean up after the build process.
+ -$(MAKE) clean
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/weechat.
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/weechat
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs
+ dh_installdocs
+ dh_installexamples
+# dh_install
+# dh_installmenu
+# dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+ dh_installman weechat.1
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+# dh_perl
+# dh_python
+# dh_makeshlibs
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/debian/weechat.substvars b/debian/weechat.substvars
new file mode 100644
index 000000000..0e328c3d3
--- /dev/null
+++ b/debian/weechat.substvars
@@ -0,0 +1 @@
+shlibs:Depends=libc6 (>= 2.3.2-1), libncurses5 (>= 5.3.20030510-1)
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 000000000..575773bb1
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,91 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=weechat
+
+OBJS=weechat.o config.o command.o completion.o history.o
+OBJS_IRC=irc/irc.a
+OBJS_GUI=gui/gui.a
+
+
+# WeeChat with Curses interface
+ifeq ($(GUI), curses)
+LIBS_CURSES=-lcurses
+DEFINES=WEE_CURSES
+
+curses: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_CURSES)
+endif
+
+# WeeChat with Gtk+ interface
+ifeq ($(GUI), gtk)
+OBJS_GTK=gui-gtk.o
+LIBS_GTK=
+DEFINES=WEE_GTK
+gtk: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_GTK)
+endif
+
+# WeeChat with Qt interface
+ifeq ($(GUI), qt)
+OBJS_QT=gui-qt.o
+LIBS_QT=
+DEFINES=WEE_QT
+qt: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_QT)
+endif
+
+# WeeChat with Text interface
+ifeq ($(GUI), text)
+OBJS_TEXT=gui-text.o
+LIBS_TEXT=
+DEFINES=WEE_TEXT
+text: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_TEXT)
+endif
+
+
+all:
+ make curses GUI=curses
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+irc/irc.a:
+ cd irc && make
+
+gui/gui.a:
+ cd gui && make $(GUI) GUI=$(GUI)
+
+clean:
+ rm -f *.o *.a *~ core $(OUTPUT)
+ cd irc && make clean
+ cd gui && make clean
+
+command.o: command.c weechat.h command.h irc/irc.h gui/gui.h completion.h \
+ history.h config.h
+completion.o: completion.c weechat.h completion.h irc/irc.h gui/gui.h \
+ history.h command.h
+config.o: config.c weechat.h config.h irc/irc.h gui/gui.h completion.h \
+ history.h
+history.o: history.c weechat.h history.h gui/gui.h completion.h
+weechat.o: weechat.c weechat.h config.h command.h irc/irc.h gui/gui.h \
+ completion.h history.h
diff --git a/src/command.c b/src/command.c
new file mode 100644
index 000000000..ddd3ce202
--- /dev/null
+++ b/src/command.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* command.c: WeeChat internal commands */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "command.h"
+#include "irc/irc.h"
+#include "config.h"
+#include "gui/gui.h"
+
+
+/* WeeChat internal commands */
+
+t_weechat_command weechat_commands[] =
+{ { "alias", N_("create an alias for a command"),
+ N_("[alias_name [command [arguments]]"),
+ N_("alias_name: name of alias\ncommand: command name (" WEECHAT_NAME
+ " or IRC command)\n" "arguments: arguments for command"),
+ 0, MAX_ARGS, weechat_cmd_alias, NULL },
+ { "clear", N_("clear window(s)"),
+ N_("[-all]"),
+ N_("-all: clear all windows"),
+ 0, 1, weechat_cmd_clear, NULL },
+ { "help", N_("display help about commands"),
+ N_("[command]"), N_("command: name of a " WEECHAT_NAME " or IRC command"),
+ 0, 1, weechat_cmd_help, NULL },
+ { "set", N_("set config parameters"),
+ N_("[option [value]]"), N_("option: name of an option\nvalue: value for option"),
+ 0, 2, weechat_cmd_set, NULL },
+ { "unalias", N_("remove an alias"),
+ N_("alias_name"), N_("alias_name: name of alias to remove"),
+ 1, 1, weechat_cmd_unalias, NULL },
+ { NULL, NULL, NULL, NULL, 0, 0, NULL, NULL }
+};
+
+t_index_command *index_commands;
+t_index_command *last_index_command;
+
+
+/*
+ * index_find_pos: find position for a command index (for sorting index)
+ */
+
+t_index_command *
+index_command_find_pos (char *command)
+{
+ t_index_command *ptr_index;
+
+ for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index)
+ {
+ if (strcasecmp (command, ptr_index->command_name) < 0)
+ return ptr_index;
+ }
+ return NULL;
+}
+
+/*
+ * index_command_insert_sorted: insert index into sorted list
+ */
+
+void
+index_command_insert_sorted (t_index_command *index)
+{
+ t_index_command *pos_index;
+
+ pos_index = index_command_find_pos (index->command_name);
+
+ if (index_commands)
+ {
+ if (pos_index)
+ {
+ /* insert index into the list (before index found) */
+ index->prev_index = pos_index->prev_index;
+ index->next_index = pos_index;
+ if (pos_index->prev_index)
+ pos_index->prev_index->next_index = index;
+ else
+ index_commands = index;
+ pos_index->prev_index = index;
+ }
+ else
+ {
+ /* add index to the end */
+ index->prev_index = last_index_command;
+ index->next_index = NULL;
+ last_index_command->next_index = index;
+ last_index_command = index;
+ }
+ }
+ else
+ {
+ index->prev_index = NULL;
+ index->next_index = NULL;
+ index_commands = index;
+ last_index_command = index;
+ }
+ return;
+}
+
+/*
+ * index_command_build: build an index of commands (internal, irc and alias)
+ * This list will be sorted, and used for completion
+ */
+
+void
+index_command_build ()
+{
+ int i;
+ t_index_command *new_index;
+
+ index_commands = NULL;
+ last_index_command = NULL;
+ i = 0;
+ while (weechat_commands[i].command_name)
+ {
+ if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command)))))
+ {
+ new_index->command_name = strdup (weechat_commands[i].command_name);
+ index_command_insert_sorted (new_index);
+ }
+ i++;
+ }
+ i = 0;
+ while (irc_commands[i].command_name)
+ {
+ if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg)
+ {
+ if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command)))))
+ {
+ new_index->command_name = strdup (irc_commands[i].command_name);
+ index_command_insert_sorted (new_index);
+ }
+ }
+ i++;
+ }
+}
+
+/*
+ * explode_string: explode a string according to separators
+ */
+
+char **
+explode_string (char *string, char *separators, int num_items_max,
+ int *num_items)
+{
+ int i, n_items;
+ char **array;
+ char *ptr, *ptr1, *ptr2;
+
+ if (num_items != NULL)
+ *num_items = 0;
+
+ n_items = num_items_max;
+
+ if (string == NULL)
+ return NULL;
+
+ if (num_items_max == 0)
+ {
+ /* calculate number of items */
+ ptr = string;
+ i = 1;
+ while ((ptr = strpbrk (ptr, separators)))
+ {
+ while (strchr (separators, ptr[0]) != NULL)
+ ptr++;
+ i++;
+ }
+ n_items = i;
+ }
+
+ array =
+ (char **) malloc ((num_items_max ? n_items : n_items + 1) *
+ sizeof (char *));
+
+ ptr1 = string;
+ ptr2 = string;
+
+ for (i = 0; i < n_items; i++)
+ {
+ while (strchr (separators, ptr1[0]) != NULL)
+ ptr1++;
+ if (i == (n_items - 1) || (ptr2 = strpbrk (ptr1, separators)) == NULL)
+ if ((ptr2 = strchr (ptr1, '\r')) == NULL)
+ if ((ptr2 = strchr (ptr1, '\n')) == NULL)
+ ptr2 = strchr (ptr1, '\0');
+
+ if ((ptr1 == NULL) || (ptr2 == NULL))
+ {
+ array[i] = NULL;
+ }
+ else
+ {
+ if (ptr2 - ptr1 > 0)
+ {
+ array[i] =
+ (char *) malloc ((ptr2 - ptr1 + 1) * sizeof (char));
+ array[i] = strncpy (array[i], ptr1, ptr2 - ptr1);
+ array[i][ptr2 - ptr1] = '\0';
+ ptr1 = ++ptr2;
+ }
+ else
+ {
+ array[i] = NULL;
+ }
+ }
+ }
+ if (num_items_max == 0)
+ {
+ array[i] = NULL;
+ if (num_items != NULL)
+ *num_items = i;
+ }
+ else
+ {
+ if (num_items != NULL)
+ *num_items = num_items_max;
+ }
+
+ return array;
+}
+
+/*
+ * exec_weechat_command: executes a command (WeeChat internal or IRC)
+ * returns: 1 if command was executed succesfully
+ * 0 if error (command not executed)
+ */
+
+int
+exec_weechat_command (t_irc_server *server, char *string)
+{
+ int i, j, argc, return_code;
+ char *pos, *ptr_args, **argv;
+
+ if ((!string[0]) || (string[0] != '/'))
+ return 0;
+
+ /* look for end of command */
+ ptr_args = NULL;
+ pos = strchr (string, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ ptr_args = pos;
+ if (!ptr_args[0])
+ ptr_args = NULL;
+ }
+
+ argv = explode_string (ptr_args, " ", 0, &argc);
+
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ if (strcasecmp (weechat_commands[i].command_name, string + 1) == 0)
+ {
+ if ((argc < weechat_commands[i].min_arg)
+ || (argc > weechat_commands[i].max_arg))
+ {
+ if (weechat_commands[i].min_arg ==
+ weechat_commands[i].max_arg)
+ gui_printf (NULL,
+ _("%s wrong argument count for "
+ WEECHAT_NAME " command '%s' "
+ "(expected: %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ weechat_commands[i].max_arg,
+ (weechat_commands[i].max_arg >
+ 1) ? "s" : "");
+ else
+ gui_printf (NULL,
+ _("%s wrong argument count for "
+ WEECHAT_NAME " command '%s' "
+ "(expected: between %d and %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ weechat_commands[i].min_arg,
+ weechat_commands[i].max_arg,
+ (weechat_commands[i].max_arg >
+ 1) ? "s" : "");
+ }
+ else
+ {
+ if (weechat_commands[i].cmd_function_args != NULL)
+ return_code = (int) (weechat_commands[i].cmd_function_args)
+ (argc, argv);
+ else
+ return_code = (int) (weechat_commands[i].cmd_function_1arg)
+ (ptr_args);
+ if (return_code < 0)
+ gui_printf (NULL,
+ _("%s " WEECHAT_NAME " command \"%s\" failed\n"),
+ WEECHAT_ERROR, string + 1);
+ }
+ if (argv)
+ {
+ for (j = 0; argv[j]; j++)
+ free (argv[j]);
+ free (argv);
+ }
+ return 1;
+ }
+ }
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if (strcasecmp (irc_commands[i].command_name, string + 1) == 0)
+ {
+ if ((argc < irc_commands[i].min_arg)
+ || (argc > irc_commands[i].max_arg))
+ {
+ if (irc_commands[i].min_arg == irc_commands[i].max_arg)
+ gui_printf
+ (NULL,
+ _("%s wrong argument count for IRC command '%s' "
+ "(expected: %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ irc_commands[i].max_arg,
+ (irc_commands[i].max_arg > 1) ? "s" : "");
+ else
+ gui_printf
+ (NULL,
+ _("%s wrong argument count for IRC command '%s' "
+ "(expected: between %d and %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ irc_commands[i].min_arg, irc_commands[i].max_arg,
+ (irc_commands[i].max_arg > 1) ? "s" : "");
+ }
+ else
+ {
+ if ((irc_commands[i].need_connection) &&
+ ((!server) || (!server->is_connected)))
+ {
+ gui_printf (NULL,
+ _("%s command '%s' needs a server connection!\n"),
+ WEECHAT_ERROR, irc_commands[i].command_name);
+ return 0;
+ }
+ if (irc_commands[i].cmd_function_args != NULL)
+ return_code = (int) (irc_commands[i].cmd_function_args)
+ (server, argc, argv);
+ else
+ return_code = (int) (irc_commands[i].cmd_function_1arg)
+ (server, ptr_args);
+ if (return_code < 0)
+ gui_printf (NULL,
+ _("%s IRC command \"%s\" failed\n"),
+ WEECHAT_ERROR, string + 1);
+ }
+ if (argv)
+ {
+ for (j = 0; argv[j]; j++)
+ free (argv[j]);
+ free (argv);
+ }
+ return 1;
+ }
+ }
+ gui_printf (server->window,
+ _("%s unknown command '%s' (type /help for help)\n"),
+ WEECHAT_ERROR,
+ string + 1);
+ if (argv)
+ {
+ for (j = 0; argv[j]; j++)
+ free (argv[j]);
+ free (argv);
+ }
+ return 0;
+}
+
+/*
+ * user_command: interprets user command (if beginning with '/')
+ * any other text is sent to the server, if connected
+ */
+
+void
+user_command (t_irc_server *server, char *command)
+{
+ t_irc_nick *ptr_nick;
+
+ if ((!command) || (command[0] == '\r') || (command[0] == '\n'))
+ return;
+ if ((command[0] == '/') && (command[1] != '/'))
+ {
+ /* WeeChat internal command (or IRC command) */
+ exec_weechat_command (server, command);
+ }
+ else
+ {
+ if ((command[0] == '/') && (command[1] == '/'))
+ command++;
+ if (!WIN_IS_SERVER(gui_current_window))
+ {
+ server_sendf (server, "PRIVMSG %s :%s\r\n",
+ CHANNEL(gui_current_window)->name,
+ command);
+
+ if (WIN_IS_PRIVATE(gui_current_window))
+ {
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "<");
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_NICK_SELF,
+ "%s", server->nick);
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "> ");
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", command);
+ }
+ else
+ {
+ ptr_nick = nick_search (CHANNEL(gui_current_window), server->nick);
+ if (ptr_nick)
+ {
+ irc_display_nick (CHANNEL(gui_current_window)->window, ptr_nick,
+ MSG_TYPE_NICK, 1, 1, 0);
+ gui_printf_color (CHANNEL(gui_current_window)->window,
+ COLOR_WIN_CHAT, "%s\n", command);
+ }
+ else
+ gui_printf (server->window,
+ _("%s cannot find nick for sending message\n"),
+ WEECHAT_ERROR);
+ }
+ }
+ else
+ gui_printf (server->window, _("This window is not a channel!\n"));
+ }
+}
+
+/*
+ * weechat_cmd_alias: display or create alias
+ */
+
+int
+weechat_cmd_alias (int argc, char **argv)
+{
+ if (argc == 0)
+ {
+ /* List all aliases */
+ }
+ argv = NULL;
+ gui_printf (NULL, _("(TODO) \"/alias\" command not developed!\n"));
+ return 0;
+}
+
+/*
+ * weechat_cmd_clear: display or create alias
+ */
+
+int
+weechat_cmd_clear (int argc, char **argv)
+{
+ if (argc == 1)
+ {
+ if (strcmp (argv[0], "-all") == 0)
+ gui_window_clear_all ();
+ else
+ {
+ gui_printf (NULL,
+ _("unknown parameter \"%s\" for /clear command\n"),
+ argv[0]);
+ return -1;
+ }
+ }
+ else
+ gui_window_clear (gui_current_window);
+ return 0;
+}
+
+/*
+ * weechat_cmd_help: display help
+ */
+
+int
+weechat_cmd_help (int argc, char **argv)
+{
+ int i;
+
+ if (argc == 0)
+ {
+ gui_printf (NULL,
+ _("> List of " WEECHAT_NAME " internal commands:\n"));
+ for (i = 0; weechat_commands[i].command_name; i++)
+ gui_printf (NULL, " %s - %s\n",
+ weechat_commands[i].command_name,
+ weechat_commands[i].command_description);
+ gui_printf (NULL, _("> List of IRC commands:\n"));
+ for (i = 0; irc_commands[i].command_name; i++)
+ if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg)
+ gui_printf (NULL, " %s - %s\n",
+ irc_commands[i].command_name,
+ irc_commands[i].command_description);
+ }
+ if (argc == 1)
+ {
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ if (strcasecmp (weechat_commands[i].command_name, argv[0]) == 0)
+ {
+ gui_printf
+ (NULL,
+ _("> Help on " WEECHAT_NAME " internal command '%s':\n"),
+ weechat_commands[i].command_name);
+ gui_printf (NULL,
+ _("Syntax: /%s %s\n"),
+ weechat_commands[i].command_name,
+ (weechat_commands[i].
+ arguments) ? weechat_commands[i].
+ arguments : "");
+ if (weechat_commands[i].arguments_description)
+ {
+ gui_printf (NULL, "%s\n",
+ weechat_commands[i].
+ arguments_description);
+ }
+ return 0;
+ }
+ }
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if (strcasecmp (irc_commands[i].command_name, argv[0]) == 0)
+ {
+ gui_printf (NULL,
+ _("> Help on IRC command '%s':\n"),
+ irc_commands[i].command_name);
+ gui_printf (NULL, _("Syntax: /%s %s\n"),
+ irc_commands[i].command_name,
+ (irc_commands[i].arguments) ?
+ irc_commands[i].arguments : "");
+ if (irc_commands[i].arguments_description)
+ {
+ gui_printf (NULL, "%s\n",
+ irc_commands[i].
+ arguments_description);
+ }
+ return 0;
+ }
+ }
+ gui_printf (NULL,
+ _("No help available, \"%s\" is an unknown command\n"),
+ argv[0]);
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_set: set options
+ */
+
+int
+weechat_cmd_set (int argc, char **argv)
+{
+ int i, j, section_displayed;
+ char *color_name;
+
+ /* TODO: complete /set command */
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ section_displayed = 0;
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ if ((argc == 0) ||
+ ((argc > 0)
+ && (strstr (weechat_options[i][j].option_name, argv[0])
+ != NULL)))
+ {
+ if (!section_displayed)
+ {
+ gui_printf (NULL, "[%s]\n",
+ config_sections[i].section_name);
+ section_displayed = 1;
+ }
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ gui_printf (NULL, " %s = %s\n",
+ weechat_options[i][j].option_name,
+ (*weechat_options[i][j].ptr_int) ?
+ "ON" : "OFF");
+ break;
+ case OPTION_TYPE_INT:
+ gui_printf (NULL,
+ " %s = %d\n",
+ weechat_options[i][j].option_name,
+ *weechat_options[i][j].ptr_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ gui_printf (NULL,
+ " %s = %s\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].array_values[*weechat_options[i][j].ptr_int]);
+ break;
+ case OPTION_TYPE_COLOR:
+ color_name = gui_get_color_by_value (*weechat_options[i][j].ptr_int);
+ gui_printf (NULL,
+ " %s = %s\n",
+ weechat_options[i][j].option_name,
+ (color_name) ? color_name : _("(unknown)"));
+ break;
+ case OPTION_TYPE_STRING:
+ gui_printf (NULL, " %s = %s\n",
+ weechat_options[i][j].
+ option_name,
+ (*weechat_options[i][j].
+ ptr_string) ?
+ *weechat_options[i][j].
+ ptr_string : "");
+ break;
+ }
+ }
+ }
+ }
+ }
+ gui_printf (NULL, _("(TODO) \"/set\" command not developed!\n"));
+ return 0;
+}
+
+/*
+ * cmd_unalias: remove an alias
+ */
+
+int
+weechat_cmd_unalias (int argc, char **argv)
+{
+ if (argc != 1)
+ {
+ gui_printf
+ (NULL,
+ _("Wrong argument count for unalias function (expexted: 1 arg)\n"));
+ return -1;
+ }
+ argv = NULL;
+ gui_printf (NULL, _("(TODO) \"/unalias\" not developed!\n"));
+ return 0;
+}
diff --git a/src/command.h b/src/command.h
new file mode 100644
index 000000000..5bec6c92e
--- /dev/null
+++ b/src/command.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_COMMAND_H
+#define __WEECHAT_COMMAND_H 1
+
+#include "irc/irc.h"
+
+#define MAX_ARGS 8192
+
+typedef struct t_weechat_command t_weechat_command;
+
+struct t_weechat_command
+{
+ char *command_name;
+ char *command_description;
+ char *arguments;
+ char *arguments_description;
+ int min_arg, max_arg;
+ int (*cmd_function_args)(int, char **);
+ int (*cmd_function_1arg)(char *);
+};
+
+typedef struct t_index_command t_index_command;
+
+struct t_index_command
+{
+ char *command_name;
+ t_index_command *prev_index;
+ t_index_command *next_index;
+};
+
+extern t_index_command *index_commands;
+
+extern void index_command_build ();
+extern int exec_weechat_command (t_irc_server *, char *);
+extern void user_command (t_irc_server *, char *);
+extern int weechat_cmd_alias(int, char **);
+extern int weechat_cmd_clear(int, char **);
+extern int weechat_cmd_help (int, char **);
+extern int weechat_cmd_set (int, char **);
+extern int weechat_cmd_unalias (int, char **);
+
+#endif /* command.h */
diff --git a/src/completion.c b/src/completion.c
new file mode 100644
index 000000000..6809d8100
--- /dev/null
+++ b/src/completion.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* completion.c: completes words according to context (cmd/nick) */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "completion.h"
+#include "irc/irc.h"
+#include "command.h"
+
+
+/*
+ * completion_init: init completion
+ */
+
+void
+completion_init (t_completion *completion)
+{
+ completion->position = -1;
+ completion->base_word = NULL;
+}
+
+/*
+ * completion_command: complete a command
+ */
+
+void
+completion_command (t_completion *completion)
+{
+ int length, word_found_seen;
+ t_index_command *ptr_index;
+
+ length = strlen (completion->base_word) - 1;
+ word_found_seen = 0;
+ for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index)
+ {
+ if (strncasecmp (ptr_index->command_name, completion->base_word + 1, length) == 0)
+ {
+ if ((!completion->word_found) || word_found_seen)
+ {
+ completion->word_found = ptr_index->command_name;
+ return;
+ }
+ }
+ if (completion->word_found &&
+ (strcasecmp (ptr_index->command_name, completion->word_found) == 0))
+ word_found_seen = 1;
+ }
+ if (completion->word_found)
+ {
+ completion->word_found = NULL;
+ completion_command (completion);
+ }
+}
+
+/*
+ * completion_nick: complete a nick
+ */
+
+void
+completion_nick (t_completion *completion, t_irc_channel *channel)
+{
+ int length, word_found_seen;
+ t_irc_nick *ptr_nick;
+
+ length = strlen (completion->base_word);
+ word_found_seen = 0;
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ if (strncasecmp (ptr_nick->nick, completion->base_word, length) == 0)
+ {
+ if ((!completion->word_found) || word_found_seen)
+ {
+ completion->word_found = ptr_nick->nick;
+ return;
+ }
+ }
+ if (completion->word_found &&
+ (strcasecmp (ptr_nick->nick, completion->word_found) == 0))
+ word_found_seen = 1;
+ }
+ if (completion->word_found)
+ {
+ completion->word_found = NULL;
+ completion_nick (completion, channel);
+ }
+}
+
+/*
+ * completion_search: complete word according to context
+ */
+
+void
+completion_search (t_completion *completion, void *channel,
+ char *buffer, int size, int pos)
+{
+ int i, pos_start, pos_end;
+ char *old_word_found;
+
+ /* TODO: complete when no word is there with command according to context */
+ if (size == 0)
+ {
+ completion->word_found = NULL;
+ return;
+ }
+
+ /* if new complation => look for base word */
+ if (pos != completion->position)
+ {
+ completion->word_found = NULL;
+
+ if ((pos == size) || (buffer[pos-1] != ' '))
+ pos--;
+ if ((pos > 0) && (buffer[pos] == ' '))
+ return;
+
+ i = pos;
+ while ((i >= 0) && (buffer[i] != ' '))
+ i--;
+ pos_start = i + 1;
+ i = pos;
+ while ((i < size) && (buffer[i] != ' '))
+ i++;
+ pos_end = i - 1;
+
+ if (pos_start > pos_end)
+ return;
+
+ completion->base_word_pos = pos_start;
+
+ if (completion->base_word)
+ free (completion->base_word);
+ completion->base_word = (char *) malloc (pos_end - pos_start + 2);
+
+ for (i = pos_start; i <= pos_end; i++)
+ completion->base_word[i - pos_start] = buffer[i];
+ completion->base_word[pos_end - pos_start + 1] = '\0';
+
+ if (completion->base_word[0] == '/')
+ completion->position_replace = pos_start + 1;
+ else
+ completion->position_replace = pos_start;
+ }
+
+ /* completion */
+ old_word_found = completion->word_found;
+ if (completion->base_word[0] == '/')
+ {
+ completion_command (completion);
+ if (completion->word_found)
+ {
+ if (old_word_found)
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (old_word_found);
+ else
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (completion->base_word) + 1;
+ }
+ }
+ else
+ {
+ if (channel)
+ {
+ completion_nick (completion, (t_irc_channel *)channel);
+ if (completion->word_found)
+ {
+ if (old_word_found)
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (old_word_found);
+ else
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (completion->base_word);
+ }
+ }
+ }
+}
diff --git a/src/completion.h b/src/completion.h
new file mode 100644
index 000000000..f07d4a1f7
--- /dev/null
+++ b/src/completion.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_COMPLETION_H
+#define __WEECHAT_COMPLETION_H 1
+
+typedef struct t_completion t_completion;
+
+struct t_completion
+{
+ char *base_word; /* word to complete (when Tab was pressed) */
+ int base_word_pos; /* beggining of base word */
+ int position; /* position where we shoud complete */
+ char *word_found; /* word found (to replace base word) */
+ int position_replace; /* position where word should be replaced */
+ int diff_size; /* size difference (< 0 = char(s) deleted) */
+};
+
+extern void completion_init (t_completion *);
+extern void completion_search (t_completion *, void *, char *, int, int);
+
+#endif /* completion.h */
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 000000000..ad93695b9
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* config.c: WeeChat configuration */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#include "weechat.h"
+#include "config.h"
+#include "irc/irc.h"
+#include "gui/gui.h"
+
+
+/* config sections */
+
+t_config_section config_sections[CONFIG_NUMBER_SECTIONS] =
+{ { CONFIG_SECTION_LOOK, "look" },
+ { CONFIG_SECTION_COLORS, "colors" },
+ { CONFIG_SECTION_HISTORY, "history" },
+ { CONFIG_SECTION_LOG, "log" },
+ { CONFIG_SECTION_DCC, "dcc" },
+ { CONFIG_SECTION_PROXY, "proxy" },
+ { CONFIG_SECTION_SERVER, "server" }
+};
+
+/* config, look & feel section */
+
+int cfg_look_startup_logo;
+int cfg_look_startup_version;
+char *cfg_look_weechat_slogan;
+int cfg_look_color_nicks;
+int cfg_look_color_actions;
+int cfg_look_remove_colors_from_msgs;
+int cfg_look_nicklist;
+int cfg_look_nicklist_position;
+char *cfg_look_nicklist_position_values[] =
+{ "left", "right", "top", "bottom", NULL };
+int cfg_look_nicklist_min_size;
+int cfg_look_nicklist_max_size;
+int cfg_look_nickmode;
+int cfg_look_nickmode_empty;
+char *cfg_look_no_nickname;
+char *cfg_look_completor;
+
+t_config_option weechat_options_look[] =
+{ { "look_startup_logo", N_("display " WEECHAT_NAME " logo at startup"),
+ N_("display " WEECHAT_NAME " logo at startup"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_startup_logo, NULL, NULL },
+ { "look_startup_version", N_("display " WEECHAT_NAME " version at startup"),
+ N_("display " WEECHAT_NAME " version at startup"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_startup_version, NULL, NULL },
+ { "look_weechat_slogan", N_(WEECHAT_NAME "slogan"),
+ N_(WEECHAT_NAME "slogan (if empty, slogan is not used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "the geekest IRC client!", NULL, NULL, &cfg_look_weechat_slogan, NULL },
+ { "look_color_nicks", N_("display nick names with different colors"),
+ N_("display nick names with different colors"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_color_nicks, NULL, NULL },
+ { "look_color_actions", N_("display actions with different colors"),
+ N_("display actions with different colors"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_color_actions, NULL, NULL },
+ { "look_remove_colors_from_msgs", N_("remove colors from incoming messages"),
+ N_("remove colors from incoming messages"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_remove_colors_from_msgs, NULL, NULL },
+ { "look_nicklist", N_("display nicklist window"),
+ N_("display nicklist window (for channel windows)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nicklist, NULL, NULL },
+ { "look_nicklist_position", N_("nicklist position"),
+ N_("nicklist position (top, left, right (default), bottom)"),
+ OPTION_TYPE_INT_WITH_STRING, 0, 0, 0,
+ "right", cfg_look_nicklist_position_values, &cfg_look_nicklist_position, NULL, NULL },
+ { "look_nicklist_min_size", N_("min size for nicklist"),
+ N_("min size for nicklist (width or height, depending on look_nicklist_position "
+ "(0 = no min size))"),
+ OPTION_TYPE_INT, 0, 100, 0,
+ NULL, NULL, &cfg_look_nicklist_min_size, NULL, NULL },
+ { "look_nicklist_max_size", N_("max size for nicklist"),
+ N_("max size for nicklist (width or height, depending on look_nicklist_position "
+ "(0 = no max size; if min == max and > 0, then size is fixed))"),
+ OPTION_TYPE_INT, 0, 100, 0,
+ NULL, NULL, &cfg_look_nicklist_max_size, NULL, NULL },
+ { "look_no_nickname", N_("text to display instead of nick when not connected"),
+ N_("text to display instead of nick when not connected"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "-cmd-", NULL, NULL, &cfg_look_no_nickname, NULL },
+ { "look_nickmode", N_("display nick mode ((half)op/voice) before each nick"),
+ N_("display nick mode ((half)op/voice) before each nick"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nickmode, NULL, NULL },
+ { "look_nickmode_empty", N_("display space if nick mode is not (half)op/voice"),
+ N_("display space if nick mode is not (half)op/voice"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_look_nickmode_empty, NULL, NULL },
+ { "look_nick_completor", N_("the string inserted after nick completion"),
+ N_("the string inserted after nick completion"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ ":", NULL, NULL, &cfg_look_completor, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, colors section */
+
+int cfg_col_title;
+int cfg_col_title_bg;
+int cfg_col_chat;
+int cfg_col_chat_time;
+int cfg_col_chat_time_sep;
+int cfg_col_chat_prefix1;
+int cfg_col_chat_prefix2;
+int cfg_col_chat_nick;
+int cfg_col_chat_host;
+int cfg_col_chat_channel;
+int cfg_col_chat_dark;
+int cfg_col_chat_bg;
+int cfg_col_status;
+int cfg_col_status_active;
+int cfg_col_status_data_msg;
+int cfg_col_status_data_other;
+int cfg_col_status_more;
+int cfg_col_status_bg;
+int cfg_col_input;
+int cfg_col_input_channel;
+int cfg_col_input_nick;
+int cfg_col_input_bg;
+int cfg_col_nick;
+int cfg_col_nick_op;
+int cfg_col_nick_halfop;
+int cfg_col_nick_voice;
+int cfg_col_nick_sep;
+int cfg_col_nick_self;
+int cfg_col_nick_private;
+int cfg_col_nick_bg;
+
+t_config_option weechat_options_colors[] =
+{ /* title window */
+ { "col_title", N_("color for title bar"),
+ N_("color for title bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_title, NULL, NULL },
+ { "col_title_bg", N_("background for title bar"),
+ N_("background for title bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_title_bg, NULL, NULL },
+
+ /* chat window */
+ { "col_chat", N_("color for chat text"),
+ N_("color for chat text"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_chat, NULL, NULL },
+ { "col_chat_time", N_("color for time"),
+ N_("color for time in chat window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_chat_time, NULL, NULL },
+ { "col_chat_time_sep", N_("color for time separator"),
+ N_("color for time separator (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_chat_time_sep, NULL, NULL },
+ { "col_chat_prefix1", N_("color for 1st and 3rd char of prefix"),
+ N_("color for 1st and 3rd char of prefix"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_chat_prefix1, NULL, NULL },
+ { "col_chat_prefix2", N_("color for middle char of prefix"),
+ N_("color for middle char of prefix"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_chat_prefix2, NULL, NULL },
+ { "col_chat_nick", N_("color for nicks in actions"),
+ N_("color for nicks in actions (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_chat_nick, NULL, NULL },
+ { "col_chat_host", N_("color for hostnames"),
+ N_("color for hostnames (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_chat_host, NULL, NULL },
+ { "col_chat_channel", N_("color for channel names in actions"),
+ N_("color for channel names in actions (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_chat_channel, NULL, NULL },
+ { "col_chat_dark", N_("color for dark separators"),
+ N_("color for dark separators (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "green", NULL, &cfg_col_chat_dark, NULL, NULL },
+ { "col_chat_bg", N_("background for chat"),
+ N_("background for chat window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_chat_bg, NULL, NULL },
+
+ /* status window */
+ { "col_status", N_("color for status bar"),
+ N_("color for status bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_status, NULL, NULL },
+ { "col_status_active", N_("color for active window"),
+ N_("color for active window (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_status_active, NULL, NULL },
+ { "col_status_data_msg", N_("color for window with new messages"),
+ N_("color for window with new messages (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightred", NULL, &cfg_col_status_data_msg, NULL, NULL },
+ { "col_status_data_other", N_("color for window with new data (not messages)"),
+ N_("color for window with new data (not messages) (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_status_data_other, NULL, NULL },
+ { "col_status_more", N_("color for \"*MORE*\" text"),
+ N_("color for window with new data (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_status_more, NULL, NULL },
+ { "col_status_bg", N_("background for status window"),
+ N_("background for status window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_status_bg, NULL, NULL },
+
+ /* input window */
+ { "col_input", N_("color for input text"),
+ N_("color for input text"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_input, NULL, NULL },
+ { "col_input_channel", N_("color for input text (channel name)"),
+ N_("color for input text (channel name)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_input_channel, NULL, NULL },
+ { "col_input_nick", N_("color for input text (nick name)"),
+ N_("color for input text (nick name)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_input_nick, NULL, NULL },
+ { "col_input_bg", N_("background for input window"),
+ N_("background for input window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_input_bg, NULL, NULL },
+
+ /* nick window */
+ { "col_nick", N_("color for nicknames"),
+ N_("color for nicknames"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_nick, NULL, NULL },
+ { "col_nick_op", N_("color for operator symbol"),
+ N_("color for operator symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_nick_op, NULL, NULL },
+ { "col_nick_halfop", N_("color for half-operator symbol"),
+ N_("color for half-operator symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_nick_halfop, NULL, NULL },
+ { "col_nick_voice", N_("color for voice symbol"),
+ N_("color for voice symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_nick_voice, NULL, NULL },
+ { "col_nick_sep", N_("color for nick separator"),
+ N_("color for nick separator"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_nick_sep, NULL, NULL },
+ { "col_nick_self", N_("color for local nick"),
+ N_("color for local nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_nick_self, NULL, NULL },
+ { "col_nick_private", N_("color for other nick in private window"),
+ N_("color for other nick in private window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_nick_private, NULL, NULL },
+ { "col_nick_bg", N_("background for nicknames"),
+ N_("background for nicknames"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_nick_bg, NULL, NULL },
+
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, history section */
+
+int cfg_history_max_lines;
+int cfg_history_max_commands;
+
+t_config_option weechat_options_history[] =
+{ { "history_max_lines", N_("max lines in history (per window)"),
+ N_("maximum number of lines in history "
+ "for one server/channel/private window (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 4096,
+ NULL, NULL, &cfg_history_max_lines, NULL, NULL },
+ { "history_max_commands", N_("max user commands in history"),
+ N_("maximum number of user commands in history (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 100,
+ NULL, NULL, &cfg_history_max_commands, NULL, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, log section */
+
+int cfg_log_auto_channels;
+int cfg_log_auto_private;
+char *cfg_log_path;
+char *cfg_log_name;
+char *cfg_log_timestamp;
+char *cfg_log_start_string;
+char *cfg_log_end_string;
+
+t_config_option weechat_options_log[] =
+{ { "log_auto_channels", N_("automatically log channel chats"),
+ N_("automatically log channel chats"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_log_auto_channels, NULL, NULL },
+ { "log_auto_private", N_("automatically log private chats"),
+ N_("automatically log private chats"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_log_auto_private, NULL, NULL },
+ { "log_path", N_("path for log files"),
+ N_("path for " WEECHAT_NAME " log files"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "~/.weechat/logs/", NULL, NULL, &cfg_log_path, NULL },
+ { "log_name", N_("name for log files"),
+ N_("name for log files (%S == irc server name, "
+ "%N == channel name (or nickname if private chat)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%S,%N.weechatlog", NULL, NULL, &cfg_log_name, NULL },
+ { "log_timestamp", N_("timestamp for log"),
+ N_("timestamp for log (see man strftime for date/time specifiers)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "~", NULL, NULL, &cfg_log_timestamp, NULL },
+ { "log_start_string", N_("start string for log files"),
+ N_("text writed when starting new log file "
+ "(see man strftime for date/time specifiers)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "--- Log started %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_start_string, NULL },
+ { "log_end_string", N_("end string for log files"),
+ N_("text writed when ending log file "
+ "(see man strftime for date/time specifiers)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "--- Log ended %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_end_string, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, dcc section */
+
+int cfg_dcc_auto_accept_files;
+int cfg_dcc_auto_accept_max_size;
+int cfg_dcc_auto_accept_chats;
+int cfg_dcc_timeout;
+char *cfg_dcc_download_path;
+char *cfg_dcc_upload_path;
+int cfg_dcc_auto_rename;
+int cfg_dcc_auto_resume;
+
+t_config_option weechat_options_dcc[] =
+{ { "dcc_auto_accept_files", N_("automatically accept dcc files"),
+ N_("automatically accept incoming dcc files"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_accept_files, NULL, NULL },
+ { "dcc_auto_accept_max_size", N_("max size when auto accepting file"),
+ N_("maximum size for incoming file when automatically accepted"),
+ OPTION_TYPE_INT, 0, INT_MAX, 0,
+ NULL, NULL, &cfg_dcc_auto_accept_max_size, NULL, NULL },
+ { "dcc_auto_accept_chats", N_("automatically accept dcc chats"),
+ N_("automatically accept dcc chats (use carefully!)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_accept_chats, NULL, NULL },
+ { "dcc_timeout", N_("timeout for dcc request"),
+ N_("timeout for dcc request (in seconds)"),
+ OPTION_TYPE_INT, 1, INT_MAX, 300,
+ NULL, NULL, &cfg_dcc_timeout, NULL, NULL },
+ { "dcc_download_path", N_("path for incoming files with dcc"),
+ N_("path for writing incoming files with dcc (default: user home)"),
+ OPTION_TYPE_STRING, 0, 0, 0, "~",
+ NULL, NULL, &cfg_dcc_download_path, NULL },
+ { "dcc_upload_path", N_("default path for sending files with dcc"),
+ N_("path for reading files when sending thru dcc (when no path is specified)"),
+ OPTION_TYPE_STRING, 0, 0, 0, "~",
+ NULL, NULL, &cfg_dcc_upload_path, NULL },
+ { "dcc_auto_rename", N_("automatically rename dcc files if already exists"),
+ N_("rename incoming files if already exists (add '.1', '.2', ...)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_rename, NULL, NULL },
+ { "dcc_auto_resume", N_("automatically resume aborted transfers"),
+ N_("automatically resume dcc trsnafer if connection with remote host is loosed"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_resume, NULL, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, proxy section */
+
+int cfg_proxy_use;
+char *cfg_proxy_address;
+int cfg_proxy_port;
+char *cfg_proxy_password;
+
+t_config_option weechat_options_proxy[] =
+{ { "proxy_use", N_("use proxy"),
+ N_("use a proxy server to connect to irc server"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_proxy_use, NULL, NULL },
+ { "proxy_address", N_("proxy address"),
+ N_("proxy server address (IP or hostname)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_proxy_address, NULL },
+ { "proxy_port", N_("port for proxy"),
+ N_("port for connecting to proxy server"),
+ OPTION_TYPE_INT, 0, 65535, 1080,
+ NULL, NULL, &cfg_proxy_port, NULL, NULL },
+ { "proxy_password", N_("proxy password"),
+ N_("password for proxy server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_proxy_password, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, server section */
+
+static t_irc_server cfg_server;
+
+t_config_option weechat_options_server[] =
+{ { "server_name", N_("server name"),
+ N_("name associated to IRC server (for display only)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.name), NULL },
+ { "server_address", N_("server address or hostname"),
+ N_("IP address or hostname of IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.address), NULL },
+ { "server_port", N_("port for IRC server"),
+ N_("port for connecting to server"),
+ OPTION_TYPE_INT, 0, 65535, 6667,
+ NULL, NULL, &(cfg_server.port), NULL, NULL },
+ { "server_password", N_("server password"),
+ N_("password for IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.password), NULL },
+ { "server_nick1", N_("nickname for server"),
+ N_("nickname to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick1), NULL },
+ { "server_nick2", N_("alternate nickname for server"),
+ N_("alternate nickname to use on IRC server (if nickname is already used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick2), NULL },
+ { "server_nick3", N_("2nd alternate nickname for server"),
+ N_("2nd alternate nickname to use on IRC server (if alternate nickname is already used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick3), NULL },
+ { "server_username", N_("user name for server"),
+ N_("user name to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.username), NULL },
+ { "server_realname", N_("real name for server"),
+ N_("real name to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.realname), NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* all weechat options */
+
+t_config_option *weechat_options[CONFIG_NUMBER_SECTIONS] =
+{ weechat_options_look, weechat_options_colors, weechat_options_history,
+ weechat_options_log, weechat_options_dcc, weechat_options_proxy,
+ weechat_options_server
+};
+
+
+/*
+ * get_pos_array_values: returns position of a string in an array of values
+ * returns -1 if not found, otherwise position
+ */
+
+int
+get_pos_array_values (char **array, char *string)
+{
+ int i;
+
+ i = 0;
+ while (array[i])
+ {
+ if (strcasecmp (array[i], string) == 0)
+ return i;
+ i++;
+ }
+ /* string not found in array */
+ return -1;
+}
+
+/*
+ * config_init_server: init server struct
+ */
+
+void
+config_init_server ()
+{
+ cfg_server.name = NULL;
+ cfg_server.address = NULL;
+ cfg_server.port = -1;
+ cfg_server.password = NULL;
+ cfg_server.nick1 = NULL;
+ cfg_server.nick2 = NULL;
+ cfg_server.nick3 = NULL;
+ cfg_server.username = NULL;
+ cfg_server.realname = NULL;
+}
+
+/*
+ * config_allocate_server: allocate a new server
+ */
+
+int
+config_allocate_server (char *filename, int line_number)
+{
+ if (!cfg_server.name
+ || !cfg_server.address
+ || cfg_server.port < 0
+ || !cfg_server.nick1
+ || !cfg_server.nick2
+ || !cfg_server.nick3
+ || !cfg_server.username
+ || !cfg_server.realname)
+ {
+ server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: new server, but previous was incomplete\n"),
+ WEECHAT_WARNING, filename, line_number);
+ return 0;
+
+ }
+ if (server_name_already_exists (cfg_server.name))
+ {
+ server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: server '%s' already exists\n"),
+ WEECHAT_WARNING, filename, line_number, cfg_server.name);
+ return 0;
+ }
+ if (!server_new (cfg_server.name,
+ cfg_server.address, cfg_server.port, cfg_server.password,
+ cfg_server.nick1, cfg_server.nick2, cfg_server.nick3,
+ cfg_server.username, cfg_server.realname))
+ {
+ server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: unable to create server\n"),
+ WEECHAT_WARNING, filename, line_number);
+ return 0;
+ }
+ if (cfg_server.name)
+ free (cfg_server.name);
+ if (cfg_server.address)
+ free (cfg_server.address);
+ if (cfg_server.password)
+ free (cfg_server.password);
+ if (cfg_server.nick1)
+ free (cfg_server.nick1);
+ if (cfg_server.nick2)
+ free (cfg_server.nick2);
+ if (cfg_server.nick3)
+ free (cfg_server.nick3);
+ if (cfg_server.username)
+ free (cfg_server.username);
+ if (cfg_server.realname)
+ free (cfg_server.realname);
+ if (cfg_server.nick)
+ free (cfg_server.nick);
+
+ config_init_server ();
+
+ return 1;
+}
+
+/*
+ * config_default_values: initialize config variables with default values
+ */
+
+void
+config_default_values ()
+{
+ int i, j, int_value;
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ case OPTION_TYPE_INT:
+ *weechat_options[i][j].ptr_int =
+ weechat_options[i][j].default_int;
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ int_value = get_pos_array_values (
+ weechat_options[i][j].array_values,
+ weechat_options[i][j].default_string);
+ if (int_value < 0)
+ gui_printf (NULL,
+ _("%s unable to assign default int with string (\"%s\")\n"),
+ weechat_options[i][j].default_string);
+ else
+ *weechat_options[i][j].ptr_int =
+ int_value;
+ break;
+ case OPTION_TYPE_COLOR:
+ if (!gui_assign_color (
+ weechat_options[i][j].ptr_int,
+ weechat_options[i][j].default_string))
+ gui_printf (NULL,
+ _("%s unable to assign default color (\"%s\")\n"),
+ weechat_options[i][j].default_string);
+ break;
+ case OPTION_TYPE_STRING:
+ *weechat_options[i][j].ptr_string =
+ strdup (weechat_options[i][j].default_string);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * config_read: read WeeChat configuration
+ * returns: 0 = successful
+ * -1 = config file file not found
+ * < -1 = other error (fatal)
+ */
+
+int
+config_read ()
+{
+ char *filename;
+ FILE *file;
+ int section, line_number, i, option_number, int_value;
+ int server_found;
+ char line[1024], *ptr_line, *pos, *pos2;
+
+ filename =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME"));
+ if ((file = fopen (filename, "rt")) == NULL)
+ {
+ gui_printf (NULL, _("%s config file \"%s\" not found.\n"),
+ WEECHAT_WARNING, filename);
+ free (filename);
+ return -1;
+ }
+
+ config_default_values ();
+ config_init_server ();
+
+ /* read config file */
+ section = CONFIG_SECTION_NONE;
+ server_found = 0;
+ line_number = 0;
+ while (!feof (file))
+ {
+ ptr_line = fgets (line, sizeof (line) - 1, file);
+ line_number++;
+ if (ptr_line)
+ {
+ /* skip spaces */
+ while (ptr_line[0] == ' ')
+ ptr_line++;
+ /* not a comment and not an empty line */
+ if ((ptr_line[0] != '#') && (ptr_line[0] != '\r')
+ && (ptr_line[0] != '\n'))
+ {
+ /* beginning of section */
+ if (ptr_line[0] == '[')
+ {
+ pos = strchr (line, ']');
+ if (pos == NULL)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid syntax, missing \"]\"\n"),
+ WEECHAT_WARNING, filename, line_number);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ pos[0] = '\0';
+ pos = ptr_line + 1;
+ section = CONFIG_SECTION_NONE;
+ for (i = 0; config_sections[i].section_name; i++)
+ {
+ if (strcmp (config_sections[i].section_name, pos) == 0)
+ {
+ section = i;
+ break;
+ }
+ }
+ if (section == CONFIG_SECTION_NONE)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: unknown section identifier (\"%s\")\n"),
+ WEECHAT_WARNING, filename, line_number, pos);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ if (server_found)
+ {
+ /* if server already started => create it */
+ if (!config_allocate_server (filename, line_number))
+ {
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ }
+ server_found = (section == CONFIG_SECTION_SERVER) ? 1 : 0;
+ }
+ else
+ {
+ pos = strchr (line, '=');
+ if (pos == NULL)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid syntax, missing \"=\"\n"),
+ WEECHAT_WARNING, filename, line_number);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ else
+ {
+ pos[0] = '\0';
+ pos++;
+ pos2 = strchr (pos, '\r');
+ if (pos2 != NULL)
+ pos2[0] = '\0';
+ pos2 = strchr (pos, '\n');
+ if (pos2 != NULL)
+ pos2[0] = '\0';
+ option_number = -1;
+ for (i = 0;
+ weechat_options[section][i].option_name; i++)
+ {
+ if (strcmp
+ (weechat_options[section][i].option_name,
+ ptr_line) == 0)
+ {
+ option_number = i;
+ break;
+ }
+ }
+ if (option_number < 0)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid option \"%s\"\n"),
+ WEECHAT_WARNING, filename, line_number, ptr_line);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ else
+ {
+ switch (weechat_options[section]
+ [option_number].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ if (strcasecmp (pos, "on") == 0)
+ *weechat_options[section]
+ [option_number].ptr_int = BOOL_TRUE;
+ else if (strcasecmp (pos, "off") == 0)
+ *weechat_options[section]
+ [option_number].ptr_int = BOOL_FALSE;
+ else
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for"
+ "option '%s'\n"
+ "Expected: boolean value: "
+ "'off' or 'on'\n"),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ break;
+ case OPTION_TYPE_INT:
+ int_value = atoi (pos);
+ if ((int_value <
+ weechat_options[section]
+ [option_number].min)
+ || (int_value >
+ weechat_options[section]
+ [option_number].max))
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for"
+ "option '%s'\n"
+ "Expected: integer between %d "
+ "and %d\n"),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line,
+ weechat_options[section][option_number].min,
+ weechat_options[section][option_number].max);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ *weechat_options[section][option_number].ptr_int =
+ int_value;
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ int_value = get_pos_array_values (
+ weechat_options[section][option_number].array_values,
+ pos);
+ if (int_value < 0)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for"
+ "option '%s'\n"
+ "Expected: one of these strings: "),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line);
+ i = 0;
+ while (weechat_options[section][option_number].array_values[i])
+ {
+ gui_printf (NULL, "\"%s\" ",
+ weechat_options[section][option_number].array_values[i]);
+ i++;
+ }
+ gui_printf (NULL, "\n");
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ *weechat_options[section][option_number].ptr_int =
+ int_value;
+ break;
+ case OPTION_TYPE_COLOR:
+ if (!gui_assign_color (
+ weechat_options[section][option_number].ptr_int,
+ pos))
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid color "
+ "name for option '%s'\n"),
+ WEECHAT_WARNING, filename,
+ line_number,
+ ptr_line);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ break;
+ case OPTION_TYPE_STRING:
+ if (*weechat_options[section]
+ [option_number].ptr_string)
+ free (*weechat_options[section][option_number].ptr_string);
+ *weechat_options[section][option_number].ptr_string =
+ strdup (pos);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (server_found)
+ {
+ if (!config_allocate_server (filename, line_number))
+ {
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ }
+
+ /* set default colors for colors not set */
+ /*for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ if ((weechat_options[i][j].option_type == OPTION_TYPE_COLOR) &&
+ (*weechat_options[i][j].ptr_int == COLOR_NOT_SET))
+ *weechat_options[i][j].ptr_int =
+ gui_get_color_by_name (weechat_options[i][j].default_string);
+ }
+ }
+ }*/
+
+ fclose (file);
+ free (filename);
+
+ return 0;
+}
+
+
+/*
+ * config_create_default: create default WeeChat config
+ */
+
+int
+config_create_default ()
+{
+ char *filename;
+ char line[1024];
+ FILE *file;
+ int i, j;
+ time_t current_time;
+
+ filename =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME"));
+ if ((file = fopen (filename, "wt")) == NULL)
+ {
+ free (filename);
+ gui_printf (NULL, _("%s cannot create file \"%s\"\n"),
+ WEECHAT_ERROR, filename);
+ return -1;
+ }
+
+ printf (_(WEECHAT_NAME ": creating default config file...\n"));
+
+ current_time = time (NULL);
+ sprintf (line, _("#\n# " WEECHAT_NAME " configuration file, generated by "
+ WEECHAT_NAME " " WEECHAT_VERSION " on %s"), ctime (&current_time));
+ fputs (line, file);
+ fputs (_("# This file may be edited by user. Invalid syntax will prevent "
+ WEECHAT_NAME " from running!\n#\n"), file);
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ sprintf (line, "\n[%s]\n", config_sections[i].section_name);
+ fputs (line, file);
+ if ((i == CONFIG_SECTION_HISTORY) || (i == CONFIG_SECTION_LOG) ||
+ (i == CONFIG_SECTION_DCC) || (i == CONFIG_SECTION_PROXY))
+ {
+ sprintf (line,
+ "# WARNING!!! Options for section \"%s\" are not developed!\n",
+ config_sections[i].section_name);
+ fputs (line, file);
+ }
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ sprintf (line, "%s=%s\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].
+ default_int) ? "on" : "off");
+ break;
+ case OPTION_TYPE_INT:
+ sprintf (line, "%s=%d\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].default_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ case OPTION_TYPE_COLOR:
+ case OPTION_TYPE_STRING:
+ sprintf (line, "%s=%s\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].default_string);
+ break;
+ }
+ fputs (line, file);
+ }
+ }
+ }
+
+ /* default server is freenode */
+ fputs ("\n[server]\n", file);
+ fputs ("server_name=freenode\n", file);
+ fputs ("server_address=irc.freenode.net\n", file);
+ fputs ("server_port=6667\n", file);
+ fputs ("server_password=\n", file);
+ fputs ("server_nick1=weechat_user\n", file);
+ fputs ("server_nick2=weechat2\n", file);
+ fputs ("server_nick3=weechat3\n", file);
+ fputs ("server_username=weechat\n", file);
+ fputs ("server_realname=WeeChat default realname\n", file);
+
+ fclose (file);
+ free (filename);
+ return 0;
+}
+
+/*
+ * config_write: write WeeChat configurtion
+ */
+
+void
+config_write ()
+{
+ /* TODO: write "config_write" function! */
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 000000000..cc84eaab6
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_CONFIG_H
+#define __WEECHAT_CONFIG_H 1
+
+#define WEECHAT_CONFIG_NAME "weechat.rc"
+
+#define CONFIG_SECTION_NONE -1
+#define CONFIG_SECTION_LOOK 0
+#define CONFIG_SECTION_COLORS 1
+#define CONFIG_SECTION_HISTORY 2
+#define CONFIG_SECTION_LOG 3
+#define CONFIG_SECTION_DCC 4
+#define CONFIG_SECTION_PROXY 5
+#define CONFIG_SECTION_SERVER 6
+#define CONFIG_NUMBER_SECTIONS 7
+
+#define OPTION_TYPE_BOOLEAN 1 /* values: on/off */
+#define OPTION_TYPE_INT 2 /* values: from min to max */
+#define OPTION_TYPE_INT_WITH_STRING 3 /* values: one from **array_values */
+#define OPTION_TYPE_COLOR 4 /* values: a color name */
+#define OPTION_TYPE_STRING 5 /* values: any string, may be empty */
+
+#define BOOL_FALSE 0
+#define BOOL_TRUE 1
+
+#define CFG_LOOK_NICKLIST_LEFT 0
+#define CFG_LOOK_NICKLIST_RIGHT 1
+#define CFG_LOOK_NICKLIST_TOP 2
+#define CFG_LOOK_NICKLIST_BOTTOM 3
+
+typedef struct t_config_section t_config_section;
+
+struct t_config_section
+{
+ int section_number;
+ char *section_name;
+};
+
+typedef struct t_config_option t_config_option;
+
+struct t_config_option
+{
+ char *option_name;
+ char *short_description;
+ char *long_description;
+ int option_type;
+ int min, max;
+ int default_int;
+ char *default_string;
+ char **array_values;
+ int *ptr_int;
+ char **ptr_string;
+ int (*handler_change)(int *, char **);
+};
+
+extern int cfg_look_startup_logo;
+extern int cfg_look_startup_version;
+extern char *cfg_look_weechat_slogan;
+extern int cfg_look_color_nicks;
+extern int cfg_look_color_actions;
+extern int cfg_look_remove_colors_from_msgs;
+extern int cfg_look_nicklist;
+extern int cfg_look_nicklist_position;
+extern int cfg_look_nicklist_min_size;
+extern int cfg_look_nicklist_max_size;
+extern int cfg_look_nickmode;
+extern int cfg_look_nickmode_empty;
+extern char *cfg_look_no_nickname;
+extern char *cfg_look_completor;
+
+extern int cfg_col_title;
+extern int cfg_col_title_bg;
+extern int cfg_col_chat;
+extern int cfg_col_chat_time;
+extern int cfg_col_chat_time_sep;
+extern int cfg_col_chat_prefix1;
+extern int cfg_col_chat_prefix2;
+extern int cfg_col_chat_nick;
+extern int cfg_col_chat_host;
+extern int cfg_col_chat_channel;
+extern int cfg_col_chat_dark;
+extern int cfg_col_chat_bg;
+extern int cfg_col_status;
+extern int cfg_col_status_active;
+extern int cfg_col_status_data_msg;
+extern int cfg_col_status_data_other;
+extern int cfg_col_status_more;
+extern int cfg_col_status_bg;
+extern int cfg_col_input;
+extern int cfg_col_input_channel;
+extern int cfg_col_input_nick;
+extern int cfg_col_input_bg;
+extern int cfg_col_nick;
+extern int cfg_col_nick_op;
+extern int cfg_col_nick_halfop;
+extern int cfg_col_nick_voice;
+extern int cfg_col_nick_sep;
+extern int cfg_col_nick_self;
+extern int cfg_col_nick_private;
+extern int cfg_col_nick_bg;
+
+extern int cfg_history_max_lines;
+extern int cfg_history_max_commands;
+
+extern int cfg_log_auto_channels;
+extern int cfg_log_auto_private;
+extern char *cfg_log_path;
+extern char *cfg_log_name;
+extern char *cfg_log_timestamp;
+extern char *cfg_log_start_string;
+extern char *cfg_log_end_string;
+
+extern int cfg_dcc_auto_accept_files;
+extern int cfg_dcc_auto_accept_max_size;
+extern int cfg_dcc_auto_accept_chats;
+extern int cfg_dcc_timeout;
+extern char *cfg_dcc_download_path;
+extern char *cfg_dcc_upload_path;
+extern int cfg_dcc_auto_rename;
+extern int cfg_dcc_auto_resume;
+
+extern int cfg_proxy_use;
+extern char *cfg_proxy_address;
+extern int cfg_proxy_port;
+extern char *cfg_proxy_password;
+
+extern t_config_section config_sections [CONFIG_NUMBER_SECTIONS];
+extern t_config_option * weechat_options [CONFIG_NUMBER_SECTIONS];
+
+extern int config_read ();
+extern int config_create_default ();
+extern void config_write ();
+
+#endif /* config.h */
diff --git a/src/gui/Makefile b/src/gui/Makefile
new file mode 100644
index 000000000..77d66bea7
--- /dev/null
+++ b/src/gui/Makefile
@@ -0,0 +1,55 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# WeeChat with Curses interface
+ifeq ($(GUI), curses)
+curses: curses/gui.a
+curses/gui.a:
+ cd curses && make
+endif
+
+# WeeChat with Gtk+ interface
+ifeq ($(GUI), gtk)
+gtk: gtk/gui.a
+gtk/gui.a:
+ cd gtk && make
+endif
+
+# WeeChat with Qt interface
+ifeq ($(GUI), qt)
+qt: qt/gui.a
+qt/gui.a:
+ cd qt && make
+endif
+
+# WeeChat with Text interface
+ifeq ($(GUI), text)
+text: text/gui.a
+text/gui.a:
+ cd text && make
+endif
+
+
+all:
+ make curses GUI=curses
+
+clean:
+ rm -f *.o *.a *~ core
+ cd curses && make clean
+ cd gtk && make clean
+ cd qt && make clean
+ cd text && make clean
diff --git a/src/gui/curses/Makefile b/src/gui/curses/Makefile
new file mode 100644
index 000000000..80f800dd9
--- /dev/null
+++ b/src/gui/curses/Makefile
@@ -0,0 +1,38 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_CURSES
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../completion.h \
+ ../../history.h ../../config.h ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h ../../completion.h \
+ ../../history.h ../../command.h ../../irc/irc.h ../../gui/gui.h
diff --git a/src/gui/curses/gui-display.c b/src/gui/curses/gui-display.c
new file mode 100644
index 000000000..9ad67edac
--- /dev/null
+++ b/src/gui/curses/gui-display.c
@@ -0,0 +1,1730 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-display.c: display functions for Curses GUI */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <curses.h>
+
+#include "../../weechat.h"
+#include "../gui.h"
+#include "../../config.h"
+#include "../../irc/irc.h"
+
+
+int gui_ready; /* = 1 if GUI is initialized */
+
+t_gui_window *gui_windows = NULL; /* pointer to first window */
+t_gui_window *last_gui_window = NULL; /* pointer to last window */
+t_gui_window *gui_current_window = NULL; /* pointer to current window */
+
+t_gui_color gui_colors[] =
+{ { "default", -1 | A_NORMAL },
+ { "black", COLOR_BLACK | A_NORMAL },
+ { "red", COLOR_RED | A_NORMAL },
+ { "lightred", COLOR_RED | A_BOLD },
+ { "green", COLOR_GREEN | A_NORMAL },
+ { "lightgreen", COLOR_GREEN | A_BOLD },
+ { "brown", COLOR_YELLOW | A_NORMAL },
+ { "yellow", COLOR_YELLOW | A_BOLD },
+ { "blue", COLOR_BLUE | A_NORMAL },
+ { "lightblue", COLOR_BLUE | A_BOLD },
+ { "magenta", COLOR_MAGENTA | A_NORMAL },
+ { "lightmagenta", COLOR_MAGENTA | A_BOLD },
+ { "cyan", COLOR_CYAN | A_NORMAL },
+ { "lightcyan", COLOR_CYAN | A_BOLD },
+ { "gray", COLOR_WHITE },
+ { "white", COLOR_WHITE | A_BOLD },
+ { NULL, 0 }
+};
+
+char *nicks_colors[COLOR_WIN_NICK_NUMBER] =
+{ "cyan", "magenta", "green", "brown", "lightblue", "gray",
+ "lightcyan", "lightmagenta", "lightgreen", "blue" };
+
+int color_attr[NUM_COLORS];
+
+/*
+ * gui_assign_color: assign a color (read from config)
+ */
+
+int
+gui_assign_color (int *color, char *color_name)
+{
+ int i;
+
+ /* look for curses colors in table */
+ i = 0;
+ while (gui_colors[i].name)
+ {
+ if (strcasecmp (gui_colors[i].name, color_name) == 0)
+ {
+ *color = gui_colors[i].color;
+ return 1;
+ }
+ i++;
+ }
+
+ /* color not found */
+ return 0;
+}
+
+/*
+ * gui_get_color_by_name: get color by name
+ */
+
+int
+gui_get_color_by_name (char *color_name)
+{
+ int i;
+
+ /* look for curses colors in table */
+ i = 0;
+ while (gui_colors[i].name)
+ {
+ if (strcasecmp (gui_colors[i].name, color_name) == 0)
+ return gui_colors[i].color;
+ i++;
+ }
+
+ /* color not found */
+ return -1;
+}
+
+/*
+ * gui_get_color_by_value: get color name by value
+ */
+
+char *
+gui_get_color_by_value (int color_value)
+{
+ int i;
+
+ /* look for curses colors in table */
+ i = 0;
+ while (gui_colors[i].name)
+ {
+ if (gui_colors[i].color == color_value)
+ return gui_colors[i].name;
+ i++;
+ }
+
+ /* color not found */
+ return NULL;
+}
+
+/*
+ * gui_window_set_color: set color for window
+ */
+
+void
+gui_window_set_color (WINDOW *window, int num_color)
+{
+ if (has_colors)
+ {
+ if (color_attr[num_color - 1] & A_BOLD)
+ wattron (window, COLOR_PAIR (num_color) | A_BOLD);
+ else
+ {
+ wattroff (window, A_BOLD);
+ wattron (window, COLOR_PAIR (num_color));
+ }
+ }
+}
+
+/*
+ * gui_calculate_pos_size: calculate position and size for a window & sub-win
+ */
+
+void
+gui_calculate_pos_size (t_gui_window *window)
+{
+ int max_length, lines;
+ int num_nicks, num_op, num_halfop, num_voice, num_normal;
+
+ /* global position & size */
+ /* TODO: get values from function parameters */
+ window->win_x = 0;
+ window->win_y = 0;
+ window->win_width = COLS;
+ window->win_height = LINES;
+
+ /* init chat & nicklist settings */
+ /* TODO: calculate values from function parameters */
+ if (WIN_IS_CHANNEL(window))
+ {
+ max_length = nick_get_max_length (CHANNEL(window));
+
+ switch (cfg_look_nicklist_position)
+ {
+ case CFG_LOOK_NICKLIST_LEFT:
+ window->win_chat_x = max_length + 2;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS - max_length - 2;
+ window->win_chat_height = LINES - 3;
+ window->win_nick_x = 0;
+ window->win_nick_y = 1;
+ window->win_nick_width = max_length + 2;
+ window->win_nick_height = LINES - 3;
+ break;
+ case CFG_LOOK_NICKLIST_RIGHT:
+ window->win_chat_x = 0;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS - max_length - 2;
+ window->win_chat_height = LINES - 3;
+ window->win_nick_x = COLS - max_length - 2;
+ window->win_nick_y = 1;
+ window->win_nick_width = max_length + 2;
+ window->win_nick_height = LINES - 3;
+ break;
+ case CFG_LOOK_NICKLIST_TOP:
+ nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop,
+ &num_voice, &num_normal);
+ if (((max_length + 1) * num_nicks) % COLS == 0)
+ lines = ((max_length + 1) * num_nicks) / COLS;
+ else
+ lines = (((max_length + 1) * num_nicks) / COLS) + 1;
+ window->win_chat_x = 0;
+ window->win_chat_y = 1 + (lines + 1);
+ window->win_chat_width = COLS;
+ window->win_chat_height = LINES - 3 - (lines + 1);
+ window->win_nick_x = 0;
+ window->win_nick_y = 1;
+ window->win_nick_width = COLS;
+ window->win_nick_height = lines + 1;
+ break;
+ case CFG_LOOK_NICKLIST_BOTTOM:
+ nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop,
+ &num_voice, &num_normal);
+ if (((max_length + 1) * num_nicks) % COLS == 0)
+ lines = ((max_length + 1) * num_nicks) / COLS;
+ else
+ lines = (((max_length + 1) * num_nicks) / COLS) + 1;
+ window->win_chat_x = 0;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS;
+ window->win_chat_height = LINES - 3 - (lines + 1);
+ window->win_nick_x = 0;
+ window->win_nick_y = LINES - 2 - (lines + 1);
+ window->win_nick_width = COLS;
+ window->win_nick_height = lines + 1;
+ break;
+ }
+
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = 0;
+ }
+ else
+ {
+ window->win_chat_x = 0;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS;
+ window->win_chat_height = LINES - 3;
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = 0;
+ window->win_nick_x = -1;
+ window->win_nick_y = -1;
+ window->win_nick_width = -1;
+ window->win_nick_height = -1;
+ }
+}
+
+/*
+ * gui_curses_window_clear: clear a window
+ */
+
+void
+gui_curses_window_clear (WINDOW *window)
+{
+ werase (window);
+ wmove (window, 0, 0);
+ //wrefresh (window);
+}
+
+/*
+ * gui_draw_window_title: draw title window
+ */
+
+void
+gui_draw_window_title (t_gui_window *window)
+{
+ char format[32];
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_title, COLOR_WIN_TITLE);
+ wborder (window->win_title, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_title);
+ refresh ();
+ }
+ if (CHANNEL(window))
+ {
+ sprintf (format, "%%-%ds", window->win_width);
+ if (CHANNEL(window)->topic)
+ mvwprintw (window->win_title, 0, 0, format,
+ CHANNEL(window)->topic);
+ }
+ else
+ {
+ /* TODO: change this copyright as title? */
+ mvwprintw (window->win_title, 0, 0,
+ "%s", WEECHAT_NAME_AND_VERSION " - " WEECHAT_WEBSITE);
+ mvwprintw (window->win_title, 0, COLS - strlen (WEECHAT_COPYRIGHT),
+ "%s", WEECHAT_COPYRIGHT);
+ }
+ wrefresh (window->win_title);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_title: redraw title window
+ */
+
+void
+gui_redraw_window_title (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_title);
+ gui_draw_window_title (window);
+}
+
+/*
+ * gui_get_line_num_splits: returns number of lines on window
+ * (depending on window width and type (server/channel)
+ * for alignment)
+ */
+
+int
+gui_get_line_num_splits (t_gui_window *window, t_gui_line *line)
+{
+ int length, width;
+
+ /* TODO: modify arbitraty value for non aligning messages on time/nick? */
+ if (line->length_align >= window->win_chat_width - 5)
+ {
+ length = line->length;
+ width = window->win_chat_width;
+ }
+ else
+ {
+ length = line->length - line->length_align;
+ width = window->win_chat_width - line->length_align;
+ }
+
+ return (length % width == 0) ? (length / width) : ((length / width) + 1);
+}
+
+/*
+ * gui_display_end_of_line: display end of a line in the chat window
+ */
+
+void
+gui_display_end_of_line (t_gui_window *window, t_gui_line *line, int count)
+{
+ int lines_displayed, num_lines, offset, remainder, num_displayed;
+ t_gui_message *ptr_message;
+ char saved_char, format_align[32];
+
+ sprintf (format_align, "%%-%ds", line->length_align);
+ num_lines = gui_get_line_num_splits (window, line);
+ ptr_message = line->messages;
+ offset = 0;
+ lines_displayed = 0;
+ while (ptr_message)
+ {
+ /* set text color if beginning of message */
+ if (offset == 0)
+ gui_window_set_color (window->win_chat, ptr_message->color);
+
+ /* insert spaces for align text under time/nick */
+ if ((lines_displayed > 0) && (window->win_chat_cursor_x == 0))
+ {
+ if (lines_displayed >= num_lines - count)
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ format_align, " ");
+ window->win_chat_cursor_x += line->length_align;
+ }
+
+ remainder = strlen (ptr_message->message + offset);
+ if (window->win_chat_cursor_x + remainder >
+ window->win_chat_width - 1)
+ {
+ num_displayed = window->win_chat_width -
+ window->win_chat_cursor_x;
+ saved_char = ptr_message->message[offset + num_displayed];
+ ptr_message->message[offset + num_displayed] = '\0';
+ if (lines_displayed >= num_lines - count)
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ ptr_message->message[offset + num_displayed] = saved_char;
+ offset += num_displayed;
+ }
+ else
+ {
+ num_displayed = remainder;
+ if (lines_displayed >= num_lines - count)
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ ptr_message = ptr_message->next_message;
+ offset = 0;
+ }
+ window->win_chat_cursor_x += num_displayed;
+ if (!ptr_message ||
+ (window->win_chat_cursor_x > (window->win_chat_width - 1)))
+ {
+ window->win_chat_cursor_x = 0;
+ if (lines_displayed >= num_lines - count)
+ {
+ window->win_chat_cursor_y++;
+ }
+ lines_displayed++;
+ }
+ }
+}
+
+/*
+ * gui_display_line: display a line in the chat window
+ * if stop_at_end == 1, screen will not scroll and then we
+ * exit since chat window is full
+ * returns: 1 if stop_at_end == 0 or screen not full
+ * 0 if screen is full and if stop_at_end == 1
+ */
+
+int
+gui_display_line (t_gui_window *window, t_gui_line *line, int stop_at_end)
+{
+ int offset, remainder, num_displayed;
+ t_gui_message *ptr_message;
+ char saved_char, format_align[32];
+
+ sprintf (format_align, "%%-%ds", line->length_align);
+ ptr_message = line->messages;
+ offset = 0;
+ while (ptr_message)
+ {
+ /* cursor is below end line of chat window */
+ if (window->win_chat_cursor_y > window->win_chat_height - 1)
+ {
+ /*if (!stop_at_end)
+ wscrl (window->win_chat, +1);*/
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = window->win_chat_height - 1;
+ if (stop_at_end)
+ return 0;
+ window->first_line_displayed = 0;
+ }
+
+ /* set text color if beginning of message */
+ if (offset == 0)
+ gui_window_set_color (window->win_chat, ptr_message->color);
+
+ /* insert spaces for align text under time/nick */
+ if ((window->win_chat_cursor_x == 0) &&
+ (ptr_message->type != MSG_TYPE_TIME) &&
+ (ptr_message->type != MSG_TYPE_NICK) &&
+ (line->length_align > 0) &&
+ /* TODO: modify arbitraty value for non aligning messages on time/nick? */
+ (line->length_align < (window->win_chat_width - 5)))
+ {
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ format_align, " ");
+ window->win_chat_cursor_x += line->length_align;
+ }
+
+ remainder = strlen (ptr_message->message + offset);
+ if (window->win_chat_cursor_x + remainder > window->win_chat_width)
+ {
+ num_displayed = window->win_chat_width -
+ window->win_chat_cursor_x;
+ saved_char = ptr_message->message[offset + num_displayed];
+ ptr_message->message[offset + num_displayed] = '\0';
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ ptr_message->message[offset + num_displayed] = saved_char;
+ offset += num_displayed;
+ }
+ else
+ {
+ num_displayed = remainder;
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ offset = 0;
+ ptr_message = ptr_message->next_message;
+ }
+ window->win_chat_cursor_x += num_displayed;
+ if (!ptr_message ||
+ (window->win_chat_cursor_x > (window->win_chat_width - 1)))
+ {
+ if (!ptr_message ||
+ ((window->win_chat_cursor_y <= window->win_chat_height - 1) &&
+ (window->win_chat_cursor_x > window->win_chat_width - 1)))
+ window->win_chat_cursor_y++;
+ window->win_chat_cursor_x = 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * gui_draw_window_chat: draw chat window
+ */
+
+void
+gui_draw_window_chat (t_gui_window *window)
+{
+ t_gui_line *ptr_line;
+ int lines_used;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_chat, COLOR_WIN_CHAT);
+ wborder (window->win_chat, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_chat);
+ }
+
+ ptr_line = window->last_line;
+ lines_used = 0;
+ while (ptr_line
+ && (lines_used < (window->win_chat_height + window->sub_lines)))
+ {
+ lines_used += gui_get_line_num_splits (window, ptr_line);
+ ptr_line = ptr_line->prev_line;
+ }
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = 0;
+ if (lines_used > (window->win_chat_height + window->sub_lines))
+ {
+ /* screen will be full (we'll display only end of 1st line) */
+ ptr_line = (ptr_line) ? ptr_line->next_line : window->lines;
+ gui_display_end_of_line (window, ptr_line,
+ gui_get_line_num_splits (window, ptr_line) -
+ (lines_used - (window->win_chat_height + window->sub_lines)));
+ ptr_line = ptr_line->next_line;
+ window->first_line_displayed = 0;
+ }
+ else
+ {
+ /* all lines are displayed */
+ if (!ptr_line)
+ {
+ window->first_line_displayed = 1;
+ ptr_line = window->lines;
+ }
+ else
+ {
+ window->first_line_displayed = 0;
+ ptr_line = ptr_line->next_line;
+ }
+ }
+ while (ptr_line)
+ {
+ if (!gui_display_line (window, ptr_line, 1))
+ break;
+
+ ptr_line = ptr_line->next_line;
+ }
+ /*if (window->win_chat_cursor_y <= window->win_chat_height - 1)
+ window->sub_lines = 0;*/
+ wrefresh (window->win_chat);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_chat: redraw chat window
+ */
+
+void
+gui_redraw_window_chat (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_chat);
+ gui_draw_window_chat (window);
+}
+
+/*
+ * gui_draw_window_nick: draw nick window
+ */
+
+void
+gui_draw_window_nick (t_gui_window *window)
+{
+ int i, x, y, column, max_length;
+ char format[32];
+ t_irc_nick *ptr_nick;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (CHANNEL(window) && CHANNEL(window)->nicks)
+ {
+ max_length = nick_get_max_length (CHANNEL(window));
+ if ((max_length + 2) != window->win_nick_width)
+ {
+ gui_calculate_pos_size (window);
+ delwin (window->win_chat);
+ delwin (window->win_nick);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ window->win_nick = newwin (window->win_nick_height,
+ window->win_nick_width,
+ window->win_nick_y,
+ window->win_nick_x);
+ //scrollok (window->win_chat, TRUE);
+ gui_redraw_window_chat (window);
+ }
+ sprintf (format, "%%-%ds", max_length);
+
+ if (has_colors ())
+ {
+ switch (cfg_look_nicklist_position)
+ {
+ case CFG_LOOK_NICKLIST_LEFT:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP);
+ for (i = 0; i < window->win_chat_height; i++)
+ mvwprintw (window->win_nick,
+ i, window->win_nick_width - 1, " ");
+ break;
+ case CFG_LOOK_NICKLIST_RIGHT:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP);
+ for (i = 0; i < window->win_chat_height; i++)
+ mvwprintw (window->win_nick,
+ i, 0, " ");
+ break;
+ case CFG_LOOK_NICKLIST_TOP:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ for (i = 0; i < window->win_chat_width; i += 2)
+ mvwprintw (window->win_nick,
+ window->win_nick_height - 1, i, "-");
+ break;
+ case CFG_LOOK_NICKLIST_BOTTOM:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ for (i = 0; i < window->win_chat_width; i += 2)
+ mvwprintw (window->win_nick,
+ 0, i, "-");
+ break;
+ }
+ }
+
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ x = 0;
+ y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM) ? 1 : 0;
+ column = 0;
+ for (ptr_nick = CHANNEL(window)->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ switch (cfg_look_nicklist_position)
+ {
+ case CFG_LOOK_NICKLIST_LEFT:
+ x = 0;
+ break;
+ case CFG_LOOK_NICKLIST_RIGHT:
+ x = 1;
+ break;
+ case CFG_LOOK_NICKLIST_TOP:
+ case CFG_LOOK_NICKLIST_BOTTOM:
+ x = column;
+ break;
+ }
+ if (ptr_nick->is_op)
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_OP);
+ mvwprintw (window->win_nick, y, x, "@");
+ x++;
+ }
+ else
+ {
+ if (ptr_nick->is_halfop)
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_HALFOP);
+ mvwprintw (window->win_nick, y, x, "%%");
+ x++;
+ }
+ else
+ {
+ if (ptr_nick->has_voice)
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_VOICE);
+ mvwprintw (window->win_nick, y, x, "+");
+ x++;
+ }
+ else
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ mvwprintw (window->win_nick, y, x, " ");
+ x++;
+ }
+ }
+ }
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ mvwprintw (window->win_nick, y, x, format, ptr_nick->nick);
+ y++;
+ if ((cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) ||
+ (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM))
+ {
+ if (y >= window->win_nick_height - 1)
+ {
+ column += max_length + 1;
+ y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) ?
+ 0 : 1;
+ }
+ }
+ }
+ }
+ wrefresh (window->win_nick);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_nick: redraw nick window
+ */
+
+void
+gui_redraw_window_nick (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_nick);
+ gui_draw_window_nick (window);
+}
+
+/*
+ * gui_draw_window_status: draw status window
+ */
+
+void
+gui_draw_window_status (t_gui_window *window)
+{
+ t_gui_window *ptr_win;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_status, COLOR_WIN_STATUS);
+ wborder (window->win_status, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_status);
+ }
+ //refresh ();
+ wmove (window->win_status, 0, 0);
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (SERVER(ptr_win) && !CHANNEL(ptr_win))
+ {
+ if (gui_current_window == SERVER(ptr_win)->window)
+ {
+ if (ptr_win->unread_data)
+ {
+ if (ptr_win->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_ACTIVE);
+ }
+ else
+ {
+ if (SERVER(ptr_win)->window &&
+ ((SERVER(ptr_win)->window)->unread_data))
+ {
+ if (SERVER(ptr_win)->window->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS);
+ }
+ if (SERVER(ptr_win)->is_connected)
+ wprintw (window->win_status, "[%s] ",
+ SERVER(ptr_win)->name);
+ else
+ wprintw (window->win_status, "(%s) ",
+ SERVER(ptr_win)->name);
+ }
+ if (SERVER(ptr_win) && CHANNEL(ptr_win))
+ {
+ if (gui_current_window == CHANNEL(ptr_win)->window)
+ {
+ if ((CHANNEL(ptr_win)->window) &&
+ (CHANNEL(ptr_win)->window->unread_data))
+ {
+ if (CHANNEL(ptr_win)->window->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_ACTIVE);
+ }
+ else
+ {
+ if ((CHANNEL(ptr_win)->window) &&
+ (CHANNEL(ptr_win)->window->unread_data))
+ {
+ if (CHANNEL(ptr_win)->window->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS);
+ }
+ wprintw (window->win_status, "%s ", CHANNEL(ptr_win)->name);
+ }
+ if (!SERVER(ptr_win))
+ {
+ gui_window_set_color (window->win_status, COLOR_WIN_STATUS);
+ wprintw (window->win_status, _("[not connected] "));
+ }
+ }
+
+ /* display "*MORE*" if last line is not displayed */
+ gui_window_set_color (window->win_status, COLOR_WIN_STATUS_MORE);
+ if (window->sub_lines > 0)
+ mvwprintw (window->win_status, 0, COLS - 7, "-MORE-");
+ else
+ mvwprintw (window->win_status, 0, COLS - 7, " ");
+
+ wrefresh (window->win_status);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_status: redraw status window
+ */
+
+void
+gui_redraw_window_status (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_status);
+ gui_draw_window_status (window);
+}
+
+/*
+ * gui_get_input_width: return input width (max # chars displayed)
+ */
+
+int
+gui_get_input_width (t_gui_window *window)
+{
+ if (CHANNEL(window))
+ return (COLS - strlen (CHANNEL(window)->name) -
+ strlen (SERVER(window)->nick) - 3);
+ else
+ {
+ if (SERVER(window) && (SERVER(window)->is_connected))
+ return (COLS - strlen (SERVER(window)->nick) - 2);
+ else
+ return (COLS - strlen (cfg_look_no_nickname) - 2);
+ }
+}
+
+/*
+ * gui_draw_window_input: draw input window
+ */
+
+void
+gui_draw_window_input (t_gui_window *window)
+{
+ char format[32];
+ char *ptr_nickname;
+ int input_width;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_input, COLOR_WIN_INPUT);
+ wborder (window->win_input, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_input);
+ }
+ //refresh ();
+
+ if (window->input_buffer_size == 0)
+ window->input_buffer[0] = '\0';
+
+ input_width = gui_get_input_width (window);
+
+ if (window->input_buffer_pos - window->input_buffer_1st_display + 1 >
+ input_width)
+ window->input_buffer_1st_display = window->input_buffer_pos -
+ input_width + 1;
+ else
+ {
+ if (window->input_buffer_pos < window->input_buffer_1st_display)
+ window->input_buffer_1st_display = window->input_buffer_pos;
+ else
+ {
+ if ((window->input_buffer_1st_display > 0) &&
+ (window->input_buffer_pos -
+ window->input_buffer_1st_display + 1) < input_width)
+ {
+ window->input_buffer_1st_display =
+ window->input_buffer_pos - input_width + 1;
+ if (window->input_buffer_1st_display < 0)
+ window->input_buffer_1st_display = 0;
+ }
+ }
+ }
+ if (CHANNEL(window))
+ {
+ sprintf (format, "%%s %%s> %%-%ds", input_width);
+ mvwprintw (window->win_input, 0, 0, format,
+ CHANNEL(window)->name,
+ SERVER(window)->nick,
+ window->input_buffer + window->input_buffer_1st_display);
+ wclrtoeol (window->win_input);
+ move (LINES - 1, strlen (CHANNEL(window)->name) +
+ strlen (SERVER(window)->nick) + 3 +
+ (window->input_buffer_pos - window->input_buffer_1st_display));
+ }
+ else
+ {
+ sprintf (format, "%%s> %%-%ds", input_width);
+ if (SERVER(window) && (SERVER(window)->is_connected))
+ ptr_nickname = SERVER(window)->nick;
+ else
+ ptr_nickname = cfg_look_no_nickname;
+ mvwprintw (window->win_input, 0, 0, format,
+ ptr_nickname,
+ window->input_buffer + window->input_buffer_1st_display);
+ wclrtoeol (window->win_input);
+ move (LINES - 1, strlen (ptr_nickname) + 2 +
+ (window->input_buffer_pos - window->input_buffer_1st_display));
+ }
+
+ wrefresh (window->win_input);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_input: redraw input window
+ */
+
+void
+gui_redraw_window_input (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_input);
+ gui_draw_window_input (window);
+}
+
+/*
+ * gui_redraw_window: redraw a window
+ */
+
+void
+gui_redraw_window (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_redraw_window_title (window);
+ gui_redraw_window_chat (window);
+ if (window->win_nick)
+ gui_redraw_window_nick (window);
+ gui_redraw_window_status (window);
+ gui_redraw_window_input (window);
+}
+
+/*
+ * gui_window_clear: clear window content
+ */
+
+void
+gui_window_clear (t_gui_window *window)
+{
+ t_gui_line *ptr_line;
+ t_gui_message *ptr_message;
+
+ while (window->lines)
+ {
+ ptr_line = window->lines->next_line;
+ while (window->lines->messages)
+ {
+ ptr_message = window->lines->messages->next_message;
+ if (window->lines->messages->message)
+ free (window->lines->messages->message);
+ free (window->lines->messages);
+ window->lines->messages = ptr_message;
+ }
+ free (window->lines);
+ window->lines = ptr_line;
+ }
+
+ window->lines = NULL;
+ window->last_line = NULL;
+ window->first_line_displayed = 1;
+ window->sub_lines = 0;
+ window->line_complete = 1;
+ window->unread_data = 0;
+
+ if (window == gui_current_window)
+ gui_redraw_window_chat (window);
+}
+
+/*
+ * gui_window_clear_all: clear all windows content
+ */
+
+void
+gui_window_clear_all ()
+{
+ t_gui_window *ptr_win;
+
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ gui_window_clear (ptr_win);
+}
+
+/*
+ * gui_switch_to_window: switch to another window
+ */
+
+void
+gui_switch_to_window (t_gui_window *window)
+{
+ int another_window;
+ t_gui_window *ptr_win;
+
+ another_window = 0;
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (ptr_win->win_title)
+ {
+ /* TODO: manage splitted windows */
+ another_window = 1;
+ window->win_title = ptr_win->win_title;
+ window->win_chat = ptr_win->win_chat;
+ window->win_nick = ptr_win->win_nick;
+ window->win_status = ptr_win->win_status;
+ window->win_input = ptr_win->win_input;
+ ptr_win->win_title = NULL;
+ ptr_win->win_chat = NULL;
+ ptr_win->win_nick = NULL;
+ ptr_win->win_status = NULL;
+ ptr_win->win_input = NULL;
+ break;
+ }
+ }
+
+ /* first time creation for windows */
+ if (!another_window)
+ {
+ /* create new windows */
+ gui_calculate_pos_size (window);
+ window->win_title = newwin (1, COLS, 0, 0);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ //scrollok (window->win_chat, TRUE);
+ if (CHANNEL(window))
+ window->win_nick = newwin (window->win_nick_height,
+ window->win_nick_width,
+ window->win_nick_y,
+ window->win_nick_x);
+ else
+ window->win_nick = NULL;
+ window->win_status = newwin (1, COLS, LINES - 2, 0);
+ window->win_input = newwin (1, COLS, LINES - 1, 0);
+ }
+ else
+ {
+ gui_calculate_pos_size (window);
+
+ /* create chat & nick windows */
+ if (WIN_IS_CHANNEL(window) && !(window->win_nick))
+ {
+ /* add nick list window */
+ delwin (window->win_chat);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ //scrollok (window->win_chat, TRUE);
+ window->win_nick = newwin (window->win_nick_height,
+ window->win_nick_width,
+ window->win_nick_y,
+ window->win_nick_x);
+ }
+ if (!(WIN_IS_CHANNEL(window)) && window->win_nick)
+ {
+ /* remove nick list window */
+ delwin (window->win_nick);
+ window->win_nick = NULL;
+ delwin (window->win_chat);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ //scrollok (window->win_chat, TRUE);
+ }
+ }
+
+ /* change current window to the new window */
+ gui_current_window = window;
+
+ window->unread_data = 0;
+}
+
+/*
+ * gui_switch_to_previous_window: switch to previous window
+ */
+
+void
+gui_switch_to_previous_window ()
+{
+ /* if only one windows then return */
+ if (gui_windows == last_gui_window)
+ return;
+
+ if (gui_current_window->prev_window)
+ gui_switch_to_window (gui_current_window->prev_window);
+ else
+ gui_switch_to_window (last_gui_window);
+ gui_redraw_window (gui_current_window);
+}
+
+/*
+ * gui_switch_to_next_window: switch to next window
+ */
+
+void
+gui_switch_to_next_window ()
+{
+ /* if only one windows then return */
+ if (gui_windows == last_gui_window)
+ return;
+
+ if (gui_current_window->next_window)
+ gui_switch_to_window (gui_current_window->next_window);
+ else
+ gui_switch_to_window (gui_windows);
+ gui_redraw_window (gui_current_window);
+}
+
+/*
+ * gui_move_page_up: display previous page on window
+ */
+
+void
+gui_move_page_up ()
+{
+ if (!gui_current_window->first_line_displayed)
+ {
+ gui_current_window->sub_lines += gui_current_window->win_chat_height - 1;
+ gui_redraw_window_chat (gui_current_window);
+ gui_redraw_window_status (gui_current_window);
+ }
+}
+
+/*
+ * gui_move_page_down: display next page on window
+ */
+
+void
+gui_move_page_down ()
+{
+ if (gui_current_window->sub_lines > 0)
+ {
+ gui_current_window->sub_lines -= gui_current_window->win_chat_height - 1;
+ if (gui_current_window->sub_lines < 0)
+ gui_current_window->sub_lines = 0;
+ if (gui_current_window->sub_lines == 0)
+ gui_current_window->unread_data = 0;
+ gui_redraw_window_chat (gui_current_window);
+ gui_redraw_window_status (gui_current_window);
+ }
+}
+
+/*
+ * gui_window_new: create a new window
+ * (TODO: add coordinates and size, for splited windows)
+ */
+
+t_gui_window *
+gui_window_new (void *server, void *channel
+ /*int x, int y, int width, int height*/)
+{
+ t_gui_window *new_window;
+
+ if ((new_window = (t_gui_window *)(malloc (sizeof (t_gui_window)))))
+ {
+ /* assign server and channel to window */
+ SERVER(new_window) = server;
+ CHANNEL(new_window) = channel;
+ /* assign window to server and channel */
+ if (server && !channel)
+ SERVER(new_window)->window = new_window;
+ if (channel)
+ CHANNEL(new_window)->window = new_window;
+
+ gui_calculate_pos_size (new_window);
+
+ /* init windows */
+ new_window->win_title = NULL;
+ new_window->win_chat = NULL;
+ new_window->win_nick = NULL;
+ new_window->win_status = NULL;
+ new_window->win_input = NULL;
+
+ /* init lines */
+ new_window->lines = NULL;
+ new_window->last_line = NULL;
+ new_window->first_line_displayed = 1;
+ new_window->sub_lines = 0;
+ new_window->line_complete = 1;
+ new_window->unread_data = 0;
+
+ /* init input buffer */
+ new_window->input_buffer_alloc = INPUT_BUFFER_BLOCK_SIZE;
+ new_window->input_buffer = (char *) malloc (INPUT_BUFFER_BLOCK_SIZE);
+ new_window->input_buffer[0] = '\0';
+ new_window->input_buffer_size = 0;
+ new_window->input_buffer_pos = 0;
+ new_window->input_buffer_1st_display = 0;
+
+ /* init completion */
+ completion_init (&(new_window->completion));
+
+ /* init history */
+ new_window->history = NULL;
+ new_window->ptr_history = NULL;
+
+ /* switch to new window */
+ gui_switch_to_window (new_window);
+
+ /* add window to windows queue */
+ new_window->prev_window = last_gui_window;
+ if (gui_windows)
+ last_gui_window->next_window = new_window;
+ else
+ gui_windows = new_window;
+ last_gui_window = new_window;
+ new_window->next_window = NULL;
+
+ /* redraw whole screen */
+ gui_redraw_window (new_window);
+ }
+ else
+ return NULL;
+ return new_window;
+}
+
+/*
+ * gui_window_free: delete a window
+ */
+
+void
+gui_window_free (t_gui_window *window)
+{
+ t_gui_line *ptr_line;
+ t_gui_message *ptr_message;
+
+ /* TODO: manage splitted windows! */
+ if (window == gui_current_window)
+ gui_switch_to_previous_window ();
+
+ /* free lines and messages */
+ while (window->lines)
+ {
+ ptr_line = window->lines->next_line;
+ while (window->lines->messages)
+ {
+ ptr_message = window->lines->messages->next_message;
+ if (window->lines->messages->message)
+ free (window->lines->messages->message);
+ free (window->lines->messages);
+ window->lines->messages = ptr_message;
+ }
+ free (window->lines);
+ window->lines = ptr_line;
+ }
+ if (window->input_buffer)
+ free (window->input_buffer);
+
+ /* TODO: free completion struct */
+ /* there... */
+
+ /* remove window from windows list */
+ if (window->prev_window)
+ window->prev_window->next_window = window->next_window;
+ if (window->next_window)
+ window->next_window->prev_window = window->prev_window;
+ if (gui_windows == window)
+ gui_windows = window->next_window;
+ if (last_gui_window == window)
+ last_gui_window = window->prev_window;
+
+ free (window);
+}
+
+/*
+ * gui_resize_term_handler: called when term size is modified
+ */
+
+void
+gui_resize_term_handler ()
+{
+ t_gui_window *ptr_win;
+ int width, height;
+
+ endwin ();
+ refresh ();
+
+ getmaxyx (stdscr, height, width);
+
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ gui_calculate_pos_size (ptr_win);
+ // TODO: manage splitted windows!
+ if (ptr_win->win_title)
+ {
+ if (ptr_win->win_title)
+ delwin (ptr_win->win_title);
+ if (ptr_win->win_chat)
+ delwin (ptr_win->win_chat);
+ if (ptr_win->win_nick)
+ delwin (ptr_win->win_nick);
+ if (ptr_win->win_status)
+ delwin (ptr_win->win_status);
+ if (ptr_win->win_input)
+ delwin (ptr_win->win_input);
+ ptr_win->win_title = NULL;
+ ptr_win->win_chat = NULL;
+ ptr_win->win_nick = NULL;
+ ptr_win->win_status = NULL;
+ ptr_win->win_input = NULL;
+ gui_switch_to_window (ptr_win);
+ }
+ }
+}
+
+/*
+ * gui_init_colors: init GUI colors
+ */
+
+void
+gui_init_colors ()
+{
+ int i, color;
+
+ if (has_colors ())
+ {
+ start_color ();
+ use_default_colors ();
+
+ init_pair (COLOR_WIN_TITLE,
+ cfg_col_title & A_CHARTEXT, cfg_col_title_bg);
+ init_pair (COLOR_WIN_CHAT,
+ cfg_col_chat & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_TIME,
+ cfg_col_chat_time & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_TIME_SEP,
+ cfg_col_chat_time_sep & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_PREFIX1,
+ cfg_col_chat_prefix1 & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_PREFIX2,
+ cfg_col_chat_prefix2 & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_NICK,
+ cfg_col_chat_nick & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_HOST,
+ cfg_col_chat_host & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_CHANNEL,
+ cfg_col_chat_channel & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_DARK,
+ cfg_col_chat_dark & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_STATUS,
+ cfg_col_status & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_ACTIVE,
+ cfg_col_status_active & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_DATA_MSG,
+ cfg_col_status_data_msg & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_DATA_OTHER,
+ cfg_col_status_data_other & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_MORE,
+ cfg_col_status_more & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_INPUT,
+ cfg_col_input & A_CHARTEXT, cfg_col_input_bg);
+ init_pair (COLOR_WIN_INPUT_CHANNEL,
+ cfg_col_input_channel & A_CHARTEXT, cfg_col_input_bg);
+ init_pair (COLOR_WIN_INPUT_NICK,
+ cfg_col_input_nick & A_CHARTEXT, cfg_col_input_bg);
+ init_pair (COLOR_WIN_NICK,
+ cfg_col_nick & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_OP,
+ cfg_col_nick_op & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_HALFOP,
+ cfg_col_nick_halfop & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_VOICE,
+ cfg_col_nick_voice & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_SEP,
+ COLOR_BLACK & A_CHARTEXT, cfg_col_nick_sep);
+ init_pair (COLOR_WIN_NICK_SELF,
+ cfg_col_nick_self & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_PRIVATE,
+ cfg_col_nick_private & A_CHARTEXT, cfg_col_nick_bg);
+
+ for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++)
+ {
+ gui_assign_color (&color, nicks_colors[i]);
+ init_pair (COLOR_WIN_NICK_FIRST + i, color & A_CHARTEXT, cfg_col_chat_bg);
+ color_attr[COLOR_WIN_NICK_FIRST + i - 1] =
+ (color & A_BOLD) ? A_BOLD : 0;
+ }
+
+ color_attr[COLOR_WIN_TITLE - 1] = cfg_col_title & A_BOLD;
+ color_attr[COLOR_WIN_CHAT - 1] = cfg_col_chat & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_TIME - 1] = cfg_col_chat_time & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_TIME_SEP - 1] = cfg_col_chat_time_sep & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_PREFIX1 - 1] = cfg_col_chat_prefix1 & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_PREFIX2 - 1] = cfg_col_chat_prefix2 & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_NICK - 1] = cfg_col_chat_nick & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_HOST - 1] = cfg_col_chat_host & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_CHANNEL - 1] = cfg_col_chat_channel & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD;
+ color_attr[COLOR_WIN_STATUS - 1] = cfg_col_status & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_ACTIVE - 1] = cfg_col_status_active & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_DATA_MSG - 1] = cfg_col_status_data_msg & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_DATA_OTHER - 1] = cfg_col_status_data_other & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_MORE - 1] = cfg_col_status_more & A_BOLD;
+ color_attr[COLOR_WIN_INPUT - 1] = cfg_col_input & A_BOLD;
+ color_attr[COLOR_WIN_INPUT_CHANNEL - 1] = cfg_col_input_channel & A_BOLD;
+ color_attr[COLOR_WIN_INPUT_NICK - 1] = cfg_col_input_nick & A_BOLD;
+ color_attr[COLOR_WIN_NICK - 1] = cfg_col_nick & A_BOLD;
+ color_attr[COLOR_WIN_NICK_OP - 1] = cfg_col_nick_op & A_BOLD;
+ color_attr[COLOR_WIN_NICK_HALFOP - 1] = cfg_col_nick_halfop & A_BOLD;
+ color_attr[COLOR_WIN_NICK_VOICE - 1] = cfg_col_nick_voice & A_BOLD;
+ color_attr[COLOR_WIN_NICK_SEP - 1] = 0;
+ color_attr[COLOR_WIN_NICK_SELF - 1] = cfg_col_nick_self & A_BOLD;
+ color_attr[COLOR_WIN_NICK_PRIVATE - 1] = cfg_col_nick_private & A_BOLD;
+ }
+}
+
+/*
+ * gui_init: init GUI
+ */
+
+void
+gui_init ()
+{
+ initscr ();
+
+ curs_set (1);
+ keypad (stdscr, TRUE);
+ noecho ();
+ /*nonl();*/
+ nodelay (stdscr, TRUE);
+
+ gui_init_colors ();
+
+ /* create windows */
+ gui_current_window = gui_window_new (NULL, NULL /*0, 0, COLS, LINES*/);
+
+ signal (SIGWINCH, gui_resize_term_handler);
+
+ gui_ready = 1;
+}
+
+/*
+ * gui_end: GUI end
+ */
+
+void
+gui_end ()
+{
+ t_gui_window *ptr_win;
+
+ /* delete all windows */
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (ptr_win->win_title)
+ delwin (ptr_win->win_title);
+ if (ptr_win->win_chat)
+ delwin (ptr_win->win_chat);
+ if (ptr_win->win_nick)
+ delwin (ptr_win->win_nick);
+ if (ptr_win->win_status)
+ delwin (ptr_win->win_status);
+ if (ptr_win->win_input)
+ delwin (ptr_win->win_input);
+ /* TODO: free input buffer, lines, messages, completion */
+ }
+
+ /* end of ncurses output */
+ refresh ();
+ endwin ();
+}
+
+/*
+ * gui_new_line: create new line for a window
+ */
+
+t_gui_line *
+gui_new_line (t_gui_window *window)
+{
+ t_gui_line *new_line;
+
+ if ((new_line = (t_gui_line *) malloc (sizeof (struct t_gui_line))))
+ {
+ new_line->length = 0;
+ new_line->length_align = 0;
+ new_line->line_with_message = 0;
+ new_line->messages = NULL;
+ new_line->last_message = NULL;
+ if (!window->lines)
+ window->lines = new_line;
+ else
+ window->last_line->next_line = new_line;
+ new_line->prev_line = window->last_line;
+ new_line->next_line = NULL;
+ window->last_line = new_line;
+ }
+ else
+ {
+ wprintw (window->win_chat,
+ _("%s not enough memory for new line!\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+ return new_line;
+}
+
+/*
+ * gui_new_message: create a new message for last line of window
+ */
+
+t_gui_message *
+gui_new_message (t_gui_window *window)
+{
+ t_gui_message *new_message;
+
+ if ((new_message = (t_gui_message *) malloc (sizeof (struct t_gui_message))))
+ {
+ if (!window->last_line->messages)
+ window->last_line->messages = new_message;
+ else
+ window->last_line->last_message->next_message = new_message;
+ new_message->prev_message = window->last_line->last_message;
+ new_message->next_message = NULL;
+ window->last_line->last_message = new_message;
+ }
+ else
+ {
+ log_printf ("not enough memory!\n");
+ return NULL;
+ }
+ return new_message;
+}
+
+/*
+ * gui_add_message: add a message to a window
+ */
+
+void
+gui_add_message (t_gui_window *window, int type, int color, char *message)
+{
+ char *pos;
+ int length;
+
+ /* create new line if previous was ending by '\n' (or if 1st line) */
+ if (window->line_complete)
+ {
+ window->line_complete = 0;
+ if (!gui_new_line (window))
+ return;
+ }
+ if (!gui_new_message (window))
+ return;
+
+ window->last_line->last_message->type = type;
+ window->last_line->last_message->color = color;
+ pos = strchr (message, '\n');
+ if (pos)
+ {
+ pos[0] = '\0';
+ window->line_complete = 1;
+ }
+ window->last_line->last_message->message = strdup (message);
+ length = strlen (message);
+ window->last_line->length += length;
+ if (type == MSG_TYPE_MSG)
+ window->last_line->line_with_message = 1;
+ if ((type == MSG_TYPE_TIME) || (type == MSG_TYPE_NICK))
+ window->last_line->length_align += length;
+ if (pos)
+ {
+ pos[0] = '\n';
+ if ((window == gui_current_window) && (window->sub_lines == 0))
+ {
+ if ((window->win_chat_cursor_y
+ + gui_get_line_num_splits (window, window->last_line)) >
+ (window->win_chat_height - 1))
+ gui_redraw_window_chat (window);
+ else
+ gui_display_line (window, window->last_line, 1);
+ }
+ if ((window != gui_current_window) || (window->sub_lines > 0))
+ {
+ window->unread_data = 1 + window->last_line->line_with_message;
+ gui_redraw_window_status (gui_current_window);
+ }
+ }
+}
+
+/*
+ * gui_printf_color_type: display a message in a window
+ */
+
+void
+gui_printf_color_type (t_gui_window *window, int type, int color, char *message, ...)
+{
+ static char buffer[8192];
+ char timestamp[16];
+ char *pos;
+ va_list argptr;
+ static time_t seconds;
+ struct tm *date_tmp;
+
+ if (gui_ready)
+ {
+ if (color == -1)
+ color = COLOR_WIN_CHAT;
+
+ if (window == NULL)
+ {
+ if (SERVER(gui_current_window))
+ window = SERVER(gui_current_window)->window;
+ else
+ window = gui_current_window;
+ }
+
+ if (window == NULL)
+ {
+ log_printf ("gui_printf without window! this is a bug, please send to developers - thanks\n");
+ return;
+ }
+ }
+
+ va_start (argptr, message);
+ vsnprintf (buffer, sizeof (buffer) - 1, message, argptr);
+ va_end (argptr);
+
+ if (gui_ready)
+ {
+ seconds = time (NULL);
+ date_tmp = localtime (&seconds);
+
+ pos = buffer - 1;
+ while (pos)
+ {
+ /* TODO: read timestamp format from config! */
+ if ((!window->last_line) || (window->line_complete))
+ {
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "[");
+ sprintf (timestamp, "%02d", date_tmp->tm_hour);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":");
+ sprintf (timestamp, "%02d", date_tmp->tm_min);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":");
+ sprintf (timestamp, "%02d", date_tmp->tm_sec);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "] ");
+ }
+ gui_add_message (window, type, color, pos+1);
+ pos = strchr (pos+1, '\n');
+ if (pos)
+ if (pos[1] == '\0')
+ pos = NULL;
+ }
+
+ wrefresh (window->win_chat);
+ refresh ();
+ }
+ else
+ printf ("%s", buffer);
+}
diff --git a/src/gui/curses/gui-input.c b/src/gui/curses/gui-input.c
new file mode 100644
index 000000000..2717d3dab
--- /dev/null
+++ b/src/gui/curses/gui-input.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-input: user input functions for Curses GUI */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <curses.h>
+
+#include "../../weechat.h"
+#include "../gui.h"
+#include "../../config.h"
+#include "../../command.h"
+#include "../../irc/irc.h"
+
+
+/*
+ * gui_optimize_input_buffer_size: optimize input buffer size by adding
+ * or deleting data block (predefined size)
+ */
+
+void
+gui_optimize_input_buffer_size (t_gui_window *window)
+{
+ int optimal_size;
+
+ optimal_size = ((window->input_buffer_size / INPUT_BUFFER_BLOCK_SIZE) *
+ INPUT_BUFFER_BLOCK_SIZE) + INPUT_BUFFER_BLOCK_SIZE;
+ if (window->input_buffer_alloc != optimal_size)
+ {
+ window->input_buffer_alloc = optimal_size;
+ window->input_buffer = realloc (window->input_buffer, optimal_size);
+ }
+}
+
+/*
+ * gui_delete_previous_word: delete previous word
+ */
+
+void
+gui_delete_previous_word ()
+{
+ int i, j, num_char_deleted, num_char_end;
+
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ i = gui_current_window->input_buffer_pos - 1;
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i--;
+ if (i >= 0)
+ {
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] != ' '))
+ i--;
+ if (i >= 0)
+ {
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i--;
+ }
+ }
+
+ if (i >= 0)
+ i++;
+ i++;
+ num_char_deleted = gui_current_window->input_buffer_pos - i;
+ num_char_end = gui_current_window->input_buffer_size -
+ gui_current_window->input_buffer_pos;
+
+ for (j = 0; j < num_char_end; j++)
+ gui_current_window->input_buffer[i + j] =
+ gui_current_window->input_buffer[gui_current_window->input_buffer_pos + j];
+
+ gui_current_window->input_buffer_size -= num_char_deleted;
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ gui_current_window->input_buffer_pos = i;
+ gui_draw_window_input (gui_current_window);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->completion.position = -1;
+ }
+}
+
+/*
+ * gui_move_previous_word: move to beginning of previous word
+ */
+
+void
+gui_move_previous_word ()
+{
+ int i;
+
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ i = gui_current_window->input_buffer_pos - 1;
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i--;
+ if (i < 0)
+ gui_current_window->input_buffer_pos = 0;
+ else
+ {
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] != ' '))
+ i--;
+ gui_current_window->input_buffer_pos = i + 1;
+ }
+ gui_draw_window_input (gui_current_window);
+ }
+}
+
+/*
+ * gui_move_next_word: move to the end of next
+ */
+
+void
+gui_move_next_word ()
+{
+ int i;
+
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size + 1)
+ {
+ i = gui_current_window->input_buffer_pos;
+ while ((i <= gui_current_window->input_buffer_size) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i++;
+ if (i > gui_current_window->input_buffer_size)
+ gui_current_window->input_buffer_pos = i - 1;
+ else
+ {
+ while ((i <= gui_current_window->input_buffer_size) &&
+ (gui_current_window->input_buffer[i] != ' '))
+ i++;
+ if (i > gui_current_window->input_buffer_size)
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ else
+ gui_current_window->input_buffer_pos = i;
+
+ }
+ gui_draw_window_input (gui_current_window);
+ }
+}
+
+/*
+ * gui_buffer_insert_string: insert a string into the input buffer
+ */
+
+void
+gui_buffer_insert_string (char *string, int pos)
+{
+ int i, start, end, length;
+
+ length = strlen (string);
+
+ /* increase buffer size */
+ gui_current_window->input_buffer_size += length;
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+
+ /* move end of string to the right */
+ start = pos + length;
+ end = gui_current_window->input_buffer_size - 1;
+ for (i = end; i >= start; i--)
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i - length];
+
+ /* insert new string */
+ strncpy (gui_current_window->input_buffer + pos, string, length);
+}
+
+/*
+ * gui_read_keyb: read keyboard line
+ */
+
+void
+gui_read_keyb ()
+{
+ int key, i;
+ t_gui_window *ptr_window;
+ char new_char[2];
+
+ key = getch ();
+ if (key != ERR)
+ {
+ switch (key)
+ {
+ /* resize event: do nothing */
+ case KEY_RESIZE:
+ gui_redraw_window (gui_current_window);
+ break;
+ case KEY_F(6):
+ gui_switch_to_previous_window ();
+ break;
+ /* next window */
+ case KEY_F(7):
+ gui_switch_to_next_window ();
+ break;
+ /* cursor up */
+ case KEY_UP:
+ if (gui_current_window->ptr_history)
+ {
+ gui_current_window->ptr_history =
+ gui_current_window->ptr_history->next_history;
+ if (!gui_current_window->ptr_history)
+ gui_current_window->ptr_history =
+ gui_current_window->history;
+ }
+ else
+ gui_current_window->ptr_history =
+ gui_current_window->history;
+ if (gui_current_window->ptr_history)
+ {
+ gui_current_window->input_buffer_size =
+ strlen (gui_current_window->ptr_history->text);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ strcpy (gui_current_window->input_buffer,
+ gui_current_window->ptr_history->text);
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* cursor down */
+ case KEY_DOWN:
+ if (gui_current_window->ptr_history)
+ {
+ gui_current_window->ptr_history =
+ gui_current_window->ptr_history->prev_history;
+ if (gui_current_window->ptr_history)
+ gui_current_window->input_buffer_size =
+ strlen (gui_current_window->ptr_history->text);
+ else
+ gui_current_window->input_buffer_size = 0;
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ if (gui_current_window->ptr_history)
+ strcpy (gui_current_window->input_buffer,
+ gui_current_window->ptr_history->text);
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* cursor left */
+ case KEY_LEFT:
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ gui_current_window->input_buffer_pos--;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* cursor right */
+ case KEY_RIGHT:
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size)
+ {
+ gui_current_window->input_buffer_pos++;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* home key */
+ case KEY_HOME:
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ gui_current_window->input_buffer_pos = 0;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* end key */
+ case KEY_END:
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size)
+ {
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* page up */
+ case KEY_PPAGE:
+ gui_move_page_up ();
+ break;
+ /* page down */
+ case KEY_NPAGE:
+ gui_move_page_down ();
+ break;
+ /* erase before cursor and move cursor to the left */
+ case 127:
+ case KEY_BACKSPACE:
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ i = gui_current_window->input_buffer_pos-1;
+ while (gui_current_window->input_buffer[i])
+ {
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i+1];
+ i++;
+ }
+ gui_current_window->input_buffer_size--;
+ gui_current_window->input_buffer_pos--;
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ gui_draw_window_input (gui_current_window);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->completion.position = -1;
+ }
+ break;
+ /* Control + Backspace */
+ case 0x08:
+ gui_delete_previous_word ();
+ break;
+ /* erase char under cursor */
+ case KEY_DC:
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size)
+ {
+ i = gui_current_window->input_buffer_pos;
+ while (gui_current_window->input_buffer[i])
+ {
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i+1];
+ i++;
+ }
+ gui_current_window->input_buffer_size--;
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ gui_draw_window_input (gui_current_window);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->completion.position = -1;
+ }
+ break;
+ /* Tab : completion */
+ case '\t':
+ completion_search (&(gui_current_window->completion),
+ CHANNEL(gui_current_window),
+ gui_current_window->input_buffer,
+ gui_current_window->input_buffer_size,
+ gui_current_window->input_buffer_pos);
+ if (gui_current_window->completion.word_found)
+ {
+ // replace word with new completed word into input buffer
+ gui_current_window->input_buffer_size +=
+ gui_current_window->completion.diff_size;
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+
+ if (gui_current_window->completion.diff_size > 0)
+ {
+ for (i = gui_current_window->input_buffer_size - 1;
+ i >= gui_current_window->completion.position_replace +
+ (int)strlen (gui_current_window->completion.word_found); i--)
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i -
+ gui_current_window->completion.diff_size];
+ }
+ else
+ {
+ for (i = gui_current_window->completion.position_replace +
+ strlen (gui_current_window->completion.word_found);
+ i < gui_current_window->input_buffer_size; i++)
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i -
+ gui_current_window->completion.diff_size];
+ }
+
+ strncpy (gui_current_window->input_buffer + gui_current_window->completion.position_replace,
+ gui_current_window->completion.word_found,
+ strlen (gui_current_window->completion.word_found));
+ gui_current_window->input_buffer_pos =
+ gui_current_window->completion.position_replace +
+ strlen (gui_current_window->completion.word_found);
+ gui_current_window->completion.position =
+ gui_current_window->input_buffer_pos;
+
+ /* add space or completor to the end of completion, if needed */
+ if (gui_current_window->completion.base_word[0] == '/')
+ {
+ if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ')
+ gui_buffer_insert_string (" ",
+ gui_current_window->input_buffer_pos);
+ gui_current_window->completion.position++;
+ gui_current_window->input_buffer_pos++;
+ }
+ else
+ {
+ if (gui_current_window->completion.base_word_pos == 0)
+ {
+ if (strncmp (gui_current_window->input_buffer + gui_current_window->input_buffer_pos,
+ cfg_look_completor, strlen (cfg_look_completor)) != 0)
+ gui_buffer_insert_string (cfg_look_completor,
+ gui_current_window->input_buffer_pos);
+ gui_current_window->completion.position += strlen (cfg_look_completor);
+ gui_current_window->input_buffer_pos += strlen (cfg_look_completor);
+ if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ')
+ gui_buffer_insert_string (" ",
+ gui_current_window->input_buffer_pos);
+ gui_current_window->completion.position++;
+ gui_current_window->input_buffer_pos++;
+ }
+ }
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* escape code (for control-key) */
+ case KEY_ESCAPE:
+ if ((key = getch()) != ERR)
+ {
+ switch (key)
+ {
+ case KEY_LEFT:
+ gui_switch_to_previous_window ();
+ break;
+ case KEY_RIGHT:
+ gui_switch_to_next_window ();
+ break;
+ case 79:
+ /* TODO: replace 79 by constant name! */
+ if (key == 79)
+ {
+ if ((key = getch()) != ERR)
+ {
+ switch (key)
+ {
+ /* Control + Right */
+ case 99:
+ gui_move_next_word ();
+ break;
+ /* Control + Left */
+ case 100:
+ gui_move_previous_word ();
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ /* send command/message */
+ case '\n':
+ if (gui_current_window->input_buffer_size > 0)
+ {
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ history_add (gui_current_window, gui_current_window->input_buffer);
+ gui_current_window->input_buffer_size = 0;
+ gui_current_window->input_buffer_pos = 0;
+ gui_current_window->input_buffer_1st_display = 0;
+ gui_current_window->completion.position = -1;
+ gui_current_window->ptr_history = NULL;
+ ptr_window = gui_current_window;
+ user_command (SERVER(gui_current_window),
+ gui_current_window->input_buffer);
+ if (ptr_window == gui_current_window)
+ gui_draw_window_input (ptr_window);
+ if (ptr_window)
+ ptr_window->input_buffer[0] = '\0';
+ }
+ break;
+ /* other key => add to input buffer */
+ default:
+ /*gui_printf (gui_current_window,
+ "[Debug] key pressed = %d, as octal: %o\n", key, key);*/
+ new_char[0] = key;
+ new_char[1] = '\0';
+ gui_buffer_insert_string (new_char,
+ gui_current_window->input_buffer_pos);
+ gui_current_window->input_buffer_pos++;
+ gui_draw_window_input (gui_current_window);
+ gui_current_window->completion.position = -1;
+ break;
+ }
+ }
+}
+
+/*
+ * gui_main_loop: main loop for WeeChat with ncurses GUI
+ */
+
+void
+gui_main_loop ()
+{
+ fd_set read_fd;
+ static struct timeval timeout;
+ t_irc_server *ptr_server;
+
+ quit_weechat = 0;
+ while (!quit_weechat)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ FD_ZERO (&read_fd);
+ FD_SET (STDIN_FILENO, &read_fd);
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->sock4 >= 0)
+ FD_SET (ptr_server->sock4, &read_fd);
+ }
+ if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout))
+ {
+ if (FD_ISSET (STDIN_FILENO, &read_fd))
+ {
+ gui_read_keyb ();
+ }
+ else
+ {
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if ((ptr_server->sock4 >= 0) &&
+ (FD_ISSET (ptr_server->sock4, &read_fd)))
+ server_recv (ptr_server);
+ }
+ }
+ }
+ }
+}
diff --git a/src/gui/gtk/Makefile b/src/gui/gtk/Makefile
new file mode 100644
index 000000000..6d2de6eba
--- /dev/null
+++ b/src/gui/gtk/Makefile
@@ -0,0 +1,37 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_GTK
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \
+ ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h
diff --git a/src/gui/gtk/gui-gtk.c b/src/gui/gtk/gui-gtk.c
new file mode 100644
index 000000000..8e9aa5db3
--- /dev/null
+++ b/src/gui/gtk/gui-gtk.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-gtk.c: Gtk+ GUI for WeeChat */
+
+
+/* ***** Gtk+ GUI for WeeChat, NOT developed! ***** */
diff --git a/src/gui/gtk/gui-gtk.h b/src/gui/gtk/gui-gtk.h
new file mode 100644
index 000000000..889f75e60
--- /dev/null
+++ b/src/gui/gtk/gui-gtk.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_GTK_H
+#define __WEECHAT_GUI_GTK_H 1
+
+#endif /* gui-gtk.h */
diff --git a/src/gui/gui.h b/src/gui/gui.h
new file mode 100644
index 000000000..d8e3aca99
--- /dev/null
+++ b/src/gui/gui.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_H
+#define __WEECHAT_GUI_H 1
+
+#ifdef WEE_CURSES
+#include <curses.h>
+#endif
+
+#include "../completion.h"
+#include "../history.h"
+
+#ifdef WEE_CURSES
+#define KEY_ESCAPE 27
+#endif
+
+#define INPUT_BUFFER_BLOCK_SIZE 256
+
+#define NUM_COLORS 35
+#define COLOR_WIN_TITLE 1
+#define COLOR_WIN_CHAT 2
+#define COLOR_WIN_CHAT_TIME 3
+#define COLOR_WIN_CHAT_TIME_SEP 4
+#define COLOR_WIN_CHAT_PREFIX1 5
+#define COLOR_WIN_CHAT_PREFIX2 6
+#define COLOR_WIN_CHAT_NICK 7
+#define COLOR_WIN_CHAT_HOST 8
+#define COLOR_WIN_CHAT_CHANNEL 9
+#define COLOR_WIN_CHAT_DARK 10
+#define COLOR_WIN_STATUS 11
+#define COLOR_WIN_STATUS_ACTIVE 12
+#define COLOR_WIN_STATUS_DATA_MSG 13
+#define COLOR_WIN_STATUS_DATA_OTHER 14
+#define COLOR_WIN_STATUS_MORE 15
+#define COLOR_WIN_INPUT 16
+#define COLOR_WIN_INPUT_CHANNEL 17
+#define COLOR_WIN_INPUT_NICK 18
+#define COLOR_WIN_NICK 19
+#define COLOR_WIN_NICK_OP 20
+#define COLOR_WIN_NICK_HALFOP 21
+#define COLOR_WIN_NICK_VOICE 22
+#define COLOR_WIN_NICK_SEP 23
+#define COLOR_WIN_NICK_SELF 24
+#define COLOR_WIN_NICK_PRIVATE 25
+#define COLOR_WIN_NICK_FIRST 26
+#define COLOR_WIN_NICK_LAST 35
+#define COLOR_WIN_NICK_NUMBER (COLOR_WIN_NICK_LAST - COLOR_WIN_NICK_FIRST + 1)
+
+#define SERVER(window) ((t_irc_server *)(window->server))
+#define CHANNEL(window) ((t_irc_channel *)(window->channel))
+
+#define WIN_IS_SERVER(window) (SERVER(window) && !CHANNEL(window))
+#define WIN_IS_CHANNEL(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_CHANNEL))
+#define WIN_IS_PRIVATE(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_PRIVATE))
+
+#define MSG_TYPE_TIME 0
+#define MSG_TYPE_NICK 1
+#define MSG_TYPE_INFO 2
+#define MSG_TYPE_MSG 3
+
+#define gui_printf_color(window, color, fmt, argz...) \
+ gui_printf_color_type(window, MSG_TYPE_INFO, color, fmt, ##argz)
+
+#define gui_printf(window, fmt, argz...) \
+ gui_printf_color_type(window, MSG_TYPE_INFO, -1, fmt, ##argz)
+
+typedef struct t_gui_message t_gui_message;
+
+struct t_gui_message
+{
+ int type; /* type of message (time, nick, other) */
+ int color; /* color of message */
+ char *message; /* message content */
+ t_gui_message *prev_message; /* link to previous message for line */
+ t_gui_message *next_message; /* link to next message for line */
+};
+
+typedef struct t_gui_line t_gui_line;
+
+struct t_gui_line
+{
+ int length; /* length of the line (in char) */
+ int length_align; /* alignment length (time or time/nick) */
+ int line_with_message; /* line contains a message from a user? */
+ t_gui_message *messages; /* messages for the line */
+ t_gui_message *last_message; /* last message of the line */
+ t_gui_line *prev_line; /* link to previous line */
+ t_gui_line *next_line; /* link to next line */
+};
+
+typedef struct t_gui_color t_gui_color;
+
+struct t_gui_color
+{
+ char *name;
+ int color;
+};
+
+typedef struct t_gui_window t_gui_window;
+
+struct t_gui_window
+{
+ /* server/channel */
+ void *server; /* window's server */
+ void *channel; /* window's channel */
+
+ /* global position & size */
+ int win_x, win_y; /* position of window */
+ int win_width, win_height; /* window geometry */
+
+ /* chat window settings */
+ int win_chat_x, win_chat_y; /* chat window position */
+ int win_chat_width; /* width of chat window */
+ int win_chat_height; /* height of chat window */
+ int win_chat_cursor_x; /* position of cursor in chat window */
+ int win_chat_cursor_y; /* position of cursor in chat window */
+
+ /* nicklist window settings */
+ int win_nick_x, win_nick_y; /* chat window position */
+ int win_nick_width; /* width of chat window */
+ int win_nick_height; /* height of chat window */
+
+ /* windows */
+ #ifdef WEE_CURSES
+ WINDOW *win_title; /* title window */
+ WINDOW *win_chat; /* chat window (exemple: channel) */
+ WINDOW *win_nick; /* nick window */
+ WINDOW *win_status; /* status window */
+ WINDOW *win_input; /* input window */
+ #endif
+ #ifdef WEE_GTK
+ /* TODO: declare Gtk+ window */
+ #endif
+ #ifdef WEE_QT
+ /* TODO: declare Qt window */
+ #endif
+
+ /* chat content (lines, line is composed by many messages) */
+ t_gui_line *lines; /* lines of chat window */
+ t_gui_line *last_line; /* last line of chat window */
+ int first_line_displayed; /* = 1 if first line is displayed */
+ int sub_lines; /* if > 0 then do not display until end */
+ int line_complete; /* current line complete ? (\n ending) */
+ int unread_data; /* highlight windows with unread data */
+
+ /* inupt buffer */
+ char *input_buffer; /* input buffer */
+ int input_buffer_alloc; /* input buffer: allocated size in mem */
+ int input_buffer_size; /* buffer size (user input length) */
+ int input_buffer_pos; /* position into buffer */
+ int input_buffer_1st_display; /* first char displayed on screen */
+
+ /* completion */
+ t_completion completion; /* for cmds/nicks completion */
+
+ /* history */
+ t_history *history; /* commands history */
+ t_history *ptr_history; /* current command in history */
+
+ /* link to next window */
+ t_gui_window *prev_window; /* link to previous window */
+ t_gui_window *next_window; /* link to next window */
+};
+
+/* variables */
+
+extern int gui_ready;
+extern t_gui_window *gui_windows;
+extern t_gui_window *gui_current_window;
+
+/* prototypes */
+
+extern int gui_assign_color (int *, char *);
+extern int gui_get_color_by_name (char *);
+extern char *gui_get_color_by_value (int);
+
+extern void gui_draw_window_title (t_gui_window *);
+extern void gui_redraw_window_title (t_gui_window *);
+extern void gui_draw_window_chat (t_gui_window *);
+extern void gui_redraw_window_chat (t_gui_window *);
+extern void gui_draw_window_nick (t_gui_window *);
+extern void gui_redraw_window_nick (t_gui_window *);
+extern void gui_draw_window_status (t_gui_window *);
+extern void gui_redraw_window_status (t_gui_window *);
+extern void gui_draw_window_input (t_gui_window *);
+extern void gui_redraw_window_input (t_gui_window *);
+extern void gui_redraw_window (t_gui_window *);
+
+extern void gui_window_clear (t_gui_window *);
+extern void gui_window_clear_all ();
+
+extern void gui_switch_to_window (t_gui_window *);
+extern void gui_switch_to_previous_window ();
+extern void gui_switch_to_next_window ();
+
+extern void gui_move_page_up ();
+extern void gui_move_page_down ();
+
+extern void gui_init ();
+/* TODO: add coordinates and size */
+extern t_gui_window *gui_window_new (void *, void * /*int, int, int, int*/);
+extern void gui_window_free (t_gui_window *);
+extern void gui_end ();
+extern void gui_printf_color_type (t_gui_window *, int, int, char *, ...);
+extern void gui_display_nick (t_gui_window *, void *, int, int, int, int);
+
+extern void gui_main_loop ();
+
+#endif /* gui.h */
diff --git a/src/gui/qt/Makefile b/src/gui/qt/Makefile
new file mode 100644
index 000000000..f0695d3a3
--- /dev/null
+++ b/src/gui/qt/Makefile
@@ -0,0 +1,37 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_QT
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \
+ ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h
diff --git a/src/gui/qt/gui-qt.c b/src/gui/qt/gui-qt.c
new file mode 100644
index 000000000..e8dffab14
--- /dev/null
+++ b/src/gui/qt/gui-qt.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-qt.c: Qt GUI for WeeChat */
+
+
+/* ***** Qt GUI for WeeChat, NOT developed! ***** */
diff --git a/src/gui/qt/gui-qt.h b/src/gui/qt/gui-qt.h
new file mode 100644
index 000000000..b07167d88
--- /dev/null
+++ b/src/gui/qt/gui-qt.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_QT_H
+#define __WEECHAT_GUI_QT_H 1
+
+#endif /* gui-qt.h */
diff --git a/src/gui/text/Makefile b/src/gui/text/Makefile
new file mode 100644
index 000000000..538d760a3
--- /dev/null
+++ b/src/gui/text/Makefile
@@ -0,0 +1,37 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_TEXT
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \
+ ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h
diff --git a/src/gui/text/gui-text.c b/src/gui/text/gui-text.c
new file mode 100644
index 000000000..7121e11e5
--- /dev/null
+++ b/src/gui/text/gui-text.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-text.c: text GUI - display functions */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "weechat.h"
+#include "gui-text.h"
+#include "command.h"
+#include "irc.h"
+
+
+/*
+ * gui_init: init GUI
+ */
+
+void
+gui_init ()
+{
+}
+
+
+/*
+ * gui_init_irc_window: allocates a window for a channel or server
+ */
+
+void
+gui_init_irc_window (t_irc_window * window)
+{
+ /* no window in text GUI */
+ window->text = NULL;
+ window->window = NULL;
+}
+
+
+/*
+ * gui_free_irc_window: free a GUI window
+ */
+
+void
+gui_free_irc_window (t_irc_window * window)
+{
+ /* no window in text GUI */
+}
+
+
+/*
+ * gui_end: GUI end
+ */
+
+void
+gui_end ()
+{
+}
+
+
+/*
+ * read_keyb: read keyboard line
+ */
+
+void
+read_keyb ()
+{
+ int num_read;
+ static char buffer[4096];
+ static int pos_buffer = 0;
+ char buffer_tmp[1024];
+ int pos_buffer_tmp;
+
+ num_read = read (STDIN_FILENO, buffer_tmp, sizeof (buffer_tmp) - 1);
+ pos_buffer_tmp = 0;
+ while (pos_buffer_tmp < num_read)
+ {
+ switch (buffer_tmp[pos_buffer_tmp])
+ {
+ case '\r':
+ break;
+ case '\n':
+ buffer[pos_buffer] = '\0';
+ pos_buffer = 0;
+ user_command (buffer);
+ break;
+ default:
+ buffer[pos_buffer] = buffer_tmp[pos_buffer_tmp];
+ if (pos_buffer < (int) (sizeof (buffer) - 2))
+ pos_buffer++;
+ }
+ pos_buffer_tmp++;
+ }
+}
+
+
+/*
+ * gui_main_loop: main loop for WeeChat with text GUI
+ */
+
+void
+gui_main_loop ()
+{
+ struct timeval timeout;
+ fd_set read_fd;
+ t_irc_server *ptr_server;
+
+ quit_weechat = 0;
+ while (!quit_weechat)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ FD_ZERO (&read_fd);
+ FD_SET (STDIN_FILENO, &read_fd);
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ FD_SET (ptr_server->sock4, &read_fd);
+ }
+ select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout);
+ if (FD_ISSET (STDIN_FILENO, &read_fd))
+ {
+ read_keyb ();
+ }
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (FD_ISSET (ptr_server->sock4, &read_fd))
+ recv_from_server (ptr_server);
+ }
+ }
+}
+
+
+/*
+ * gui_display_message: display a message on the screen
+ */
+
+void
+gui_display_message (char *message)
+{
+ printf ("%s\n", message);
+}
diff --git a/src/gui/text/gui-text.h b/src/gui/text/gui-text.h
new file mode 100644
index 000000000..2e62d1a55
--- /dev/null
+++ b/src/gui/text/gui-text.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_TEXT_H
+#define __WEECHAT_GUI_TEXT_H 1
+
+#endif /* gui-text.h */
diff --git a/src/history.c b/src/history.c
new file mode 100644
index 000000000..9e13e6935
--- /dev/null
+++ b/src/history.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* history.c: memorize and call again commands or text */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "history.h"
+#include "gui/gui.h"
+
+
+t_history *history_general = NULL;
+t_history *history_general_ptr = NULL;
+
+
+/*
+ * history_add: add a text/command to history
+ */
+
+void
+history_add (void *window, char *string)
+{
+ t_history *new_history;
+
+ new_history = (t_history *)malloc (sizeof (t_history));
+ if (new_history)
+ {
+ new_history->text = strdup (string);
+
+ /* add history to general history */
+ if (history_general)
+ history_general->prev_history = new_history;
+ new_history->next_history = history_general;
+ new_history->prev_history = NULL;
+ history_general = new_history;
+
+ /* add history to local history */
+ if (((t_gui_window *)(window))->history)
+ ((t_gui_window *)(window))->history->prev_history = new_history;
+ new_history->next_history = ((t_gui_window *)(window))->history;
+ new_history->prev_history = NULL;
+ ((t_gui_window *)window)->history = new_history;
+ }
+}
diff --git a/src/history.h b/src/history.h
new file mode 100644
index 000000000..946f2e792
--- /dev/null
+++ b/src/history.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_HISTORY_H
+#define __WEECHAT_HISTORY_H 1
+
+typedef struct t_history t_history;
+
+struct t_history
+{
+ char *text; /* text or command (as entered by user) */
+ t_history *next_history; /* link to next text/command */
+ t_history *prev_history; /* link to previous text/command */
+};
+
+extern void history_add (void *, char *);
+
+#endif /* history.h */
diff --git a/src/irc/Makefile b/src/irc/Makefile
new file mode 100644
index 000000000..d22617bda
--- /dev/null
+++ b/src/irc/Makefile
@@ -0,0 +1,44 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=irc.a
+OBJS=irc-commands.o irc-display.o irc-server.o irc-channel.o irc-nick.o
+DEFINES=WEE_CURSES
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+irc-channel.o: irc-channel.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h
+irc-commands.o: irc-commands.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h ../command.h ../irc/irc.h ../config.h
+irc-display.o: irc-display.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h
+irc-nick.o: irc-nick.c ../weechat.h irc.h ../gui/gui.h ../completion.h \
+ ../history.h
+irc-server.o: irc-server.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h
diff --git a/src/irc/irc-channel.c b/src/irc/irc-channel.c
new file mode 100644
index 000000000..bdad12265
--- /dev/null
+++ b/src/irc/irc-channel.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-channel.c: manages a chat (channel or private chat) */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../weechat.h"
+#include "irc.h"
+
+
+t_irc_channel *current_channel = NULL;
+
+
+/*
+ * channel_new: allocate a new channel for a server and add it to the server queue
+ */
+
+t_irc_channel *
+channel_new (t_irc_server *server, int channel_type, char *channel_name)
+{
+ t_irc_channel *new_channel;
+
+ #if DEBUG >= 1
+ log_printf ("joining channel %s\n", channel_name);
+ #endif
+
+ /* alloc memory for new channel */
+ if ((new_channel = (t_irc_channel *) malloc (sizeof (t_irc_channel))) == NULL)
+ {
+ fprintf (stderr, _("%s cannot allocate new channel"), WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new channel */
+ new_channel->type = channel_type;
+ new_channel->name = strdup (channel_name);
+ new_channel->topic = NULL;
+ new_channel->nicks = NULL;
+ new_channel->last_nick = NULL;
+
+ /* add new channel to queue */
+ new_channel->prev_channel = server->last_channel;
+ new_channel->next_channel = NULL;
+ if (server->channels)
+ server->last_channel->next_channel = new_channel;
+ else
+ server->channels = new_channel;
+ server->last_channel = new_channel;
+
+ gui_window_new (server, new_channel);
+
+ /* all is ok, return address of new channel */
+ return new_channel;
+}
+
+/*
+ * channel_free: free a channel and remove it from channels queue
+ */
+
+void
+channel_free (t_irc_server *server, t_irc_channel *channel)
+{
+ t_irc_channel *new_channels;
+
+ /* remove channel from queue */
+ if (server->last_channel == channel)
+ server->last_channel = channel->prev_channel;
+ if (channel->prev_channel)
+ {
+ (channel->prev_channel)->next_channel = channel->next_channel;
+ new_channels = server->channels;
+ }
+ else
+ new_channels = channel->next_channel;
+
+ if (channel->next_channel)
+ (channel->next_channel)->prev_channel = channel->prev_channel;
+
+ /* free data */
+ if (channel->name)
+ free (channel->name);
+ if (channel->topic)
+ free (channel->topic);
+ nick_free_all (channel);
+ free (channel);
+ server->channels = new_channels;
+}
+
+/*
+ * channel_free_all: free all allocated channels
+ */
+
+void
+channel_free_all (t_irc_server *server)
+{
+ /* remove all channels for the server */
+ while (server->channels)
+ channel_free (server, server->channels);
+}
+
+/*
+ * channel_search: returns pointer on a channel with name
+ */
+
+t_irc_channel *
+channel_search (t_irc_server *server, char *channel_name)
+{
+ t_irc_channel *ptr_channel;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (strcasecmp (ptr_channel->name, channel_name) == 0)
+ return ptr_channel;
+ }
+ return NULL;
+}
+
+/*
+ * string_is_channel: returns 1 if string is channel
+ */
+
+int
+string_is_channel (char *string)
+{
+ char first_char[2];
+
+ first_char[0] = string[0];
+ first_char[1] = '\0';
+ return (strpbrk (first_char, CHANNEL_PREFIX)) ? 1 : 0;
+}
diff --git a/src/irc/irc-commands.c b/src/irc/irc-commands.c
new file mode 100644
index 000000000..2b4cf33ec
--- /dev/null
+++ b/src/irc/irc-commands.c
@@ -0,0 +1,3064 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-commands.c: implementation of IRC commands, according to
+ RFC 1459,2810,2811,2812 */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "../weechat.h"
+#include "irc.h"
+#include "../command.h"
+#include "../config.h"
+#include "../gui/gui.h"
+
+
+t_irc_command irc_commands[] =
+{ { "away", N_("toggle away status"),
+ N_("[-all] [message]"),
+ N_("-all: toggle away status on all connected servers\n"
+ "message: message for away (if no message is given, away status is removed)"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_away, NULL },
+ { "ctcp", N_("send a ctcp message"),
+ N_("nickname type"),
+ N_("nickname: user to send ctcp to\ntype: \"action\" or \"version\""),
+ 2, MAX_ARGS, 1, NULL, irc_cmd_send_ctcp, NULL },
+ { "deop", N_("removes channel operator status from nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_deop, NULL, NULL },
+ { "devoice", N_("removes voice from nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_devoice, NULL, NULL },
+ { "error", N_("error received from IRC server"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_error },
+ { "invite", N_("invite a nick on a channel"),
+ N_("nickname channel"),
+ N_("nickname: nick to invite\nchannel: channel to invite"),
+ 2, 2, 1, NULL, irc_cmd_send_invite, NULL },
+ { "join", N_("join a channel"),
+ N_("channel[,channel] [key[,key]]"),
+ N_("channel: channel name to join\nkey: key to join the channel"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_join, irc_cmd_recv_join },
+ { "kick", N_("forcibly remove a user from a channel"),
+ N_("[channel] nickname [comment]"),
+ N_("channel: channel where user is\nnickname: nickname to kick\ncomment: comment for kick"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_kick, irc_cmd_recv_kick },
+ { "kill", N_("close client-server connection"),
+ N_("nickname comment"),
+ N_("nickname: nickname\ncomment: comment for kill"),
+ 2, MAX_ARGS, 1, NULL, irc_cmd_send_kill, NULL },
+ { "list", N_("list channels and their topic"),
+ N_("[channel[,channel] [server]]"),
+ N_("channel: channel to list\nserver: server name"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_list, NULL },
+ { "me", N_("send a ctcp action to the current channel"),
+ N_("message"),
+ N_("message: message to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_me, NULL },
+ { "mode", N_("change channel or user mode"),
+ N_("{ channel {[+|-]|o|p|s|i|t|n|b|v} [limit] [user] [ban mask] } | "
+ "{ nickname {[+|-]|i|w|s|o}"),
+ N_("channel modes:\n"
+ " channel: channel name to modify\n"
+ " o: give/take channel operator privileges\n"
+ " p: private channel flag\n"
+ " s: secret channel flag\n"
+ " i: invite-only channel flag\n"
+ " t: topic settable by channel operator only flag\n"
+ " n: no messages to channel from clients on the outside\n"
+ " m: moderated channel\n"
+ " l: set the user limit to channel\n"
+ " b: set a ban mask to keep users out\n"
+ " v: give/take the ability to speak on a moderated channel\n"
+ " k: set a channel key (password)\n"
+ "user modes:\n"
+ " nickname: nickname to modify\n"
+ " i: mark a user as invisible\n"
+ " s: mark a user for receive server notices\n"
+ " w: user receives wallops\n"
+ " o: operator flag\n"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_mode, irc_cmd_recv_mode },
+ { "msg", N_("send message to a nick or channel"),
+ N_("receiver[,receiver] text"), N_("receiver: nick or channel (may be mask)"
+ "\ntext: text to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_msg, NULL },
+ { "names", N_("list nicknames on channels"),
+ N_("[channel[,channel]]"), N_("channel: channel name"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_names, NULL },
+ { "nick", N_("change current nickname"),
+ N_("nickname"), N_("nickname: new nickname for current IRC server"),
+ 1, 1, 1, irc_cmd_send_nick, NULL, irc_cmd_recv_nick },
+ { "notice", N_("send notice message to user"),
+ N_("nickname text"), N_("nickname: user to send notice to\ntext: text to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_notice, irc_cmd_recv_notice },
+ { "op", N_("gives channel operator status to nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_op, NULL, NULL },
+ { "oper", N_("get operator privileges"),
+ N_("user password"),
+ N_("user/password: used to get privileges on current IRC server"),
+ 2, 2, 1, irc_cmd_send_oper, NULL, NULL },
+ { "part", N_("leave a channel"),
+ N_("[channel[,channel]]"), N_("channel: channel name to join"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_part, irc_cmd_recv_part },
+ { "ping", N_("ping server"),
+ N_("server1 [server2]"),
+ N_("server1: server to ping\nserver2: forward ping to this server"),
+ 1, 2, 1, irc_cmd_send_ping, NULL, irc_cmd_recv_ping },
+ { "pong", N_("answer to a ping message"),
+ N_("daemon [daemon2]"), N_("daemon: daemon who has responded to Ping message\n"
+ "daemon2: forward message to this daemon"),
+ 1, 2, 1, irc_cmd_send_pong, NULL, NULL },
+ { "privmsg", N_("message received"),
+ "", "",
+ 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_privmsg },
+ { "quit", N_("close all connections & quit " WEECHAT_NAME),
+ N_("[quit_message]"),
+ N_("quit_message: quit message (displayed to other users)"),
+ 0, MAX_ARGS, 0, NULL, irc_cmd_send_quit, irc_cmd_recv_quit },
+ { "quote", N_("send raw data to server without parsing"),
+ N_("data"),
+ N_("data: raw data to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_quote, NULL },
+ { "topic", N_("get/set channel topic"),
+ N_("[channel] [topic]"), N_("channel: channel name\ntopic: new topic for channel "
+ "(if topic is \"-delete\" then topic is deleted)"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_topic, irc_cmd_recv_topic },
+ { "version", N_("gives the version info of nick or server (current or specified)"),
+ N_("[server | nickname]"), N_("server: server name\nnickname: nickname"),
+ 0, 1, 1, NULL, irc_cmd_send_version, NULL },
+ { "voice", N_("gives voice to nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_voice, NULL, NULL },
+ { "whois", N_("query information about user(s)"),
+ N_("[server] nickname[,nickname]"), N_("server: server name\n"
+ "nickname: nickname (may be a mask)"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_whois, NULL },
+ { "001", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "002", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "003", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "004", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_004 },
+ { "005", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "250", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "251", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "252", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "253", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "254", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "255", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "256", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "257", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "258", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "259", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "260", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "261", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "262", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "263", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "264", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "265", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "266", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "267", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "268", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "269", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "301", N_("away message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_301 },
+ { "305", N_("unaway"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply },
+ { "306", N_("now away"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply },
+ { "311", N_("whois (user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_311 },
+ { "312", N_("whois (server)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_312 },
+ { "313", N_("whois (operator)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_313 },
+ { "317", N_("whois (idle)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_317 },
+ { "318", N_("whois (end)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_318 },
+ { "319", N_("whois (channels)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_319 },
+ { "320", N_("whois (identified user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_320 },
+ { "321", N_("/list start"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_321 },
+ { "322", N_("channel (for /list)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_322 },
+ { "323", N_("/list end"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_323 },
+ { "331", N_("no topic for channel"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_331 },
+ { "332", N_("topic of channel"),
+ N_("channel :topic"),
+ N_("channel: name of channel\ntopic: topic of the channel"),
+ 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_332 },
+ { "333", N_("infos about topic (nick & date changed)"),
+ "", "",
+ 0, 0, 1, NULL, NULL, irc_cmd_recv_333 },
+ { "351", N_("server version"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_351 },
+ { "353", N_("list of nicks on channel"),
+ N_("channel :[[@|+]nick ...]"),
+ N_("channel: name of channel\nnick: nick on the channel"),
+ 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_353 },
+ { "366", N_("end of /names list"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_366 },
+ { "371", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "372", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "373", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "374", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "375", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "376", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "401", N_("no such nick/channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "402", N_("no such server"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "403", N_("no such channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "404", N_("cannot send to channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "405", N_("too many channels"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "406", N_("was no such nick"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "406", N_("was no such nick"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "407", N_("was no such nick"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "409", N_("no origin"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "411", N_("no recipient"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "412", N_("no text to send"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "413", N_("no toplevel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "414", N_("wilcard in toplevel domain"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "421", N_("unknown command"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "422", N_("MOTD is missing"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "423", N_("no administrative info"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "424", N_("file error"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "431", N_("no nickname given"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "432", N_("erroneus nickname"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "433", N_("nickname already in use"),
+ "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_433 },
+ { "436", N_("nickname collision"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "441", N_("user not in channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "442", N_("not on channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "443", N_("user already on channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "444", N_("user not logged in"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "445", N_("summon has been disabled"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "446", N_("users has been disabled"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "451", N_("you are not registered"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "461", N_("not enough parameters"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "462", N_("you may not register"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "463", N_("your host isn't among the privileged"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "464", N_("password incorrect"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "465", N_("you are banned from this server"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "467", N_("channel key already set"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "471", N_("channel is already full"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "472", N_("unknown mode char to me"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "473", N_("cannot join channel (invite only)"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "474", N_("cannot join channel (banned from channel)"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "475", N_("cannot join channel (bad channel key)"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "481", N_("you're not an IRC operator"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "482", N_("you're not channel operator"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "483", N_("you can't kill a server!"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "491", N_("no O-lines for your host"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "501", N_("unknown mode flag"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "502", N_("can't change mode for other users"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { NULL, NULL, NULL, NULL, 0, 0, 1, NULL, NULL, NULL }
+};
+
+
+/*
+ * irc_recv_command: executes action when receiving IRC command
+ * returns: 0 = all ok, command executed
+ * -1 = command failed
+ * -2 = no command to execute
+ * -3 = command not found
+ */
+
+int
+irc_recv_command (t_irc_server *server,
+ char *host, char *command, char *arguments)
+{
+ int i, cmd_found;
+
+ #if DEBUG >= 2
+ gui_printf (server->window, "recv_irc_command: cmd=%s args=%s\n",
+ command, arguments);
+ #endif
+
+ if (command == NULL)
+ return -2;
+
+ /* looks for irc command */
+ cmd_found = -1;
+ for (i = 0; irc_commands[i].command_name; i++)
+ if (strcasecmp (irc_commands[i].command_name, command) == 0)
+ {
+ cmd_found = i;
+ break;
+ }
+
+ /* command not found */
+ if (cmd_found < 0)
+ return -3;
+
+ if (irc_commands[i].recv_function != NULL)
+ return (int) (irc_commands[i].recv_function) (server, host, arguments);
+
+ return 0;
+}
+
+/*
+ * irc_login: login to irc server
+ */
+
+void
+irc_login (t_irc_server *server)
+{
+ char hostname[128];
+
+ if ((server->password) && (server->password[0]))
+ server_sendf (server, "PASS %s\r\n", server->password);
+
+ gethostname (hostname, sizeof (hostname) - 1);
+ hostname[sizeof (hostname) - 1] = '\0';
+ if (!hostname[0])
+ strcpy (hostname, _("unknown"));
+ gui_printf (server->window,
+ _(WEECHAT_NAME ": using local hostname \"%s\"\n"),
+ hostname);
+ server_sendf (server,
+ "NICK %s\r\n"
+ "USER %s %s %s :%s\r\n",
+ server->nick, server->username, hostname, "servername",
+ server->realname);
+}
+
+/*
+ * irc_cmd_send_away: toggle away status
+ */
+
+int
+irc_cmd_send_away (t_irc_server *server, char *arguments)
+{
+ char *pos;
+ t_irc_server *ptr_server;
+
+ if (arguments && (strncmp (arguments, "-all", 4) == 0))
+ {
+ pos = arguments + 4;
+ while (pos[0] == ' ')
+ pos++;
+ if (!pos[0])
+ pos = NULL;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (server->is_connected)
+ {
+ if (pos)
+ server_sendf (ptr_server, "AWAY :%s\r\n", pos);
+ else
+ server_sendf (ptr_server, "AWAY\r\n");
+ }
+ }
+ }
+ else
+ {
+ if (arguments)
+ server_sendf (server, "AWAY :%s\r\n", arguments);
+ else
+ server_sendf (server, "AWAY\r\n");
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_ctcp: send a ctcp message
+ */
+
+int
+irc_cmd_send_ctcp (t_irc_server *server, char *arguments)
+{
+ char *pos, *pos2;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ }
+ else
+ pos2 = NULL;
+
+ if (strcasecmp (pos, "version") == 0)
+ {
+ if (pos2)
+ server_sendf (server, "PRIVMSG %s :\01VERSION %s\01\r\n",
+ arguments, pos2);
+ else
+ server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n",
+ arguments);
+ }
+ if (strcasecmp (pos, "action") == 0)
+ {
+ if (pos2)
+ server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n",
+ arguments, pos2);
+ else
+ server_sendf (server, "PRIVMSG %s :\01ACTION\01\r\n",
+ arguments);
+ }
+
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_deop: remove operator privileges from nickname(s)
+ */
+
+int
+irc_cmd_send_deop (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s -o %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ gui_printf (server->window,
+ _("%s \"deop\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_devoice: remove voice from nickname(s)
+ */
+
+int
+irc_cmd_send_devoice (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s -v %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"devoice\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_invite: invite a nick on a channel
+ */
+
+int
+irc_cmd_send_invite (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "INVITE %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_join: join a new channel
+ */
+
+int
+irc_cmd_send_join (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "JOIN %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_kick: forcibly remove a user from a channel
+ */
+
+int
+irc_cmd_send_kick (t_irc_server *server, char *arguments)
+{
+ if (string_is_channel (arguments))
+ server_sendf (server, "KICK %s\r\n", arguments);
+ else
+ {
+ if (WIN_IS_CHANNEL (gui_current_window))
+ {
+ server_sendf (server,
+ "KICK %s %s\r\n",
+ CHANNEL(gui_current_window)->name, arguments);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"kick\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_kill: close client-server connection
+ */
+
+int
+irc_cmd_send_kill (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "KILL %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_list: close client-server connection
+ */
+
+int
+irc_cmd_send_list (t_irc_server *server, char *arguments)
+{
+ if (arguments)
+ server_sendf (server, "LIST %s\r\n", arguments);
+ else
+ server_sendf (server, "LIST\r\n");
+ return 0;
+}
+
+/*
+ * irc_cmd_send_me: send a ctcp action to the current channel
+ */
+
+int
+irc_cmd_send_me (t_irc_server *server, char *arguments)
+{
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"me\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n",
+ CHANNEL(gui_current_window)->name, arguments);
+ irc_display_prefix (gui_current_window, PREFIX_ACTION_ME);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_NICK, "%s", server->nick);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, " %s\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_mode: change mode for channel/nickname
+ */
+
+int
+irc_cmd_send_mode (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "MODE %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_msg: send a message to a nick or channel
+ */
+
+int
+irc_cmd_send_msg (t_irc_server *server, char *arguments)
+{
+ char *pos, *pos_comma;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+
+ while (arguments && arguments[0])
+ {
+ pos_comma = strchr (arguments, ',');
+ if (pos_comma)
+ {
+ pos_comma[0] = '\0';
+ pos_comma++;
+ }
+ if (string_is_channel (arguments))
+ {
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ ptr_nick = nick_search (ptr_channel, server->nick);
+ if (ptr_nick)
+ {
+ irc_display_nick (ptr_channel->window, ptr_nick,
+ MSG_TYPE_NICK, 1, 1, 0);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ }
+ else
+ gui_printf (server->window,
+ _("%s nick not found for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ }
+ server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos);
+ }
+ else
+ {
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ ptr_channel = channel_new (server, CHAT_PRIVATE, arguments);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s cannot create new private window \"%s\"\n"),
+ WEECHAT_ERROR,
+ arguments);
+ return -1;
+ }
+ gui_redraw_window_title (ptr_channel->window);
+ }
+
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "<");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_NICK_SELF,
+ "%s", server->nick);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "> ");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos);
+ }
+ arguments = pos_comma;
+ }
+ }
+ else
+ gui_printf (server->window,
+ _("%s wrong number of args for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_names: list nicknames on channels
+ */
+
+int
+irc_cmd_send_names (t_irc_server *server, char *arguments)
+{
+ if (arguments)
+ server_sendf (server, "NAMES %s\r\n", arguments);
+ else
+ {
+ if (!WIN_IS_CHANNEL(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"names\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ else
+ server_sendf (server, "NAMES %s\r\n",
+ CHANNEL(gui_current_window)->name);
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_nick: change nickname
+ */
+
+int
+irc_cmd_send_nick (t_irc_server *server, int argc, char **argv)
+{
+ if (argc != 1)
+ return -1;
+ server_sendf (server, "NICK %s\r\n", argv[0]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_notice: send notice message
+ */
+
+int
+irc_cmd_send_notice (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "NOTICE %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_op: give operator privileges to nickname(s)
+ */
+
+int
+irc_cmd_send_op (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s +o %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"op\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_oper: get oper privileges
+ */
+
+int
+irc_cmd_send_oper (t_irc_server *server, int argc, char **argv)
+{
+ if (argc != 2)
+ return -1;
+ server_sendf (server, "OPER %s %s\r\n", argv[0], argv[1]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_part: leave a channel or close a private window
+ */
+
+int
+irc_cmd_send_part (t_irc_server *server, char *arguments)
+{
+ char *channel_name, *pos_args;
+ t_irc_channel *ptr_channel;
+
+ if (arguments)
+ {
+ if (string_is_channel (arguments))
+ {
+ channel_name = arguments;
+ pos_args = strchr (arguments, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ }
+ }
+ else
+ {
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"part\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ channel_name = CHANNEL(gui_current_window)->name;
+ pos_args = arguments;
+ }
+ }
+ else
+ {
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"part\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ if (WIN_IS_PRIVATE(gui_current_window))
+ {
+ ptr_channel = CHANNEL(gui_current_window);
+ gui_window_free (ptr_channel->window);
+ channel_free (server, ptr_channel);
+ gui_redraw_window_status (gui_current_window);
+ gui_redraw_window_input (gui_current_window);
+ return 0;
+ }
+ channel_name = CHANNEL(gui_current_window)->name;
+ pos_args = NULL;
+ }
+
+ if (pos_args)
+ server_sendf (server, "PART %s :%s\r\n", channel_name, pos_args);
+ else
+ server_sendf (server, "PART %s\r\n", channel_name);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_ping: ping a server
+ */
+
+int
+irc_cmd_send_ping (t_irc_server *server, int argc, char **argv)
+{
+ if (argc == 1)
+ server_sendf (server, "PING %s\r\n", argv[0]);
+ if (argc == 2)
+ server_sendf (server, "PING %s %s\r\n", argv[0],
+ argv[1]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_pong: send pong answer to a daemon
+ */
+
+int
+irc_cmd_send_pong (t_irc_server *server, int argc, char **argv)
+{
+ if (argc == 1)
+ server_sendf (server, "PONG %s\r\n", argv[0]);
+ if (argc == 2)
+ server_sendf (server, "PONG %s %s\r\n", argv[0],
+ argv[1]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_quit: disconnect from all servers and quit WeeChat
+ */
+
+int
+irc_cmd_send_quit (t_irc_server *server, char *arguments)
+{
+ if (server && server->is_connected)
+ {
+ if (arguments)
+ server_sendf (server, "QUIT :%s\r\n", arguments);
+ else
+ server_sendf (server, "QUIT\r\n");
+ }
+ quit_weechat = 1;
+ return 0;
+}
+
+/*
+ * irc_cmd_send_quote: send raw data to server
+ */
+
+int
+irc_cmd_send_quote (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "%s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_topic: get/set topic for a channel
+ */
+
+int
+irc_cmd_send_topic (t_irc_server *server, char *arguments)
+{
+ char *channel_name, *new_topic, *pos;
+
+ channel_name = NULL;
+ new_topic = NULL;
+
+ if (arguments)
+ {
+ if (string_is_channel (arguments))
+ {
+ channel_name = arguments;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ new_topic = (pos[0]) ? pos : NULL;
+ }
+ }
+ else
+ new_topic = arguments;
+ }
+
+ /* look for current channel if not specified */
+ if (!channel_name)
+ {
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"topic\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ channel_name = CHANNEL(gui_current_window)->name;
+ }
+
+ if (new_topic)
+ {
+ if (strcmp (new_topic, "-delete") == 0)
+ server_sendf (server, "TOPIC %s :\r\n", channel_name);
+ else
+ server_sendf (server, "TOPIC %s :%s\r\n", channel_name, new_topic);
+ }
+ else
+ server_sendf (server, "TOPIC %s\r\n", channel_name);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_version: gives the version info of nick or server (current or specified)
+ */
+
+int
+irc_cmd_send_version (t_irc_server *server, char *arguments)
+{
+ if (arguments)
+ {
+ if (WIN_IS_CHANNEL(gui_current_window) &&
+ nick_search (CHANNEL(gui_current_window), arguments))
+ server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n",
+ arguments);
+ else
+ server_sendf (server, "VERSION %s\r\n",
+ arguments);
+ }
+ else
+ {
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s, compiled on %s %s\n",
+ WEECHAT_NAME_AND_VERSION,
+ __DATE__, __TIME__);
+ server_sendf (server, "VERSION\r\n");
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_voice: give voice to nickname(s)
+ */
+
+int
+irc_cmd_send_voice (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s +v %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"voice\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_whois: query information about user(s)
+ */
+
+int
+irc_cmd_send_whois (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "WHOIS %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_error: error received from server
+ */
+
+int
+irc_cmd_recv_error (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ int first;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ if (strncmp (arguments, "Closing Link", 12) == 0)
+ {
+ server_disconnect (server);
+ return 0;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_ERROR);
+ first = 1;
+
+ while (pos && pos[0])
+ {
+ pos2 = strchr (pos, ' ');
+ if ((pos[0] == ':') || (!pos2))
+ {
+ if (pos[0] == ':')
+ pos++;
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ "%s%s\n", (first) ? "" : ": ", pos);
+ pos = NULL;
+ }
+ else
+ {
+ pos2[0] = '\0';
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s%s",
+ (first) ? "" : " ", pos);
+ first = 0;
+ pos = pos2 + 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_join: 'join' message received
+ */
+
+int
+irc_cmd_recv_join (t_irc_server *server, char *host, char *arguments)
+{
+ t_irc_channel *ptr_channel;
+ char *pos;
+
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ ptr_channel = channel_new (server, CHAT_CHANNEL, arguments);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s cannot create new channel \"%s\"\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+ }
+
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ irc_display_prefix (ptr_channel->window, PREFIX_JOIN);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK,
+ "%s ", host);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ "(");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_HOST,
+ "%s", pos + 1);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ ")");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _(" has joined "));
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s\n", arguments);
+ nick_new (ptr_channel, host, 0, 0, 0);
+ gui_redraw_window_nick (gui_current_window);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_kick: 'kick' message received
+ */
+
+int
+irc_cmd_recv_kick (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos_nick, *pos_comment;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+
+ pos_comment = strchr (pos_nick, ' ');
+ if (pos_comment)
+ {
+ pos_comment[0] = '\0';
+ pos_comment++;
+ while (pos_comment[0] == ' ')
+ pos_comment++;
+ if (pos_comment[0] == ':')
+ pos_comment++;
+ }
+
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"kick\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ irc_display_prefix (ptr_channel->window, PREFIX_PART);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK,
+ "%s", host);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _(" has kicked "));
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK,
+ "%s", pos_nick);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _(" from "));
+ if (pos_comment)
+ {
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s ", arguments);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ "(");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ "%s", pos_comment);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ ")\n");
+ }
+ else
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s\n", arguments);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s nick not found for \"kick\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ ptr_nick = nick_search (ptr_channel, pos_nick);
+ if (ptr_nick)
+ {
+ nick_free (ptr_channel, ptr_nick);
+ gui_redraw_window_nick (gui_current_window);
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_mode: 'mode' message received
+ */
+
+int
+irc_cmd_recv_mode (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2, *pos_parm;
+ char set_flag;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"mode\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ pos = strchr (arguments, ' ');
+ if (!pos)
+ {
+ gui_printf (server->window,
+ _("%s \"mode\" command received without channel or nickname\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+
+ pos_parm = strchr (pos, ' ');
+ if (pos_parm)
+ {
+ pos_parm[0] = '\0';
+ pos_parm++;
+ while (pos_parm[0] == ' ')
+ pos_parm++;
+ pos2 = strchr (pos_parm, ' ');
+ if (pos2)
+ pos2[0] = '\0';
+ }
+
+ set_flag = '+';
+
+ if (string_is_channel (arguments))
+ {
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ /* channel modes */
+ while (pos && pos[0])
+ {
+ switch (pos[0])
+ {
+ case '+':
+ set_flag = '+';
+ break;
+ case '-':
+ set_flag = '-';
+ break;
+ case 'b':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "b", host,
+ (set_flag == '+') ?
+ _("sets ban on") :
+ _("removes ban on"),
+ pos_parm);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'i':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "i", host,
+ (set_flag == '+') ?
+ _("sets invite-only channel flag") :
+ _("removes invite-only channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'l':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "l", host,
+ (set_flag == '+') ?
+ _("sets the user limit to") :
+ _("removes user limit"),
+ (set_flag == '+') ? pos_parm : NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'm':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "m", host,
+ (set_flag == '+') ?
+ _("sets moderated channel flag") :
+ _("removes moderated channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'o':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "o", host,
+ (set_flag == '+') ?
+ _("gives channel operator status to") :
+ _("removes channel operator status from"),
+ pos_parm);
+ ptr_nick = nick_search (ptr_channel, pos_parm);
+ if (ptr_nick)
+ {
+ ptr_nick->is_op = (set_flag == '+') ? 1 : 0;
+ nick_resort (ptr_channel, ptr_nick);
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ break;
+ /* TODO: remove this obsolete (?) channel flag? */
+ case 'p':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "p", host,
+ (set_flag == '+') ?
+ _("sets private channel flag") :
+ _("removes private channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 's':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "s", host,
+ (set_flag == '+') ?
+ _("sets secret channel flag") :
+ _("removes secret channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 't':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "t", host,
+ (set_flag == '+') ?
+ _("sets topic protection") :
+ _("removes topic protection"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'v':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "v", host,
+ (set_flag == '+') ?
+ _("gives voice to") :
+ _("removes voice from"),
+ pos_parm);
+
+ ptr_nick = nick_search (ptr_channel, pos_parm);
+ if (ptr_nick)
+ {
+ ptr_nick->has_voice = (set_flag == '+') ? 1 : 0;
+ nick_resort (ptr_channel, ptr_nick);
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ break;
+ }
+ pos++;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"mode\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ /* nickname modes */
+ gui_printf (server->window, "(TODO!) nickname modes: channel=%s, args=%s\n", arguments, pos);
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_nick: 'nick' message received
+ */
+
+int
+irc_cmd_recv_nick (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ int nick_is_me;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"nick\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ ptr_nick = nick_search (ptr_channel, host);
+ if (ptr_nick)
+ {
+ nick_is_me = (strcmp (ptr_nick->nick, server->nick) == 0);
+ nick_change (ptr_channel, ptr_nick, arguments);
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ if (nick_is_me)
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ _("You are "));
+ else
+ {
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK,
+ "%s", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, " is ");
+ }
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ _("now known as "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK,
+ "%s\n",
+ arguments);
+ if (ptr_channel->window->win_nick)
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ }
+
+ if (strcmp (server->nick, host) == 0)
+ {
+ free (server->nick);
+ server->nick = strdup (arguments);
+ }
+ gui_redraw_window_input (gui_current_window);
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_notice: 'notice' message received
+ */
+
+int
+irc_cmd_recv_notice (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+
+ if (host)
+ {
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s nickname not found for \"notice\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ irc_display_prefix (server->window, PREFIX_SERVER);
+ if (strncmp (pos, "\01VERSION", 8) == 0)
+ {
+ pos += 9;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ gui_printf_color (server->window, COLOR_WIN_CHAT, "CTCP ");
+ gui_printf_color (server->window, COLOR_WIN_CHAT_CHANNEL, "VERSION");
+ gui_printf_color (server->window, COLOR_WIN_CHAT, " reply from ");
+ gui_printf_color (server->window, COLOR_WIN_CHAT_NICK, "%s", host);
+ gui_printf_color (server->window, COLOR_WIN_CHAT, ": %s\n", pos);
+ }
+ else
+ gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_part: 'part' message received
+ */
+
+int
+irc_cmd_recv_part (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos_args;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (!host || !arguments)
+ {
+ gui_printf (server->window,
+ _("%s \"part\" command received without host or channel\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ pos_args = strchr (arguments, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ if (pos_args[0] == ':')
+ pos_args++;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ ptr_nick = nick_search (ptr_channel, host);
+ if (ptr_nick)
+ {
+ if (strcmp (ptr_nick->nick, server->nick) == 0)
+ {
+ /* part request was issued by local client */
+ gui_window_free (ptr_channel->window);
+ channel_free (server, ptr_channel);
+ gui_redraw_window_status (gui_current_window);
+ gui_redraw_window_input (gui_current_window);
+ }
+ else
+ {
+
+ /* remove nick from nick list and display message */
+ nick_free (ptr_channel, ptr_nick);
+ irc_display_prefix (ptr_channel->window, PREFIX_PART);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s ", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_HOST, "%s", pos+1);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _(" has left "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s", ptr_channel->name);
+ if (pos_args && pos_args[0])
+ {
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, " (");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, "%s", pos_args);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ }
+ gui_printf (ptr_channel->window, "\n");
+
+ /* redraw nick list if this is current window */
+ if (ptr_channel->window->win_nick)
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"part\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_ping: 'ping' command received
+ */
+
+int
+irc_cmd_recv_ping (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ (void)host;
+ pos = strrchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+ server_sendf (server, "PONG :%s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_privmsg: 'privmsg' command received
+ */
+
+int
+irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2, *host2;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"privmsg\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ {
+ pos[0] = '\0';
+ host2 = pos+1;
+ }
+ else
+ host2 = host;
+
+ /* receiver is a channel ? */
+ if (string_is_channel (arguments))
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ if (strncmp (pos, "\01ACTION ", 8) == 0)
+ {
+ pos += 8;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ irc_display_prefix (ptr_channel->window, PREFIX_ACTION_ME);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, " %s\n", pos);
+ }
+ else
+ {
+ ptr_nick = nick_search (ptr_channel, host);
+ if (ptr_nick)
+ {
+ irc_display_nick (ptr_channel->window, ptr_nick,
+ MSG_TYPE_NICK, 1, 1, 0);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s nick not found for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+
+ if (strcmp (pos, "\01VERSION\01") == 0)
+ server_sendf (server,
+ "NOTICE %s :\01VERSION "
+ WEECHAT_NAME " v"
+ WEECHAT_VERSION ", compiled on " __DATE__ "\01\r\n",
+ host);
+ else
+ {
+ /* private message received */
+ ptr_channel = channel_search (server, host);
+ if (!ptr_channel)
+ {
+ ptr_channel = channel_new (server, CHAT_PRIVATE, host);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s cannot create new private window \"%s\"\n"),
+ WEECHAT_ERROR, host);
+ return -1;
+ }
+ }
+ if (!ptr_channel->topic)
+ {
+ ptr_channel->topic = strdup (host2);
+ gui_redraw_window_title (ptr_channel->window);
+ }
+
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "<");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_NICK_PRIVATE,
+ "%s", host);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "> ");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot parse \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_quit: 'quit' command received
+ */
+
+int
+irc_cmd_recv_quit (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"quit\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ptr_channel->type == CHAT_PRIVATE)
+ ptr_nick = NULL;
+ else
+ ptr_nick = nick_search (ptr_channel, host);
+
+ if (ptr_nick || (strcmp (ptr_channel->name, host) == 0))
+ {
+ if (ptr_nick)
+ nick_free (ptr_channel, ptr_nick);
+ irc_display_prefix (ptr_channel->window, PREFIX_QUIT);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s ", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_HOST, "%s", pos + 1);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _(" has quit "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, "%s",
+ arguments);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")\n");
+ if ((ptr_channel->window == gui_current_window) &&
+ (ptr_channel->window->win_nick))
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_server_msg: command received from server (numeric)
+ */
+
+int
+irc_cmd_recv_server_msg (t_irc_server *server, char *host, char *arguments)
+{
+ /* make gcc happy */
+ (void) host;
+
+ /* skip nickname if at beginning of server message */
+ if (strncmp (server->nick, arguments, strlen (server->nick)) == 0)
+ {
+ arguments += strlen (server->nick) + 1;
+ while (arguments[0] == ' ')
+ arguments++;
+ }
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ /* display server message */
+ irc_display_prefix (server->window, PREFIX_SERVER);
+ gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_server_reply: server reply
+ */
+
+int
+irc_cmd_recv_server_reply (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ int first;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_ERROR);
+ first = 1;
+
+ while (pos && pos[0])
+ {
+ pos2 = strchr (pos, ' ');
+ if ((pos[0] == ':') || (!pos2))
+ {
+ if (pos[0] == ':')
+ pos++;
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ "%s%s\n", (first) ? "" : ": ", pos);
+ pos = NULL;
+ }
+ else
+ {
+ pos2[0] = '\0';
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s%s",
+ (first) ? "" : " ", pos);
+ first = 0;
+ pos = pos2 + 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_topic: 'topic' command received
+ */
+
+int
+irc_cmd_recv_topic (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_gui_window *window;
+
+ /* make gcc happy */
+ (void) host;
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ if (string_is_channel (arguments))
+ {
+ gui_printf (server->window,
+ _("%s \"topic\" command received without channel\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+ if (!pos[0])
+ pos = NULL;
+ }
+
+ ptr_channel = channel_search (server, arguments);
+ window = (ptr_channel) ? ptr_channel->window : server->window;
+
+ irc_display_prefix (window, PREFIX_INFO);
+ gui_printf_color (window,
+ COLOR_WIN_CHAT_NICK, "%s",
+ host);
+ if (pos)
+ {
+ gui_printf_color (window,
+ COLOR_WIN_CHAT, _(" has changed topic for "));
+ gui_printf_color (window,
+ COLOR_WIN_CHAT_CHANNEL, "%s",
+ arguments);
+ gui_printf_color (window,
+ COLOR_WIN_CHAT, _(" to: \"%s\"\n"),
+ pos);
+ }
+ else
+ {
+ gui_printf_color (window,
+ COLOR_WIN_CHAT, _(" has unset topic for "));
+ gui_printf_color (window,
+ COLOR_WIN_CHAT_CHANNEL, "%s\n",
+ arguments);
+ }
+
+ if (ptr_channel)
+ {
+ if (ptr_channel->topic)
+ free (ptr_channel->topic);
+ if (pos)
+ ptr_channel->topic = strdup (pos);
+ else
+ ptr_channel->topic = strdup ("");
+ gui_redraw_window_title (ptr_channel->window);
+ }
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_004: '004' command (connected to irc server ?????)
+ */
+
+int
+irc_cmd_recv_004 (t_irc_server *server, char *host, char *arguments)
+{
+ /* make gcc happy */
+ (void) host;
+ (void) arguments;
+
+ irc_cmd_recv_server_msg (server, host, arguments);
+
+ /* connection to IRC server is ok! */
+ server->is_connected = 1;
+ gui_redraw_window_status (server->window);
+ gui_redraw_window_input (server->window);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_311: '311' command (away message)
+ */
+
+int
+irc_cmd_recv_301 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (gui_current_window, PREFIX_INFO);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, _(" is away: %s\n"), pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_311: '311' command (whois, user)
+ */
+
+int
+irc_cmd_recv_311 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_user, *pos_host, *pos_realname;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_user = strchr (pos_nick, ' ');
+ if (pos_user)
+ {
+ pos_user[0] = '\0';
+ pos_user++;
+ while (pos_user[0] == ' ')
+ pos_user++;
+ pos_host = strchr (pos_user, ' ');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+ while (pos_host[0] == ' ')
+ pos_host++;
+ pos_realname = strchr (pos_host, ' ');
+ if (pos_realname)
+ {
+ pos_realname[0] = '\0';
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ if (pos_realname[0] == '*')
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ if (pos_realname[0] == ':')
+ pos_realname++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] (");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_HOST, "%s@%s",
+ pos_user, pos_host);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, ": %s\n", pos_realname);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_312: '312' command (whois, server)
+ */
+
+int
+irc_cmd_recv_312 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_server, *pos_serverinfo;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_server = strchr (pos_nick, ' ');
+ if (pos_server)
+ {
+ pos_server[0] = '\0';
+ pos_server++;
+ while (pos_server[0] == ' ')
+ pos_server++;
+ pos_serverinfo = strchr (pos_server, ' ');
+ if (pos_serverinfo)
+ {
+ pos_serverinfo[0] = '\0';
+ pos_serverinfo++;
+ while (pos_serverinfo[0] == ' ')
+ pos_serverinfo++;
+ if (pos_serverinfo[0] == ':')
+ pos_serverinfo++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s ", pos_server);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s", pos_serverinfo);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, ")\n");
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_313: '313' command (whois, operator)
+ */
+
+int
+irc_cmd_recv_313 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s\n", pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_317: '317' command (whois, idle)
+ */
+
+int
+irc_cmd_recv_317 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_idle, *pos_signon, *pos_message;
+ int idle_time, day, hour, min, sec;
+ time_t datetime;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_idle = strchr (pos_nick, ' ');
+ if (pos_idle)
+ {
+ pos_idle[0] = '\0';
+ pos_idle++;
+ while (pos_idle[0] == ' ')
+ pos_idle++;
+ pos_signon = strchr (pos_idle, ' ');
+ if (pos_signon)
+ {
+ pos_signon[0] = '\0';
+ pos_signon++;
+ while (pos_signon[0] == ' ')
+ pos_signon++;
+ pos_message = strchr (pos_signon, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+
+ idle_time = atoi (pos_idle);
+ day = idle_time / (60 * 60 * 24);
+ hour = (idle_time % (60 * 60 * 24)) / (60 * 60);
+ min = ((idle_time % (60 * 60 * 24)) % (60 * 60)) / 60;
+ sec = ((idle_time % (60 * 60 * 24)) % (60 * 60)) % 60;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, _("idle: "));
+ if (day > 0)
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", day);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (day > 1) ? _("days") : _("day"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ }
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%02d ", hour);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (hour > 1) ? _("hours") : _("hour"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ " %02d ", min);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (min > 1) ? _("minutes") : _("minute"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ " %02d ", sec);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (sec > 1) ? _("seconds") : _("second"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, _("signon at: "));
+ datetime = (time_t)(atol (pos_signon));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s", ctime (&datetime));
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_318: '318' command (whois, end)
+ */
+
+int
+irc_cmd_recv_318 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s\n", pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_319: '319' command (whois, end)
+ */
+
+int
+irc_cmd_recv_319 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_channel, *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_channel = strchr (pos_nick, ' ');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ if (pos_channel[0] == ':')
+ pos_channel++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, _("Channels: "));
+
+ while (pos_channel && pos_channel[0])
+ {
+ if (pos_channel[0] == '@')
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_NICK_OP, "@");
+ pos_channel++;
+ }
+ else
+ {
+ if (pos_channel[0] == '%')
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_NICK_HALFOP, "%");
+ pos_channel++;
+ }
+ else
+ if (pos_channel[0] == '+')
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_NICK_VOICE, "+");
+ pos_channel++;
+ }
+ }
+ pos = strchr (pos_channel, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s%s",
+ pos_channel,
+ (pos && pos[0]) ? " " : "\n");
+ pos_channel = pos;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_320: '320' command (whois, identified user)
+ */
+
+int
+irc_cmd_recv_320 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s\n", pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_321: '321' command (/list start)
+ */
+
+int
+irc_cmd_recv_321 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_322: '322' command (channel for /list)
+ */
+
+int
+irc_cmd_recv_322 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_323: '323' command (/list end)
+ */
+
+int
+irc_cmd_recv_323 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_331: '331' command received (no topic for channel)
+ */
+
+int
+irc_cmd_recv_331 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, _("No topic set for "));
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_CHANNEL, "%s\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_332: '332' command received (topic of channel)
+ */
+
+int
+irc_cmd_recv_332 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ t_irc_channel *ptr_channel;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ ptr_channel = channel_search (server, pos);
+ if (ptr_channel)
+ {
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (pos2[0] == ':')
+ pos2++;
+ if (ptr_channel->topic)
+ free (ptr_channel->topic);
+ ptr_channel->topic = strdup (pos2);
+
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _("Topic for "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL, "%s", pos);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _(" is: \"%s\"\n"), pos2);
+
+ gui_redraw_window_title (ptr_channel->window);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"332\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify channel for \"332\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_333: '333' command received (infos about topic (nick / date)
+ */
+
+int
+irc_cmd_recv_333 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_channel, *pos_nick, *pos_date;
+ t_irc_channel *ptr_channel;
+ time_t datetime;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ pos_nick = strchr (pos_channel, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_date = strchr (pos_nick, ' ');
+ if (pos_date)
+ {
+ pos_date[0] = '\0';
+ pos_date++;
+ while (pos_date[0] == ' ')
+ pos_date++;
+
+ ptr_channel = channel_search (server, pos_channel);
+ if (ptr_channel)
+ {
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _("Topic set by "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ datetime = (time_t)(atol (pos_date));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, ", %s", ctime (&datetime));
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify date/time for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify nickname for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify channel for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_351: '351' command received (server version)
+ */
+
+int
+irc_cmd_recv_351 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ pos2 = strstr (pos, " :");
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2 += 2;
+ }
+
+ irc_display_prefix (server->window, PREFIX_SERVER);
+ if (pos2)
+ gui_printf (server->window, "%s %s\n", pos, pos2);
+ else
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_353: '353' command received (list of users on a channel)
+ */
+
+int
+irc_cmd_recv_353 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos_nick;
+ int is_op, is_halfop, has_voice;
+ t_irc_channel *ptr_channel;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strstr (arguments, " = ");
+ if (pos)
+ arguments = pos + 3;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ return 0;
+
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] != ':')
+ {
+ gui_printf (server->window,
+ _("%s cannot parse \"353\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ pos++;
+ if (pos[0])
+ {
+ while (pos && pos[0])
+ {
+ is_op = 0;
+ is_halfop = 0;
+ has_voice = 0;
+ while ((pos[0] == '@') || (pos[0] == '%') || (pos[0] == '+'))
+ {
+ if (pos[0] == '@')
+ is_op = 1;
+ if (pos[0] == '%')
+ is_halfop = 1;
+ if (pos[0] == '+')
+ has_voice = 1;
+ pos++;
+ }
+ pos_nick = pos;
+ pos = strchr (pos, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ }
+ if (!nick_new (ptr_channel, pos_nick, is_op, is_halfop, has_voice))
+ gui_printf (server->window,
+ _("%s cannot create nick \"%s\" for channel \"%s\"\n"),
+ WEECHAT_ERROR, pos_nick, ptr_channel->name);
+ }
+ }
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot parse \"353\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_366: '366' command received (end of /names list)
+ */
+
+int
+irc_cmd_recv_366 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ int num_nicks, num_op, num_halfop, num_voice, num_normal;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (pos2[0] == ':')
+ pos2++;
+
+ ptr_channel = channel_search (server, pos);
+ if (ptr_channel)
+ {
+
+ /* display users on channel */
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _("Nicks "));
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s", ptr_channel->name);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, ": ");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "[");
+
+ for (ptr_nick = ptr_channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ irc_display_nick (ptr_channel->window, ptr_nick,
+ MSG_TYPE_INFO, 0, 0, 1);
+ if (ptr_nick != ptr_channel->last_nick)
+ gui_printf (ptr_channel->window, " ");
+ }
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "]\n");
+
+ /* display number of nicks, ops, halfops & voices on the channel */
+ nick_count (ptr_channel, &num_nicks, &num_op, &num_halfop, &num_voice,
+ &num_normal);
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _("Channel "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s", ptr_channel->name);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, ": ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_nicks);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_nicks > 1) ? _("nicks") : _("nick"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, " (");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_op);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_op > 1) ? _("ops") : _("op"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_halfop);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_halfop > 1) ? _("halfops") : _("halfop"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_voice);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_voice > 1) ? _("voices") : _("voice"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_normal);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ _("normal"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")\n");
+ }
+ else
+ {
+ irc_display_prefix (gui_current_window, PREFIX_INFO);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_CHANNEL, pos);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, ": %s\n", pos2);
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_433: '433' command received (nickname already in use)
+ */
+
+int
+irc_cmd_recv_433 (t_irc_server *server, char *host, char *arguments)
+{
+ char hostname[128];
+
+ if (!server->is_connected)
+ {
+ if (strcmp (server->nick, server->nick1) == 0)
+ {
+ gui_printf (server->window,
+ _(WEECHAT_NAME
+ ": nickname \"%s\" is already in use, "
+ "trying 2nd nickname \"%s\"\n"),
+ server->nick, server->nick2);
+ free (server->nick);
+ server->nick = strdup (server->nick2);
+ }
+ else
+ {
+ if (strcmp (server->nick, server->nick2) == 0)
+ {
+ gui_printf (server->window,
+ _(WEECHAT_NAME
+ ": nickname \"%s\" is already in use, "
+ "trying 3rd nickname \"%s\"\n"),
+ server->nick, server->nick3);
+ free (server->nick);
+ server->nick = strdup (server->nick3);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _(WEECHAT_NAME
+ ": all declared nicknames are already in use, "
+ "closing connection with server!\n"));
+ server_disconnect (server);
+ return 0;
+ }
+ }
+
+ gethostname (hostname, sizeof (hostname) - 1);
+ hostname[sizeof (hostname) - 1] = '\0';
+ if (!hostname[0])
+ strcpy (hostname, _("unknown"));
+ server_sendf (server,
+ "NICK %s\r\n",
+ server->nick);
+ }
+ else
+ return irc_cmd_recv_error (server, host, arguments);
+ return 0;
+}
diff --git a/src/irc/irc-display.c b/src/irc/irc-display.c
new file mode 100644
index 000000000..2f2f9931b
--- /dev/null
+++ b/src/irc/irc-display.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-display.c: display functions for IRC */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../weechat.h"
+#include "irc.h"
+#include "../config.h"
+#include "../gui/gui.h"
+
+
+/*
+ * irc_display_prefix: display prefix for action or info message
+ * prefix must be 3 chars length
+ */
+
+void
+irc_display_prefix (t_gui_window *window, char *prefix)
+{
+ if (prefix[0] == prefix[2])
+ {
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c", prefix[0]);
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX2, "%c", prefix[1]);
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c ", prefix[2]);
+ }
+ else
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%s ", prefix);
+}
+
+/*
+ * irc_display_nick: display nick in chat window
+ */
+
+void
+irc_display_nick (t_gui_window *window, t_irc_nick *nick, int message_type,
+ int display_around, int color_nick, int no_nickmode)
+{
+ if (display_around)
+ gui_printf_color_type (window,
+ message_type, COLOR_WIN_CHAT_DARK, "<");
+ if (cfg_look_nickmode)
+ {
+ if (nick->is_op)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_NICK_OP, "@");
+ else
+ {
+ if (nick->is_halfop)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_NICK_HALFOP, "%%");
+ else
+ {
+ if (nick->has_voice)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_NICK_VOICE, "+");
+ else
+ if (cfg_look_nickmode_empty && !no_nickmode)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_CHAT, " ");
+ }
+ }
+ }
+ gui_printf_color_type (window,
+ message_type,
+ (color_nick) ?
+ ((cfg_look_color_nicks) ?
+ nick->color : COLOR_WIN_CHAT) :
+ COLOR_WIN_CHAT,
+ "%s", nick->nick);
+
+ if (display_around)
+ gui_printf_color_type (window,
+ message_type, COLOR_WIN_CHAT_DARK, "> ");
+}
+
+/*
+ * irc_display_mode: display IRC message for mode change
+ */
+
+void
+irc_display_mode (t_gui_window *window, char *channel_name, char set_flag,
+ char *symbol, char *nick_host, char *message, char *param)
+{
+ irc_display_prefix (window, PREFIX_INFO);
+ gui_printf_color (window, COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%s", channel_name);
+ gui_printf_color (window, COLOR_WIN_CHAT, "/");
+ gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%c%s", set_flag, symbol);
+ gui_printf_color (window, COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s", nick_host);
+ if (param)
+ {
+ gui_printf_color (window, COLOR_WIN_CHAT, " %s ", message);
+ gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s\n", param);
+ }
+ else
+ gui_printf_color (window, COLOR_WIN_CHAT, " %s\n", message);
+}
diff --git a/src/irc/irc-nick.c b/src/irc/irc-nick.c
new file mode 100644
index 000000000..1f9faf3b3
--- /dev/null
+++ b/src/irc/irc-nick.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-nick.c: manages nick list for channels */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "../weechat.h"
+#include "irc.h"
+
+
+/*
+ * nick_find_color: find a color for a nick (less used will be better!)
+ */
+
+int
+nick_find_color (t_irc_channel *channel)
+{
+ int i, color_less_used, min_used;
+ int count_used[COLOR_WIN_NICK_NUMBER];
+ t_irc_nick *ptr_nick;
+
+ /* initialize array for counting usage of color */
+ for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++)
+ count_used[i] = 0;
+
+ /* summarize each color usage */
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ count_used[ptr_nick->color - COLOR_WIN_NICK_FIRST]++;
+
+ /* look for color less used on channel */
+ color_less_used = -1;
+ min_used = INT_MAX;
+ for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++)
+ {
+ if (count_used[i] < min_used)
+ {
+ color_less_used = i;
+ min_used = count_used[i];
+ }
+ }
+
+ return (color_less_used < 0) ?
+ COLOR_WIN_NICK_FIRST : COLOR_WIN_NICK_FIRST + color_less_used;
+}
+
+/*
+ * nick_compare: compare two nicks
+ * return: -1 is nick1 < nick2
+ * 0 if nick1 = nick2
+ * +1 if nick1 > nick2
+ * status sort: operator > voice > normal nick
+ */
+
+int
+nick_compare (t_irc_nick *nick1, t_irc_nick *nick2)
+{
+ int score1, score2, comp;
+
+ score1 = - ( (nick1->is_op * 3) + (nick1->is_halfop * 2) + nick1->has_voice );
+ score2 = - ( (nick2->is_op * 3) + (nick2->is_halfop * 2) + nick2->has_voice );
+
+ comp = strcasecmp(nick1->nick, nick2->nick);
+ if (comp > 0)
+ score1++;
+ else
+ if (comp < 0)
+ score2++;
+
+ /* nick1 > nick2 */
+ if (score1 > score2)
+ return 1;
+ /* nick1 < nick2 */
+ if (score1 < score2)
+ return -1;
+ /* nick1 == nick2 */
+ return 0;
+}
+
+/*
+ * nick_find_pos: find position for a nick (for sorting nick list)
+ */
+
+t_irc_nick *
+nick_find_pos (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *ptr_nick;
+
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ if (nick_compare (nick, ptr_nick) < 0)
+ return ptr_nick;
+ }
+ return NULL;
+}
+
+/*
+ * nick_insert_sorted: insert nick into sorted list
+ */
+
+void
+nick_insert_sorted (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *pos_nick;
+
+ if (channel->nicks)
+ {
+ pos_nick = nick_find_pos (channel, nick);
+
+ if (pos_nick)
+ {
+ /* insert nick into the list (before nick found) */
+ nick->prev_nick = pos_nick->prev_nick;
+ nick->next_nick = pos_nick;
+ if (pos_nick->prev_nick)
+ pos_nick->prev_nick->next_nick = nick;
+ else
+ channel->nicks = nick;
+ pos_nick->prev_nick = nick;
+ }
+ else
+ {
+ /* add nick to the end */
+ nick->prev_nick = channel->last_nick;
+ nick->next_nick = NULL;
+ channel->last_nick->next_nick = nick;
+ channel->last_nick = nick;
+ }
+ }
+ else
+ {
+ nick->prev_nick = NULL;
+ nick->next_nick = NULL;
+ channel->nicks = nick;
+ channel->last_nick = nick;
+ }
+}
+
+/*
+ * nick_new: allocate a new nick for a channel and add it to the nick list
+ */
+
+t_irc_nick *
+nick_new (t_irc_channel *channel, char *nick_name,
+ int is_op, int is_halfop, int has_voice)
+{
+ t_irc_nick *new_nick;
+
+ /* nick already exists on this channel? */
+ if ((new_nick = nick_search (channel, nick_name)))
+ {
+ /* update nick */
+ new_nick->is_op = is_op;
+ new_nick->is_halfop = is_halfop;
+ new_nick->has_voice = has_voice;
+ return new_nick;
+ }
+
+ /* alloc memory for new nick */
+ if ((new_nick = (t_irc_nick *) malloc (sizeof (t_irc_nick))) == NULL)
+ {
+ gui_printf (channel->window,
+ _("%s cannot allocate new nick\n"), WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new nick */
+ new_nick->nick = strdup (nick_name);
+ new_nick->is_op = is_op;
+ new_nick->is_halfop = is_halfop;
+ new_nick->has_voice = has_voice;
+ if (strcasecmp (new_nick->nick, SERVER(channel->window)->nick) == 0)
+ new_nick->color = COLOR_WIN_NICK_SELF;
+ else
+ new_nick->color = nick_find_color (channel);
+
+ nick_insert_sorted (channel, new_nick);
+
+ /* all is ok, return address of new nick */
+ return new_nick;
+}
+
+/*
+ * nick_resort: resort nick in the list
+ */
+
+void
+nick_resort (t_irc_channel *channel, t_irc_nick *nick)
+{
+ /* temporarly remove nick from list */
+ if (nick == channel->nicks)
+ channel->nicks = nick->next_nick;
+ else
+ nick->prev_nick->next_nick = nick->next_nick;
+ if (nick->next_nick)
+ nick->next_nick->prev_nick = nick->prev_nick;
+ if (nick == channel->last_nick)
+ channel->last_nick = nick->prev_nick;
+
+ /* insert again nick into sorted list */
+ nick_insert_sorted (channel, nick);
+}
+
+/*
+ * nick_change: change nickname and move it if necessary (list is sorted)
+ */
+
+void
+nick_change (t_irc_channel *channel, t_irc_nick *nick, char *new_nick)
+{
+ /* change nickname */
+ if (nick->nick)
+ free (nick->nick);
+ nick->nick = strdup (new_nick);
+
+ /* insert again nick into sorted list */
+ nick_resort (channel, nick);
+}
+
+/*
+ * nick_free: free a nick and remove it from nicks queue
+ */
+
+void
+nick_free (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *new_nicks;
+
+ /* remove nick from queue */
+ if (channel->last_nick == nick)
+ channel->last_nick = nick->prev_nick;
+ if (nick->prev_nick)
+ {
+ (nick->prev_nick)->next_nick = nick->next_nick;
+ new_nicks = channel->nicks;
+ }
+ else
+ new_nicks = nick->next_nick;
+
+ if (nick->next_nick)
+ (nick->next_nick)->prev_nick = nick->prev_nick;
+
+ /* free data */
+ if (nick->nick)
+ free (nick->nick);
+ free (nick);
+ channel->nicks = new_nicks;
+}
+
+/*
+ * nick_free_all: free all allocated nicks for a channel
+ */
+
+void
+nick_free_all (t_irc_channel *channel)
+{
+ /* remove all nicks for the channel */
+ while (channel->nicks)
+ nick_free (channel, channel->nicks);
+}
+
+/*
+ * nick_search: returns pointer on a nick
+ */
+
+t_irc_nick *
+nick_search (t_irc_channel *channel, char *nickname)
+{
+ t_irc_nick *ptr_nick;
+
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ if (strcasecmp (ptr_nick->nick, nickname) == 0)
+ return ptr_nick;
+ }
+ return NULL;
+}
+
+/*
+ * nick_count: returns number of nicks (total, op, halfop, voice) on a channel
+ */
+
+void
+nick_count (t_irc_channel *channel, int *total, int *count_op,
+ int *count_halfop, int *count_voice, int *count_normal)
+{
+ t_irc_nick *ptr_nick;
+
+ (*total) = 0;
+ (*count_op) = 0;
+ (*count_halfop) = 0;
+ (*count_voice) = 0;
+ (*count_normal) = 0;
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ (*total)++;
+ if (ptr_nick->is_op)
+ (*count_op)++;
+ else
+ {
+ if (ptr_nick->is_halfop)
+ (*count_halfop)++;
+ else
+ {
+ if (ptr_nick->has_voice)
+ (*count_voice)++;
+ else
+ (*count_normal)++;
+ }
+ }
+ }
+}
+
+/*
+ * nick_get_max_length: returns longer nickname on a channel
+ */
+
+int
+nick_get_max_length (t_irc_channel *channel)
+{
+ int length, max_length;
+ t_irc_nick *ptr_nick;
+
+ max_length = 0;
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ length = strlen (ptr_nick->nick);
+ if (length > max_length)
+ max_length = length;
+ }
+ return max_length;
+}
diff --git a/src/irc/irc-server.c b/src/irc/irc-server.c
new file mode 100644
index 000000000..b8bacc303
--- /dev/null
+++ b/src/irc/irc-server.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-server.c: (dis)connection and communication with irc server */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "../weechat.h"
+#include "irc.h"
+#include "../gui/gui.h"
+
+
+t_irc_server *irc_servers = NULL;
+t_irc_server *last_irc_server = NULL;
+t_irc_server *current_irc_server = NULL;
+
+t_irc_message *recv_msgq, *msgq_last_msg;
+
+/* buffer containing beginning of message if not ending with \r\n */
+char *unterminated_message = NULL;
+
+
+/*
+ * server_alloc: allocate a new server and add it to the servers queue
+ */
+
+t_irc_server *
+server_alloc ()
+{
+ t_irc_server *new_server;
+
+ #if DEBUG >= 1
+ log_printf ("allocating new server\n");
+ #endif
+
+ /* alloc memory for new server */
+ if ((new_server = (t_irc_server *) malloc (sizeof (t_irc_server))) == NULL)
+ {
+ fprintf (stderr, _("%s cannot allocate new server"), WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new server */
+ new_server->name = NULL;
+ new_server->address = NULL;
+ new_server->password = NULL;
+ new_server->nick1 = NULL;
+ new_server->nick2 = NULL;
+ new_server->nick3 = NULL;
+ new_server->username = NULL;
+ new_server->realname = NULL;
+ new_server->nick = NULL;
+ new_server->is_connected = 0;
+ new_server->sock4 = -1;
+ new_server->is_away = 0;
+ new_server->server_read = -1;
+ new_server->server_write = -1;
+ new_server->window = NULL;
+ new_server->channels = NULL;
+ new_server->last_channel = NULL;
+
+ /* add new server to queue */
+ new_server->prev_server = last_irc_server;
+ new_server->next_server = NULL;
+ if (irc_servers)
+ last_irc_server->next_server = new_server;
+ else
+ irc_servers = new_server;
+ last_irc_server = new_server;
+
+ /* all is ok, return address of new server */
+ return new_server;
+}
+
+/*
+ * server_create_window: create windows for a server
+ */
+
+void
+server_create_window (t_irc_server *server)
+{
+ if (!SERVER(gui_windows))
+ {
+ server->window = gui_windows;
+ SERVER(gui_windows) = server;
+ }
+ else
+ gui_window_new (server, NULL);
+}
+
+/*
+ * server_free: free a server and remove it from servers queue
+ */
+
+void
+server_free (t_irc_server *server)
+{
+ t_irc_server *new_irc_servers;
+
+ /* remove server from queue */
+ if (server->prev_server)
+ {
+ (server->prev_server)->next_server = server->next_server;
+ new_irc_servers = irc_servers;
+ }
+ else
+ new_irc_servers = server->next_server;
+
+ if (server->next_server)
+ (server->next_server)->prev_server = server->prev_server;
+
+ /* free data */
+ if (server->name)
+ free (server->name);
+ if (server->address)
+ free (server->address);
+ if (server->password)
+ free (server->password);
+ if (server->nick1)
+ free (server->nick1);
+ if (server->nick2)
+ free (server->nick2);
+ if (server->nick3)
+ free (server->nick3);
+ if (server->username)
+ free (server->username);
+ if (server->realname)
+ free (server->realname);
+ if (server->nick)
+ free (server->nick);
+ if (server->channels)
+ channel_free_all (server);
+ /* TODO: free weechat window (???) */
+ /* (...) */
+ free (server);
+ irc_servers = new_irc_servers;
+}
+
+/*
+ * server_free_all: free all allocated servers
+ */
+
+void
+server_free_all ()
+{
+ /* for each server in memory, remove it */
+ while (irc_servers)
+ server_free (irc_servers);
+}
+
+/*
+ * server_new: creates a new server, and initialize it
+ */
+
+t_irc_server *
+server_new (char *name, char *address, int port, char *password,
+ char *nick1, char *nick2, char *nick3,
+ char *username, char *realname)
+{
+ t_irc_server *new_server;
+
+ if (!name || !address || (port < 0) || !nick1 || !nick2 || !nick3
+ || !username || !realname)
+ return NULL;
+
+ #if DEBUG >= 1
+ log_printf ("creating new server (name:%s, address:%s, port:%d, pwd:%s, "
+ "nick1:%s, nick2:%s, nick3:%s, username:%s, realname:%s)\n",
+ name, address, port, password, nick1, nick2, nick3,
+ username, realname);
+ #endif
+
+ if ((new_server = server_alloc ()))
+ {
+ new_server->name = strdup (name);
+ new_server->address = strdup (address);
+ new_server->port = port;
+ new_server->password = (password) ? strdup (password) : strdup ("");
+ new_server->nick1 = (nick1) ? strdup (nick1) : strdup ("weechat_user");
+ new_server->nick2 = (nick2) ? strdup (nick2) : strdup ("weechat2");
+ new_server->nick3 = (nick3) ? strdup (nick3) : strdup ("weechat3");
+ new_server->username =
+ (username) ? strdup (username) : strdup ("weechat");
+ new_server->realname =
+ (realname) ? strdup (realname) : strdup ("realname");
+ new_server->nick = strdup (new_server->nick1);
+ }
+ else
+ return NULL;
+ return new_server;
+}
+
+/*
+ * server_send: send data to irc server
+ */
+
+int
+server_send (t_irc_server * server, char *buffer, int size_buf)
+{
+ if (!server)
+ return -1;
+
+ return send (server->sock4, buffer, size_buf, 0);
+}
+
+/*
+ * server_sendf: send formatted data to irc server
+ */
+
+int
+server_sendf (t_irc_server * server, char *fmt, ...)
+{
+ va_list args;
+ static char buffer[1024];
+ int size_buf;
+
+ if (!server)
+ return -1;
+
+ va_start (args, fmt);
+ size_buf = vsnprintf (buffer, sizeof (buffer) - 1, fmt, args);
+ va_end (args);
+
+ if ((size_buf == 0) || (strcmp (buffer, "\r\n") == 0))
+ return 0;
+
+ buffer[sizeof (buffer) - 1] = '\0';
+ if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1)))
+ size_buf = strlen (buffer);
+ buffer[size_buf - 2] = '\0';
+ #if DEBUG >= 2
+ gui_printf (server->window, "[DEBUG] Sending to server >>> %s\n", buffer);
+ #endif
+ buffer[size_buf - 2] = '\r';
+ return server_send (server, buffer, size_buf);
+}
+
+/*
+ * server_msgq_add_msg: add a message to received messages queue (at the end)
+ */
+
+void
+server_msgq_add_msg (t_irc_server * server, char *msg)
+{
+ t_irc_message *message;
+
+ message = (t_irc_message *) malloc (sizeof (t_irc_message));
+ message->server = server;
+ if (unterminated_message)
+ {
+ message->data = (char *) malloc (strlen (unterminated_message) +
+ strlen (msg) + 1);
+ strcpy (message->data, unterminated_message);
+ strcat (message->data, msg);
+ free (unterminated_message);
+ unterminated_message = NULL;
+ }
+ else
+ message->data = strdup (msg);
+ message->next_message = NULL;
+
+ if (msgq_last_msg)
+ {
+ msgq_last_msg->next_message = message;
+ msgq_last_msg = message;
+ }
+ else
+ {
+ recv_msgq = message;
+ msgq_last_msg = message;
+ }
+}
+
+/*
+ * server_msgq_add_buffer: explode received buffer, creating queued messages
+ */
+
+void
+server_msgq_add_buffer (t_irc_server * server, char *buffer)
+{
+ char *pos;
+
+ while (buffer[0])
+ {
+ pos = strstr (buffer, "\r\n");
+ if (pos)
+ {
+ pos[0] = '\0';
+ server_msgq_add_msg (server, buffer);
+ buffer = pos + 2;
+ }
+ else
+ {
+ pos = strchr (buffer, '\0');
+ if (pos)
+ {
+ unterminated_message =
+ (char *) realloc (unterminated_message,
+ strlen (buffer) + 1);
+ strcpy (unterminated_message, buffer);
+ return;
+ }
+ gui_printf (server->window,
+ _("%s unable to explode received buffer\n"),
+ WEECHAT_ERROR);
+ }
+ }
+}
+
+/*
+ * server_msgq_flush: flush message queue
+ */
+
+void
+server_msgq_flush ()
+{
+ t_irc_message *next;
+ /*char **argv;
+ int argc;*/
+ char *ptr_data, *pos, *pos2;
+ char *host, *command, *args;
+
+ /* TODO: optimize this function, parse only a few messages (for low CPU time!) */
+ while (recv_msgq)
+ {
+ #if DEBUG >= 2
+ gui_printf (gui_current_window, "[DEBUG] %s\n", recv_msgq->data);
+ #endif
+
+ ptr_data = recv_msgq->data;
+
+ while (ptr_data[0] == ' ')
+ ptr_data++;
+
+ if (ptr_data)
+ {
+ #if DEBUG >= 2
+ gui_printf (NULL, "[DEBUG] data received from server: %s\n", ptr_data);
+ #endif
+
+ host = NULL;
+ command = NULL;
+ args = ptr_data;
+
+ if (ptr_data[0] == ':')
+ {
+ pos = strchr(ptr_data, ' ');
+ pos[0] = '\0';
+ host = ptr_data+1;
+ pos++;
+ }
+ else
+ pos = ptr_data;
+
+ if (pos != NULL)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr(pos, ' ');
+ if (pos2 != NULL)
+ {
+ pos2[0] = '\0';
+ command = strdup(pos);
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ args = (pos2[0] == ':') ? pos2+1 : pos2;
+ }
+ }
+
+ switch (irc_recv_command (recv_msgq->server, host, command, args))
+ {
+ case -1:
+ gui_printf (recv_msgq->server->window,
+ _("Command '%s' failed!\n"), command);
+ break;
+ case -2:
+ gui_printf (recv_msgq->server->window,
+ _("No command to execute!\n"));
+ break;
+ case -3:
+ gui_printf (recv_msgq->server->window,
+ _("Unknown command: cmd=%s, args=%s\n"),
+ command, args);
+ break;
+ }
+ }
+
+ free (recv_msgq->data);
+ next = recv_msgq->next_message;
+ free (recv_msgq);
+ recv_msgq = next;
+ if (recv_msgq == NULL)
+ msgq_last_msg = NULL;
+ }
+}
+
+/*
+ * server_recv: receive data from an irc server
+ */
+
+void
+server_recv (t_irc_server *server)
+{
+ static char buffer[4096 + 2];
+ int num_read;
+
+ num_read = recv (server->sock4, buffer, sizeof (buffer) - 2, 0);
+ if (num_read > 0)
+ {
+ buffer[num_read] = '\0';
+ server_msgq_add_buffer (server, buffer);
+ server_msgq_flush ();
+ }
+}
+
+/*
+ * server_connect: connect to an irc server
+ */
+
+int
+server_connect (t_irc_server *server)
+{
+ int set;
+ struct hostent *ip4_hostent;
+ struct sockaddr_in addr;
+ char *ip_address;
+ int error;
+ int server_pipe[2];
+
+ gui_printf (server->window,
+ _(WEECHAT_NAME ": connecting to %s:%d...\n"),
+ server->address, server->port);
+ log_printf ("connecting to server %s:%d...\n",
+ server->address, server->port);
+ server->is_connected = 0;
+
+ /* create pipe */
+ if (pipe (server_pipe) < 0)
+ {
+ gui_printf (server->window,
+ _("%s cannot create pipe\n"), WEECHAT_ERROR);
+ server_free (server);
+ return 0;
+ }
+ server->server_read = server_pipe[0];
+ server->server_write = server_pipe[1];
+
+ /* create socket and set options */
+ server->sock4 = socket (AF_INET, SOCK_STREAM, 0);
+ set = 1;
+ if (setsockopt
+ (server->sock4, SOL_SOCKET, SO_REUSEADDR, (char *) &set,
+ sizeof (set)) == -1)
+ gui_printf (server->window,
+ _("%s cannot set socket option 'SO_REUSEADDR'\n"),
+ WEECHAT_ERROR);
+ set = 1;
+ if (setsockopt
+ (server->sock4, SOL_SOCKET, SO_KEEPALIVE, (char *) &set,
+ sizeof (set)) == -1)
+ gui_printf (server->window,
+ _("%s cannot set socket option \"SO_KEEPALIVE\"\n"),
+ WEECHAT_ERROR);
+
+ /* bind to hostname */
+ ip4_hostent = gethostbyname (server->address);
+ if (!ip4_hostent)
+ {
+ gui_printf (server->window,
+ _("%s address \"%s\" not found\n"),
+ WEECHAT_ERROR, server->address);
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->sock4 = -1;
+ return 0;
+ }
+ memset (&addr, 0, sizeof (addr));
+ memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length);
+ addr.sin_port = htons (server->port);
+ addr.sin_family = AF_INET;
+ /*error = bind(server->sock4, (struct sockaddr *)(&addr), sizeof(addr));
+ if (error != 0)
+ {
+ gui_printf (server->window,
+ WEECHAT_ERORR "server_connect: can't bind to hostname\n");
+ return 0;
+ } */
+ ip_address = inet_ntoa (addr.sin_addr);
+ if (!ip_address)
+ {
+ gui_printf (server->window,
+ _("%s IP address not found\n"), WEECHAT_ERROR);
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->sock4 = -1;
+ return 0;
+ }
+
+ /* connection to server */
+ gui_printf (server->window,
+ _(WEECHAT_NAME ": server IP is: %s\n"), ip_address);
+
+ error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr));
+ if (error != 0)
+ {
+ gui_printf (server->window,
+ _("%s cannot connect to irc server\n"), WEECHAT_ERROR);
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->sock4 = -1;
+ return 0;
+ }
+
+ current_irc_server = server;
+ return 1;
+}
+
+/*
+ * server_disconnect: disconnect from an irc server
+ */
+
+void
+server_disconnect (t_irc_server *server)
+{
+ if (server->is_connected)
+ {
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->is_connected = 0;
+ }
+}
+
+/*
+ * server_disconnect_all: disconnect from all irc servers
+ */
+
+void
+server_disconnect_all ()
+{
+ t_irc_server *ptr_server;
+
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ server_disconnect (ptr_server);
+}
+
+/*
+ * server_get_number_connected: returns number of connected server
+ */
+
+int
+server_get_number_connected ()
+{
+ t_irc_server *ptr_server;
+ int number;
+
+ number = 0;
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->is_connected)
+ number++;
+ }
+ return number;
+}
+
+/*
+ * server_name_already_exists: return 1 if server name already exists
+ * otherwise return 0
+ */
+
+int
+server_name_already_exists (char *name)
+{
+ t_irc_server *ptr_server;
+
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ {
+ if (strcmp (ptr_server->name, name) == 0)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/irc/irc.h b/src/irc/irc.h
new file mode 100644
index 000000000..f1f3698be
--- /dev/null
+++ b/src/irc/irc.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_IRC_H
+#define __WEECHAT_IRC_H 1
+
+#include "../gui/gui.h"
+
+#define PREFIX_SERVER "-@-"
+#define PREFIX_INFO "-=-"
+#define PREFIX_ACTION_ME "-*-"
+#define PREFIX_JOIN "-->"
+#define PREFIX_PART "<--"
+#define PREFIX_QUIT "<--"
+#define PREFIX_ERROR "=!="
+
+#define CHANNEL_PREFIX "#&+!"
+
+/* nick types */
+
+typedef struct t_irc_nick t_irc_nick;
+
+struct t_irc_nick
+{
+ char *nick; /* nickname */
+ int is_op; /* operator privileges? */
+ int is_halfop; /* half operaor privileges? */
+ int has_voice; /* nick has voice? */
+ int color; /* color for nickname */
+ t_irc_nick *prev_nick; /* link to previous nick on the channel */
+ t_irc_nick *next_nick; /* link to next nick on the channel */
+};
+
+/* channel types */
+
+typedef struct t_irc_channel t_irc_channel;
+
+#define CHAT_UNKNOWN -1
+#define CHAT_CHANNEL 0
+#define CHAT_PRIVATE 1
+
+struct t_irc_channel
+{
+ int type; /* channel type */
+ char *name; /* name of channel (exemple: "#abc") */
+ char *topic; /* topic of channel (host for private) */
+ t_irc_nick *nicks; /* nicks on the channel */
+ t_irc_nick *last_nick; /* last nick on the channel */
+ t_gui_window *window; /* GUI window allocated for channel */
+ t_irc_channel *prev_channel; /* link to previous channel */
+ t_irc_channel *next_channel; /* link to next channel */
+};
+
+/* server types */
+
+typedef struct t_irc_server t_irc_server;
+
+struct t_irc_server
+{
+ /* user choices */
+ char *name; /* name of server (only for display) */
+ char *address; /* address of server (IP or name) */
+ int port; /* port for server (6667 by default) */
+ char *password; /* password for server */
+ char *nick1; /* first nickname for the server */
+ char *nick2; /* alternate nickname */
+ char *nick3; /* 2nd alternate nickname */
+ char *username; /* user name */
+ char *realname; /* real name */
+
+ /* internal vars */
+ char *nick; /* current nickname */
+ int is_connected; /* 1 if WeeChat is connected to server */
+ int sock4; /* socket for server */
+ int is_away; /* 1 is user is marker as away */
+ int server_read; /* pipe for reading server data */
+ int server_write; /* pipe for sending data to server */
+ t_gui_window *window; /* GUI window allocated for server */
+ t_irc_channel *channels; /* opened channels on server */
+ t_irc_channel *last_channel; /* last opened channal on server */
+ t_irc_server *prev_server; /* link to previous server */
+ t_irc_server *next_server; /* link to next server */
+};
+
+/* irc commands */
+
+typedef struct t_irc_command t_irc_command;
+
+struct t_irc_command
+{
+ char *command_name; /* command name (internal or IRC cmd) */
+ char *command_description; /* command description */
+ char *arguments; /* command parameters */
+ char *arguments_description; /* parameters description */
+ int min_arg, max_arg; /* min & max number of parameters */
+ int need_connection; /* = 1 if cmd needs server connection */
+ int (*cmd_function_args)(t_irc_server *, int, char **);
+ /* function called when user enters cmd */
+ int (*cmd_function_1arg)(t_irc_server *, char *);
+ /* function called when user enters cmd */
+ int (*recv_function)(t_irc_server *, char *, char *);
+ /* function called when cmd is received */
+};
+
+typedef struct t_irc_message t_irc_message;
+
+struct t_irc_message
+{
+ t_irc_server *server; /* server pointer for received msg */
+ char *data; /* message content */
+ t_irc_message *next_message; /* link to next message */
+};
+
+extern t_irc_command irc_commands[];
+extern t_irc_server *irc_servers, *current_irc_server;
+extern t_irc_message *recv_msgq, *msgq_last_msg;
+extern t_irc_channel *current_channel;
+
+/* server functions (irc-server.c) */
+
+extern t_irc_server *server_alloc ();
+extern void server_create_window (t_irc_server *);
+extern void server_free (t_irc_server *);
+extern void server_free_all ();
+extern t_irc_server *server_new (char *, char *, int, char *, char *, char *,
+ char *, char *, char *);
+extern int server_send (t_irc_server *, char *, int);
+extern int server_sendf (t_irc_server *, char *, ...);
+extern void server_recv (t_irc_server *);
+extern int server_connect ();
+extern void server_disconnect (t_irc_server *);
+extern void server_disconnect_all ();
+extern int server_get_number_connected ();
+extern int server_name_already_exists (char *);
+
+/* channel functions (irc-channel.c) */
+
+extern t_irc_channel *channel_new (t_irc_server *, int, char *);
+extern void channel_free (t_irc_server *, t_irc_channel *);
+extern void channel_free_all (t_irc_server *);
+extern t_irc_channel *channel_search (t_irc_server *, char *);
+extern int string_is_channel (char *);
+
+/* nick functions (irc-nick.c) */
+
+extern t_irc_nick *nick_new (t_irc_channel *, char *, int, int, int);
+extern void nick_resort (t_irc_channel *, t_irc_nick *);
+extern void nick_change (t_irc_channel *, t_irc_nick *, char *);
+extern void nick_free (t_irc_channel *, t_irc_nick *);
+extern void nick_free_all (t_irc_channel *);
+extern t_irc_nick *nick_search (t_irc_channel *, char *);
+extern void nick_count (t_irc_channel *, int *, int *, int *, int *, int *);
+extern int nick_get_max_length (t_irc_channel *);
+
+/* IRC display (irc-diplay.c) */
+
+extern void irc_display_prefix (t_gui_window *, char *);
+extern void irc_display_nick (t_gui_window *, t_irc_nick *, int, int, int, int);
+extern void irc_display_mode (t_gui_window *, char *, char, char *, char *,
+ char *, char *);
+
+/* IRC protocol (irc-commands.c) */
+
+extern int irc_recv_command (t_irc_server *, char *, char *, char *);
+extern void irc_login (t_irc_server *);
+/* IRC commands issued by user */
+extern int irc_cmd_send_away (t_irc_server *, char *);
+extern int irc_cmd_send_ctcp (t_irc_server *, char *);
+extern int irc_cmd_send_deop (t_irc_server *, int, char **);
+extern int irc_cmd_send_devoice (t_irc_server *, int, char **);
+extern int irc_cmd_send_invite (t_irc_server *, char *);
+extern int irc_cmd_send_join (t_irc_server *, char *);
+extern int irc_cmd_send_kick (t_irc_server *, char *);
+extern int irc_cmd_send_kill (t_irc_server *, char *);
+extern int irc_cmd_send_list (t_irc_server *, char *);
+extern int irc_cmd_send_me (t_irc_server *, char *);
+extern int irc_cmd_send_mode (t_irc_server *, char *);
+extern int irc_cmd_send_msg (t_irc_server *, char *);
+extern int irc_cmd_send_names (t_irc_server *, char *);
+extern int irc_cmd_send_nick (t_irc_server *, int, char **);
+extern int irc_cmd_send_notice (t_irc_server *, char *);
+extern int irc_cmd_send_op (t_irc_server *, int, char **);
+extern int irc_cmd_send_oper (t_irc_server *, int, char **);
+extern int irc_cmd_send_part (t_irc_server *, char *);
+extern int irc_cmd_send_ping (t_irc_server *, int, char **);
+extern int irc_cmd_send_pong (t_irc_server *, int, char **);
+extern int irc_cmd_send_quit (t_irc_server *, char *);
+extern int irc_cmd_send_quote (t_irc_server *, char *);
+extern int irc_cmd_send_topic (t_irc_server *, char *);
+extern int irc_cmd_send_version (t_irc_server *, char *);
+extern int irc_cmd_send_voice (t_irc_server *, int, char **);
+extern int irc_cmd_send_whois (t_irc_server *, char *);
+/* IRC commands executed when received from server */
+extern int irc_cmd_recv_error (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_join (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_kick (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_mode (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_nick (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_notice (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_part (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_ping (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_privmsg (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_quit (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_server_msg (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_server_reply (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_topic (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_001 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_004 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_301 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_311 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_312 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_313 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_317 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_318 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_319 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_320 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_321 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_322 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_323 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_331 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_332 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_333 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_351 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_353 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_366 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_433 (t_irc_server *, char *, char *);
+
+#endif /* irc.h */
diff --git a/src/plugins/README b/src/plugins/README
new file mode 100644
index 000000000..978e37655
--- /dev/null
+++ b/src/plugins/README
@@ -0,0 +1,9 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+This is plugins directory for WeeChat.
+In the future, you'll find there interfaces with many famous languages for
+writing extensions to WeeChat:
+- Perl interface,
+- Python interface,
+- Ruby interface.
diff --git a/src/weechat.c b/src/weechat.c
new file mode 100644
index 000000000..25f7a34d6
--- /dev/null
+++ b/src/weechat.c
@@ -0,0 +1,311 @@
+/* ############################################################################
+ * ### ___ __ ______________ _____ ###
+ * ### __ | / /___________ ____/__ /_______ __ /_ ###
+ * ### __ | /| / /_ _ \ _ \ / __ __ \ __ `/ __/ ###
+ * ### __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ ###
+ * ### ____/|__/ \___/\___/\____/ /_/ /_/\__,_/ \__/ ###
+ * ### ###
+ * ### WeeChat - Wee Enhanced Environment for Chat ###
+ * ### Fast & light environment for Chat ###
+ * ### ###
+ * ### By: FlashCode <flashcode@flashtux.org> ###
+ * ### Bounga <bounga@altern.org> ###
+ * ### Xahlexx <xahlexx@tuxisland.org> ###
+ * ### ###
+ * ### http://weechat.flashtux.org ###
+ * ### ###
+ * ############################################################################
+ *
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* weechat.c: core functions for WeeChat */
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "weechat.h"
+#include "config.h"
+#include "command.h"
+#include "irc/irc.h"
+#include "gui/gui.h"
+
+
+/* char *display_name; */
+int quit_weechat; /* = 1 if quit request from user... why ? :'( */
+
+FILE *log_file; /* WeeChat log file (~/.weechat/weechat.log */
+
+
+/*
+ * log_printf: displays a message in WeeChat log (~/.weechat/weechat.log)
+ */
+
+void
+log_printf (char *message, ...)
+{
+ static char buffer[4096];
+ va_list argptr;
+ static time_t seconds;
+ struct tm *date_tmp;
+
+ if (!log_file)
+ return;
+
+ va_start (argptr, message);
+ vsnprintf (buffer, sizeof (buffer) - 1, message, argptr);
+ va_end (argptr);
+
+ seconds = time (NULL);
+ date_tmp = localtime (&seconds);
+ fprintf (log_file, "[%04d-%02d-%02d %02d:%02d:%02d] %s",
+ date_tmp->tm_year + 1900, date_tmp->tm_mon + 1, date_tmp->tm_mday,
+ date_tmp->tm_hour, date_tmp->tm_min, date_tmp->tm_sec,
+ buffer);
+ fflush (log_file);
+}
+
+/*
+ * wee_parse_args: parse command line args
+ */
+
+void
+wee_parse_args (int argc, char *argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if ((strcmp (argv[i], "-h") == 0)
+ || (strcmp (argv[i], "--help") == 0))
+ {
+ printf ("\n%s%s", WEE_USAGE);
+ exit (0);
+ }
+ else if ((strcmp (argv[i], "-l") == 0)
+ || (strcmp (argv[i], "--license") == 0))
+ {
+ printf ("\n%s%s", WEE_LICENSE);
+ exit (0);
+ }
+ /*else if ((strcmp (argv[i], "-d") == 0)
+ || (strcmp (argv[i], "--display") == 0))
+ {
+ if (i == (argc - 1))
+ fprintf (stderr,
+ _("%s no display specified (parameter '%s'), ignored\n"),
+ WEECHAT_WARNING, argv[i]);
+ else
+ {
+ display_name = argv[i + 1];
+ i++;
+ }
+ }*/
+ else if ((strcmp (argv[i], "-v") == 0)
+ || (strcmp (argv[i], "--version") == 0))
+ {
+ printf (WEECHAT_VERSION "\n");
+ exit (0);
+ }
+ else
+ {
+ fprintf (stderr,
+ _("%s unknown parameter '%s', ignored\n"),
+ WEECHAT_WARNING, argv[i]);
+ }
+ }
+}
+
+/*
+ * wee_create_home_dir: create weechat home directory (if not found)
+ */
+
+void
+wee_create_home_dir ()
+{
+ char *weechat_home_dir;
+ int return_code;
+
+ weechat_home_dir =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (weechat_home_dir, "%s/.weechat", getenv ("HOME"));
+ return_code = mkdir (weechat_home_dir, 0755);
+ if (return_code < 0)
+ {
+ if (errno != EEXIST)
+ {
+ fprintf (stderr, _("%s cannot create directory \"%s\"\n"),
+ WEECHAT_ERROR, weechat_home_dir);
+ free (weechat_home_dir);
+ exit (1);
+ }
+ }
+ free (weechat_home_dir);
+}
+
+/*
+ * wee_init_vars: initialize some variables
+ */
+
+void
+wee_init_vars ()
+{
+ /* GUI not yet initialized */
+ gui_ready = 0;
+
+ /* init received messages queue */
+ recv_msgq = NULL;
+ msgq_last_msg = NULL;
+}
+
+/*
+ * wee_init_log: initialize log file
+ */
+
+void
+wee_init_log ()
+{
+ char *filename;
+
+ filename =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (filename, "%s/.weechat/" WEECHAT_LOG_NAME, getenv ("HOME"));
+ if ((log_file = fopen (filename, "wt")) == NULL)
+ {
+ free (filename);
+ fprintf (stderr,
+ _("%s unable to create/append to log file (~/.weechat/"
+ WEECHAT_LOG_NAME), WEECHAT_ERROR);
+ }
+ free (filename);
+}
+
+/*
+ * wee_shutdown: shutdown WeeChat
+ */
+
+void
+wee_shutdown ()
+{
+ gui_end ();
+ server_free_all ();
+ if (log_file)
+ fclose (log_file);
+ exit (0);
+}
+
+/*
+ * main: WeeChat startup
+ */
+
+int
+main (int argc, char *argv[])
+{
+ t_irc_server *ptr_server;
+
+ /* initialize variables */
+ wee_init_vars ();
+
+ /* parse command line args */
+ wee_parse_args (argc, argv);
+
+ /* create weechat home directory */
+ wee_create_home_dir ();
+
+ /* init log file */
+ wee_init_log ();
+
+ /* read configuration */
+ switch (config_read ())
+ {
+ case 0: /* success */
+ break;
+ case -1: /* config file not found */
+ config_create_default ();
+ config_read ();
+ break;
+ default: /* other error (fatal) */
+ server_free_all ();
+ return 1;
+ }
+
+ /* init gui */
+ gui_init ();
+
+ /* build commands index (sorted), for completion */
+ index_command_build ();
+
+ /* Welcome message - yeah! */
+ if (cfg_look_startup_logo)
+ {
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1,
+ " ___ __ ______________ _____ \n"
+ " __ | / /___________ ____/__ /_______ __ /_\n"
+ " __ | /| / /_ _ \\ _ \\ / __ __ \\ __ `/ __/\n"
+ " __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ \n"
+ " ____/|__/ \\___/\\___/\\____/ /_/ /_/\\__,_/ \\__/ \n");
+ }
+ if (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0])
+ {
+ gui_printf_color (NULL, COLOR_WIN_CHAT, _("%sWelcome to "),
+ (cfg_look_startup_logo) ? " " : "");
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2, WEECHAT_NAME);
+ gui_printf_color (NULL, COLOR_WIN_CHAT,
+ ", %s\n", cfg_look_weechat_slogan);
+ }
+ if (cfg_look_startup_version)
+ {
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2,
+ "%s" WEECHAT_NAME_AND_VERSION,
+ (cfg_look_startup_logo) ? " " : "");
+ gui_printf_color (NULL, COLOR_WIN_CHAT,
+ ", %s %s %s\n",
+ _("compiled on"), __DATE__, __TIME__);
+ }
+ if (cfg_look_startup_logo ||
+ (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0]) ||
+ cfg_look_startup_version)
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1,
+ "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
+
+ /* connect to all servers */
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ server_create_window (ptr_server);
+ if (server_connect (ptr_server))
+ irc_login (ptr_server);
+ }
+ gui_main_loop ();
+ server_disconnect_all ();
+
+ /* program ending */
+ wee_shutdown ();
+
+ /* make gcc happy (statement never executed) */
+ return 0;
+}
diff --git a/src/weechat.h b/src/weechat.h
new file mode 100644
index 000000000..027d4e743
--- /dev/null
+++ b/src/weechat.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_H
+#define __WEECHAT_H 1
+
+#include <stdio.h>
+#include <libintl.h>
+
+#define _(string) gettext(string)
+#define N_(string) (string)
+
+#define WEECHAT_NAME "WeeChat"
+#define WEECHAT_VERSION "0.0.1"
+
+#define WEECHAT_NAME_AND_VERSION WEECHAT_NAME " " WEECHAT_VERSION
+#define WEECHAT_COPYRIGHT WEECHAT_NAME " (c) 2003 by Wee Team"
+#define WEECHAT_WEBSITE "http://weechat.flashtux.org"
+
+#define WEECHAT_ERROR _(WEECHAT_NAME " Error:")
+#define WEECHAT_WARNING _(WEECHAT_NAME " Warning:")
+
+/* debug mode, 0=normal use, 1=some debug msg, 2=full debug (developers only) */
+#define DEBUG 0
+
+/* log file */
+
+#define WEECHAT_LOG_NAME "weechat.log"
+
+/* license */
+
+#define WEE_LICENSE \
+ WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \
+ "Developed by FlashCode <flashcode@flashtux.org>\n" \
+ " Bounga <bounga@altern.org>\n" \
+ " Xahlexx <xahlexx@tuxisland.org>\n\n" \
+ "This program is free software; you can redistribute it and/or modify\n" \
+ "it under the terms of the GNU General Public License as published by\n" \
+ "the Free Software Foundation; either version 2 of the License, or\n" \
+ "(at your option) any later version.\n" \
+ "\n", \
+ \
+ "This program is distributed in the hope that it will be useful,\n" \
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
+ "GNU General Public License for more details.\n" \
+ "\n" \
+ "You should have received a copy of the GNU General Public License\n" \
+ "along with this program; if not, write to the Free Software\n" \
+ "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n"
+
+#define WEE_USAGE \
+ WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \
+ "Developed by FlashCode <flashcode@flashtux.org>\n" \
+ " Bounga <bounga@altern.org>\n" \
+ " Xahlexx <xahlexx@tuxisland.org>\n\n" \
+ " Bounga <bounga@altern.org>\n" \
+ " Xahlexx <xahlexx@tuxisland.org>\n\n" \
+ " -h, --help this help screen\n", \
+ " -l, --license display WeeChat license\n" \
+ " -v, --version display WeeChat version\n\n"
+
+/* " -d, --display choose X display\n" \*/
+
+
+/*#define DEFAULT_DISPLAY ":0" */
+
+
+/*extern char *display_name; */
+int quit_weechat;
+
+extern int quit_weechat;
+
+extern void log_printf (char *, ...);
+extern void wee_shutdown ();
+
+#endif /* weechat.h */
diff --git a/weechat.1 b/weechat.1
new file mode 100644
index 000000000..4d03e5cd0
--- /dev/null
+++ b/weechat.1
@@ -0,0 +1,44 @@
+.TH WEECHAT 1 "September 2003" "FlashCode"
+
+.SH NAME
+weechat \- wee enhanced environment for chat
+
+.SH SYNOPSIS
+.B weechat
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+Fast, light and extensible IRC client for many operating systems. Everything can be
+done with a keyboard. It is customizable and extensible with scripts.
+
+.SH OPTIONS
+.TP
+.B \-h, \-\-help
+.br
+display summary of options
+.TP
+.B \-l, \-\-license
+.br
+display program license
+.TP
+.B \-v, \-\-version
+.br
+display WeeChat version
+
+.SH FILES
+.TP
+.B $HOME/.weechat/weechat.rc
+configuration file for WeeChat
+
+.SH AUTHOR
+WeeChat is written by:
+.br
+ - FlashCode <flashcode@flashtux.org>
+ - Bounga <bounga@altern.org>
+ - Xahlexx <xahlexx@tuxisland.org>
+.br
+WeeChat on the web:
+.UR
+http://weechat.flashtux.org
+.UE
diff --git a/weechat.spec b/weechat.spec
new file mode 100644
index 000000000..6bf1a5f61
--- /dev/null
+++ b/weechat.spec
@@ -0,0 +1,41 @@
+%define name weechat
+%define version 0.0.1
+%define release 1
+
+Name: %{name}
+Summary: portable, fast, light and extensible IRC client
+Version: %{version}
+Release: %{release}
+Source: http://weechat.flashtux.org/download/%{name}-%{version}.tar.gz
+URL: http://weechat.flashtux.org
+Group: Networking/IRC
+BuildRoot: %{_tmppath}/%{name}-buildroot
+License: GPL
+
+%description
+WeeChat (Wee Enhanced Environment for Chat) is a portable, fast, light and
+extensible IRC client. Everything can be done with a keyboard.
+It is customizable and extensible with scripts.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+%setup
+
+%build
+make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local"
+
+%install
+make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local" install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root,0755)
+%doc AUTHORS BUGS ChangeLog COPYING FAQ INSTALL NEWS README TODO
+/usr/share/man/man1/weechat.1*
+/usr/local/bin/weechat
+
+%changelog
+* Thu Sep 27 2003 FlashCode <flashcode@flashtux.org> 0.0.1-1
+- Released version 0.0.1
diff --git a/weechat/AUTHORS b/weechat/AUTHORS
new file mode 100644
index 000000000..dcb0ba274
--- /dev/null
+++ b/weechat/AUTHORS
@@ -0,0 +1,29 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+Developers:
+----------
+
+All developers are connected to IRC:
+server: irc.freenode.net, channel: #weechat
+
+FlashCode <flashcode@flashtux.org>
+ Web : http://www.flashtux.org
+ IRC : nick is "FlashCode"
+ Jabber: flashcode@jabber.org
+ ICQ : 160677660
+ AIM : FlashCode AIM
+ Yahoo : FlashCode_Y
+
+Bounga <bounga@altern.org>
+ Web : http://bounga.ath.cx
+ IRC : nick is "Bounga"
+ Jabber: Bounga@jabber.org
+ ICQ : 178297842
+
+Xahlexx <xahlexx@tuxisland.org>
+ Web : http://www.tuxisland.org
+ IRC : nick is "xahlexx"
+
+
+See README file for licence detail.
diff --git a/weechat/BUGS b/weechat/BUGS
new file mode 100644
index 000000000..0a6a5f3f3
--- /dev/null
+++ b/weechat/BUGS
@@ -0,0 +1,17 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+WeeChat known bugs, 2003-09-27
+
+- too much nicks in the channel (> height of window) => display bug
+- some IRC commands are marked as 'unknown' when received
+ (irc protocol is under dev!)
+- bug in nicklist resize (sometimes resize doesn't work and there is display
+ problem)
+- alias/unalias commands doesn't work
+- config is not saved (to ~/.weechat/weechatrc)
+- intercept Ctrl-C (do not quit immediately if Ctrl-C pressed!)
+- program is stopped when bad option in config file (it should not, only display
+ warning)
+- too much opened channel => display bug
+- when kicked, channel is not prefixed by '(' and sufixed by ')'
diff --git a/weechat/COPYING b/weechat/COPYING
new file mode 100644
index 000000000..5b6e7c66c
--- /dev/null
+++ b/weechat/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/weechat/ChangeLog b/weechat/ChangeLog
new file mode 100644
index 000000000..2bc1255bd
--- /dev/null
+++ b/weechat/ChangeLog
@@ -0,0 +1,88 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+ChangeLog - 2003-09-27
+
+* 2003-09-27:
+ - WeeChat 0.0.1 released!
+
+* 2003-09-26:
+ - added completor prefix (in config: look_nick_completor)
+ - fixef log_printf command (bug with year & month)
+ - added "/kill" command
+ - fixed /version and /ctcp commands (missing ":" before message)
+
+* 2003-09-25:
+ - added "/kick" command
+ - added IRC errors 402 to 407
+ - added "/invite" command
+
+* 2003-09-24:
+ - "ctcp version" received is now correctly displayed
+ - "/version" command is ok
+
+* 2003-09-23:
+ - log file (~/.weechat/weechat.log)
+ - renamed config file (~/.weechat/weechatrc to ~/.weechat/weechat.rc)
+
+* 2003-09-21:
+ - "demi-highlight": 2 types of windows highlight: lightred for windows with
+ unread messages (from other users), lightmagenta for windows with other
+ unread data (join, part, quit, away, ...)
+ - "320" IRC message management
+ - "/clear" command
+
+* 2003-09-19:
+ - préparation des sources pour l'internationalisation avec gettext
+ - "301" IRC command (away message)
+ - functions renamed in rc-commands.c, irc-server.c,
+ command.c and config.c (all functions are beginning with a prefix:
+ irc_cmd_recv_xxx, irc_cmd_send_xxx, server_xxx, weechat_cmd_xxx and
+ config_xxx). Moreover, all commands (sent and received) return a value
+ (success or not)
+ - "/quote" command
+ - "/whois" command (and colored display of /whois result in server window)
+
+* 2003-09-18:
+ - use of alternate nickname (and 2nd alternate) if nick is already used
+ on server (changed/added in config file: options "nick1", "nick2", "nick3"
+ for a server, all are mandatory)
+ - "433" IRC error management (nickname already in use)
+ - "mode" command received correctly for "channel flags" and
+ op/deop/voice/devoice actions for a nick
+ - "401" IRC error management (no such nick/channel)
+ - private windows management (when received and opened, with /privmsg),
+ "/privmsg" completed consequently
+
+* 2003-09-17:
+ - nickmode display ((half)op/voice) before nicks (as option, look at config
+ options beginning with "look_nickmode")
+ - windows history is now ok (pgup/pgdn on any window type)
+ - "/me" command (and OK when received)
+ - display nicks count when joining channel or with "/names" command
+ (total, ops, halfops, voices et normaux)
+
+* 2003-09-16:
+ - added and normalized chat window colors
+ (new colors in config file)
+ - "/topic" command
+ - nicklist can be moved on top, bottom, left or right of window
+
+* 2003-09-15:
+ - auto-resize of nicklist, according to nick max length
+ - IRC multi-servers is OK
+
+* 2003-09-14:
+ - no hangup if "/part" command is executed on server window
+ - continue if no server is declared in config file
+ (empty window will be opened for executing WeeChat commands)
+ - string array for strings in config file
+ example: cfg_look_nicklist_position can take values "left", "right",
+ "top", "bottom", which are converted to int (from 0 for "left" to 3 for
+ "bottom")
+ - messages are aligned under time (server window) or under time + nick
+ (channel window)
+
+* 2003-09-13:
+ - sources exploded in many directories: ./irc, ./gui/curses, ./gui/gtk,
+ ./gui/qt and ./gui/text
diff --git a/weechat/FAQ b/weechat/FAQ
new file mode 100644
index 000000000..f949ac4e8
--- /dev/null
+++ b/weechat/FAQ
@@ -0,0 +1,6 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+WeeChat FAQ, 2003-09-19
+
+<<< TO DO ! >>>
diff --git a/weechat/INSTALL b/weechat/INSTALL
new file mode 100644
index 000000000..8ef31434c
--- /dev/null
+++ b/weechat/INSTALL
@@ -0,0 +1,10 @@
+WeeChat - Installation instructions
+===================================
+
+1) Run 'make'
+
+2) As root, run 'make install'
+
+3) Enjoy ! :-)
+
+See AUTHORS for any support, feel free to contact us for any problem ;)
diff --git a/weechat/Makefile b/weechat/Makefile
new file mode 100644
index 000000000..22b2a4ec1
--- /dev/null
+++ b/weechat/Makefile
@@ -0,0 +1,31 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+OUTPUT=weechat
+
+all:
+ cd src && make
+
+install:
+ @mkdir -v -p $(DESTDIR)/usr/$(LOCALRPM)/bin
+ @cp -v src/$(OUTPUT) $(DESTDIR)/usr/$(LOCALRPM)/bin/
+ @mkdir -v -p $(DESTDIR)/usr/share/man/man1
+ @cp -v weechat.1 $(DESTDIR)/usr/share/man/man1/
+ @echo -e "\n=== WeeChat installed!\n"
+
+clean:
+ cd src && make clean
diff --git a/weechat/NEWS b/weechat/NEWS
new file mode 100644
index 000000000..fb7c6bbb8
--- /dev/null
+++ b/weechat/NEWS
@@ -0,0 +1,6 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+FlashCode, 2003-09-27
+
+WeeChat 0.0.1 released.
diff --git a/weechat/README b/weechat/README
new file mode 100644
index 000000000..bca3871dc
--- /dev/null
+++ b/weechat/README
@@ -0,0 +1,50 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+
+WeeChat (Wee Enhanced Environment for Chat) is a fast and light chat
+environment for many operating systems. Everything can be done with a keyboard.
+It is customizable and extensible with scripts.
+
+
+Features
+--------
+ * IRC chat client with multi-server connection
+ * many GUI (curses, text, Gtk, QT) (1)
+ * small, fast and very light
+ * customizable and extensible with scripts (Perl, Python, Ruby) (2)
+ * compliant with RFC 1459,2810,2811,2812,2813
+ * multi-platform (GNU/Linux, *BSD, Windows & other) (3)
+ * 100% GPL & free
+
+
+Copyright
+---------
+
+WeeChat (c) Copyright 2003
+ by: FlashCode <flashcode@flashtux.org>
+ Xahlexx <xahlex@tuxisland.org>
+ Bounga <bounga@altern.org>
+(see AUTHORS file if you want to contact authors)
+
+WeeChat is distributed under GPL licence (see COPYING file for complete license):
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+---
+(1) only curses & text interfaces are available today
+(2) plugin interfaces are not yet developed
+(3) only GNU/Linux version is available today
diff --git a/weechat/TODO b/weechat/TODO
new file mode 100644
index 000000000..e65f0a957
--- /dev/null
+++ b/weechat/TODO
@@ -0,0 +1,130 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+TODO - 2003-09-27
+
+Legend:
+ # done
+ + currently in development
+ - pending
+ ? is this really necessary?
+
+
+v0.0.1:
+
+ * IRC protocol:
+ # "/quote" command: send a raw string to the server without parsing it
+ # "/me" command (for user actions description)
+ # "/away" command (to toggle the away status)
+ # "/op", "/deop", "/voice", "/devoice" commands
+ # "/invite" command
+ # "/kick", "/ban", "/unban" commands
+ # "/kill" command
+ # "/list" command: list of channels
+ # "/names" command: view who is on a given channel without being
+ on it (for example /names #weechat gives all the nicks present on
+ #weechat, except those who have the +i flag (server side))
+ # "/oper" command: become operator on the irc network
+ # "/topic" command: change the topic of a channel
+ # "/version" command: give the irc client version (CTCP VERSION)
+ of a given nick/channel (without parameter: gives WeeChat version)
+ # "/whois" command
+
+ * WeeChat commands:
+ # "/clear": to clear window content
+
+ * Interface:
+ # "demi-highlight" when joins/quits etc
+ # log messages/warning/errors to ~/.weechat/log file
+ # improve editing zone (left arrow <> backspace)
+ # sort nick list
+ # choose nick list position (top, left, right (default), bottom)
+ # auto-resize nicklist (when nick too long)
+ # do pretty cutting of long lines (align on the nick or after hour for server)
+ # keep history of commands and call them again with up/down arrow
+ # text GUI
+ # ncurses GUI:
+ # one window for each channel
+ # color display
+ # private windows
+ # redraw window when term size is modified
+ # chat history (pgup/pgdn for displaying history)
+ # switch to other channel window
+
+ * TCP/IP communication:
+ # IPv4 protocol implementation
+
+ * Configuration:
+ # write default config file
+
+
+Future versions:
+
+ * IRC protocol:
+ - implement RFC 2812
+ + "/mode" command: change the user/channels modes
+ - "/dcc" command (for chat and sending/receiving files)
+ - manage "halfop" status
+ - complete "/list" command: add regexp search, display only channels that
+ match regexp
+ - "/connect" and "/disconnect" commands (for multiservers use)
+ - "/ignore" and "/unignore" commands: hide all that is write by a given
+ nick/host
+ - when we're away, WeeChat should log all the lines begenning by our nick.
+ When we come back from our away it should print it to the current window
+ - "/rehash" command: tell the server to reload its config file
+ - "/restart" command: tell the server to restart itself
+ - "/notify" and "/unnotify" command to be warn by WeeChat when a given
+ nick/host connect to the given irc network
+ - "/wallops" command: write the same string to all the
+ persons with the flag +w enable
+
+ * WeeChat commands:
+ - "/completion" command: do shortcuts (for example when we type "u"
+ in the text bar it send it to the server as "you")
+ - "/exec" command: execute a command as if we was in shell
+ and show us the output on the current window. An option to exec
+ like -o could send the output to the server, on the current
+ channel/private
+ - "/reload" command: reload the WeeChat's config file
+ - "/set" command: allow the user to set the WeeChat variables
+ under WeeChat without editing the config file (colours, time
+ format, etc)
+ - "/highlight" command: highlight a given word when it appears on
+ channels/privates
+
+ * Interface:
+ - display current channel modes (example : #weechat(+nt))
+ - interpret ^B in messages (this means bold text)
+ - internationalization (traduce WeeChat in many languages)
+ - many channel windows in one window/term (window split)
+ - add lag indicator
+ - log chats to file
+ - forget some old lines that were displayed long time ago (now all is saved,
+ if WeeChat is running for long time, a lot of memory is used!)
+ - improve completion (for example complete command parameters when possible)
+ - understand incomplete commands if unambigous (for example: /he for /help is ok)
+ - add clock (in status bar?)
+ - Gtk GUI
+ ? Qt GUI
+
+ * TCP/IP communication:
+ - IPv6 protocol implementation
+
+ * Configuration:
+ - add key bindings to config file
+ - add missing options for config file
+ - write config file
+ - add an option for each server in order to run commands on join
+ (example: /msg nickserv identify password)
+ - channel list for auto-join (for each server)
+ - do not stop program if problem with options in config file
+ - load config file after GUI (so init values by default (colors, ...) before
+ loading config)
+
+ * Plugins:
+ - add Perl plugin
+ - add Python plugin
+ - add Ruby plugin
+ - "/load" and "/unload" commands to (un)load extension scripts
+ (perl, python, ruby, ...)
diff --git a/weechat/debian/changelog b/weechat/debian/changelog
new file mode 100644
index 000000000..7ab78b78a
--- /dev/null
+++ b/weechat/debian/changelog
@@ -0,0 +1,5 @@
+weechat (0.0.1-1) unstable; urgency=low
+
+ * First version.
+
+ -- FlashCode <flashcode@flashtux.org> Sat, 27 Jun 2003 12:00:00 +0200
diff --git a/weechat/debian/compat b/weechat/debian/compat
new file mode 100644
index 000000000..b8626c4cf
--- /dev/null
+++ b/weechat/debian/compat
@@ -0,0 +1 @@
+4
diff --git a/weechat/debian/control b/weechat/debian/control
new file mode 100644
index 000000000..0a4844738
--- /dev/null
+++ b/weechat/debian/control
@@ -0,0 +1,14 @@
+Source: weechat
+Section: net
+Priority: optional
+Maintainer: FlashCode <flashcode@flashtux.org>
+Build-Depends: debhelper (>> 4.0.0)
+Standards-Version: 3.5.8
+
+Package: weechat
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Fast, light and extensible IRC client
+ WeeChat (Wee Enhanced Environment for Chat) is a fast and light IRC client
+ for many operating systems. Everything can be done with a keyboard.
+ It is customizable and extensible with scripts.
diff --git a/weechat/debian/copyright b/weechat/debian/copyright
new file mode 100644
index 000000000..1a1dbdde6
--- /dev/null
+++ b/weechat/debian/copyright
@@ -0,0 +1,17 @@
+This package was debianized by FlashCode <flashcode@flashtux.org> on
+Sat, 27 Sep 2003 10:00:00 +0200.
+
+It was downloaded from http://weechat.flashtux.org/download
+
+Upstream Author(s): FlashCode <flashcode@flashtux.org>
+
+Copyright:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+On Debian systems, the complete text of the GNU General Public
+License, Version 2 can be found in the file
+/usr/share/common-licenses/GPL
diff --git a/weechat/debian/dirs b/weechat/debian/dirs
new file mode 100644
index 000000000..e77248175
--- /dev/null
+++ b/weechat/debian/dirs
@@ -0,0 +1 @@
+usr/bin
diff --git a/weechat/debian/docs b/weechat/debian/docs
new file mode 100644
index 000000000..a204c4610
--- /dev/null
+++ b/weechat/debian/docs
@@ -0,0 +1,9 @@
+AUTHORS
+BUGS
+ChangeLog
+COPYING
+FAQ
+INSTALL
+NEWS
+README
+TODO
diff --git a/weechat/debian/files b/weechat/debian/files
new file mode 100644
index 000000000..48f4dc400
--- /dev/null
+++ b/weechat/debian/files
@@ -0,0 +1 @@
+weechat_0.0.1-1_i386.deb net optional
diff --git a/weechat/debian/rules b/weechat/debian/rules
new file mode 100755
index 000000000..db43ab7e6
--- /dev/null
+++ b/weechat/debian/rules
@@ -0,0 +1,97 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ # Add here commands to configure the package.
+
+ touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+ dh_testdir
+
+ # Add here commands to compile the package.
+ $(MAKE)
+ #/usr/bin/docbook-to-man debian/weechat.sgml > weechat.1
+
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+
+ # Add here commands to clean up after the build process.
+ -$(MAKE) clean
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/weechat.
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/weechat
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs
+ dh_installdocs
+ dh_installexamples
+# dh_install
+# dh_installmenu
+# dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+ dh_installman weechat.1
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+# dh_perl
+# dh_python
+# dh_makeshlibs
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/weechat/debian/weechat.substvars b/weechat/debian/weechat.substvars
new file mode 100644
index 000000000..0e328c3d3
--- /dev/null
+++ b/weechat/debian/weechat.substvars
@@ -0,0 +1 @@
+shlibs:Depends=libc6 (>= 2.3.2-1), libncurses5 (>= 5.3.20030510-1)
diff --git a/weechat/src/Makefile b/weechat/src/Makefile
new file mode 100644
index 000000000..575773bb1
--- /dev/null
+++ b/weechat/src/Makefile
@@ -0,0 +1,91 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=weechat
+
+OBJS=weechat.o config.o command.o completion.o history.o
+OBJS_IRC=irc/irc.a
+OBJS_GUI=gui/gui.a
+
+
+# WeeChat with Curses interface
+ifeq ($(GUI), curses)
+LIBS_CURSES=-lcurses
+DEFINES=WEE_CURSES
+
+curses: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_CURSES)
+endif
+
+# WeeChat with Gtk+ interface
+ifeq ($(GUI), gtk)
+OBJS_GTK=gui-gtk.o
+LIBS_GTK=
+DEFINES=WEE_GTK
+gtk: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_GTK)
+endif
+
+# WeeChat with Qt interface
+ifeq ($(GUI), qt)
+OBJS_QT=gui-qt.o
+LIBS_QT=
+DEFINES=WEE_QT
+qt: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_QT)
+endif
+
+# WeeChat with Text interface
+ifeq ($(GUI), text)
+OBJS_TEXT=gui-text.o
+LIBS_TEXT=
+DEFINES=WEE_TEXT
+text: $(OBJS) $(OBJS_IRC) $(OBJS_GUI)
+ $(CC) $(OPTIONS) $(OBJS) $(OBJS_IRC) $(OBJS_GUI) -o $(OUTPUT) $(LIBS_TEXT)
+endif
+
+
+all:
+ make curses GUI=curses
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+irc/irc.a:
+ cd irc && make
+
+gui/gui.a:
+ cd gui && make $(GUI) GUI=$(GUI)
+
+clean:
+ rm -f *.o *.a *~ core $(OUTPUT)
+ cd irc && make clean
+ cd gui && make clean
+
+command.o: command.c weechat.h command.h irc/irc.h gui/gui.h completion.h \
+ history.h config.h
+completion.o: completion.c weechat.h completion.h irc/irc.h gui/gui.h \
+ history.h command.h
+config.o: config.c weechat.h config.h irc/irc.h gui/gui.h completion.h \
+ history.h
+history.o: history.c weechat.h history.h gui/gui.h completion.h
+weechat.o: weechat.c weechat.h config.h command.h irc/irc.h gui/gui.h \
+ completion.h history.h
diff --git a/weechat/src/command.c b/weechat/src/command.c
new file mode 100644
index 000000000..ddd3ce202
--- /dev/null
+++ b/weechat/src/command.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* command.c: WeeChat internal commands */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "command.h"
+#include "irc/irc.h"
+#include "config.h"
+#include "gui/gui.h"
+
+
+/* WeeChat internal commands */
+
+t_weechat_command weechat_commands[] =
+{ { "alias", N_("create an alias for a command"),
+ N_("[alias_name [command [arguments]]"),
+ N_("alias_name: name of alias\ncommand: command name (" WEECHAT_NAME
+ " or IRC command)\n" "arguments: arguments for command"),
+ 0, MAX_ARGS, weechat_cmd_alias, NULL },
+ { "clear", N_("clear window(s)"),
+ N_("[-all]"),
+ N_("-all: clear all windows"),
+ 0, 1, weechat_cmd_clear, NULL },
+ { "help", N_("display help about commands"),
+ N_("[command]"), N_("command: name of a " WEECHAT_NAME " or IRC command"),
+ 0, 1, weechat_cmd_help, NULL },
+ { "set", N_("set config parameters"),
+ N_("[option [value]]"), N_("option: name of an option\nvalue: value for option"),
+ 0, 2, weechat_cmd_set, NULL },
+ { "unalias", N_("remove an alias"),
+ N_("alias_name"), N_("alias_name: name of alias to remove"),
+ 1, 1, weechat_cmd_unalias, NULL },
+ { NULL, NULL, NULL, NULL, 0, 0, NULL, NULL }
+};
+
+t_index_command *index_commands;
+t_index_command *last_index_command;
+
+
+/*
+ * index_find_pos: find position for a command index (for sorting index)
+ */
+
+t_index_command *
+index_command_find_pos (char *command)
+{
+ t_index_command *ptr_index;
+
+ for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index)
+ {
+ if (strcasecmp (command, ptr_index->command_name) < 0)
+ return ptr_index;
+ }
+ return NULL;
+}
+
+/*
+ * index_command_insert_sorted: insert index into sorted list
+ */
+
+void
+index_command_insert_sorted (t_index_command *index)
+{
+ t_index_command *pos_index;
+
+ pos_index = index_command_find_pos (index->command_name);
+
+ if (index_commands)
+ {
+ if (pos_index)
+ {
+ /* insert index into the list (before index found) */
+ index->prev_index = pos_index->prev_index;
+ index->next_index = pos_index;
+ if (pos_index->prev_index)
+ pos_index->prev_index->next_index = index;
+ else
+ index_commands = index;
+ pos_index->prev_index = index;
+ }
+ else
+ {
+ /* add index to the end */
+ index->prev_index = last_index_command;
+ index->next_index = NULL;
+ last_index_command->next_index = index;
+ last_index_command = index;
+ }
+ }
+ else
+ {
+ index->prev_index = NULL;
+ index->next_index = NULL;
+ index_commands = index;
+ last_index_command = index;
+ }
+ return;
+}
+
+/*
+ * index_command_build: build an index of commands (internal, irc and alias)
+ * This list will be sorted, and used for completion
+ */
+
+void
+index_command_build ()
+{
+ int i;
+ t_index_command *new_index;
+
+ index_commands = NULL;
+ last_index_command = NULL;
+ i = 0;
+ while (weechat_commands[i].command_name)
+ {
+ if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command)))))
+ {
+ new_index->command_name = strdup (weechat_commands[i].command_name);
+ index_command_insert_sorted (new_index);
+ }
+ i++;
+ }
+ i = 0;
+ while (irc_commands[i].command_name)
+ {
+ if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg)
+ {
+ if ((new_index = ((t_index_command *) malloc (sizeof (t_index_command)))))
+ {
+ new_index->command_name = strdup (irc_commands[i].command_name);
+ index_command_insert_sorted (new_index);
+ }
+ }
+ i++;
+ }
+}
+
+/*
+ * explode_string: explode a string according to separators
+ */
+
+char **
+explode_string (char *string, char *separators, int num_items_max,
+ int *num_items)
+{
+ int i, n_items;
+ char **array;
+ char *ptr, *ptr1, *ptr2;
+
+ if (num_items != NULL)
+ *num_items = 0;
+
+ n_items = num_items_max;
+
+ if (string == NULL)
+ return NULL;
+
+ if (num_items_max == 0)
+ {
+ /* calculate number of items */
+ ptr = string;
+ i = 1;
+ while ((ptr = strpbrk (ptr, separators)))
+ {
+ while (strchr (separators, ptr[0]) != NULL)
+ ptr++;
+ i++;
+ }
+ n_items = i;
+ }
+
+ array =
+ (char **) malloc ((num_items_max ? n_items : n_items + 1) *
+ sizeof (char *));
+
+ ptr1 = string;
+ ptr2 = string;
+
+ for (i = 0; i < n_items; i++)
+ {
+ while (strchr (separators, ptr1[0]) != NULL)
+ ptr1++;
+ if (i == (n_items - 1) || (ptr2 = strpbrk (ptr1, separators)) == NULL)
+ if ((ptr2 = strchr (ptr1, '\r')) == NULL)
+ if ((ptr2 = strchr (ptr1, '\n')) == NULL)
+ ptr2 = strchr (ptr1, '\0');
+
+ if ((ptr1 == NULL) || (ptr2 == NULL))
+ {
+ array[i] = NULL;
+ }
+ else
+ {
+ if (ptr2 - ptr1 > 0)
+ {
+ array[i] =
+ (char *) malloc ((ptr2 - ptr1 + 1) * sizeof (char));
+ array[i] = strncpy (array[i], ptr1, ptr2 - ptr1);
+ array[i][ptr2 - ptr1] = '\0';
+ ptr1 = ++ptr2;
+ }
+ else
+ {
+ array[i] = NULL;
+ }
+ }
+ }
+ if (num_items_max == 0)
+ {
+ array[i] = NULL;
+ if (num_items != NULL)
+ *num_items = i;
+ }
+ else
+ {
+ if (num_items != NULL)
+ *num_items = num_items_max;
+ }
+
+ return array;
+}
+
+/*
+ * exec_weechat_command: executes a command (WeeChat internal or IRC)
+ * returns: 1 if command was executed succesfully
+ * 0 if error (command not executed)
+ */
+
+int
+exec_weechat_command (t_irc_server *server, char *string)
+{
+ int i, j, argc, return_code;
+ char *pos, *ptr_args, **argv;
+
+ if ((!string[0]) || (string[0] != '/'))
+ return 0;
+
+ /* look for end of command */
+ ptr_args = NULL;
+ pos = strchr (string, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ ptr_args = pos;
+ if (!ptr_args[0])
+ ptr_args = NULL;
+ }
+
+ argv = explode_string (ptr_args, " ", 0, &argc);
+
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ if (strcasecmp (weechat_commands[i].command_name, string + 1) == 0)
+ {
+ if ((argc < weechat_commands[i].min_arg)
+ || (argc > weechat_commands[i].max_arg))
+ {
+ if (weechat_commands[i].min_arg ==
+ weechat_commands[i].max_arg)
+ gui_printf (NULL,
+ _("%s wrong argument count for "
+ WEECHAT_NAME " command '%s' "
+ "(expected: %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ weechat_commands[i].max_arg,
+ (weechat_commands[i].max_arg >
+ 1) ? "s" : "");
+ else
+ gui_printf (NULL,
+ _("%s wrong argument count for "
+ WEECHAT_NAME " command '%s' "
+ "(expected: between %d and %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ weechat_commands[i].min_arg,
+ weechat_commands[i].max_arg,
+ (weechat_commands[i].max_arg >
+ 1) ? "s" : "");
+ }
+ else
+ {
+ if (weechat_commands[i].cmd_function_args != NULL)
+ return_code = (int) (weechat_commands[i].cmd_function_args)
+ (argc, argv);
+ else
+ return_code = (int) (weechat_commands[i].cmd_function_1arg)
+ (ptr_args);
+ if (return_code < 0)
+ gui_printf (NULL,
+ _("%s " WEECHAT_NAME " command \"%s\" failed\n"),
+ WEECHAT_ERROR, string + 1);
+ }
+ if (argv)
+ {
+ for (j = 0; argv[j]; j++)
+ free (argv[j]);
+ free (argv);
+ }
+ return 1;
+ }
+ }
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if (strcasecmp (irc_commands[i].command_name, string + 1) == 0)
+ {
+ if ((argc < irc_commands[i].min_arg)
+ || (argc > irc_commands[i].max_arg))
+ {
+ if (irc_commands[i].min_arg == irc_commands[i].max_arg)
+ gui_printf
+ (NULL,
+ _("%s wrong argument count for IRC command '%s' "
+ "(expected: %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ irc_commands[i].max_arg,
+ (irc_commands[i].max_arg > 1) ? "s" : "");
+ else
+ gui_printf
+ (NULL,
+ _("%s wrong argument count for IRC command '%s' "
+ "(expected: between %d and %d arg%s)\n"),
+ WEECHAT_ERROR,
+ string + 1,
+ irc_commands[i].min_arg, irc_commands[i].max_arg,
+ (irc_commands[i].max_arg > 1) ? "s" : "");
+ }
+ else
+ {
+ if ((irc_commands[i].need_connection) &&
+ ((!server) || (!server->is_connected)))
+ {
+ gui_printf (NULL,
+ _("%s command '%s' needs a server connection!\n"),
+ WEECHAT_ERROR, irc_commands[i].command_name);
+ return 0;
+ }
+ if (irc_commands[i].cmd_function_args != NULL)
+ return_code = (int) (irc_commands[i].cmd_function_args)
+ (server, argc, argv);
+ else
+ return_code = (int) (irc_commands[i].cmd_function_1arg)
+ (server, ptr_args);
+ if (return_code < 0)
+ gui_printf (NULL,
+ _("%s IRC command \"%s\" failed\n"),
+ WEECHAT_ERROR, string + 1);
+ }
+ if (argv)
+ {
+ for (j = 0; argv[j]; j++)
+ free (argv[j]);
+ free (argv);
+ }
+ return 1;
+ }
+ }
+ gui_printf (server->window,
+ _("%s unknown command '%s' (type /help for help)\n"),
+ WEECHAT_ERROR,
+ string + 1);
+ if (argv)
+ {
+ for (j = 0; argv[j]; j++)
+ free (argv[j]);
+ free (argv);
+ }
+ return 0;
+}
+
+/*
+ * user_command: interprets user command (if beginning with '/')
+ * any other text is sent to the server, if connected
+ */
+
+void
+user_command (t_irc_server *server, char *command)
+{
+ t_irc_nick *ptr_nick;
+
+ if ((!command) || (command[0] == '\r') || (command[0] == '\n'))
+ return;
+ if ((command[0] == '/') && (command[1] != '/'))
+ {
+ /* WeeChat internal command (or IRC command) */
+ exec_weechat_command (server, command);
+ }
+ else
+ {
+ if ((command[0] == '/') && (command[1] == '/'))
+ command++;
+ if (!WIN_IS_SERVER(gui_current_window))
+ {
+ server_sendf (server, "PRIVMSG %s :%s\r\n",
+ CHANNEL(gui_current_window)->name,
+ command);
+
+ if (WIN_IS_PRIVATE(gui_current_window))
+ {
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "<");
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_NICK_SELF,
+ "%s", server->nick);
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "> ");
+ gui_printf_color_type (CHANNEL(gui_current_window)->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", command);
+ }
+ else
+ {
+ ptr_nick = nick_search (CHANNEL(gui_current_window), server->nick);
+ if (ptr_nick)
+ {
+ irc_display_nick (CHANNEL(gui_current_window)->window, ptr_nick,
+ MSG_TYPE_NICK, 1, 1, 0);
+ gui_printf_color (CHANNEL(gui_current_window)->window,
+ COLOR_WIN_CHAT, "%s\n", command);
+ }
+ else
+ gui_printf (server->window,
+ _("%s cannot find nick for sending message\n"),
+ WEECHAT_ERROR);
+ }
+ }
+ else
+ gui_printf (server->window, _("This window is not a channel!\n"));
+ }
+}
+
+/*
+ * weechat_cmd_alias: display or create alias
+ */
+
+int
+weechat_cmd_alias (int argc, char **argv)
+{
+ if (argc == 0)
+ {
+ /* List all aliases */
+ }
+ argv = NULL;
+ gui_printf (NULL, _("(TODO) \"/alias\" command not developed!\n"));
+ return 0;
+}
+
+/*
+ * weechat_cmd_clear: display or create alias
+ */
+
+int
+weechat_cmd_clear (int argc, char **argv)
+{
+ if (argc == 1)
+ {
+ if (strcmp (argv[0], "-all") == 0)
+ gui_window_clear_all ();
+ else
+ {
+ gui_printf (NULL,
+ _("unknown parameter \"%s\" for /clear command\n"),
+ argv[0]);
+ return -1;
+ }
+ }
+ else
+ gui_window_clear (gui_current_window);
+ return 0;
+}
+
+/*
+ * weechat_cmd_help: display help
+ */
+
+int
+weechat_cmd_help (int argc, char **argv)
+{
+ int i;
+
+ if (argc == 0)
+ {
+ gui_printf (NULL,
+ _("> List of " WEECHAT_NAME " internal commands:\n"));
+ for (i = 0; weechat_commands[i].command_name; i++)
+ gui_printf (NULL, " %s - %s\n",
+ weechat_commands[i].command_name,
+ weechat_commands[i].command_description);
+ gui_printf (NULL, _("> List of IRC commands:\n"));
+ for (i = 0; irc_commands[i].command_name; i++)
+ if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg)
+ gui_printf (NULL, " %s - %s\n",
+ irc_commands[i].command_name,
+ irc_commands[i].command_description);
+ }
+ if (argc == 1)
+ {
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ if (strcasecmp (weechat_commands[i].command_name, argv[0]) == 0)
+ {
+ gui_printf
+ (NULL,
+ _("> Help on " WEECHAT_NAME " internal command '%s':\n"),
+ weechat_commands[i].command_name);
+ gui_printf (NULL,
+ _("Syntax: /%s %s\n"),
+ weechat_commands[i].command_name,
+ (weechat_commands[i].
+ arguments) ? weechat_commands[i].
+ arguments : "");
+ if (weechat_commands[i].arguments_description)
+ {
+ gui_printf (NULL, "%s\n",
+ weechat_commands[i].
+ arguments_description);
+ }
+ return 0;
+ }
+ }
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if (strcasecmp (irc_commands[i].command_name, argv[0]) == 0)
+ {
+ gui_printf (NULL,
+ _("> Help on IRC command '%s':\n"),
+ irc_commands[i].command_name);
+ gui_printf (NULL, _("Syntax: /%s %s\n"),
+ irc_commands[i].command_name,
+ (irc_commands[i].arguments) ?
+ irc_commands[i].arguments : "");
+ if (irc_commands[i].arguments_description)
+ {
+ gui_printf (NULL, "%s\n",
+ irc_commands[i].
+ arguments_description);
+ }
+ return 0;
+ }
+ }
+ gui_printf (NULL,
+ _("No help available, \"%s\" is an unknown command\n"),
+ argv[0]);
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_set: set options
+ */
+
+int
+weechat_cmd_set (int argc, char **argv)
+{
+ int i, j, section_displayed;
+ char *color_name;
+
+ /* TODO: complete /set command */
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ section_displayed = 0;
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ if ((argc == 0) ||
+ ((argc > 0)
+ && (strstr (weechat_options[i][j].option_name, argv[0])
+ != NULL)))
+ {
+ if (!section_displayed)
+ {
+ gui_printf (NULL, "[%s]\n",
+ config_sections[i].section_name);
+ section_displayed = 1;
+ }
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ gui_printf (NULL, " %s = %s\n",
+ weechat_options[i][j].option_name,
+ (*weechat_options[i][j].ptr_int) ?
+ "ON" : "OFF");
+ break;
+ case OPTION_TYPE_INT:
+ gui_printf (NULL,
+ " %s = %d\n",
+ weechat_options[i][j].option_name,
+ *weechat_options[i][j].ptr_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ gui_printf (NULL,
+ " %s = %s\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].array_values[*weechat_options[i][j].ptr_int]);
+ break;
+ case OPTION_TYPE_COLOR:
+ color_name = gui_get_color_by_value (*weechat_options[i][j].ptr_int);
+ gui_printf (NULL,
+ " %s = %s\n",
+ weechat_options[i][j].option_name,
+ (color_name) ? color_name : _("(unknown)"));
+ break;
+ case OPTION_TYPE_STRING:
+ gui_printf (NULL, " %s = %s\n",
+ weechat_options[i][j].
+ option_name,
+ (*weechat_options[i][j].
+ ptr_string) ?
+ *weechat_options[i][j].
+ ptr_string : "");
+ break;
+ }
+ }
+ }
+ }
+ }
+ gui_printf (NULL, _("(TODO) \"/set\" command not developed!\n"));
+ return 0;
+}
+
+/*
+ * cmd_unalias: remove an alias
+ */
+
+int
+weechat_cmd_unalias (int argc, char **argv)
+{
+ if (argc != 1)
+ {
+ gui_printf
+ (NULL,
+ _("Wrong argument count for unalias function (expexted: 1 arg)\n"));
+ return -1;
+ }
+ argv = NULL;
+ gui_printf (NULL, _("(TODO) \"/unalias\" not developed!\n"));
+ return 0;
+}
diff --git a/weechat/src/command.h b/weechat/src/command.h
new file mode 100644
index 000000000..5bec6c92e
--- /dev/null
+++ b/weechat/src/command.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_COMMAND_H
+#define __WEECHAT_COMMAND_H 1
+
+#include "irc/irc.h"
+
+#define MAX_ARGS 8192
+
+typedef struct t_weechat_command t_weechat_command;
+
+struct t_weechat_command
+{
+ char *command_name;
+ char *command_description;
+ char *arguments;
+ char *arguments_description;
+ int min_arg, max_arg;
+ int (*cmd_function_args)(int, char **);
+ int (*cmd_function_1arg)(char *);
+};
+
+typedef struct t_index_command t_index_command;
+
+struct t_index_command
+{
+ char *command_name;
+ t_index_command *prev_index;
+ t_index_command *next_index;
+};
+
+extern t_index_command *index_commands;
+
+extern void index_command_build ();
+extern int exec_weechat_command (t_irc_server *, char *);
+extern void user_command (t_irc_server *, char *);
+extern int weechat_cmd_alias(int, char **);
+extern int weechat_cmd_clear(int, char **);
+extern int weechat_cmd_help (int, char **);
+extern int weechat_cmd_set (int, char **);
+extern int weechat_cmd_unalias (int, char **);
+
+#endif /* command.h */
diff --git a/weechat/src/completion.c b/weechat/src/completion.c
new file mode 100644
index 000000000..6809d8100
--- /dev/null
+++ b/weechat/src/completion.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* completion.c: completes words according to context (cmd/nick) */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "completion.h"
+#include "irc/irc.h"
+#include "command.h"
+
+
+/*
+ * completion_init: init completion
+ */
+
+void
+completion_init (t_completion *completion)
+{
+ completion->position = -1;
+ completion->base_word = NULL;
+}
+
+/*
+ * completion_command: complete a command
+ */
+
+void
+completion_command (t_completion *completion)
+{
+ int length, word_found_seen;
+ t_index_command *ptr_index;
+
+ length = strlen (completion->base_word) - 1;
+ word_found_seen = 0;
+ for (ptr_index = index_commands; ptr_index; ptr_index = ptr_index->next_index)
+ {
+ if (strncasecmp (ptr_index->command_name, completion->base_word + 1, length) == 0)
+ {
+ if ((!completion->word_found) || word_found_seen)
+ {
+ completion->word_found = ptr_index->command_name;
+ return;
+ }
+ }
+ if (completion->word_found &&
+ (strcasecmp (ptr_index->command_name, completion->word_found) == 0))
+ word_found_seen = 1;
+ }
+ if (completion->word_found)
+ {
+ completion->word_found = NULL;
+ completion_command (completion);
+ }
+}
+
+/*
+ * completion_nick: complete a nick
+ */
+
+void
+completion_nick (t_completion *completion, t_irc_channel *channel)
+{
+ int length, word_found_seen;
+ t_irc_nick *ptr_nick;
+
+ length = strlen (completion->base_word);
+ word_found_seen = 0;
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ if (strncasecmp (ptr_nick->nick, completion->base_word, length) == 0)
+ {
+ if ((!completion->word_found) || word_found_seen)
+ {
+ completion->word_found = ptr_nick->nick;
+ return;
+ }
+ }
+ if (completion->word_found &&
+ (strcasecmp (ptr_nick->nick, completion->word_found) == 0))
+ word_found_seen = 1;
+ }
+ if (completion->word_found)
+ {
+ completion->word_found = NULL;
+ completion_nick (completion, channel);
+ }
+}
+
+/*
+ * completion_search: complete word according to context
+ */
+
+void
+completion_search (t_completion *completion, void *channel,
+ char *buffer, int size, int pos)
+{
+ int i, pos_start, pos_end;
+ char *old_word_found;
+
+ /* TODO: complete when no word is there with command according to context */
+ if (size == 0)
+ {
+ completion->word_found = NULL;
+ return;
+ }
+
+ /* if new complation => look for base word */
+ if (pos != completion->position)
+ {
+ completion->word_found = NULL;
+
+ if ((pos == size) || (buffer[pos-1] != ' '))
+ pos--;
+ if ((pos > 0) && (buffer[pos] == ' '))
+ return;
+
+ i = pos;
+ while ((i >= 0) && (buffer[i] != ' '))
+ i--;
+ pos_start = i + 1;
+ i = pos;
+ while ((i < size) && (buffer[i] != ' '))
+ i++;
+ pos_end = i - 1;
+
+ if (pos_start > pos_end)
+ return;
+
+ completion->base_word_pos = pos_start;
+
+ if (completion->base_word)
+ free (completion->base_word);
+ completion->base_word = (char *) malloc (pos_end - pos_start + 2);
+
+ for (i = pos_start; i <= pos_end; i++)
+ completion->base_word[i - pos_start] = buffer[i];
+ completion->base_word[pos_end - pos_start + 1] = '\0';
+
+ if (completion->base_word[0] == '/')
+ completion->position_replace = pos_start + 1;
+ else
+ completion->position_replace = pos_start;
+ }
+
+ /* completion */
+ old_word_found = completion->word_found;
+ if (completion->base_word[0] == '/')
+ {
+ completion_command (completion);
+ if (completion->word_found)
+ {
+ if (old_word_found)
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (old_word_found);
+ else
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (completion->base_word) + 1;
+ }
+ }
+ else
+ {
+ if (channel)
+ {
+ completion_nick (completion, (t_irc_channel *)channel);
+ if (completion->word_found)
+ {
+ if (old_word_found)
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (old_word_found);
+ else
+ completion->diff_size = strlen (completion->word_found) -
+ strlen (completion->base_word);
+ }
+ }
+ }
+}
diff --git a/weechat/src/completion.h b/weechat/src/completion.h
new file mode 100644
index 000000000..f07d4a1f7
--- /dev/null
+++ b/weechat/src/completion.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_COMPLETION_H
+#define __WEECHAT_COMPLETION_H 1
+
+typedef struct t_completion t_completion;
+
+struct t_completion
+{
+ char *base_word; /* word to complete (when Tab was pressed) */
+ int base_word_pos; /* beggining of base word */
+ int position; /* position where we shoud complete */
+ char *word_found; /* word found (to replace base word) */
+ int position_replace; /* position where word should be replaced */
+ int diff_size; /* size difference (< 0 = char(s) deleted) */
+};
+
+extern void completion_init (t_completion *);
+extern void completion_search (t_completion *, void *, char *, int, int);
+
+#endif /* completion.h */
diff --git a/weechat/src/config.c b/weechat/src/config.c
new file mode 100644
index 000000000..ad93695b9
--- /dev/null
+++ b/weechat/src/config.c
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* config.c: WeeChat configuration */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#include "weechat.h"
+#include "config.h"
+#include "irc/irc.h"
+#include "gui/gui.h"
+
+
+/* config sections */
+
+t_config_section config_sections[CONFIG_NUMBER_SECTIONS] =
+{ { CONFIG_SECTION_LOOK, "look" },
+ { CONFIG_SECTION_COLORS, "colors" },
+ { CONFIG_SECTION_HISTORY, "history" },
+ { CONFIG_SECTION_LOG, "log" },
+ { CONFIG_SECTION_DCC, "dcc" },
+ { CONFIG_SECTION_PROXY, "proxy" },
+ { CONFIG_SECTION_SERVER, "server" }
+};
+
+/* config, look & feel section */
+
+int cfg_look_startup_logo;
+int cfg_look_startup_version;
+char *cfg_look_weechat_slogan;
+int cfg_look_color_nicks;
+int cfg_look_color_actions;
+int cfg_look_remove_colors_from_msgs;
+int cfg_look_nicklist;
+int cfg_look_nicklist_position;
+char *cfg_look_nicklist_position_values[] =
+{ "left", "right", "top", "bottom", NULL };
+int cfg_look_nicklist_min_size;
+int cfg_look_nicklist_max_size;
+int cfg_look_nickmode;
+int cfg_look_nickmode_empty;
+char *cfg_look_no_nickname;
+char *cfg_look_completor;
+
+t_config_option weechat_options_look[] =
+{ { "look_startup_logo", N_("display " WEECHAT_NAME " logo at startup"),
+ N_("display " WEECHAT_NAME " logo at startup"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_startup_logo, NULL, NULL },
+ { "look_startup_version", N_("display " WEECHAT_NAME " version at startup"),
+ N_("display " WEECHAT_NAME " version at startup"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_startup_version, NULL, NULL },
+ { "look_weechat_slogan", N_(WEECHAT_NAME "slogan"),
+ N_(WEECHAT_NAME "slogan (if empty, slogan is not used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "the geekest IRC client!", NULL, NULL, &cfg_look_weechat_slogan, NULL },
+ { "look_color_nicks", N_("display nick names with different colors"),
+ N_("display nick names with different colors"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_color_nicks, NULL, NULL },
+ { "look_color_actions", N_("display actions with different colors"),
+ N_("display actions with different colors"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_color_actions, NULL, NULL },
+ { "look_remove_colors_from_msgs", N_("remove colors from incoming messages"),
+ N_("remove colors from incoming messages"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_remove_colors_from_msgs, NULL, NULL },
+ { "look_nicklist", N_("display nicklist window"),
+ N_("display nicklist window (for channel windows)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nicklist, NULL, NULL },
+ { "look_nicklist_position", N_("nicklist position"),
+ N_("nicklist position (top, left, right (default), bottom)"),
+ OPTION_TYPE_INT_WITH_STRING, 0, 0, 0,
+ "right", cfg_look_nicklist_position_values, &cfg_look_nicklist_position, NULL, NULL },
+ { "look_nicklist_min_size", N_("min size for nicklist"),
+ N_("min size for nicklist (width or height, depending on look_nicklist_position "
+ "(0 = no min size))"),
+ OPTION_TYPE_INT, 0, 100, 0,
+ NULL, NULL, &cfg_look_nicklist_min_size, NULL, NULL },
+ { "look_nicklist_max_size", N_("max size for nicklist"),
+ N_("max size for nicklist (width or height, depending on look_nicklist_position "
+ "(0 = no max size; if min == max and > 0, then size is fixed))"),
+ OPTION_TYPE_INT, 0, 100, 0,
+ NULL, NULL, &cfg_look_nicklist_max_size, NULL, NULL },
+ { "look_no_nickname", N_("text to display instead of nick when not connected"),
+ N_("text to display instead of nick when not connected"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "-cmd-", NULL, NULL, &cfg_look_no_nickname, NULL },
+ { "look_nickmode", N_("display nick mode ((half)op/voice) before each nick"),
+ N_("display nick mode ((half)op/voice) before each nick"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nickmode, NULL, NULL },
+ { "look_nickmode_empty", N_("display space if nick mode is not (half)op/voice"),
+ N_("display space if nick mode is not (half)op/voice"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_look_nickmode_empty, NULL, NULL },
+ { "look_nick_completor", N_("the string inserted after nick completion"),
+ N_("the string inserted after nick completion"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ ":", NULL, NULL, &cfg_look_completor, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, colors section */
+
+int cfg_col_title;
+int cfg_col_title_bg;
+int cfg_col_chat;
+int cfg_col_chat_time;
+int cfg_col_chat_time_sep;
+int cfg_col_chat_prefix1;
+int cfg_col_chat_prefix2;
+int cfg_col_chat_nick;
+int cfg_col_chat_host;
+int cfg_col_chat_channel;
+int cfg_col_chat_dark;
+int cfg_col_chat_bg;
+int cfg_col_status;
+int cfg_col_status_active;
+int cfg_col_status_data_msg;
+int cfg_col_status_data_other;
+int cfg_col_status_more;
+int cfg_col_status_bg;
+int cfg_col_input;
+int cfg_col_input_channel;
+int cfg_col_input_nick;
+int cfg_col_input_bg;
+int cfg_col_nick;
+int cfg_col_nick_op;
+int cfg_col_nick_halfop;
+int cfg_col_nick_voice;
+int cfg_col_nick_sep;
+int cfg_col_nick_self;
+int cfg_col_nick_private;
+int cfg_col_nick_bg;
+
+t_config_option weechat_options_colors[] =
+{ /* title window */
+ { "col_title", N_("color for title bar"),
+ N_("color for title bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_title, NULL, NULL },
+ { "col_title_bg", N_("background for title bar"),
+ N_("background for title bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_title_bg, NULL, NULL },
+
+ /* chat window */
+ { "col_chat", N_("color for chat text"),
+ N_("color for chat text"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_chat, NULL, NULL },
+ { "col_chat_time", N_("color for time"),
+ N_("color for time in chat window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_chat_time, NULL, NULL },
+ { "col_chat_time_sep", N_("color for time separator"),
+ N_("color for time separator (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_chat_time_sep, NULL, NULL },
+ { "col_chat_prefix1", N_("color for 1st and 3rd char of prefix"),
+ N_("color for 1st and 3rd char of prefix"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_chat_prefix1, NULL, NULL },
+ { "col_chat_prefix2", N_("color for middle char of prefix"),
+ N_("color for middle char of prefix"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_chat_prefix2, NULL, NULL },
+ { "col_chat_nick", N_("color for nicks in actions"),
+ N_("color for nicks in actions (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_chat_nick, NULL, NULL },
+ { "col_chat_host", N_("color for hostnames"),
+ N_("color for hostnames (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_chat_host, NULL, NULL },
+ { "col_chat_channel", N_("color for channel names in actions"),
+ N_("color for channel names in actions (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_chat_channel, NULL, NULL },
+ { "col_chat_dark", N_("color for dark separators"),
+ N_("color for dark separators (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "green", NULL, &cfg_col_chat_dark, NULL, NULL },
+ { "col_chat_bg", N_("background for chat"),
+ N_("background for chat window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_chat_bg, NULL, NULL },
+
+ /* status window */
+ { "col_status", N_("color for status bar"),
+ N_("color for status bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_status, NULL, NULL },
+ { "col_status_active", N_("color for active window"),
+ N_("color for active window (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_status_active, NULL, NULL },
+ { "col_status_data_msg", N_("color for window with new messages"),
+ N_("color for window with new messages (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightred", NULL, &cfg_col_status_data_msg, NULL, NULL },
+ { "col_status_data_other", N_("color for window with new data (not messages)"),
+ N_("color for window with new data (not messages) (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_status_data_other, NULL, NULL },
+ { "col_status_more", N_("color for \"*MORE*\" text"),
+ N_("color for window with new data (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_status_more, NULL, NULL },
+ { "col_status_bg", N_("background for status window"),
+ N_("background for status window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_status_bg, NULL, NULL },
+
+ /* input window */
+ { "col_input", N_("color for input text"),
+ N_("color for input text"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_input, NULL, NULL },
+ { "col_input_channel", N_("color for input text (channel name)"),
+ N_("color for input text (channel name)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_input_channel, NULL, NULL },
+ { "col_input_nick", N_("color for input text (nick name)"),
+ N_("color for input text (nick name)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_input_nick, NULL, NULL },
+ { "col_input_bg", N_("background for input window"),
+ N_("background for input window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_input_bg, NULL, NULL },
+
+ /* nick window */
+ { "col_nick", N_("color for nicknames"),
+ N_("color for nicknames"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "gray", NULL, &cfg_col_nick, NULL, NULL },
+ { "col_nick_op", N_("color for operator symbol"),
+ N_("color for operator symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_nick_op, NULL, NULL },
+ { "col_nick_halfop", N_("color for half-operator symbol"),
+ N_("color for half-operator symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_nick_halfop, NULL, NULL },
+ { "col_nick_voice", N_("color for voice symbol"),
+ N_("color for voice symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_nick_voice, NULL, NULL },
+ { "col_nick_sep", N_("color for nick separator"),
+ N_("color for nick separator"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_nick_sep, NULL, NULL },
+ { "col_nick_self", N_("color for local nick"),
+ N_("color for local nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_nick_self, NULL, NULL },
+ { "col_nick_private", N_("color for other nick in private window"),
+ N_("color for other nick in private window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_nick_private, NULL, NULL },
+ { "col_nick_bg", N_("background for nicknames"),
+ N_("background for nicknames"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_nick_bg, NULL, NULL },
+
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, history section */
+
+int cfg_history_max_lines;
+int cfg_history_max_commands;
+
+t_config_option weechat_options_history[] =
+{ { "history_max_lines", N_("max lines in history (per window)"),
+ N_("maximum number of lines in history "
+ "for one server/channel/private window (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 4096,
+ NULL, NULL, &cfg_history_max_lines, NULL, NULL },
+ { "history_max_commands", N_("max user commands in history"),
+ N_("maximum number of user commands in history (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 100,
+ NULL, NULL, &cfg_history_max_commands, NULL, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, log section */
+
+int cfg_log_auto_channels;
+int cfg_log_auto_private;
+char *cfg_log_path;
+char *cfg_log_name;
+char *cfg_log_timestamp;
+char *cfg_log_start_string;
+char *cfg_log_end_string;
+
+t_config_option weechat_options_log[] =
+{ { "log_auto_channels", N_("automatically log channel chats"),
+ N_("automatically log channel chats"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_log_auto_channels, NULL, NULL },
+ { "log_auto_private", N_("automatically log private chats"),
+ N_("automatically log private chats"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_log_auto_private, NULL, NULL },
+ { "log_path", N_("path for log files"),
+ N_("path for " WEECHAT_NAME " log files"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "~/.weechat/logs/", NULL, NULL, &cfg_log_path, NULL },
+ { "log_name", N_("name for log files"),
+ N_("name for log files (%S == irc server name, "
+ "%N == channel name (or nickname if private chat)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%S,%N.weechatlog", NULL, NULL, &cfg_log_name, NULL },
+ { "log_timestamp", N_("timestamp for log"),
+ N_("timestamp for log (see man strftime for date/time specifiers)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "~", NULL, NULL, &cfg_log_timestamp, NULL },
+ { "log_start_string", N_("start string for log files"),
+ N_("text writed when starting new log file "
+ "(see man strftime for date/time specifiers)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "--- Log started %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_start_string, NULL },
+ { "log_end_string", N_("end string for log files"),
+ N_("text writed when ending log file "
+ "(see man strftime for date/time specifiers)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "--- Log ended %a %b %d %Y %H:%M:%s", NULL, NULL, &cfg_log_end_string, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, dcc section */
+
+int cfg_dcc_auto_accept_files;
+int cfg_dcc_auto_accept_max_size;
+int cfg_dcc_auto_accept_chats;
+int cfg_dcc_timeout;
+char *cfg_dcc_download_path;
+char *cfg_dcc_upload_path;
+int cfg_dcc_auto_rename;
+int cfg_dcc_auto_resume;
+
+t_config_option weechat_options_dcc[] =
+{ { "dcc_auto_accept_files", N_("automatically accept dcc files"),
+ N_("automatically accept incoming dcc files"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_accept_files, NULL, NULL },
+ { "dcc_auto_accept_max_size", N_("max size when auto accepting file"),
+ N_("maximum size for incoming file when automatically accepted"),
+ OPTION_TYPE_INT, 0, INT_MAX, 0,
+ NULL, NULL, &cfg_dcc_auto_accept_max_size, NULL, NULL },
+ { "dcc_auto_accept_chats", N_("automatically accept dcc chats"),
+ N_("automatically accept dcc chats (use carefully!)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_accept_chats, NULL, NULL },
+ { "dcc_timeout", N_("timeout for dcc request"),
+ N_("timeout for dcc request (in seconds)"),
+ OPTION_TYPE_INT, 1, INT_MAX, 300,
+ NULL, NULL, &cfg_dcc_timeout, NULL, NULL },
+ { "dcc_download_path", N_("path for incoming files with dcc"),
+ N_("path for writing incoming files with dcc (default: user home)"),
+ OPTION_TYPE_STRING, 0, 0, 0, "~",
+ NULL, NULL, &cfg_dcc_download_path, NULL },
+ { "dcc_upload_path", N_("default path for sending files with dcc"),
+ N_("path for reading files when sending thru dcc (when no path is specified)"),
+ OPTION_TYPE_STRING, 0, 0, 0, "~",
+ NULL, NULL, &cfg_dcc_upload_path, NULL },
+ { "dcc_auto_rename", N_("automatically rename dcc files if already exists"),
+ N_("rename incoming files if already exists (add '.1', '.2', ...)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_rename, NULL, NULL },
+ { "dcc_auto_resume", N_("automatically resume aborted transfers"),
+ N_("automatically resume dcc trsnafer if connection with remote host is loosed"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_resume, NULL, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, proxy section */
+
+int cfg_proxy_use;
+char *cfg_proxy_address;
+int cfg_proxy_port;
+char *cfg_proxy_password;
+
+t_config_option weechat_options_proxy[] =
+{ { "proxy_use", N_("use proxy"),
+ N_("use a proxy server to connect to irc server"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_proxy_use, NULL, NULL },
+ { "proxy_address", N_("proxy address"),
+ N_("proxy server address (IP or hostname)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_proxy_address, NULL },
+ { "proxy_port", N_("port for proxy"),
+ N_("port for connecting to proxy server"),
+ OPTION_TYPE_INT, 0, 65535, 1080,
+ NULL, NULL, &cfg_proxy_port, NULL, NULL },
+ { "proxy_password", N_("proxy password"),
+ N_("password for proxy server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_proxy_password, NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, server section */
+
+static t_irc_server cfg_server;
+
+t_config_option weechat_options_server[] =
+{ { "server_name", N_("server name"),
+ N_("name associated to IRC server (for display only)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.name), NULL },
+ { "server_address", N_("server address or hostname"),
+ N_("IP address or hostname of IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.address), NULL },
+ { "server_port", N_("port for IRC server"),
+ N_("port for connecting to server"),
+ OPTION_TYPE_INT, 0, 65535, 6667,
+ NULL, NULL, &(cfg_server.port), NULL, NULL },
+ { "server_password", N_("server password"),
+ N_("password for IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.password), NULL },
+ { "server_nick1", N_("nickname for server"),
+ N_("nickname to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick1), NULL },
+ { "server_nick2", N_("alternate nickname for server"),
+ N_("alternate nickname to use on IRC server (if nickname is already used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick2), NULL },
+ { "server_nick3", N_("2nd alternate nickname for server"),
+ N_("2nd alternate nickname to use on IRC server (if alternate nickname is already used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick3), NULL },
+ { "server_username", N_("user name for server"),
+ N_("user name to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.username), NULL },
+ { "server_realname", N_("real name for server"),
+ N_("real name to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.realname), NULL },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* all weechat options */
+
+t_config_option *weechat_options[CONFIG_NUMBER_SECTIONS] =
+{ weechat_options_look, weechat_options_colors, weechat_options_history,
+ weechat_options_log, weechat_options_dcc, weechat_options_proxy,
+ weechat_options_server
+};
+
+
+/*
+ * get_pos_array_values: returns position of a string in an array of values
+ * returns -1 if not found, otherwise position
+ */
+
+int
+get_pos_array_values (char **array, char *string)
+{
+ int i;
+
+ i = 0;
+ while (array[i])
+ {
+ if (strcasecmp (array[i], string) == 0)
+ return i;
+ i++;
+ }
+ /* string not found in array */
+ return -1;
+}
+
+/*
+ * config_init_server: init server struct
+ */
+
+void
+config_init_server ()
+{
+ cfg_server.name = NULL;
+ cfg_server.address = NULL;
+ cfg_server.port = -1;
+ cfg_server.password = NULL;
+ cfg_server.nick1 = NULL;
+ cfg_server.nick2 = NULL;
+ cfg_server.nick3 = NULL;
+ cfg_server.username = NULL;
+ cfg_server.realname = NULL;
+}
+
+/*
+ * config_allocate_server: allocate a new server
+ */
+
+int
+config_allocate_server (char *filename, int line_number)
+{
+ if (!cfg_server.name
+ || !cfg_server.address
+ || cfg_server.port < 0
+ || !cfg_server.nick1
+ || !cfg_server.nick2
+ || !cfg_server.nick3
+ || !cfg_server.username
+ || !cfg_server.realname)
+ {
+ server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: new server, but previous was incomplete\n"),
+ WEECHAT_WARNING, filename, line_number);
+ return 0;
+
+ }
+ if (server_name_already_exists (cfg_server.name))
+ {
+ server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: server '%s' already exists\n"),
+ WEECHAT_WARNING, filename, line_number, cfg_server.name);
+ return 0;
+ }
+ if (!server_new (cfg_server.name,
+ cfg_server.address, cfg_server.port, cfg_server.password,
+ cfg_server.nick1, cfg_server.nick2, cfg_server.nick3,
+ cfg_server.username, cfg_server.realname))
+ {
+ server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: unable to create server\n"),
+ WEECHAT_WARNING, filename, line_number);
+ return 0;
+ }
+ if (cfg_server.name)
+ free (cfg_server.name);
+ if (cfg_server.address)
+ free (cfg_server.address);
+ if (cfg_server.password)
+ free (cfg_server.password);
+ if (cfg_server.nick1)
+ free (cfg_server.nick1);
+ if (cfg_server.nick2)
+ free (cfg_server.nick2);
+ if (cfg_server.nick3)
+ free (cfg_server.nick3);
+ if (cfg_server.username)
+ free (cfg_server.username);
+ if (cfg_server.realname)
+ free (cfg_server.realname);
+ if (cfg_server.nick)
+ free (cfg_server.nick);
+
+ config_init_server ();
+
+ return 1;
+}
+
+/*
+ * config_default_values: initialize config variables with default values
+ */
+
+void
+config_default_values ()
+{
+ int i, j, int_value;
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ case OPTION_TYPE_INT:
+ *weechat_options[i][j].ptr_int =
+ weechat_options[i][j].default_int;
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ int_value = get_pos_array_values (
+ weechat_options[i][j].array_values,
+ weechat_options[i][j].default_string);
+ if (int_value < 0)
+ gui_printf (NULL,
+ _("%s unable to assign default int with string (\"%s\")\n"),
+ weechat_options[i][j].default_string);
+ else
+ *weechat_options[i][j].ptr_int =
+ int_value;
+ break;
+ case OPTION_TYPE_COLOR:
+ if (!gui_assign_color (
+ weechat_options[i][j].ptr_int,
+ weechat_options[i][j].default_string))
+ gui_printf (NULL,
+ _("%s unable to assign default color (\"%s\")\n"),
+ weechat_options[i][j].default_string);
+ break;
+ case OPTION_TYPE_STRING:
+ *weechat_options[i][j].ptr_string =
+ strdup (weechat_options[i][j].default_string);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * config_read: read WeeChat configuration
+ * returns: 0 = successful
+ * -1 = config file file not found
+ * < -1 = other error (fatal)
+ */
+
+int
+config_read ()
+{
+ char *filename;
+ FILE *file;
+ int section, line_number, i, option_number, int_value;
+ int server_found;
+ char line[1024], *ptr_line, *pos, *pos2;
+
+ filename =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME"));
+ if ((file = fopen (filename, "rt")) == NULL)
+ {
+ gui_printf (NULL, _("%s config file \"%s\" not found.\n"),
+ WEECHAT_WARNING, filename);
+ free (filename);
+ return -1;
+ }
+
+ config_default_values ();
+ config_init_server ();
+
+ /* read config file */
+ section = CONFIG_SECTION_NONE;
+ server_found = 0;
+ line_number = 0;
+ while (!feof (file))
+ {
+ ptr_line = fgets (line, sizeof (line) - 1, file);
+ line_number++;
+ if (ptr_line)
+ {
+ /* skip spaces */
+ while (ptr_line[0] == ' ')
+ ptr_line++;
+ /* not a comment and not an empty line */
+ if ((ptr_line[0] != '#') && (ptr_line[0] != '\r')
+ && (ptr_line[0] != '\n'))
+ {
+ /* beginning of section */
+ if (ptr_line[0] == '[')
+ {
+ pos = strchr (line, ']');
+ if (pos == NULL)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid syntax, missing \"]\"\n"),
+ WEECHAT_WARNING, filename, line_number);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ pos[0] = '\0';
+ pos = ptr_line + 1;
+ section = CONFIG_SECTION_NONE;
+ for (i = 0; config_sections[i].section_name; i++)
+ {
+ if (strcmp (config_sections[i].section_name, pos) == 0)
+ {
+ section = i;
+ break;
+ }
+ }
+ if (section == CONFIG_SECTION_NONE)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: unknown section identifier (\"%s\")\n"),
+ WEECHAT_WARNING, filename, line_number, pos);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ if (server_found)
+ {
+ /* if server already started => create it */
+ if (!config_allocate_server (filename, line_number))
+ {
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ }
+ server_found = (section == CONFIG_SECTION_SERVER) ? 1 : 0;
+ }
+ else
+ {
+ pos = strchr (line, '=');
+ if (pos == NULL)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid syntax, missing \"=\"\n"),
+ WEECHAT_WARNING, filename, line_number);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ else
+ {
+ pos[0] = '\0';
+ pos++;
+ pos2 = strchr (pos, '\r');
+ if (pos2 != NULL)
+ pos2[0] = '\0';
+ pos2 = strchr (pos, '\n');
+ if (pos2 != NULL)
+ pos2[0] = '\0';
+ option_number = -1;
+ for (i = 0;
+ weechat_options[section][i].option_name; i++)
+ {
+ if (strcmp
+ (weechat_options[section][i].option_name,
+ ptr_line) == 0)
+ {
+ option_number = i;
+ break;
+ }
+ }
+ if (option_number < 0)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid option \"%s\"\n"),
+ WEECHAT_WARNING, filename, line_number, ptr_line);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ else
+ {
+ switch (weechat_options[section]
+ [option_number].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ if (strcasecmp (pos, "on") == 0)
+ *weechat_options[section]
+ [option_number].ptr_int = BOOL_TRUE;
+ else if (strcasecmp (pos, "off") == 0)
+ *weechat_options[section]
+ [option_number].ptr_int = BOOL_FALSE;
+ else
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for"
+ "option '%s'\n"
+ "Expected: boolean value: "
+ "'off' or 'on'\n"),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ break;
+ case OPTION_TYPE_INT:
+ int_value = atoi (pos);
+ if ((int_value <
+ weechat_options[section]
+ [option_number].min)
+ || (int_value >
+ weechat_options[section]
+ [option_number].max))
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for"
+ "option '%s'\n"
+ "Expected: integer between %d "
+ "and %d\n"),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line,
+ weechat_options[section][option_number].min,
+ weechat_options[section][option_number].max);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ *weechat_options[section][option_number].ptr_int =
+ int_value;
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ int_value = get_pos_array_values (
+ weechat_options[section][option_number].array_values,
+ pos);
+ if (int_value < 0)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for"
+ "option '%s'\n"
+ "Expected: one of these strings: "),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line);
+ i = 0;
+ while (weechat_options[section][option_number].array_values[i])
+ {
+ gui_printf (NULL, "\"%s\" ",
+ weechat_options[section][option_number].array_values[i]);
+ i++;
+ }
+ gui_printf (NULL, "\n");
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ *weechat_options[section][option_number].ptr_int =
+ int_value;
+ break;
+ case OPTION_TYPE_COLOR:
+ if (!gui_assign_color (
+ weechat_options[section][option_number].ptr_int,
+ pos))
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid color "
+ "name for option '%s'\n"),
+ WEECHAT_WARNING, filename,
+ line_number,
+ ptr_line);
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ break;
+ case OPTION_TYPE_STRING:
+ if (*weechat_options[section]
+ [option_number].ptr_string)
+ free (*weechat_options[section][option_number].ptr_string);
+ *weechat_options[section][option_number].ptr_string =
+ strdup (pos);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (server_found)
+ {
+ if (!config_allocate_server (filename, line_number))
+ {
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ }
+
+ /* set default colors for colors not set */
+ /*for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ if ((weechat_options[i][j].option_type == OPTION_TYPE_COLOR) &&
+ (*weechat_options[i][j].ptr_int == COLOR_NOT_SET))
+ *weechat_options[i][j].ptr_int =
+ gui_get_color_by_name (weechat_options[i][j].default_string);
+ }
+ }
+ }*/
+
+ fclose (file);
+ free (filename);
+
+ return 0;
+}
+
+
+/*
+ * config_create_default: create default WeeChat config
+ */
+
+int
+config_create_default ()
+{
+ char *filename;
+ char line[1024];
+ FILE *file;
+ int i, j;
+ time_t current_time;
+
+ filename =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (filename, "%s/.weechat/" WEECHAT_CONFIG_NAME, getenv ("HOME"));
+ if ((file = fopen (filename, "wt")) == NULL)
+ {
+ free (filename);
+ gui_printf (NULL, _("%s cannot create file \"%s\"\n"),
+ WEECHAT_ERROR, filename);
+ return -1;
+ }
+
+ printf (_(WEECHAT_NAME ": creating default config file...\n"));
+
+ current_time = time (NULL);
+ sprintf (line, _("#\n# " WEECHAT_NAME " configuration file, generated by "
+ WEECHAT_NAME " " WEECHAT_VERSION " on %s"), ctime (&current_time));
+ fputs (line, file);
+ fputs (_("# This file may be edited by user. Invalid syntax will prevent "
+ WEECHAT_NAME " from running!\n#\n"), file);
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if (i != CONFIG_SECTION_SERVER)
+ {
+ sprintf (line, "\n[%s]\n", config_sections[i].section_name);
+ fputs (line, file);
+ if ((i == CONFIG_SECTION_HISTORY) || (i == CONFIG_SECTION_LOG) ||
+ (i == CONFIG_SECTION_DCC) || (i == CONFIG_SECTION_PROXY))
+ {
+ sprintf (line,
+ "# WARNING!!! Options for section \"%s\" are not developed!\n",
+ config_sections[i].section_name);
+ fputs (line, file);
+ }
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ sprintf (line, "%s=%s\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].
+ default_int) ? "on" : "off");
+ break;
+ case OPTION_TYPE_INT:
+ sprintf (line, "%s=%d\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].default_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ case OPTION_TYPE_COLOR:
+ case OPTION_TYPE_STRING:
+ sprintf (line, "%s=%s\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].default_string);
+ break;
+ }
+ fputs (line, file);
+ }
+ }
+ }
+
+ /* default server is freenode */
+ fputs ("\n[server]\n", file);
+ fputs ("server_name=freenode\n", file);
+ fputs ("server_address=irc.freenode.net\n", file);
+ fputs ("server_port=6667\n", file);
+ fputs ("server_password=\n", file);
+ fputs ("server_nick1=weechat_user\n", file);
+ fputs ("server_nick2=weechat2\n", file);
+ fputs ("server_nick3=weechat3\n", file);
+ fputs ("server_username=weechat\n", file);
+ fputs ("server_realname=WeeChat default realname\n", file);
+
+ fclose (file);
+ free (filename);
+ return 0;
+}
+
+/*
+ * config_write: write WeeChat configurtion
+ */
+
+void
+config_write ()
+{
+ /* TODO: write "config_write" function! */
+}
diff --git a/weechat/src/config.h b/weechat/src/config.h
new file mode 100644
index 000000000..cc84eaab6
--- /dev/null
+++ b/weechat/src/config.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_CONFIG_H
+#define __WEECHAT_CONFIG_H 1
+
+#define WEECHAT_CONFIG_NAME "weechat.rc"
+
+#define CONFIG_SECTION_NONE -1
+#define CONFIG_SECTION_LOOK 0
+#define CONFIG_SECTION_COLORS 1
+#define CONFIG_SECTION_HISTORY 2
+#define CONFIG_SECTION_LOG 3
+#define CONFIG_SECTION_DCC 4
+#define CONFIG_SECTION_PROXY 5
+#define CONFIG_SECTION_SERVER 6
+#define CONFIG_NUMBER_SECTIONS 7
+
+#define OPTION_TYPE_BOOLEAN 1 /* values: on/off */
+#define OPTION_TYPE_INT 2 /* values: from min to max */
+#define OPTION_TYPE_INT_WITH_STRING 3 /* values: one from **array_values */
+#define OPTION_TYPE_COLOR 4 /* values: a color name */
+#define OPTION_TYPE_STRING 5 /* values: any string, may be empty */
+
+#define BOOL_FALSE 0
+#define BOOL_TRUE 1
+
+#define CFG_LOOK_NICKLIST_LEFT 0
+#define CFG_LOOK_NICKLIST_RIGHT 1
+#define CFG_LOOK_NICKLIST_TOP 2
+#define CFG_LOOK_NICKLIST_BOTTOM 3
+
+typedef struct t_config_section t_config_section;
+
+struct t_config_section
+{
+ int section_number;
+ char *section_name;
+};
+
+typedef struct t_config_option t_config_option;
+
+struct t_config_option
+{
+ char *option_name;
+ char *short_description;
+ char *long_description;
+ int option_type;
+ int min, max;
+ int default_int;
+ char *default_string;
+ char **array_values;
+ int *ptr_int;
+ char **ptr_string;
+ int (*handler_change)(int *, char **);
+};
+
+extern int cfg_look_startup_logo;
+extern int cfg_look_startup_version;
+extern char *cfg_look_weechat_slogan;
+extern int cfg_look_color_nicks;
+extern int cfg_look_color_actions;
+extern int cfg_look_remove_colors_from_msgs;
+extern int cfg_look_nicklist;
+extern int cfg_look_nicklist_position;
+extern int cfg_look_nicklist_min_size;
+extern int cfg_look_nicklist_max_size;
+extern int cfg_look_nickmode;
+extern int cfg_look_nickmode_empty;
+extern char *cfg_look_no_nickname;
+extern char *cfg_look_completor;
+
+extern int cfg_col_title;
+extern int cfg_col_title_bg;
+extern int cfg_col_chat;
+extern int cfg_col_chat_time;
+extern int cfg_col_chat_time_sep;
+extern int cfg_col_chat_prefix1;
+extern int cfg_col_chat_prefix2;
+extern int cfg_col_chat_nick;
+extern int cfg_col_chat_host;
+extern int cfg_col_chat_channel;
+extern int cfg_col_chat_dark;
+extern int cfg_col_chat_bg;
+extern int cfg_col_status;
+extern int cfg_col_status_active;
+extern int cfg_col_status_data_msg;
+extern int cfg_col_status_data_other;
+extern int cfg_col_status_more;
+extern int cfg_col_status_bg;
+extern int cfg_col_input;
+extern int cfg_col_input_channel;
+extern int cfg_col_input_nick;
+extern int cfg_col_input_bg;
+extern int cfg_col_nick;
+extern int cfg_col_nick_op;
+extern int cfg_col_nick_halfop;
+extern int cfg_col_nick_voice;
+extern int cfg_col_nick_sep;
+extern int cfg_col_nick_self;
+extern int cfg_col_nick_private;
+extern int cfg_col_nick_bg;
+
+extern int cfg_history_max_lines;
+extern int cfg_history_max_commands;
+
+extern int cfg_log_auto_channels;
+extern int cfg_log_auto_private;
+extern char *cfg_log_path;
+extern char *cfg_log_name;
+extern char *cfg_log_timestamp;
+extern char *cfg_log_start_string;
+extern char *cfg_log_end_string;
+
+extern int cfg_dcc_auto_accept_files;
+extern int cfg_dcc_auto_accept_max_size;
+extern int cfg_dcc_auto_accept_chats;
+extern int cfg_dcc_timeout;
+extern char *cfg_dcc_download_path;
+extern char *cfg_dcc_upload_path;
+extern int cfg_dcc_auto_rename;
+extern int cfg_dcc_auto_resume;
+
+extern int cfg_proxy_use;
+extern char *cfg_proxy_address;
+extern int cfg_proxy_port;
+extern char *cfg_proxy_password;
+
+extern t_config_section config_sections [CONFIG_NUMBER_SECTIONS];
+extern t_config_option * weechat_options [CONFIG_NUMBER_SECTIONS];
+
+extern int config_read ();
+extern int config_create_default ();
+extern void config_write ();
+
+#endif /* config.h */
diff --git a/weechat/src/gui/Makefile b/weechat/src/gui/Makefile
new file mode 100644
index 000000000..77d66bea7
--- /dev/null
+++ b/weechat/src/gui/Makefile
@@ -0,0 +1,55 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# WeeChat with Curses interface
+ifeq ($(GUI), curses)
+curses: curses/gui.a
+curses/gui.a:
+ cd curses && make
+endif
+
+# WeeChat with Gtk+ interface
+ifeq ($(GUI), gtk)
+gtk: gtk/gui.a
+gtk/gui.a:
+ cd gtk && make
+endif
+
+# WeeChat with Qt interface
+ifeq ($(GUI), qt)
+qt: qt/gui.a
+qt/gui.a:
+ cd qt && make
+endif
+
+# WeeChat with Text interface
+ifeq ($(GUI), text)
+text: text/gui.a
+text/gui.a:
+ cd text && make
+endif
+
+
+all:
+ make curses GUI=curses
+
+clean:
+ rm -f *.o *.a *~ core
+ cd curses && make clean
+ cd gtk && make clean
+ cd qt && make clean
+ cd text && make clean
diff --git a/weechat/src/gui/curses/Makefile b/weechat/src/gui/curses/Makefile
new file mode 100644
index 000000000..80f800dd9
--- /dev/null
+++ b/weechat/src/gui/curses/Makefile
@@ -0,0 +1,38 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_CURSES
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../completion.h \
+ ../../history.h ../../config.h ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h ../../completion.h \
+ ../../history.h ../../command.h ../../irc/irc.h ../../gui/gui.h
diff --git a/weechat/src/gui/curses/gui-display.c b/weechat/src/gui/curses/gui-display.c
new file mode 100644
index 000000000..9ad67edac
--- /dev/null
+++ b/weechat/src/gui/curses/gui-display.c
@@ -0,0 +1,1730 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-display.c: display functions for Curses GUI */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <curses.h>
+
+#include "../../weechat.h"
+#include "../gui.h"
+#include "../../config.h"
+#include "../../irc/irc.h"
+
+
+int gui_ready; /* = 1 if GUI is initialized */
+
+t_gui_window *gui_windows = NULL; /* pointer to first window */
+t_gui_window *last_gui_window = NULL; /* pointer to last window */
+t_gui_window *gui_current_window = NULL; /* pointer to current window */
+
+t_gui_color gui_colors[] =
+{ { "default", -1 | A_NORMAL },
+ { "black", COLOR_BLACK | A_NORMAL },
+ { "red", COLOR_RED | A_NORMAL },
+ { "lightred", COLOR_RED | A_BOLD },
+ { "green", COLOR_GREEN | A_NORMAL },
+ { "lightgreen", COLOR_GREEN | A_BOLD },
+ { "brown", COLOR_YELLOW | A_NORMAL },
+ { "yellow", COLOR_YELLOW | A_BOLD },
+ { "blue", COLOR_BLUE | A_NORMAL },
+ { "lightblue", COLOR_BLUE | A_BOLD },
+ { "magenta", COLOR_MAGENTA | A_NORMAL },
+ { "lightmagenta", COLOR_MAGENTA | A_BOLD },
+ { "cyan", COLOR_CYAN | A_NORMAL },
+ { "lightcyan", COLOR_CYAN | A_BOLD },
+ { "gray", COLOR_WHITE },
+ { "white", COLOR_WHITE | A_BOLD },
+ { NULL, 0 }
+};
+
+char *nicks_colors[COLOR_WIN_NICK_NUMBER] =
+{ "cyan", "magenta", "green", "brown", "lightblue", "gray",
+ "lightcyan", "lightmagenta", "lightgreen", "blue" };
+
+int color_attr[NUM_COLORS];
+
+/*
+ * gui_assign_color: assign a color (read from config)
+ */
+
+int
+gui_assign_color (int *color, char *color_name)
+{
+ int i;
+
+ /* look for curses colors in table */
+ i = 0;
+ while (gui_colors[i].name)
+ {
+ if (strcasecmp (gui_colors[i].name, color_name) == 0)
+ {
+ *color = gui_colors[i].color;
+ return 1;
+ }
+ i++;
+ }
+
+ /* color not found */
+ return 0;
+}
+
+/*
+ * gui_get_color_by_name: get color by name
+ */
+
+int
+gui_get_color_by_name (char *color_name)
+{
+ int i;
+
+ /* look for curses colors in table */
+ i = 0;
+ while (gui_colors[i].name)
+ {
+ if (strcasecmp (gui_colors[i].name, color_name) == 0)
+ return gui_colors[i].color;
+ i++;
+ }
+
+ /* color not found */
+ return -1;
+}
+
+/*
+ * gui_get_color_by_value: get color name by value
+ */
+
+char *
+gui_get_color_by_value (int color_value)
+{
+ int i;
+
+ /* look for curses colors in table */
+ i = 0;
+ while (gui_colors[i].name)
+ {
+ if (gui_colors[i].color == color_value)
+ return gui_colors[i].name;
+ i++;
+ }
+
+ /* color not found */
+ return NULL;
+}
+
+/*
+ * gui_window_set_color: set color for window
+ */
+
+void
+gui_window_set_color (WINDOW *window, int num_color)
+{
+ if (has_colors)
+ {
+ if (color_attr[num_color - 1] & A_BOLD)
+ wattron (window, COLOR_PAIR (num_color) | A_BOLD);
+ else
+ {
+ wattroff (window, A_BOLD);
+ wattron (window, COLOR_PAIR (num_color));
+ }
+ }
+}
+
+/*
+ * gui_calculate_pos_size: calculate position and size for a window & sub-win
+ */
+
+void
+gui_calculate_pos_size (t_gui_window *window)
+{
+ int max_length, lines;
+ int num_nicks, num_op, num_halfop, num_voice, num_normal;
+
+ /* global position & size */
+ /* TODO: get values from function parameters */
+ window->win_x = 0;
+ window->win_y = 0;
+ window->win_width = COLS;
+ window->win_height = LINES;
+
+ /* init chat & nicklist settings */
+ /* TODO: calculate values from function parameters */
+ if (WIN_IS_CHANNEL(window))
+ {
+ max_length = nick_get_max_length (CHANNEL(window));
+
+ switch (cfg_look_nicklist_position)
+ {
+ case CFG_LOOK_NICKLIST_LEFT:
+ window->win_chat_x = max_length + 2;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS - max_length - 2;
+ window->win_chat_height = LINES - 3;
+ window->win_nick_x = 0;
+ window->win_nick_y = 1;
+ window->win_nick_width = max_length + 2;
+ window->win_nick_height = LINES - 3;
+ break;
+ case CFG_LOOK_NICKLIST_RIGHT:
+ window->win_chat_x = 0;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS - max_length - 2;
+ window->win_chat_height = LINES - 3;
+ window->win_nick_x = COLS - max_length - 2;
+ window->win_nick_y = 1;
+ window->win_nick_width = max_length + 2;
+ window->win_nick_height = LINES - 3;
+ break;
+ case CFG_LOOK_NICKLIST_TOP:
+ nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop,
+ &num_voice, &num_normal);
+ if (((max_length + 1) * num_nicks) % COLS == 0)
+ lines = ((max_length + 1) * num_nicks) / COLS;
+ else
+ lines = (((max_length + 1) * num_nicks) / COLS) + 1;
+ window->win_chat_x = 0;
+ window->win_chat_y = 1 + (lines + 1);
+ window->win_chat_width = COLS;
+ window->win_chat_height = LINES - 3 - (lines + 1);
+ window->win_nick_x = 0;
+ window->win_nick_y = 1;
+ window->win_nick_width = COLS;
+ window->win_nick_height = lines + 1;
+ break;
+ case CFG_LOOK_NICKLIST_BOTTOM:
+ nick_count (CHANNEL(window), &num_nicks, &num_op, &num_halfop,
+ &num_voice, &num_normal);
+ if (((max_length + 1) * num_nicks) % COLS == 0)
+ lines = ((max_length + 1) * num_nicks) / COLS;
+ else
+ lines = (((max_length + 1) * num_nicks) / COLS) + 1;
+ window->win_chat_x = 0;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS;
+ window->win_chat_height = LINES - 3 - (lines + 1);
+ window->win_nick_x = 0;
+ window->win_nick_y = LINES - 2 - (lines + 1);
+ window->win_nick_width = COLS;
+ window->win_nick_height = lines + 1;
+ break;
+ }
+
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = 0;
+ }
+ else
+ {
+ window->win_chat_x = 0;
+ window->win_chat_y = 1;
+ window->win_chat_width = COLS;
+ window->win_chat_height = LINES - 3;
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = 0;
+ window->win_nick_x = -1;
+ window->win_nick_y = -1;
+ window->win_nick_width = -1;
+ window->win_nick_height = -1;
+ }
+}
+
+/*
+ * gui_curses_window_clear: clear a window
+ */
+
+void
+gui_curses_window_clear (WINDOW *window)
+{
+ werase (window);
+ wmove (window, 0, 0);
+ //wrefresh (window);
+}
+
+/*
+ * gui_draw_window_title: draw title window
+ */
+
+void
+gui_draw_window_title (t_gui_window *window)
+{
+ char format[32];
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_title, COLOR_WIN_TITLE);
+ wborder (window->win_title, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_title);
+ refresh ();
+ }
+ if (CHANNEL(window))
+ {
+ sprintf (format, "%%-%ds", window->win_width);
+ if (CHANNEL(window)->topic)
+ mvwprintw (window->win_title, 0, 0, format,
+ CHANNEL(window)->topic);
+ }
+ else
+ {
+ /* TODO: change this copyright as title? */
+ mvwprintw (window->win_title, 0, 0,
+ "%s", WEECHAT_NAME_AND_VERSION " - " WEECHAT_WEBSITE);
+ mvwprintw (window->win_title, 0, COLS - strlen (WEECHAT_COPYRIGHT),
+ "%s", WEECHAT_COPYRIGHT);
+ }
+ wrefresh (window->win_title);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_title: redraw title window
+ */
+
+void
+gui_redraw_window_title (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_title);
+ gui_draw_window_title (window);
+}
+
+/*
+ * gui_get_line_num_splits: returns number of lines on window
+ * (depending on window width and type (server/channel)
+ * for alignment)
+ */
+
+int
+gui_get_line_num_splits (t_gui_window *window, t_gui_line *line)
+{
+ int length, width;
+
+ /* TODO: modify arbitraty value for non aligning messages on time/nick? */
+ if (line->length_align >= window->win_chat_width - 5)
+ {
+ length = line->length;
+ width = window->win_chat_width;
+ }
+ else
+ {
+ length = line->length - line->length_align;
+ width = window->win_chat_width - line->length_align;
+ }
+
+ return (length % width == 0) ? (length / width) : ((length / width) + 1);
+}
+
+/*
+ * gui_display_end_of_line: display end of a line in the chat window
+ */
+
+void
+gui_display_end_of_line (t_gui_window *window, t_gui_line *line, int count)
+{
+ int lines_displayed, num_lines, offset, remainder, num_displayed;
+ t_gui_message *ptr_message;
+ char saved_char, format_align[32];
+
+ sprintf (format_align, "%%-%ds", line->length_align);
+ num_lines = gui_get_line_num_splits (window, line);
+ ptr_message = line->messages;
+ offset = 0;
+ lines_displayed = 0;
+ while (ptr_message)
+ {
+ /* set text color if beginning of message */
+ if (offset == 0)
+ gui_window_set_color (window->win_chat, ptr_message->color);
+
+ /* insert spaces for align text under time/nick */
+ if ((lines_displayed > 0) && (window->win_chat_cursor_x == 0))
+ {
+ if (lines_displayed >= num_lines - count)
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ format_align, " ");
+ window->win_chat_cursor_x += line->length_align;
+ }
+
+ remainder = strlen (ptr_message->message + offset);
+ if (window->win_chat_cursor_x + remainder >
+ window->win_chat_width - 1)
+ {
+ num_displayed = window->win_chat_width -
+ window->win_chat_cursor_x;
+ saved_char = ptr_message->message[offset + num_displayed];
+ ptr_message->message[offset + num_displayed] = '\0';
+ if (lines_displayed >= num_lines - count)
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ ptr_message->message[offset + num_displayed] = saved_char;
+ offset += num_displayed;
+ }
+ else
+ {
+ num_displayed = remainder;
+ if (lines_displayed >= num_lines - count)
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ ptr_message = ptr_message->next_message;
+ offset = 0;
+ }
+ window->win_chat_cursor_x += num_displayed;
+ if (!ptr_message ||
+ (window->win_chat_cursor_x > (window->win_chat_width - 1)))
+ {
+ window->win_chat_cursor_x = 0;
+ if (lines_displayed >= num_lines - count)
+ {
+ window->win_chat_cursor_y++;
+ }
+ lines_displayed++;
+ }
+ }
+}
+
+/*
+ * gui_display_line: display a line in the chat window
+ * if stop_at_end == 1, screen will not scroll and then we
+ * exit since chat window is full
+ * returns: 1 if stop_at_end == 0 or screen not full
+ * 0 if screen is full and if stop_at_end == 1
+ */
+
+int
+gui_display_line (t_gui_window *window, t_gui_line *line, int stop_at_end)
+{
+ int offset, remainder, num_displayed;
+ t_gui_message *ptr_message;
+ char saved_char, format_align[32];
+
+ sprintf (format_align, "%%-%ds", line->length_align);
+ ptr_message = line->messages;
+ offset = 0;
+ while (ptr_message)
+ {
+ /* cursor is below end line of chat window */
+ if (window->win_chat_cursor_y > window->win_chat_height - 1)
+ {
+ /*if (!stop_at_end)
+ wscrl (window->win_chat, +1);*/
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = window->win_chat_height - 1;
+ if (stop_at_end)
+ return 0;
+ window->first_line_displayed = 0;
+ }
+
+ /* set text color if beginning of message */
+ if (offset == 0)
+ gui_window_set_color (window->win_chat, ptr_message->color);
+
+ /* insert spaces for align text under time/nick */
+ if ((window->win_chat_cursor_x == 0) &&
+ (ptr_message->type != MSG_TYPE_TIME) &&
+ (ptr_message->type != MSG_TYPE_NICK) &&
+ (line->length_align > 0) &&
+ /* TODO: modify arbitraty value for non aligning messages on time/nick? */
+ (line->length_align < (window->win_chat_width - 5)))
+ {
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ format_align, " ");
+ window->win_chat_cursor_x += line->length_align;
+ }
+
+ remainder = strlen (ptr_message->message + offset);
+ if (window->win_chat_cursor_x + remainder > window->win_chat_width)
+ {
+ num_displayed = window->win_chat_width -
+ window->win_chat_cursor_x;
+ saved_char = ptr_message->message[offset + num_displayed];
+ ptr_message->message[offset + num_displayed] = '\0';
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ ptr_message->message[offset + num_displayed] = saved_char;
+ offset += num_displayed;
+ }
+ else
+ {
+ num_displayed = remainder;
+ mvwprintw (window->win_chat,
+ window->win_chat_cursor_y,
+ window->win_chat_cursor_x,
+ "%s", ptr_message->message + offset);
+ offset = 0;
+ ptr_message = ptr_message->next_message;
+ }
+ window->win_chat_cursor_x += num_displayed;
+ if (!ptr_message ||
+ (window->win_chat_cursor_x > (window->win_chat_width - 1)))
+ {
+ if (!ptr_message ||
+ ((window->win_chat_cursor_y <= window->win_chat_height - 1) &&
+ (window->win_chat_cursor_x > window->win_chat_width - 1)))
+ window->win_chat_cursor_y++;
+ window->win_chat_cursor_x = 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * gui_draw_window_chat: draw chat window
+ */
+
+void
+gui_draw_window_chat (t_gui_window *window)
+{
+ t_gui_line *ptr_line;
+ int lines_used;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_chat, COLOR_WIN_CHAT);
+ wborder (window->win_chat, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_chat);
+ }
+
+ ptr_line = window->last_line;
+ lines_used = 0;
+ while (ptr_line
+ && (lines_used < (window->win_chat_height + window->sub_lines)))
+ {
+ lines_used += gui_get_line_num_splits (window, ptr_line);
+ ptr_line = ptr_line->prev_line;
+ }
+ window->win_chat_cursor_x = 0;
+ window->win_chat_cursor_y = 0;
+ if (lines_used > (window->win_chat_height + window->sub_lines))
+ {
+ /* screen will be full (we'll display only end of 1st line) */
+ ptr_line = (ptr_line) ? ptr_line->next_line : window->lines;
+ gui_display_end_of_line (window, ptr_line,
+ gui_get_line_num_splits (window, ptr_line) -
+ (lines_used - (window->win_chat_height + window->sub_lines)));
+ ptr_line = ptr_line->next_line;
+ window->first_line_displayed = 0;
+ }
+ else
+ {
+ /* all lines are displayed */
+ if (!ptr_line)
+ {
+ window->first_line_displayed = 1;
+ ptr_line = window->lines;
+ }
+ else
+ {
+ window->first_line_displayed = 0;
+ ptr_line = ptr_line->next_line;
+ }
+ }
+ while (ptr_line)
+ {
+ if (!gui_display_line (window, ptr_line, 1))
+ break;
+
+ ptr_line = ptr_line->next_line;
+ }
+ /*if (window->win_chat_cursor_y <= window->win_chat_height - 1)
+ window->sub_lines = 0;*/
+ wrefresh (window->win_chat);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_chat: redraw chat window
+ */
+
+void
+gui_redraw_window_chat (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_chat);
+ gui_draw_window_chat (window);
+}
+
+/*
+ * gui_draw_window_nick: draw nick window
+ */
+
+void
+gui_draw_window_nick (t_gui_window *window)
+{
+ int i, x, y, column, max_length;
+ char format[32];
+ t_irc_nick *ptr_nick;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (CHANNEL(window) && CHANNEL(window)->nicks)
+ {
+ max_length = nick_get_max_length (CHANNEL(window));
+ if ((max_length + 2) != window->win_nick_width)
+ {
+ gui_calculate_pos_size (window);
+ delwin (window->win_chat);
+ delwin (window->win_nick);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ window->win_nick = newwin (window->win_nick_height,
+ window->win_nick_width,
+ window->win_nick_y,
+ window->win_nick_x);
+ //scrollok (window->win_chat, TRUE);
+ gui_redraw_window_chat (window);
+ }
+ sprintf (format, "%%-%ds", max_length);
+
+ if (has_colors ())
+ {
+ switch (cfg_look_nicklist_position)
+ {
+ case CFG_LOOK_NICKLIST_LEFT:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP);
+ for (i = 0; i < window->win_chat_height; i++)
+ mvwprintw (window->win_nick,
+ i, window->win_nick_width - 1, " ");
+ break;
+ case CFG_LOOK_NICKLIST_RIGHT:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_SEP);
+ for (i = 0; i < window->win_chat_height; i++)
+ mvwprintw (window->win_nick,
+ i, 0, " ");
+ break;
+ case CFG_LOOK_NICKLIST_TOP:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ for (i = 0; i < window->win_chat_width; i += 2)
+ mvwprintw (window->win_nick,
+ window->win_nick_height - 1, i, "-");
+ break;
+ case CFG_LOOK_NICKLIST_BOTTOM:
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ for (i = 0; i < window->win_chat_width; i += 2)
+ mvwprintw (window->win_nick,
+ 0, i, "-");
+ break;
+ }
+ }
+
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ x = 0;
+ y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM) ? 1 : 0;
+ column = 0;
+ for (ptr_nick = CHANNEL(window)->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ switch (cfg_look_nicklist_position)
+ {
+ case CFG_LOOK_NICKLIST_LEFT:
+ x = 0;
+ break;
+ case CFG_LOOK_NICKLIST_RIGHT:
+ x = 1;
+ break;
+ case CFG_LOOK_NICKLIST_TOP:
+ case CFG_LOOK_NICKLIST_BOTTOM:
+ x = column;
+ break;
+ }
+ if (ptr_nick->is_op)
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_OP);
+ mvwprintw (window->win_nick, y, x, "@");
+ x++;
+ }
+ else
+ {
+ if (ptr_nick->is_halfop)
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_HALFOP);
+ mvwprintw (window->win_nick, y, x, "%%");
+ x++;
+ }
+ else
+ {
+ if (ptr_nick->has_voice)
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK_VOICE);
+ mvwprintw (window->win_nick, y, x, "+");
+ x++;
+ }
+ else
+ {
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ mvwprintw (window->win_nick, y, x, " ");
+ x++;
+ }
+ }
+ }
+ gui_window_set_color (window->win_nick, COLOR_WIN_NICK);
+ mvwprintw (window->win_nick, y, x, format, ptr_nick->nick);
+ y++;
+ if ((cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) ||
+ (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_BOTTOM))
+ {
+ if (y >= window->win_nick_height - 1)
+ {
+ column += max_length + 1;
+ y = (cfg_look_nicklist_position == CFG_LOOK_NICKLIST_TOP) ?
+ 0 : 1;
+ }
+ }
+ }
+ }
+ wrefresh (window->win_nick);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_nick: redraw nick window
+ */
+
+void
+gui_redraw_window_nick (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_nick);
+ gui_draw_window_nick (window);
+}
+
+/*
+ * gui_draw_window_status: draw status window
+ */
+
+void
+gui_draw_window_status (t_gui_window *window)
+{
+ t_gui_window *ptr_win;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_status, COLOR_WIN_STATUS);
+ wborder (window->win_status, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_status);
+ }
+ //refresh ();
+ wmove (window->win_status, 0, 0);
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (SERVER(ptr_win) && !CHANNEL(ptr_win))
+ {
+ if (gui_current_window == SERVER(ptr_win)->window)
+ {
+ if (ptr_win->unread_data)
+ {
+ if (ptr_win->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_ACTIVE);
+ }
+ else
+ {
+ if (SERVER(ptr_win)->window &&
+ ((SERVER(ptr_win)->window)->unread_data))
+ {
+ if (SERVER(ptr_win)->window->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS);
+ }
+ if (SERVER(ptr_win)->is_connected)
+ wprintw (window->win_status, "[%s] ",
+ SERVER(ptr_win)->name);
+ else
+ wprintw (window->win_status, "(%s) ",
+ SERVER(ptr_win)->name);
+ }
+ if (SERVER(ptr_win) && CHANNEL(ptr_win))
+ {
+ if (gui_current_window == CHANNEL(ptr_win)->window)
+ {
+ if ((CHANNEL(ptr_win)->window) &&
+ (CHANNEL(ptr_win)->window->unread_data))
+ {
+ if (CHANNEL(ptr_win)->window->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_ACTIVE);
+ }
+ else
+ {
+ if ((CHANNEL(ptr_win)->window) &&
+ (CHANNEL(ptr_win)->window->unread_data))
+ {
+ if (CHANNEL(ptr_win)->window->unread_data > 1)
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_MSG);
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS_DATA_OTHER);
+ }
+ else
+ gui_window_set_color (window->win_status,
+ COLOR_WIN_STATUS);
+ }
+ wprintw (window->win_status, "%s ", CHANNEL(ptr_win)->name);
+ }
+ if (!SERVER(ptr_win))
+ {
+ gui_window_set_color (window->win_status, COLOR_WIN_STATUS);
+ wprintw (window->win_status, _("[not connected] "));
+ }
+ }
+
+ /* display "*MORE*" if last line is not displayed */
+ gui_window_set_color (window->win_status, COLOR_WIN_STATUS_MORE);
+ if (window->sub_lines > 0)
+ mvwprintw (window->win_status, 0, COLS - 7, "-MORE-");
+ else
+ mvwprintw (window->win_status, 0, COLS - 7, " ");
+
+ wrefresh (window->win_status);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_status: redraw status window
+ */
+
+void
+gui_redraw_window_status (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_status);
+ gui_draw_window_status (window);
+}
+
+/*
+ * gui_get_input_width: return input width (max # chars displayed)
+ */
+
+int
+gui_get_input_width (t_gui_window *window)
+{
+ if (CHANNEL(window))
+ return (COLS - strlen (CHANNEL(window)->name) -
+ strlen (SERVER(window)->nick) - 3);
+ else
+ {
+ if (SERVER(window) && (SERVER(window)->is_connected))
+ return (COLS - strlen (SERVER(window)->nick) - 2);
+ else
+ return (COLS - strlen (cfg_look_no_nickname) - 2);
+ }
+}
+
+/*
+ * gui_draw_window_input: draw input window
+ */
+
+void
+gui_draw_window_input (t_gui_window *window)
+{
+ char format[32];
+ char *ptr_nickname;
+ int input_width;
+
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ if (has_colors ())
+ {
+ gui_window_set_color (window->win_input, COLOR_WIN_INPUT);
+ wborder (window->win_input, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
+ wrefresh (window->win_input);
+ }
+ //refresh ();
+
+ if (window->input_buffer_size == 0)
+ window->input_buffer[0] = '\0';
+
+ input_width = gui_get_input_width (window);
+
+ if (window->input_buffer_pos - window->input_buffer_1st_display + 1 >
+ input_width)
+ window->input_buffer_1st_display = window->input_buffer_pos -
+ input_width + 1;
+ else
+ {
+ if (window->input_buffer_pos < window->input_buffer_1st_display)
+ window->input_buffer_1st_display = window->input_buffer_pos;
+ else
+ {
+ if ((window->input_buffer_1st_display > 0) &&
+ (window->input_buffer_pos -
+ window->input_buffer_1st_display + 1) < input_width)
+ {
+ window->input_buffer_1st_display =
+ window->input_buffer_pos - input_width + 1;
+ if (window->input_buffer_1st_display < 0)
+ window->input_buffer_1st_display = 0;
+ }
+ }
+ }
+ if (CHANNEL(window))
+ {
+ sprintf (format, "%%s %%s> %%-%ds", input_width);
+ mvwprintw (window->win_input, 0, 0, format,
+ CHANNEL(window)->name,
+ SERVER(window)->nick,
+ window->input_buffer + window->input_buffer_1st_display);
+ wclrtoeol (window->win_input);
+ move (LINES - 1, strlen (CHANNEL(window)->name) +
+ strlen (SERVER(window)->nick) + 3 +
+ (window->input_buffer_pos - window->input_buffer_1st_display));
+ }
+ else
+ {
+ sprintf (format, "%%s> %%-%ds", input_width);
+ if (SERVER(window) && (SERVER(window)->is_connected))
+ ptr_nickname = SERVER(window)->nick;
+ else
+ ptr_nickname = cfg_look_no_nickname;
+ mvwprintw (window->win_input, 0, 0, format,
+ ptr_nickname,
+ window->input_buffer + window->input_buffer_1st_display);
+ wclrtoeol (window->win_input);
+ move (LINES - 1, strlen (ptr_nickname) + 2 +
+ (window->input_buffer_pos - window->input_buffer_1st_display));
+ }
+
+ wrefresh (window->win_input);
+ refresh ();
+}
+
+/*
+ * gui_redraw_window_input: redraw input window
+ */
+
+void
+gui_redraw_window_input (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_curses_window_clear (window->win_input);
+ gui_draw_window_input (window);
+}
+
+/*
+ * gui_redraw_window: redraw a window
+ */
+
+void
+gui_redraw_window (t_gui_window *window)
+{
+ /* TODO: manage splitted windows! */
+ if (window != gui_current_window)
+ return;
+
+ gui_redraw_window_title (window);
+ gui_redraw_window_chat (window);
+ if (window->win_nick)
+ gui_redraw_window_nick (window);
+ gui_redraw_window_status (window);
+ gui_redraw_window_input (window);
+}
+
+/*
+ * gui_window_clear: clear window content
+ */
+
+void
+gui_window_clear (t_gui_window *window)
+{
+ t_gui_line *ptr_line;
+ t_gui_message *ptr_message;
+
+ while (window->lines)
+ {
+ ptr_line = window->lines->next_line;
+ while (window->lines->messages)
+ {
+ ptr_message = window->lines->messages->next_message;
+ if (window->lines->messages->message)
+ free (window->lines->messages->message);
+ free (window->lines->messages);
+ window->lines->messages = ptr_message;
+ }
+ free (window->lines);
+ window->lines = ptr_line;
+ }
+
+ window->lines = NULL;
+ window->last_line = NULL;
+ window->first_line_displayed = 1;
+ window->sub_lines = 0;
+ window->line_complete = 1;
+ window->unread_data = 0;
+
+ if (window == gui_current_window)
+ gui_redraw_window_chat (window);
+}
+
+/*
+ * gui_window_clear_all: clear all windows content
+ */
+
+void
+gui_window_clear_all ()
+{
+ t_gui_window *ptr_win;
+
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ gui_window_clear (ptr_win);
+}
+
+/*
+ * gui_switch_to_window: switch to another window
+ */
+
+void
+gui_switch_to_window (t_gui_window *window)
+{
+ int another_window;
+ t_gui_window *ptr_win;
+
+ another_window = 0;
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (ptr_win->win_title)
+ {
+ /* TODO: manage splitted windows */
+ another_window = 1;
+ window->win_title = ptr_win->win_title;
+ window->win_chat = ptr_win->win_chat;
+ window->win_nick = ptr_win->win_nick;
+ window->win_status = ptr_win->win_status;
+ window->win_input = ptr_win->win_input;
+ ptr_win->win_title = NULL;
+ ptr_win->win_chat = NULL;
+ ptr_win->win_nick = NULL;
+ ptr_win->win_status = NULL;
+ ptr_win->win_input = NULL;
+ break;
+ }
+ }
+
+ /* first time creation for windows */
+ if (!another_window)
+ {
+ /* create new windows */
+ gui_calculate_pos_size (window);
+ window->win_title = newwin (1, COLS, 0, 0);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ //scrollok (window->win_chat, TRUE);
+ if (CHANNEL(window))
+ window->win_nick = newwin (window->win_nick_height,
+ window->win_nick_width,
+ window->win_nick_y,
+ window->win_nick_x);
+ else
+ window->win_nick = NULL;
+ window->win_status = newwin (1, COLS, LINES - 2, 0);
+ window->win_input = newwin (1, COLS, LINES - 1, 0);
+ }
+ else
+ {
+ gui_calculate_pos_size (window);
+
+ /* create chat & nick windows */
+ if (WIN_IS_CHANNEL(window) && !(window->win_nick))
+ {
+ /* add nick list window */
+ delwin (window->win_chat);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ //scrollok (window->win_chat, TRUE);
+ window->win_nick = newwin (window->win_nick_height,
+ window->win_nick_width,
+ window->win_nick_y,
+ window->win_nick_x);
+ }
+ if (!(WIN_IS_CHANNEL(window)) && window->win_nick)
+ {
+ /* remove nick list window */
+ delwin (window->win_nick);
+ window->win_nick = NULL;
+ delwin (window->win_chat);
+ window->win_chat = newwin (window->win_chat_height,
+ window->win_chat_width,
+ window->win_chat_y,
+ window->win_chat_x);
+ //scrollok (window->win_chat, TRUE);
+ }
+ }
+
+ /* change current window to the new window */
+ gui_current_window = window;
+
+ window->unread_data = 0;
+}
+
+/*
+ * gui_switch_to_previous_window: switch to previous window
+ */
+
+void
+gui_switch_to_previous_window ()
+{
+ /* if only one windows then return */
+ if (gui_windows == last_gui_window)
+ return;
+
+ if (gui_current_window->prev_window)
+ gui_switch_to_window (gui_current_window->prev_window);
+ else
+ gui_switch_to_window (last_gui_window);
+ gui_redraw_window (gui_current_window);
+}
+
+/*
+ * gui_switch_to_next_window: switch to next window
+ */
+
+void
+gui_switch_to_next_window ()
+{
+ /* if only one windows then return */
+ if (gui_windows == last_gui_window)
+ return;
+
+ if (gui_current_window->next_window)
+ gui_switch_to_window (gui_current_window->next_window);
+ else
+ gui_switch_to_window (gui_windows);
+ gui_redraw_window (gui_current_window);
+}
+
+/*
+ * gui_move_page_up: display previous page on window
+ */
+
+void
+gui_move_page_up ()
+{
+ if (!gui_current_window->first_line_displayed)
+ {
+ gui_current_window->sub_lines += gui_current_window->win_chat_height - 1;
+ gui_redraw_window_chat (gui_current_window);
+ gui_redraw_window_status (gui_current_window);
+ }
+}
+
+/*
+ * gui_move_page_down: display next page on window
+ */
+
+void
+gui_move_page_down ()
+{
+ if (gui_current_window->sub_lines > 0)
+ {
+ gui_current_window->sub_lines -= gui_current_window->win_chat_height - 1;
+ if (gui_current_window->sub_lines < 0)
+ gui_current_window->sub_lines = 0;
+ if (gui_current_window->sub_lines == 0)
+ gui_current_window->unread_data = 0;
+ gui_redraw_window_chat (gui_current_window);
+ gui_redraw_window_status (gui_current_window);
+ }
+}
+
+/*
+ * gui_window_new: create a new window
+ * (TODO: add coordinates and size, for splited windows)
+ */
+
+t_gui_window *
+gui_window_new (void *server, void *channel
+ /*int x, int y, int width, int height*/)
+{
+ t_gui_window *new_window;
+
+ if ((new_window = (t_gui_window *)(malloc (sizeof (t_gui_window)))))
+ {
+ /* assign server and channel to window */
+ SERVER(new_window) = server;
+ CHANNEL(new_window) = channel;
+ /* assign window to server and channel */
+ if (server && !channel)
+ SERVER(new_window)->window = new_window;
+ if (channel)
+ CHANNEL(new_window)->window = new_window;
+
+ gui_calculate_pos_size (new_window);
+
+ /* init windows */
+ new_window->win_title = NULL;
+ new_window->win_chat = NULL;
+ new_window->win_nick = NULL;
+ new_window->win_status = NULL;
+ new_window->win_input = NULL;
+
+ /* init lines */
+ new_window->lines = NULL;
+ new_window->last_line = NULL;
+ new_window->first_line_displayed = 1;
+ new_window->sub_lines = 0;
+ new_window->line_complete = 1;
+ new_window->unread_data = 0;
+
+ /* init input buffer */
+ new_window->input_buffer_alloc = INPUT_BUFFER_BLOCK_SIZE;
+ new_window->input_buffer = (char *) malloc (INPUT_BUFFER_BLOCK_SIZE);
+ new_window->input_buffer[0] = '\0';
+ new_window->input_buffer_size = 0;
+ new_window->input_buffer_pos = 0;
+ new_window->input_buffer_1st_display = 0;
+
+ /* init completion */
+ completion_init (&(new_window->completion));
+
+ /* init history */
+ new_window->history = NULL;
+ new_window->ptr_history = NULL;
+
+ /* switch to new window */
+ gui_switch_to_window (new_window);
+
+ /* add window to windows queue */
+ new_window->prev_window = last_gui_window;
+ if (gui_windows)
+ last_gui_window->next_window = new_window;
+ else
+ gui_windows = new_window;
+ last_gui_window = new_window;
+ new_window->next_window = NULL;
+
+ /* redraw whole screen */
+ gui_redraw_window (new_window);
+ }
+ else
+ return NULL;
+ return new_window;
+}
+
+/*
+ * gui_window_free: delete a window
+ */
+
+void
+gui_window_free (t_gui_window *window)
+{
+ t_gui_line *ptr_line;
+ t_gui_message *ptr_message;
+
+ /* TODO: manage splitted windows! */
+ if (window == gui_current_window)
+ gui_switch_to_previous_window ();
+
+ /* free lines and messages */
+ while (window->lines)
+ {
+ ptr_line = window->lines->next_line;
+ while (window->lines->messages)
+ {
+ ptr_message = window->lines->messages->next_message;
+ if (window->lines->messages->message)
+ free (window->lines->messages->message);
+ free (window->lines->messages);
+ window->lines->messages = ptr_message;
+ }
+ free (window->lines);
+ window->lines = ptr_line;
+ }
+ if (window->input_buffer)
+ free (window->input_buffer);
+
+ /* TODO: free completion struct */
+ /* there... */
+
+ /* remove window from windows list */
+ if (window->prev_window)
+ window->prev_window->next_window = window->next_window;
+ if (window->next_window)
+ window->next_window->prev_window = window->prev_window;
+ if (gui_windows == window)
+ gui_windows = window->next_window;
+ if (last_gui_window == window)
+ last_gui_window = window->prev_window;
+
+ free (window);
+}
+
+/*
+ * gui_resize_term_handler: called when term size is modified
+ */
+
+void
+gui_resize_term_handler ()
+{
+ t_gui_window *ptr_win;
+ int width, height;
+
+ endwin ();
+ refresh ();
+
+ getmaxyx (stdscr, height, width);
+
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ gui_calculate_pos_size (ptr_win);
+ // TODO: manage splitted windows!
+ if (ptr_win->win_title)
+ {
+ if (ptr_win->win_title)
+ delwin (ptr_win->win_title);
+ if (ptr_win->win_chat)
+ delwin (ptr_win->win_chat);
+ if (ptr_win->win_nick)
+ delwin (ptr_win->win_nick);
+ if (ptr_win->win_status)
+ delwin (ptr_win->win_status);
+ if (ptr_win->win_input)
+ delwin (ptr_win->win_input);
+ ptr_win->win_title = NULL;
+ ptr_win->win_chat = NULL;
+ ptr_win->win_nick = NULL;
+ ptr_win->win_status = NULL;
+ ptr_win->win_input = NULL;
+ gui_switch_to_window (ptr_win);
+ }
+ }
+}
+
+/*
+ * gui_init_colors: init GUI colors
+ */
+
+void
+gui_init_colors ()
+{
+ int i, color;
+
+ if (has_colors ())
+ {
+ start_color ();
+ use_default_colors ();
+
+ init_pair (COLOR_WIN_TITLE,
+ cfg_col_title & A_CHARTEXT, cfg_col_title_bg);
+ init_pair (COLOR_WIN_CHAT,
+ cfg_col_chat & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_TIME,
+ cfg_col_chat_time & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_TIME_SEP,
+ cfg_col_chat_time_sep & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_PREFIX1,
+ cfg_col_chat_prefix1 & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_PREFIX2,
+ cfg_col_chat_prefix2 & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_NICK,
+ cfg_col_chat_nick & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_HOST,
+ cfg_col_chat_host & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_CHANNEL,
+ cfg_col_chat_channel & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_CHAT_DARK,
+ cfg_col_chat_dark & A_CHARTEXT, cfg_col_chat_bg);
+ init_pair (COLOR_WIN_STATUS,
+ cfg_col_status & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_ACTIVE,
+ cfg_col_status_active & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_DATA_MSG,
+ cfg_col_status_data_msg & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_DATA_OTHER,
+ cfg_col_status_data_other & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_STATUS_MORE,
+ cfg_col_status_more & A_CHARTEXT, cfg_col_status_bg);
+ init_pair (COLOR_WIN_INPUT,
+ cfg_col_input & A_CHARTEXT, cfg_col_input_bg);
+ init_pair (COLOR_WIN_INPUT_CHANNEL,
+ cfg_col_input_channel & A_CHARTEXT, cfg_col_input_bg);
+ init_pair (COLOR_WIN_INPUT_NICK,
+ cfg_col_input_nick & A_CHARTEXT, cfg_col_input_bg);
+ init_pair (COLOR_WIN_NICK,
+ cfg_col_nick & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_OP,
+ cfg_col_nick_op & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_HALFOP,
+ cfg_col_nick_halfop & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_VOICE,
+ cfg_col_nick_voice & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_SEP,
+ COLOR_BLACK & A_CHARTEXT, cfg_col_nick_sep);
+ init_pair (COLOR_WIN_NICK_SELF,
+ cfg_col_nick_self & A_CHARTEXT, cfg_col_nick_bg);
+ init_pair (COLOR_WIN_NICK_PRIVATE,
+ cfg_col_nick_private & A_CHARTEXT, cfg_col_nick_bg);
+
+ for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++)
+ {
+ gui_assign_color (&color, nicks_colors[i]);
+ init_pair (COLOR_WIN_NICK_FIRST + i, color & A_CHARTEXT, cfg_col_chat_bg);
+ color_attr[COLOR_WIN_NICK_FIRST + i - 1] =
+ (color & A_BOLD) ? A_BOLD : 0;
+ }
+
+ color_attr[COLOR_WIN_TITLE - 1] = cfg_col_title & A_BOLD;
+ color_attr[COLOR_WIN_CHAT - 1] = cfg_col_chat & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_TIME - 1] = cfg_col_chat_time & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_TIME_SEP - 1] = cfg_col_chat_time_sep & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_PREFIX1 - 1] = cfg_col_chat_prefix1 & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_PREFIX2 - 1] = cfg_col_chat_prefix2 & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_NICK - 1] = cfg_col_chat_nick & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_HOST - 1] = cfg_col_chat_host & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_CHANNEL - 1] = cfg_col_chat_channel & A_BOLD;
+ color_attr[COLOR_WIN_CHAT_DARK - 1] = cfg_col_chat_dark & A_BOLD;
+ color_attr[COLOR_WIN_STATUS - 1] = cfg_col_status & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_ACTIVE - 1] = cfg_col_status_active & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_DATA_MSG - 1] = cfg_col_status_data_msg & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_DATA_OTHER - 1] = cfg_col_status_data_other & A_BOLD;
+ color_attr[COLOR_WIN_STATUS_MORE - 1] = cfg_col_status_more & A_BOLD;
+ color_attr[COLOR_WIN_INPUT - 1] = cfg_col_input & A_BOLD;
+ color_attr[COLOR_WIN_INPUT_CHANNEL - 1] = cfg_col_input_channel & A_BOLD;
+ color_attr[COLOR_WIN_INPUT_NICK - 1] = cfg_col_input_nick & A_BOLD;
+ color_attr[COLOR_WIN_NICK - 1] = cfg_col_nick & A_BOLD;
+ color_attr[COLOR_WIN_NICK_OP - 1] = cfg_col_nick_op & A_BOLD;
+ color_attr[COLOR_WIN_NICK_HALFOP - 1] = cfg_col_nick_halfop & A_BOLD;
+ color_attr[COLOR_WIN_NICK_VOICE - 1] = cfg_col_nick_voice & A_BOLD;
+ color_attr[COLOR_WIN_NICK_SEP - 1] = 0;
+ color_attr[COLOR_WIN_NICK_SELF - 1] = cfg_col_nick_self & A_BOLD;
+ color_attr[COLOR_WIN_NICK_PRIVATE - 1] = cfg_col_nick_private & A_BOLD;
+ }
+}
+
+/*
+ * gui_init: init GUI
+ */
+
+void
+gui_init ()
+{
+ initscr ();
+
+ curs_set (1);
+ keypad (stdscr, TRUE);
+ noecho ();
+ /*nonl();*/
+ nodelay (stdscr, TRUE);
+
+ gui_init_colors ();
+
+ /* create windows */
+ gui_current_window = gui_window_new (NULL, NULL /*0, 0, COLS, LINES*/);
+
+ signal (SIGWINCH, gui_resize_term_handler);
+
+ gui_ready = 1;
+}
+
+/*
+ * gui_end: GUI end
+ */
+
+void
+gui_end ()
+{
+ t_gui_window *ptr_win;
+
+ /* delete all windows */
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (ptr_win->win_title)
+ delwin (ptr_win->win_title);
+ if (ptr_win->win_chat)
+ delwin (ptr_win->win_chat);
+ if (ptr_win->win_nick)
+ delwin (ptr_win->win_nick);
+ if (ptr_win->win_status)
+ delwin (ptr_win->win_status);
+ if (ptr_win->win_input)
+ delwin (ptr_win->win_input);
+ /* TODO: free input buffer, lines, messages, completion */
+ }
+
+ /* end of ncurses output */
+ refresh ();
+ endwin ();
+}
+
+/*
+ * gui_new_line: create new line for a window
+ */
+
+t_gui_line *
+gui_new_line (t_gui_window *window)
+{
+ t_gui_line *new_line;
+
+ if ((new_line = (t_gui_line *) malloc (sizeof (struct t_gui_line))))
+ {
+ new_line->length = 0;
+ new_line->length_align = 0;
+ new_line->line_with_message = 0;
+ new_line->messages = NULL;
+ new_line->last_message = NULL;
+ if (!window->lines)
+ window->lines = new_line;
+ else
+ window->last_line->next_line = new_line;
+ new_line->prev_line = window->last_line;
+ new_line->next_line = NULL;
+ window->last_line = new_line;
+ }
+ else
+ {
+ wprintw (window->win_chat,
+ _("%s not enough memory for new line!\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+ return new_line;
+}
+
+/*
+ * gui_new_message: create a new message for last line of window
+ */
+
+t_gui_message *
+gui_new_message (t_gui_window *window)
+{
+ t_gui_message *new_message;
+
+ if ((new_message = (t_gui_message *) malloc (sizeof (struct t_gui_message))))
+ {
+ if (!window->last_line->messages)
+ window->last_line->messages = new_message;
+ else
+ window->last_line->last_message->next_message = new_message;
+ new_message->prev_message = window->last_line->last_message;
+ new_message->next_message = NULL;
+ window->last_line->last_message = new_message;
+ }
+ else
+ {
+ log_printf ("not enough memory!\n");
+ return NULL;
+ }
+ return new_message;
+}
+
+/*
+ * gui_add_message: add a message to a window
+ */
+
+void
+gui_add_message (t_gui_window *window, int type, int color, char *message)
+{
+ char *pos;
+ int length;
+
+ /* create new line if previous was ending by '\n' (or if 1st line) */
+ if (window->line_complete)
+ {
+ window->line_complete = 0;
+ if (!gui_new_line (window))
+ return;
+ }
+ if (!gui_new_message (window))
+ return;
+
+ window->last_line->last_message->type = type;
+ window->last_line->last_message->color = color;
+ pos = strchr (message, '\n');
+ if (pos)
+ {
+ pos[0] = '\0';
+ window->line_complete = 1;
+ }
+ window->last_line->last_message->message = strdup (message);
+ length = strlen (message);
+ window->last_line->length += length;
+ if (type == MSG_TYPE_MSG)
+ window->last_line->line_with_message = 1;
+ if ((type == MSG_TYPE_TIME) || (type == MSG_TYPE_NICK))
+ window->last_line->length_align += length;
+ if (pos)
+ {
+ pos[0] = '\n';
+ if ((window == gui_current_window) && (window->sub_lines == 0))
+ {
+ if ((window->win_chat_cursor_y
+ + gui_get_line_num_splits (window, window->last_line)) >
+ (window->win_chat_height - 1))
+ gui_redraw_window_chat (window);
+ else
+ gui_display_line (window, window->last_line, 1);
+ }
+ if ((window != gui_current_window) || (window->sub_lines > 0))
+ {
+ window->unread_data = 1 + window->last_line->line_with_message;
+ gui_redraw_window_status (gui_current_window);
+ }
+ }
+}
+
+/*
+ * gui_printf_color_type: display a message in a window
+ */
+
+void
+gui_printf_color_type (t_gui_window *window, int type, int color, char *message, ...)
+{
+ static char buffer[8192];
+ char timestamp[16];
+ char *pos;
+ va_list argptr;
+ static time_t seconds;
+ struct tm *date_tmp;
+
+ if (gui_ready)
+ {
+ if (color == -1)
+ color = COLOR_WIN_CHAT;
+
+ if (window == NULL)
+ {
+ if (SERVER(gui_current_window))
+ window = SERVER(gui_current_window)->window;
+ else
+ window = gui_current_window;
+ }
+
+ if (window == NULL)
+ {
+ log_printf ("gui_printf without window! this is a bug, please send to developers - thanks\n");
+ return;
+ }
+ }
+
+ va_start (argptr, message);
+ vsnprintf (buffer, sizeof (buffer) - 1, message, argptr);
+ va_end (argptr);
+
+ if (gui_ready)
+ {
+ seconds = time (NULL);
+ date_tmp = localtime (&seconds);
+
+ pos = buffer - 1;
+ while (pos)
+ {
+ /* TODO: read timestamp format from config! */
+ if ((!window->last_line) || (window->line_complete))
+ {
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "[");
+ sprintf (timestamp, "%02d", date_tmp->tm_hour);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":");
+ sprintf (timestamp, "%02d", date_tmp->tm_min);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME_SEP, ":");
+ sprintf (timestamp, "%02d", date_tmp->tm_sec);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_TIME, timestamp);
+ gui_add_message (window, MSG_TYPE_TIME, COLOR_WIN_CHAT_DARK, "] ");
+ }
+ gui_add_message (window, type, color, pos+1);
+ pos = strchr (pos+1, '\n');
+ if (pos)
+ if (pos[1] == '\0')
+ pos = NULL;
+ }
+
+ wrefresh (window->win_chat);
+ refresh ();
+ }
+ else
+ printf ("%s", buffer);
+}
diff --git a/weechat/src/gui/curses/gui-input.c b/weechat/src/gui/curses/gui-input.c
new file mode 100644
index 000000000..2717d3dab
--- /dev/null
+++ b/weechat/src/gui/curses/gui-input.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-input: user input functions for Curses GUI */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <curses.h>
+
+#include "../../weechat.h"
+#include "../gui.h"
+#include "../../config.h"
+#include "../../command.h"
+#include "../../irc/irc.h"
+
+
+/*
+ * gui_optimize_input_buffer_size: optimize input buffer size by adding
+ * or deleting data block (predefined size)
+ */
+
+void
+gui_optimize_input_buffer_size (t_gui_window *window)
+{
+ int optimal_size;
+
+ optimal_size = ((window->input_buffer_size / INPUT_BUFFER_BLOCK_SIZE) *
+ INPUT_BUFFER_BLOCK_SIZE) + INPUT_BUFFER_BLOCK_SIZE;
+ if (window->input_buffer_alloc != optimal_size)
+ {
+ window->input_buffer_alloc = optimal_size;
+ window->input_buffer = realloc (window->input_buffer, optimal_size);
+ }
+}
+
+/*
+ * gui_delete_previous_word: delete previous word
+ */
+
+void
+gui_delete_previous_word ()
+{
+ int i, j, num_char_deleted, num_char_end;
+
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ i = gui_current_window->input_buffer_pos - 1;
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i--;
+ if (i >= 0)
+ {
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] != ' '))
+ i--;
+ if (i >= 0)
+ {
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i--;
+ }
+ }
+
+ if (i >= 0)
+ i++;
+ i++;
+ num_char_deleted = gui_current_window->input_buffer_pos - i;
+ num_char_end = gui_current_window->input_buffer_size -
+ gui_current_window->input_buffer_pos;
+
+ for (j = 0; j < num_char_end; j++)
+ gui_current_window->input_buffer[i + j] =
+ gui_current_window->input_buffer[gui_current_window->input_buffer_pos + j];
+
+ gui_current_window->input_buffer_size -= num_char_deleted;
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ gui_current_window->input_buffer_pos = i;
+ gui_draw_window_input (gui_current_window);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->completion.position = -1;
+ }
+}
+
+/*
+ * gui_move_previous_word: move to beginning of previous word
+ */
+
+void
+gui_move_previous_word ()
+{
+ int i;
+
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ i = gui_current_window->input_buffer_pos - 1;
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i--;
+ if (i < 0)
+ gui_current_window->input_buffer_pos = 0;
+ else
+ {
+ while ((i >= 0) &&
+ (gui_current_window->input_buffer[i] != ' '))
+ i--;
+ gui_current_window->input_buffer_pos = i + 1;
+ }
+ gui_draw_window_input (gui_current_window);
+ }
+}
+
+/*
+ * gui_move_next_word: move to the end of next
+ */
+
+void
+gui_move_next_word ()
+{
+ int i;
+
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size + 1)
+ {
+ i = gui_current_window->input_buffer_pos;
+ while ((i <= gui_current_window->input_buffer_size) &&
+ (gui_current_window->input_buffer[i] == ' '))
+ i++;
+ if (i > gui_current_window->input_buffer_size)
+ gui_current_window->input_buffer_pos = i - 1;
+ else
+ {
+ while ((i <= gui_current_window->input_buffer_size) &&
+ (gui_current_window->input_buffer[i] != ' '))
+ i++;
+ if (i > gui_current_window->input_buffer_size)
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ else
+ gui_current_window->input_buffer_pos = i;
+
+ }
+ gui_draw_window_input (gui_current_window);
+ }
+}
+
+/*
+ * gui_buffer_insert_string: insert a string into the input buffer
+ */
+
+void
+gui_buffer_insert_string (char *string, int pos)
+{
+ int i, start, end, length;
+
+ length = strlen (string);
+
+ /* increase buffer size */
+ gui_current_window->input_buffer_size += length;
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+
+ /* move end of string to the right */
+ start = pos + length;
+ end = gui_current_window->input_buffer_size - 1;
+ for (i = end; i >= start; i--)
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i - length];
+
+ /* insert new string */
+ strncpy (gui_current_window->input_buffer + pos, string, length);
+}
+
+/*
+ * gui_read_keyb: read keyboard line
+ */
+
+void
+gui_read_keyb ()
+{
+ int key, i;
+ t_gui_window *ptr_window;
+ char new_char[2];
+
+ key = getch ();
+ if (key != ERR)
+ {
+ switch (key)
+ {
+ /* resize event: do nothing */
+ case KEY_RESIZE:
+ gui_redraw_window (gui_current_window);
+ break;
+ case KEY_F(6):
+ gui_switch_to_previous_window ();
+ break;
+ /* next window */
+ case KEY_F(7):
+ gui_switch_to_next_window ();
+ break;
+ /* cursor up */
+ case KEY_UP:
+ if (gui_current_window->ptr_history)
+ {
+ gui_current_window->ptr_history =
+ gui_current_window->ptr_history->next_history;
+ if (!gui_current_window->ptr_history)
+ gui_current_window->ptr_history =
+ gui_current_window->history;
+ }
+ else
+ gui_current_window->ptr_history =
+ gui_current_window->history;
+ if (gui_current_window->ptr_history)
+ {
+ gui_current_window->input_buffer_size =
+ strlen (gui_current_window->ptr_history->text);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ strcpy (gui_current_window->input_buffer,
+ gui_current_window->ptr_history->text);
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* cursor down */
+ case KEY_DOWN:
+ if (gui_current_window->ptr_history)
+ {
+ gui_current_window->ptr_history =
+ gui_current_window->ptr_history->prev_history;
+ if (gui_current_window->ptr_history)
+ gui_current_window->input_buffer_size =
+ strlen (gui_current_window->ptr_history->text);
+ else
+ gui_current_window->input_buffer_size = 0;
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ if (gui_current_window->ptr_history)
+ strcpy (gui_current_window->input_buffer,
+ gui_current_window->ptr_history->text);
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* cursor left */
+ case KEY_LEFT:
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ gui_current_window->input_buffer_pos--;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* cursor right */
+ case KEY_RIGHT:
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size)
+ {
+ gui_current_window->input_buffer_pos++;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* home key */
+ case KEY_HOME:
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ gui_current_window->input_buffer_pos = 0;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* end key */
+ case KEY_END:
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size)
+ {
+ gui_current_window->input_buffer_pos =
+ gui_current_window->input_buffer_size;
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* page up */
+ case KEY_PPAGE:
+ gui_move_page_up ();
+ break;
+ /* page down */
+ case KEY_NPAGE:
+ gui_move_page_down ();
+ break;
+ /* erase before cursor and move cursor to the left */
+ case 127:
+ case KEY_BACKSPACE:
+ if (gui_current_window->input_buffer_pos > 0)
+ {
+ i = gui_current_window->input_buffer_pos-1;
+ while (gui_current_window->input_buffer[i])
+ {
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i+1];
+ i++;
+ }
+ gui_current_window->input_buffer_size--;
+ gui_current_window->input_buffer_pos--;
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ gui_draw_window_input (gui_current_window);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->completion.position = -1;
+ }
+ break;
+ /* Control + Backspace */
+ case 0x08:
+ gui_delete_previous_word ();
+ break;
+ /* erase char under cursor */
+ case KEY_DC:
+ if (gui_current_window->input_buffer_pos <
+ gui_current_window->input_buffer_size)
+ {
+ i = gui_current_window->input_buffer_pos;
+ while (gui_current_window->input_buffer[i])
+ {
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i+1];
+ i++;
+ }
+ gui_current_window->input_buffer_size--;
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ gui_draw_window_input (gui_current_window);
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->completion.position = -1;
+ }
+ break;
+ /* Tab : completion */
+ case '\t':
+ completion_search (&(gui_current_window->completion),
+ CHANNEL(gui_current_window),
+ gui_current_window->input_buffer,
+ gui_current_window->input_buffer_size,
+ gui_current_window->input_buffer_pos);
+ if (gui_current_window->completion.word_found)
+ {
+ // replace word with new completed word into input buffer
+ gui_current_window->input_buffer_size +=
+ gui_current_window->completion.diff_size;
+ gui_optimize_input_buffer_size (gui_current_window);
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+
+ if (gui_current_window->completion.diff_size > 0)
+ {
+ for (i = gui_current_window->input_buffer_size - 1;
+ i >= gui_current_window->completion.position_replace +
+ (int)strlen (gui_current_window->completion.word_found); i--)
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i -
+ gui_current_window->completion.diff_size];
+ }
+ else
+ {
+ for (i = gui_current_window->completion.position_replace +
+ strlen (gui_current_window->completion.word_found);
+ i < gui_current_window->input_buffer_size; i++)
+ gui_current_window->input_buffer[i] =
+ gui_current_window->input_buffer[i -
+ gui_current_window->completion.diff_size];
+ }
+
+ strncpy (gui_current_window->input_buffer + gui_current_window->completion.position_replace,
+ gui_current_window->completion.word_found,
+ strlen (gui_current_window->completion.word_found));
+ gui_current_window->input_buffer_pos =
+ gui_current_window->completion.position_replace +
+ strlen (gui_current_window->completion.word_found);
+ gui_current_window->completion.position =
+ gui_current_window->input_buffer_pos;
+
+ /* add space or completor to the end of completion, if needed */
+ if (gui_current_window->completion.base_word[0] == '/')
+ {
+ if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ')
+ gui_buffer_insert_string (" ",
+ gui_current_window->input_buffer_pos);
+ gui_current_window->completion.position++;
+ gui_current_window->input_buffer_pos++;
+ }
+ else
+ {
+ if (gui_current_window->completion.base_word_pos == 0)
+ {
+ if (strncmp (gui_current_window->input_buffer + gui_current_window->input_buffer_pos,
+ cfg_look_completor, strlen (cfg_look_completor)) != 0)
+ gui_buffer_insert_string (cfg_look_completor,
+ gui_current_window->input_buffer_pos);
+ gui_current_window->completion.position += strlen (cfg_look_completor);
+ gui_current_window->input_buffer_pos += strlen (cfg_look_completor);
+ if (gui_current_window->input_buffer[gui_current_window->input_buffer_pos] != ' ')
+ gui_buffer_insert_string (" ",
+ gui_current_window->input_buffer_pos);
+ gui_current_window->completion.position++;
+ gui_current_window->input_buffer_pos++;
+ }
+ }
+ gui_draw_window_input (gui_current_window);
+ }
+ break;
+ /* escape code (for control-key) */
+ case KEY_ESCAPE:
+ if ((key = getch()) != ERR)
+ {
+ switch (key)
+ {
+ case KEY_LEFT:
+ gui_switch_to_previous_window ();
+ break;
+ case KEY_RIGHT:
+ gui_switch_to_next_window ();
+ break;
+ case 79:
+ /* TODO: replace 79 by constant name! */
+ if (key == 79)
+ {
+ if ((key = getch()) != ERR)
+ {
+ switch (key)
+ {
+ /* Control + Right */
+ case 99:
+ gui_move_next_word ();
+ break;
+ /* Control + Left */
+ case 100:
+ gui_move_previous_word ();
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ /* send command/message */
+ case '\n':
+ if (gui_current_window->input_buffer_size > 0)
+ {
+ gui_current_window->input_buffer[gui_current_window->input_buffer_size] = '\0';
+ history_add (gui_current_window, gui_current_window->input_buffer);
+ gui_current_window->input_buffer_size = 0;
+ gui_current_window->input_buffer_pos = 0;
+ gui_current_window->input_buffer_1st_display = 0;
+ gui_current_window->completion.position = -1;
+ gui_current_window->ptr_history = NULL;
+ ptr_window = gui_current_window;
+ user_command (SERVER(gui_current_window),
+ gui_current_window->input_buffer);
+ if (ptr_window == gui_current_window)
+ gui_draw_window_input (ptr_window);
+ if (ptr_window)
+ ptr_window->input_buffer[0] = '\0';
+ }
+ break;
+ /* other key => add to input buffer */
+ default:
+ /*gui_printf (gui_current_window,
+ "[Debug] key pressed = %d, as octal: %o\n", key, key);*/
+ new_char[0] = key;
+ new_char[1] = '\0';
+ gui_buffer_insert_string (new_char,
+ gui_current_window->input_buffer_pos);
+ gui_current_window->input_buffer_pos++;
+ gui_draw_window_input (gui_current_window);
+ gui_current_window->completion.position = -1;
+ break;
+ }
+ }
+}
+
+/*
+ * gui_main_loop: main loop for WeeChat with ncurses GUI
+ */
+
+void
+gui_main_loop ()
+{
+ fd_set read_fd;
+ static struct timeval timeout;
+ t_irc_server *ptr_server;
+
+ quit_weechat = 0;
+ while (!quit_weechat)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ FD_ZERO (&read_fd);
+ FD_SET (STDIN_FILENO, &read_fd);
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->sock4 >= 0)
+ FD_SET (ptr_server->sock4, &read_fd);
+ }
+ if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout))
+ {
+ if (FD_ISSET (STDIN_FILENO, &read_fd))
+ {
+ gui_read_keyb ();
+ }
+ else
+ {
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if ((ptr_server->sock4 >= 0) &&
+ (FD_ISSET (ptr_server->sock4, &read_fd)))
+ server_recv (ptr_server);
+ }
+ }
+ }
+ }
+}
diff --git a/weechat/src/gui/gtk/Makefile b/weechat/src/gui/gtk/Makefile
new file mode 100644
index 000000000..6d2de6eba
--- /dev/null
+++ b/weechat/src/gui/gtk/Makefile
@@ -0,0 +1,37 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_GTK
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \
+ ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h
diff --git a/weechat/src/gui/gtk/gui-gtk.c b/weechat/src/gui/gtk/gui-gtk.c
new file mode 100644
index 000000000..8e9aa5db3
--- /dev/null
+++ b/weechat/src/gui/gtk/gui-gtk.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-gtk.c: Gtk+ GUI for WeeChat */
+
+
+/* ***** Gtk+ GUI for WeeChat, NOT developed! ***** */
diff --git a/weechat/src/gui/gtk/gui-gtk.h b/weechat/src/gui/gtk/gui-gtk.h
new file mode 100644
index 000000000..889f75e60
--- /dev/null
+++ b/weechat/src/gui/gtk/gui-gtk.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_GTK_H
+#define __WEECHAT_GUI_GTK_H 1
+
+#endif /* gui-gtk.h */
diff --git a/weechat/src/gui/gui.h b/weechat/src/gui/gui.h
new file mode 100644
index 000000000..d8e3aca99
--- /dev/null
+++ b/weechat/src/gui/gui.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_H
+#define __WEECHAT_GUI_H 1
+
+#ifdef WEE_CURSES
+#include <curses.h>
+#endif
+
+#include "../completion.h"
+#include "../history.h"
+
+#ifdef WEE_CURSES
+#define KEY_ESCAPE 27
+#endif
+
+#define INPUT_BUFFER_BLOCK_SIZE 256
+
+#define NUM_COLORS 35
+#define COLOR_WIN_TITLE 1
+#define COLOR_WIN_CHAT 2
+#define COLOR_WIN_CHAT_TIME 3
+#define COLOR_WIN_CHAT_TIME_SEP 4
+#define COLOR_WIN_CHAT_PREFIX1 5
+#define COLOR_WIN_CHAT_PREFIX2 6
+#define COLOR_WIN_CHAT_NICK 7
+#define COLOR_WIN_CHAT_HOST 8
+#define COLOR_WIN_CHAT_CHANNEL 9
+#define COLOR_WIN_CHAT_DARK 10
+#define COLOR_WIN_STATUS 11
+#define COLOR_WIN_STATUS_ACTIVE 12
+#define COLOR_WIN_STATUS_DATA_MSG 13
+#define COLOR_WIN_STATUS_DATA_OTHER 14
+#define COLOR_WIN_STATUS_MORE 15
+#define COLOR_WIN_INPUT 16
+#define COLOR_WIN_INPUT_CHANNEL 17
+#define COLOR_WIN_INPUT_NICK 18
+#define COLOR_WIN_NICK 19
+#define COLOR_WIN_NICK_OP 20
+#define COLOR_WIN_NICK_HALFOP 21
+#define COLOR_WIN_NICK_VOICE 22
+#define COLOR_WIN_NICK_SEP 23
+#define COLOR_WIN_NICK_SELF 24
+#define COLOR_WIN_NICK_PRIVATE 25
+#define COLOR_WIN_NICK_FIRST 26
+#define COLOR_WIN_NICK_LAST 35
+#define COLOR_WIN_NICK_NUMBER (COLOR_WIN_NICK_LAST - COLOR_WIN_NICK_FIRST + 1)
+
+#define SERVER(window) ((t_irc_server *)(window->server))
+#define CHANNEL(window) ((t_irc_channel *)(window->channel))
+
+#define WIN_IS_SERVER(window) (SERVER(window) && !CHANNEL(window))
+#define WIN_IS_CHANNEL(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_CHANNEL))
+#define WIN_IS_PRIVATE(window) (CHANNEL(window) && (CHANNEL(window)->type == CHAT_PRIVATE))
+
+#define MSG_TYPE_TIME 0
+#define MSG_TYPE_NICK 1
+#define MSG_TYPE_INFO 2
+#define MSG_TYPE_MSG 3
+
+#define gui_printf_color(window, color, fmt, argz...) \
+ gui_printf_color_type(window, MSG_TYPE_INFO, color, fmt, ##argz)
+
+#define gui_printf(window, fmt, argz...) \
+ gui_printf_color_type(window, MSG_TYPE_INFO, -1, fmt, ##argz)
+
+typedef struct t_gui_message t_gui_message;
+
+struct t_gui_message
+{
+ int type; /* type of message (time, nick, other) */
+ int color; /* color of message */
+ char *message; /* message content */
+ t_gui_message *prev_message; /* link to previous message for line */
+ t_gui_message *next_message; /* link to next message for line */
+};
+
+typedef struct t_gui_line t_gui_line;
+
+struct t_gui_line
+{
+ int length; /* length of the line (in char) */
+ int length_align; /* alignment length (time or time/nick) */
+ int line_with_message; /* line contains a message from a user? */
+ t_gui_message *messages; /* messages for the line */
+ t_gui_message *last_message; /* last message of the line */
+ t_gui_line *prev_line; /* link to previous line */
+ t_gui_line *next_line; /* link to next line */
+};
+
+typedef struct t_gui_color t_gui_color;
+
+struct t_gui_color
+{
+ char *name;
+ int color;
+};
+
+typedef struct t_gui_window t_gui_window;
+
+struct t_gui_window
+{
+ /* server/channel */
+ void *server; /* window's server */
+ void *channel; /* window's channel */
+
+ /* global position & size */
+ int win_x, win_y; /* position of window */
+ int win_width, win_height; /* window geometry */
+
+ /* chat window settings */
+ int win_chat_x, win_chat_y; /* chat window position */
+ int win_chat_width; /* width of chat window */
+ int win_chat_height; /* height of chat window */
+ int win_chat_cursor_x; /* position of cursor in chat window */
+ int win_chat_cursor_y; /* position of cursor in chat window */
+
+ /* nicklist window settings */
+ int win_nick_x, win_nick_y; /* chat window position */
+ int win_nick_width; /* width of chat window */
+ int win_nick_height; /* height of chat window */
+
+ /* windows */
+ #ifdef WEE_CURSES
+ WINDOW *win_title; /* title window */
+ WINDOW *win_chat; /* chat window (exemple: channel) */
+ WINDOW *win_nick; /* nick window */
+ WINDOW *win_status; /* status window */
+ WINDOW *win_input; /* input window */
+ #endif
+ #ifdef WEE_GTK
+ /* TODO: declare Gtk+ window */
+ #endif
+ #ifdef WEE_QT
+ /* TODO: declare Qt window */
+ #endif
+
+ /* chat content (lines, line is composed by many messages) */
+ t_gui_line *lines; /* lines of chat window */
+ t_gui_line *last_line; /* last line of chat window */
+ int first_line_displayed; /* = 1 if first line is displayed */
+ int sub_lines; /* if > 0 then do not display until end */
+ int line_complete; /* current line complete ? (\n ending) */
+ int unread_data; /* highlight windows with unread data */
+
+ /* inupt buffer */
+ char *input_buffer; /* input buffer */
+ int input_buffer_alloc; /* input buffer: allocated size in mem */
+ int input_buffer_size; /* buffer size (user input length) */
+ int input_buffer_pos; /* position into buffer */
+ int input_buffer_1st_display; /* first char displayed on screen */
+
+ /* completion */
+ t_completion completion; /* for cmds/nicks completion */
+
+ /* history */
+ t_history *history; /* commands history */
+ t_history *ptr_history; /* current command in history */
+
+ /* link to next window */
+ t_gui_window *prev_window; /* link to previous window */
+ t_gui_window *next_window; /* link to next window */
+};
+
+/* variables */
+
+extern int gui_ready;
+extern t_gui_window *gui_windows;
+extern t_gui_window *gui_current_window;
+
+/* prototypes */
+
+extern int gui_assign_color (int *, char *);
+extern int gui_get_color_by_name (char *);
+extern char *gui_get_color_by_value (int);
+
+extern void gui_draw_window_title (t_gui_window *);
+extern void gui_redraw_window_title (t_gui_window *);
+extern void gui_draw_window_chat (t_gui_window *);
+extern void gui_redraw_window_chat (t_gui_window *);
+extern void gui_draw_window_nick (t_gui_window *);
+extern void gui_redraw_window_nick (t_gui_window *);
+extern void gui_draw_window_status (t_gui_window *);
+extern void gui_redraw_window_status (t_gui_window *);
+extern void gui_draw_window_input (t_gui_window *);
+extern void gui_redraw_window_input (t_gui_window *);
+extern void gui_redraw_window (t_gui_window *);
+
+extern void gui_window_clear (t_gui_window *);
+extern void gui_window_clear_all ();
+
+extern void gui_switch_to_window (t_gui_window *);
+extern void gui_switch_to_previous_window ();
+extern void gui_switch_to_next_window ();
+
+extern void gui_move_page_up ();
+extern void gui_move_page_down ();
+
+extern void gui_init ();
+/* TODO: add coordinates and size */
+extern t_gui_window *gui_window_new (void *, void * /*int, int, int, int*/);
+extern void gui_window_free (t_gui_window *);
+extern void gui_end ();
+extern void gui_printf_color_type (t_gui_window *, int, int, char *, ...);
+extern void gui_display_nick (t_gui_window *, void *, int, int, int, int);
+
+extern void gui_main_loop ();
+
+#endif /* gui.h */
diff --git a/weechat/src/gui/qt/Makefile b/weechat/src/gui/qt/Makefile
new file mode 100644
index 000000000..f0695d3a3
--- /dev/null
+++ b/weechat/src/gui/qt/Makefile
@@ -0,0 +1,37 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_QT
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \
+ ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h
diff --git a/weechat/src/gui/qt/gui-qt.c b/weechat/src/gui/qt/gui-qt.c
new file mode 100644
index 000000000..e8dffab14
--- /dev/null
+++ b/weechat/src/gui/qt/gui-qt.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-qt.c: Qt GUI for WeeChat */
+
+
+/* ***** Qt GUI for WeeChat, NOT developed! ***** */
diff --git a/weechat/src/gui/qt/gui-qt.h b/weechat/src/gui/qt/gui-qt.h
new file mode 100644
index 000000000..b07167d88
--- /dev/null
+++ b/weechat/src/gui/qt/gui-qt.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_QT_H
+#define __WEECHAT_GUI_QT_H 1
+
+#endif /* gui-qt.h */
diff --git a/weechat/src/gui/text/Makefile b/weechat/src/gui/text/Makefile
new file mode 100644
index 000000000..538d760a3
--- /dev/null
+++ b/weechat/src/gui/text/Makefile
@@ -0,0 +1,37 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=../gui.a
+OBJS=gui-display.o gui-input.o
+DEFINES=WEE_TEXT
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+gui-display.o: gui-display.c ../../weechat.h ../gui.h ../../config.h \
+ ../../irc/irc.h ../../gui/gui.h
+gui-input.o: gui-input.c ../../weechat.h ../gui.h
diff --git a/weechat/src/gui/text/gui-text.c b/weechat/src/gui/text/gui-text.c
new file mode 100644
index 000000000..7121e11e5
--- /dev/null
+++ b/weechat/src/gui/text/gui-text.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* gui-text.c: text GUI - display functions */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "weechat.h"
+#include "gui-text.h"
+#include "command.h"
+#include "irc.h"
+
+
+/*
+ * gui_init: init GUI
+ */
+
+void
+gui_init ()
+{
+}
+
+
+/*
+ * gui_init_irc_window: allocates a window for a channel or server
+ */
+
+void
+gui_init_irc_window (t_irc_window * window)
+{
+ /* no window in text GUI */
+ window->text = NULL;
+ window->window = NULL;
+}
+
+
+/*
+ * gui_free_irc_window: free a GUI window
+ */
+
+void
+gui_free_irc_window (t_irc_window * window)
+{
+ /* no window in text GUI */
+}
+
+
+/*
+ * gui_end: GUI end
+ */
+
+void
+gui_end ()
+{
+}
+
+
+/*
+ * read_keyb: read keyboard line
+ */
+
+void
+read_keyb ()
+{
+ int num_read;
+ static char buffer[4096];
+ static int pos_buffer = 0;
+ char buffer_tmp[1024];
+ int pos_buffer_tmp;
+
+ num_read = read (STDIN_FILENO, buffer_tmp, sizeof (buffer_tmp) - 1);
+ pos_buffer_tmp = 0;
+ while (pos_buffer_tmp < num_read)
+ {
+ switch (buffer_tmp[pos_buffer_tmp])
+ {
+ case '\r':
+ break;
+ case '\n':
+ buffer[pos_buffer] = '\0';
+ pos_buffer = 0;
+ user_command (buffer);
+ break;
+ default:
+ buffer[pos_buffer] = buffer_tmp[pos_buffer_tmp];
+ if (pos_buffer < (int) (sizeof (buffer) - 2))
+ pos_buffer++;
+ }
+ pos_buffer_tmp++;
+ }
+}
+
+
+/*
+ * gui_main_loop: main loop for WeeChat with text GUI
+ */
+
+void
+gui_main_loop ()
+{
+ struct timeval timeout;
+ fd_set read_fd;
+ t_irc_server *ptr_server;
+
+ quit_weechat = 0;
+ while (!quit_weechat)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ FD_ZERO (&read_fd);
+ FD_SET (STDIN_FILENO, &read_fd);
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ FD_SET (ptr_server->sock4, &read_fd);
+ }
+ select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout);
+ if (FD_ISSET (STDIN_FILENO, &read_fd))
+ {
+ read_keyb ();
+ }
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (FD_ISSET (ptr_server->sock4, &read_fd))
+ recv_from_server (ptr_server);
+ }
+ }
+}
+
+
+/*
+ * gui_display_message: display a message on the screen
+ */
+
+void
+gui_display_message (char *message)
+{
+ printf ("%s\n", message);
+}
diff --git a/weechat/src/gui/text/gui-text.h b/weechat/src/gui/text/gui-text.h
new file mode 100644
index 000000000..2e62d1a55
--- /dev/null
+++ b/weechat/src/gui/text/gui-text.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_GUI_TEXT_H
+#define __WEECHAT_GUI_TEXT_H 1
+
+#endif /* gui-text.h */
diff --git a/weechat/src/history.c b/weechat/src/history.c
new file mode 100644
index 000000000..9e13e6935
--- /dev/null
+++ b/weechat/src/history.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* history.c: memorize and call again commands or text */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "history.h"
+#include "gui/gui.h"
+
+
+t_history *history_general = NULL;
+t_history *history_general_ptr = NULL;
+
+
+/*
+ * history_add: add a text/command to history
+ */
+
+void
+history_add (void *window, char *string)
+{
+ t_history *new_history;
+
+ new_history = (t_history *)malloc (sizeof (t_history));
+ if (new_history)
+ {
+ new_history->text = strdup (string);
+
+ /* add history to general history */
+ if (history_general)
+ history_general->prev_history = new_history;
+ new_history->next_history = history_general;
+ new_history->prev_history = NULL;
+ history_general = new_history;
+
+ /* add history to local history */
+ if (((t_gui_window *)(window))->history)
+ ((t_gui_window *)(window))->history->prev_history = new_history;
+ new_history->next_history = ((t_gui_window *)(window))->history;
+ new_history->prev_history = NULL;
+ ((t_gui_window *)window)->history = new_history;
+ }
+}
diff --git a/weechat/src/history.h b/weechat/src/history.h
new file mode 100644
index 000000000..946f2e792
--- /dev/null
+++ b/weechat/src/history.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_HISTORY_H
+#define __WEECHAT_HISTORY_H 1
+
+typedef struct t_history t_history;
+
+struct t_history
+{
+ char *text; /* text or command (as entered by user) */
+ t_history *next_history; /* link to next text/command */
+ t_history *prev_history; /* link to previous text/command */
+};
+
+extern void history_add (void *, char *);
+
+#endif /* history.h */
diff --git a/weechat/src/irc/Makefile b/weechat/src/irc/Makefile
new file mode 100644
index 000000000..d22617bda
--- /dev/null
+++ b/weechat/src/irc/Makefile
@@ -0,0 +1,44 @@
+# Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CC=gcc
+
+OPTIONS=-Wall -W -pipe -O2
+
+OUTPUT=irc.a
+OBJS=irc-commands.o irc-display.o irc-server.o irc-channel.o irc-nick.o
+DEFINES=WEE_CURSES
+
+all: $(OBJS)
+ ar r $(OUTPUT) $(OBJS)
+
+$(OBJS):
+ $(CC) $(OPTIONS) -o $@ -c $< $(INCLUDES) -D$(DEFINES)
+
+clean:
+ rm -f *.o *.a *~ core
+
+irc-channel.o: irc-channel.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h
+irc-commands.o: irc-commands.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h ../command.h ../irc/irc.h ../config.h
+irc-display.o: irc-display.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h
+irc-nick.o: irc-nick.c ../weechat.h irc.h ../gui/gui.h ../completion.h \
+ ../history.h
+irc-server.o: irc-server.c ../weechat.h irc.h ../gui/gui.h \
+ ../completion.h ../history.h
diff --git a/weechat/src/irc/irc-channel.c b/weechat/src/irc/irc-channel.c
new file mode 100644
index 000000000..bdad12265
--- /dev/null
+++ b/weechat/src/irc/irc-channel.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-channel.c: manages a chat (channel or private chat) */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../weechat.h"
+#include "irc.h"
+
+
+t_irc_channel *current_channel = NULL;
+
+
+/*
+ * channel_new: allocate a new channel for a server and add it to the server queue
+ */
+
+t_irc_channel *
+channel_new (t_irc_server *server, int channel_type, char *channel_name)
+{
+ t_irc_channel *new_channel;
+
+ #if DEBUG >= 1
+ log_printf ("joining channel %s\n", channel_name);
+ #endif
+
+ /* alloc memory for new channel */
+ if ((new_channel = (t_irc_channel *) malloc (sizeof (t_irc_channel))) == NULL)
+ {
+ fprintf (stderr, _("%s cannot allocate new channel"), WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new channel */
+ new_channel->type = channel_type;
+ new_channel->name = strdup (channel_name);
+ new_channel->topic = NULL;
+ new_channel->nicks = NULL;
+ new_channel->last_nick = NULL;
+
+ /* add new channel to queue */
+ new_channel->prev_channel = server->last_channel;
+ new_channel->next_channel = NULL;
+ if (server->channels)
+ server->last_channel->next_channel = new_channel;
+ else
+ server->channels = new_channel;
+ server->last_channel = new_channel;
+
+ gui_window_new (server, new_channel);
+
+ /* all is ok, return address of new channel */
+ return new_channel;
+}
+
+/*
+ * channel_free: free a channel and remove it from channels queue
+ */
+
+void
+channel_free (t_irc_server *server, t_irc_channel *channel)
+{
+ t_irc_channel *new_channels;
+
+ /* remove channel from queue */
+ if (server->last_channel == channel)
+ server->last_channel = channel->prev_channel;
+ if (channel->prev_channel)
+ {
+ (channel->prev_channel)->next_channel = channel->next_channel;
+ new_channels = server->channels;
+ }
+ else
+ new_channels = channel->next_channel;
+
+ if (channel->next_channel)
+ (channel->next_channel)->prev_channel = channel->prev_channel;
+
+ /* free data */
+ if (channel->name)
+ free (channel->name);
+ if (channel->topic)
+ free (channel->topic);
+ nick_free_all (channel);
+ free (channel);
+ server->channels = new_channels;
+}
+
+/*
+ * channel_free_all: free all allocated channels
+ */
+
+void
+channel_free_all (t_irc_server *server)
+{
+ /* remove all channels for the server */
+ while (server->channels)
+ channel_free (server, server->channels);
+}
+
+/*
+ * channel_search: returns pointer on a channel with name
+ */
+
+t_irc_channel *
+channel_search (t_irc_server *server, char *channel_name)
+{
+ t_irc_channel *ptr_channel;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (strcasecmp (ptr_channel->name, channel_name) == 0)
+ return ptr_channel;
+ }
+ return NULL;
+}
+
+/*
+ * string_is_channel: returns 1 if string is channel
+ */
+
+int
+string_is_channel (char *string)
+{
+ char first_char[2];
+
+ first_char[0] = string[0];
+ first_char[1] = '\0';
+ return (strpbrk (first_char, CHANNEL_PREFIX)) ? 1 : 0;
+}
diff --git a/weechat/src/irc/irc-commands.c b/weechat/src/irc/irc-commands.c
new file mode 100644
index 000000000..2b4cf33ec
--- /dev/null
+++ b/weechat/src/irc/irc-commands.c
@@ -0,0 +1,3064 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-commands.c: implementation of IRC commands, according to
+ RFC 1459,2810,2811,2812 */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "../weechat.h"
+#include "irc.h"
+#include "../command.h"
+#include "../config.h"
+#include "../gui/gui.h"
+
+
+t_irc_command irc_commands[] =
+{ { "away", N_("toggle away status"),
+ N_("[-all] [message]"),
+ N_("-all: toggle away status on all connected servers\n"
+ "message: message for away (if no message is given, away status is removed)"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_away, NULL },
+ { "ctcp", N_("send a ctcp message"),
+ N_("nickname type"),
+ N_("nickname: user to send ctcp to\ntype: \"action\" or \"version\""),
+ 2, MAX_ARGS, 1, NULL, irc_cmd_send_ctcp, NULL },
+ { "deop", N_("removes channel operator status from nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_deop, NULL, NULL },
+ { "devoice", N_("removes voice from nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_devoice, NULL, NULL },
+ { "error", N_("error received from IRC server"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_error },
+ { "invite", N_("invite a nick on a channel"),
+ N_("nickname channel"),
+ N_("nickname: nick to invite\nchannel: channel to invite"),
+ 2, 2, 1, NULL, irc_cmd_send_invite, NULL },
+ { "join", N_("join a channel"),
+ N_("channel[,channel] [key[,key]]"),
+ N_("channel: channel name to join\nkey: key to join the channel"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_join, irc_cmd_recv_join },
+ { "kick", N_("forcibly remove a user from a channel"),
+ N_("[channel] nickname [comment]"),
+ N_("channel: channel where user is\nnickname: nickname to kick\ncomment: comment for kick"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_kick, irc_cmd_recv_kick },
+ { "kill", N_("close client-server connection"),
+ N_("nickname comment"),
+ N_("nickname: nickname\ncomment: comment for kill"),
+ 2, MAX_ARGS, 1, NULL, irc_cmd_send_kill, NULL },
+ { "list", N_("list channels and their topic"),
+ N_("[channel[,channel] [server]]"),
+ N_("channel: channel to list\nserver: server name"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_list, NULL },
+ { "me", N_("send a ctcp action to the current channel"),
+ N_("message"),
+ N_("message: message to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_me, NULL },
+ { "mode", N_("change channel or user mode"),
+ N_("{ channel {[+|-]|o|p|s|i|t|n|b|v} [limit] [user] [ban mask] } | "
+ "{ nickname {[+|-]|i|w|s|o}"),
+ N_("channel modes:\n"
+ " channel: channel name to modify\n"
+ " o: give/take channel operator privileges\n"
+ " p: private channel flag\n"
+ " s: secret channel flag\n"
+ " i: invite-only channel flag\n"
+ " t: topic settable by channel operator only flag\n"
+ " n: no messages to channel from clients on the outside\n"
+ " m: moderated channel\n"
+ " l: set the user limit to channel\n"
+ " b: set a ban mask to keep users out\n"
+ " v: give/take the ability to speak on a moderated channel\n"
+ " k: set a channel key (password)\n"
+ "user modes:\n"
+ " nickname: nickname to modify\n"
+ " i: mark a user as invisible\n"
+ " s: mark a user for receive server notices\n"
+ " w: user receives wallops\n"
+ " o: operator flag\n"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_mode, irc_cmd_recv_mode },
+ { "msg", N_("send message to a nick or channel"),
+ N_("receiver[,receiver] text"), N_("receiver: nick or channel (may be mask)"
+ "\ntext: text to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_msg, NULL },
+ { "names", N_("list nicknames on channels"),
+ N_("[channel[,channel]]"), N_("channel: channel name"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_names, NULL },
+ { "nick", N_("change current nickname"),
+ N_("nickname"), N_("nickname: new nickname for current IRC server"),
+ 1, 1, 1, irc_cmd_send_nick, NULL, irc_cmd_recv_nick },
+ { "notice", N_("send notice message to user"),
+ N_("nickname text"), N_("nickname: user to send notice to\ntext: text to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_notice, irc_cmd_recv_notice },
+ { "op", N_("gives channel operator status to nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_op, NULL, NULL },
+ { "oper", N_("get operator privileges"),
+ N_("user password"),
+ N_("user/password: used to get privileges on current IRC server"),
+ 2, 2, 1, irc_cmd_send_oper, NULL, NULL },
+ { "part", N_("leave a channel"),
+ N_("[channel[,channel]]"), N_("channel: channel name to join"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_part, irc_cmd_recv_part },
+ { "ping", N_("ping server"),
+ N_("server1 [server2]"),
+ N_("server1: server to ping\nserver2: forward ping to this server"),
+ 1, 2, 1, irc_cmd_send_ping, NULL, irc_cmd_recv_ping },
+ { "pong", N_("answer to a ping message"),
+ N_("daemon [daemon2]"), N_("daemon: daemon who has responded to Ping message\n"
+ "daemon2: forward message to this daemon"),
+ 1, 2, 1, irc_cmd_send_pong, NULL, NULL },
+ { "privmsg", N_("message received"),
+ "", "",
+ 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_privmsg },
+ { "quit", N_("close all connections & quit " WEECHAT_NAME),
+ N_("[quit_message]"),
+ N_("quit_message: quit message (displayed to other users)"),
+ 0, MAX_ARGS, 0, NULL, irc_cmd_send_quit, irc_cmd_recv_quit },
+ { "quote", N_("send raw data to server without parsing"),
+ N_("data"),
+ N_("data: raw data to send"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_quote, NULL },
+ { "topic", N_("get/set channel topic"),
+ N_("[channel] [topic]"), N_("channel: channel name\ntopic: new topic for channel "
+ "(if topic is \"-delete\" then topic is deleted)"),
+ 0, MAX_ARGS, 1, NULL, irc_cmd_send_topic, irc_cmd_recv_topic },
+ { "version", N_("gives the version info of nick or server (current or specified)"),
+ N_("[server | nickname]"), N_("server: server name\nnickname: nickname"),
+ 0, 1, 1, NULL, irc_cmd_send_version, NULL },
+ { "voice", N_("gives voice to nickname(s)"),
+ N_("nickname [nickname]"), "",
+ 1, 1, 1, irc_cmd_send_voice, NULL, NULL },
+ { "whois", N_("query information about user(s)"),
+ N_("[server] nickname[,nickname]"), N_("server: server name\n"
+ "nickname: nickname (may be a mask)"),
+ 1, MAX_ARGS, 1, NULL, irc_cmd_send_whois, NULL },
+ { "001", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "002", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "003", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "004", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_004 },
+ { "005", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "250", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "251", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "252", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "253", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "254", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "255", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "256", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "257", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "258", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "259", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "260", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "261", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "262", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "263", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "264", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "265", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "266", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "267", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "268", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "269", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "301", N_("away message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_301 },
+ { "305", N_("unaway"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply },
+ { "306", N_("now away"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_reply },
+ { "311", N_("whois (user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_311 },
+ { "312", N_("whois (server)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_312 },
+ { "313", N_("whois (operator)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_313 },
+ { "317", N_("whois (idle)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_317 },
+ { "318", N_("whois (end)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_318 },
+ { "319", N_("whois (channels)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_319 },
+ { "320", N_("whois (identified user)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_320 },
+ { "321", N_("/list start"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_321 },
+ { "322", N_("channel (for /list)"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_322 },
+ { "323", N_("/list end"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_323 },
+ { "331", N_("no topic for channel"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_331 },
+ { "332", N_("topic of channel"),
+ N_("channel :topic"),
+ N_("channel: name of channel\ntopic: topic of the channel"),
+ 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_332 },
+ { "333", N_("infos about topic (nick & date changed)"),
+ "", "",
+ 0, 0, 1, NULL, NULL, irc_cmd_recv_333 },
+ { "351", N_("server version"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_351 },
+ { "353", N_("list of nicks on channel"),
+ N_("channel :[[@|+]nick ...]"),
+ N_("channel: name of channel\nnick: nick on the channel"),
+ 2, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_353 },
+ { "366", N_("end of /names list"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_366 },
+ { "371", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "372", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "373", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "374", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "375", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "376", N_("a server message"), "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_server_msg },
+ { "401", N_("no such nick/channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "402", N_("no such server"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "403", N_("no such channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "404", N_("cannot send to channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "405", N_("too many channels"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "406", N_("was no such nick"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "406", N_("was no such nick"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "407", N_("was no such nick"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "409", N_("no origin"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "411", N_("no recipient"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "412", N_("no text to send"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "413", N_("no toplevel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "414", N_("wilcard in toplevel domain"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "421", N_("unknown command"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "422", N_("MOTD is missing"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "423", N_("no administrative info"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "424", N_("file error"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "431", N_("no nickname given"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "432", N_("erroneus nickname"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "433", N_("nickname already in use"),
+ "", "", 0, 0, 1, NULL, NULL, irc_cmd_recv_433 },
+ { "436", N_("nickname collision"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "441", N_("user not in channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "442", N_("not on channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "443", N_("user already on channel"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "444", N_("user not logged in"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "445", N_("summon has been disabled"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "446", N_("users has been disabled"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "451", N_("you are not registered"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "461", N_("not enough parameters"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "462", N_("you may not register"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "463", N_("your host isn't among the privileged"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "464", N_("password incorrect"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "465", N_("you are banned from this server"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "467", N_("channel key already set"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "471", N_("channel is already full"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "472", N_("unknown mode char to me"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "473", N_("cannot join channel (invite only)"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "474", N_("cannot join channel (banned from channel)"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "475", N_("cannot join channel (bad channel key)"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "481", N_("you're not an IRC operator"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "482", N_("you're not channel operator"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "483", N_("you can't kill a server!"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "491", N_("no O-lines for your host"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "501", N_("unknown mode flag"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { "502", N_("can't change mode for other users"),
+ "", "", 0, MAX_ARGS, 1, NULL, NULL, irc_cmd_recv_error },
+ { NULL, NULL, NULL, NULL, 0, 0, 1, NULL, NULL, NULL }
+};
+
+
+/*
+ * irc_recv_command: executes action when receiving IRC command
+ * returns: 0 = all ok, command executed
+ * -1 = command failed
+ * -2 = no command to execute
+ * -3 = command not found
+ */
+
+int
+irc_recv_command (t_irc_server *server,
+ char *host, char *command, char *arguments)
+{
+ int i, cmd_found;
+
+ #if DEBUG >= 2
+ gui_printf (server->window, "recv_irc_command: cmd=%s args=%s\n",
+ command, arguments);
+ #endif
+
+ if (command == NULL)
+ return -2;
+
+ /* looks for irc command */
+ cmd_found = -1;
+ for (i = 0; irc_commands[i].command_name; i++)
+ if (strcasecmp (irc_commands[i].command_name, command) == 0)
+ {
+ cmd_found = i;
+ break;
+ }
+
+ /* command not found */
+ if (cmd_found < 0)
+ return -3;
+
+ if (irc_commands[i].recv_function != NULL)
+ return (int) (irc_commands[i].recv_function) (server, host, arguments);
+
+ return 0;
+}
+
+/*
+ * irc_login: login to irc server
+ */
+
+void
+irc_login (t_irc_server *server)
+{
+ char hostname[128];
+
+ if ((server->password) && (server->password[0]))
+ server_sendf (server, "PASS %s\r\n", server->password);
+
+ gethostname (hostname, sizeof (hostname) - 1);
+ hostname[sizeof (hostname) - 1] = '\0';
+ if (!hostname[0])
+ strcpy (hostname, _("unknown"));
+ gui_printf (server->window,
+ _(WEECHAT_NAME ": using local hostname \"%s\"\n"),
+ hostname);
+ server_sendf (server,
+ "NICK %s\r\n"
+ "USER %s %s %s :%s\r\n",
+ server->nick, server->username, hostname, "servername",
+ server->realname);
+}
+
+/*
+ * irc_cmd_send_away: toggle away status
+ */
+
+int
+irc_cmd_send_away (t_irc_server *server, char *arguments)
+{
+ char *pos;
+ t_irc_server *ptr_server;
+
+ if (arguments && (strncmp (arguments, "-all", 4) == 0))
+ {
+ pos = arguments + 4;
+ while (pos[0] == ' ')
+ pos++;
+ if (!pos[0])
+ pos = NULL;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (server->is_connected)
+ {
+ if (pos)
+ server_sendf (ptr_server, "AWAY :%s\r\n", pos);
+ else
+ server_sendf (ptr_server, "AWAY\r\n");
+ }
+ }
+ }
+ else
+ {
+ if (arguments)
+ server_sendf (server, "AWAY :%s\r\n", arguments);
+ else
+ server_sendf (server, "AWAY\r\n");
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_ctcp: send a ctcp message
+ */
+
+int
+irc_cmd_send_ctcp (t_irc_server *server, char *arguments)
+{
+ char *pos, *pos2;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ }
+ else
+ pos2 = NULL;
+
+ if (strcasecmp (pos, "version") == 0)
+ {
+ if (pos2)
+ server_sendf (server, "PRIVMSG %s :\01VERSION %s\01\r\n",
+ arguments, pos2);
+ else
+ server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n",
+ arguments);
+ }
+ if (strcasecmp (pos, "action") == 0)
+ {
+ if (pos2)
+ server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n",
+ arguments, pos2);
+ else
+ server_sendf (server, "PRIVMSG %s :\01ACTION\01\r\n",
+ arguments);
+ }
+
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_deop: remove operator privileges from nickname(s)
+ */
+
+int
+irc_cmd_send_deop (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s -o %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ gui_printf (server->window,
+ _("%s \"deop\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_devoice: remove voice from nickname(s)
+ */
+
+int
+irc_cmd_send_devoice (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s -v %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"devoice\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_invite: invite a nick on a channel
+ */
+
+int
+irc_cmd_send_invite (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "INVITE %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_join: join a new channel
+ */
+
+int
+irc_cmd_send_join (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "JOIN %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_kick: forcibly remove a user from a channel
+ */
+
+int
+irc_cmd_send_kick (t_irc_server *server, char *arguments)
+{
+ if (string_is_channel (arguments))
+ server_sendf (server, "KICK %s\r\n", arguments);
+ else
+ {
+ if (WIN_IS_CHANNEL (gui_current_window))
+ {
+ server_sendf (server,
+ "KICK %s %s\r\n",
+ CHANNEL(gui_current_window)->name, arguments);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"kick\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_kill: close client-server connection
+ */
+
+int
+irc_cmd_send_kill (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "KILL %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_list: close client-server connection
+ */
+
+int
+irc_cmd_send_list (t_irc_server *server, char *arguments)
+{
+ if (arguments)
+ server_sendf (server, "LIST %s\r\n", arguments);
+ else
+ server_sendf (server, "LIST\r\n");
+ return 0;
+}
+
+/*
+ * irc_cmd_send_me: send a ctcp action to the current channel
+ */
+
+int
+irc_cmd_send_me (t_irc_server *server, char *arguments)
+{
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"me\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ server_sendf (server, "PRIVMSG %s :\01ACTION %s\01\r\n",
+ CHANNEL(gui_current_window)->name, arguments);
+ irc_display_prefix (gui_current_window, PREFIX_ACTION_ME);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_NICK, "%s", server->nick);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, " %s\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_mode: change mode for channel/nickname
+ */
+
+int
+irc_cmd_send_mode (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "MODE %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_msg: send a message to a nick or channel
+ */
+
+int
+irc_cmd_send_msg (t_irc_server *server, char *arguments)
+{
+ char *pos, *pos_comma;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+
+ while (arguments && arguments[0])
+ {
+ pos_comma = strchr (arguments, ',');
+ if (pos_comma)
+ {
+ pos_comma[0] = '\0';
+ pos_comma++;
+ }
+ if (string_is_channel (arguments))
+ {
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ ptr_nick = nick_search (ptr_channel, server->nick);
+ if (ptr_nick)
+ {
+ irc_display_nick (ptr_channel->window, ptr_nick,
+ MSG_TYPE_NICK, 1, 1, 0);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ }
+ else
+ gui_printf (server->window,
+ _("%s nick not found for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ }
+ server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos);
+ }
+ else
+ {
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ ptr_channel = channel_new (server, CHAT_PRIVATE, arguments);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s cannot create new private window \"%s\"\n"),
+ WEECHAT_ERROR,
+ arguments);
+ return -1;
+ }
+ gui_redraw_window_title (ptr_channel->window);
+ }
+
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "<");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_NICK_SELF,
+ "%s", server->nick);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "> ");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ server_sendf (server, "PRIVMSG %s :%s\r\n", arguments, pos);
+ }
+ arguments = pos_comma;
+ }
+ }
+ else
+ gui_printf (server->window,
+ _("%s wrong number of args for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_names: list nicknames on channels
+ */
+
+int
+irc_cmd_send_names (t_irc_server *server, char *arguments)
+{
+ if (arguments)
+ server_sendf (server, "NAMES %s\r\n", arguments);
+ else
+ {
+ if (!WIN_IS_CHANNEL(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"names\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ else
+ server_sendf (server, "NAMES %s\r\n",
+ CHANNEL(gui_current_window)->name);
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_nick: change nickname
+ */
+
+int
+irc_cmd_send_nick (t_irc_server *server, int argc, char **argv)
+{
+ if (argc != 1)
+ return -1;
+ server_sendf (server, "NICK %s\r\n", argv[0]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_notice: send notice message
+ */
+
+int
+irc_cmd_send_notice (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "NOTICE %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_op: give operator privileges to nickname(s)
+ */
+
+int
+irc_cmd_send_op (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s +o %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"op\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_oper: get oper privileges
+ */
+
+int
+irc_cmd_send_oper (t_irc_server *server, int argc, char **argv)
+{
+ if (argc != 2)
+ return -1;
+ server_sendf (server, "OPER %s %s\r\n", argv[0], argv[1]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_part: leave a channel or close a private window
+ */
+
+int
+irc_cmd_send_part (t_irc_server *server, char *arguments)
+{
+ char *channel_name, *pos_args;
+ t_irc_channel *ptr_channel;
+
+ if (arguments)
+ {
+ if (string_is_channel (arguments))
+ {
+ channel_name = arguments;
+ pos_args = strchr (arguments, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ }
+ }
+ else
+ {
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"part\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ channel_name = CHANNEL(gui_current_window)->name;
+ pos_args = arguments;
+ }
+ }
+ else
+ {
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"part\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ if (WIN_IS_PRIVATE(gui_current_window))
+ {
+ ptr_channel = CHANNEL(gui_current_window);
+ gui_window_free (ptr_channel->window);
+ channel_free (server, ptr_channel);
+ gui_redraw_window_status (gui_current_window);
+ gui_redraw_window_input (gui_current_window);
+ return 0;
+ }
+ channel_name = CHANNEL(gui_current_window)->name;
+ pos_args = NULL;
+ }
+
+ if (pos_args)
+ server_sendf (server, "PART %s :%s\r\n", channel_name, pos_args);
+ else
+ server_sendf (server, "PART %s\r\n", channel_name);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_ping: ping a server
+ */
+
+int
+irc_cmd_send_ping (t_irc_server *server, int argc, char **argv)
+{
+ if (argc == 1)
+ server_sendf (server, "PING %s\r\n", argv[0]);
+ if (argc == 2)
+ server_sendf (server, "PING %s %s\r\n", argv[0],
+ argv[1]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_pong: send pong answer to a daemon
+ */
+
+int
+irc_cmd_send_pong (t_irc_server *server, int argc, char **argv)
+{
+ if (argc == 1)
+ server_sendf (server, "PONG %s\r\n", argv[0]);
+ if (argc == 2)
+ server_sendf (server, "PONG %s %s\r\n", argv[0],
+ argv[1]);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_quit: disconnect from all servers and quit WeeChat
+ */
+
+int
+irc_cmd_send_quit (t_irc_server *server, char *arguments)
+{
+ if (server && server->is_connected)
+ {
+ if (arguments)
+ server_sendf (server, "QUIT :%s\r\n", arguments);
+ else
+ server_sendf (server, "QUIT\r\n");
+ }
+ quit_weechat = 1;
+ return 0;
+}
+
+/*
+ * irc_cmd_send_quote: send raw data to server
+ */
+
+int
+irc_cmd_send_quote (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "%s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_topic: get/set topic for a channel
+ */
+
+int
+irc_cmd_send_topic (t_irc_server *server, char *arguments)
+{
+ char *channel_name, *new_topic, *pos;
+
+ channel_name = NULL;
+ new_topic = NULL;
+
+ if (arguments)
+ {
+ if (string_is_channel (arguments))
+ {
+ channel_name = arguments;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ new_topic = (pos[0]) ? pos : NULL;
+ }
+ }
+ else
+ new_topic = arguments;
+ }
+
+ /* look for current channel if not specified */
+ if (!channel_name)
+ {
+ if (WIN_IS_SERVER(gui_current_window))
+ {
+ gui_printf (server->window,
+ _("%s \"topic\" command can not be executed on a server window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ channel_name = CHANNEL(gui_current_window)->name;
+ }
+
+ if (new_topic)
+ {
+ if (strcmp (new_topic, "-delete") == 0)
+ server_sendf (server, "TOPIC %s :\r\n", channel_name);
+ else
+ server_sendf (server, "TOPIC %s :%s\r\n", channel_name, new_topic);
+ }
+ else
+ server_sendf (server, "TOPIC %s\r\n", channel_name);
+ return 0;
+}
+
+/*
+ * irc_cmd_send_version: gives the version info of nick or server (current or specified)
+ */
+
+int
+irc_cmd_send_version (t_irc_server *server, char *arguments)
+{
+ if (arguments)
+ {
+ if (WIN_IS_CHANNEL(gui_current_window) &&
+ nick_search (CHANNEL(gui_current_window), arguments))
+ server_sendf (server, "PRIVMSG %s :\01VERSION\01\r\n",
+ arguments);
+ else
+ server_sendf (server, "VERSION %s\r\n",
+ arguments);
+ }
+ else
+ {
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s, compiled on %s %s\n",
+ WEECHAT_NAME_AND_VERSION,
+ __DATE__, __TIME__);
+ server_sendf (server, "VERSION\r\n");
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_voice: give voice to nickname(s)
+ */
+
+int
+irc_cmd_send_voice (t_irc_server *server, int argc, char **argv)
+{
+ int i;
+
+ if (WIN_IS_CHANNEL(gui_current_window))
+ {
+ for (i = 0; i < argc; i++)
+ server_sendf (server, "MODE %s +v %s\r\n",
+ CHANNEL(gui_current_window)->name,
+ argv[i]);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s \"voice\" command can only be executed in a channel window\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_send_whois: query information about user(s)
+ */
+
+int
+irc_cmd_send_whois (t_irc_server *server, char *arguments)
+{
+ server_sendf (server, "WHOIS %s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_error: error received from server
+ */
+
+int
+irc_cmd_recv_error (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ int first;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ if (strncmp (arguments, "Closing Link", 12) == 0)
+ {
+ server_disconnect (server);
+ return 0;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_ERROR);
+ first = 1;
+
+ while (pos && pos[0])
+ {
+ pos2 = strchr (pos, ' ');
+ if ((pos[0] == ':') || (!pos2))
+ {
+ if (pos[0] == ':')
+ pos++;
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ "%s%s\n", (first) ? "" : ": ", pos);
+ pos = NULL;
+ }
+ else
+ {
+ pos2[0] = '\0';
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s%s",
+ (first) ? "" : " ", pos);
+ first = 0;
+ pos = pos2 + 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_join: 'join' message received
+ */
+
+int
+irc_cmd_recv_join (t_irc_server *server, char *host, char *arguments)
+{
+ t_irc_channel *ptr_channel;
+ char *pos;
+
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ ptr_channel = channel_new (server, CHAT_CHANNEL, arguments);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s cannot create new channel \"%s\"\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+ }
+
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ irc_display_prefix (ptr_channel->window, PREFIX_JOIN);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK,
+ "%s ", host);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ "(");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_HOST,
+ "%s", pos + 1);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ ")");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _(" has joined "));
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s\n", arguments);
+ nick_new (ptr_channel, host, 0, 0, 0);
+ gui_redraw_window_nick (gui_current_window);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_kick: 'kick' message received
+ */
+
+int
+irc_cmd_recv_kick (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos_nick, *pos_comment;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+
+ pos_comment = strchr (pos_nick, ' ');
+ if (pos_comment)
+ {
+ pos_comment[0] = '\0';
+ pos_comment++;
+ while (pos_comment[0] == ' ')
+ pos_comment++;
+ if (pos_comment[0] == ':')
+ pos_comment++;
+ }
+
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"kick\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ irc_display_prefix (ptr_channel->window, PREFIX_PART);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK,
+ "%s", host);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _(" has kicked "));
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_NICK,
+ "%s", pos_nick);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _(" from "));
+ if (pos_comment)
+ {
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s ", arguments);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ "(");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ "%s", pos_comment);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK,
+ ")\n");
+ }
+ else
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s\n", arguments);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s nick not found for \"kick\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ ptr_nick = nick_search (ptr_channel, pos_nick);
+ if (ptr_nick)
+ {
+ nick_free (ptr_channel, ptr_nick);
+ gui_redraw_window_nick (gui_current_window);
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_mode: 'mode' message received
+ */
+
+int
+irc_cmd_recv_mode (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2, *pos_parm;
+ char set_flag;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"mode\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ pos = strchr (arguments, ' ');
+ if (!pos)
+ {
+ gui_printf (server->window,
+ _("%s \"mode\" command received without channel or nickname\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+
+ pos_parm = strchr (pos, ' ');
+ if (pos_parm)
+ {
+ pos_parm[0] = '\0';
+ pos_parm++;
+ while (pos_parm[0] == ' ')
+ pos_parm++;
+ pos2 = strchr (pos_parm, ' ');
+ if (pos2)
+ pos2[0] = '\0';
+ }
+
+ set_flag = '+';
+
+ if (string_is_channel (arguments))
+ {
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ /* channel modes */
+ while (pos && pos[0])
+ {
+ switch (pos[0])
+ {
+ case '+':
+ set_flag = '+';
+ break;
+ case '-':
+ set_flag = '-';
+ break;
+ case 'b':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "b", host,
+ (set_flag == '+') ?
+ _("sets ban on") :
+ _("removes ban on"),
+ pos_parm);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'i':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "i", host,
+ (set_flag == '+') ?
+ _("sets invite-only channel flag") :
+ _("removes invite-only channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'l':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "l", host,
+ (set_flag == '+') ?
+ _("sets the user limit to") :
+ _("removes user limit"),
+ (set_flag == '+') ? pos_parm : NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'm':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "m", host,
+ (set_flag == '+') ?
+ _("sets moderated channel flag") :
+ _("removes moderated channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'o':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "o", host,
+ (set_flag == '+') ?
+ _("gives channel operator status to") :
+ _("removes channel operator status from"),
+ pos_parm);
+ ptr_nick = nick_search (ptr_channel, pos_parm);
+ if (ptr_nick)
+ {
+ ptr_nick->is_op = (set_flag == '+') ? 1 : 0;
+ nick_resort (ptr_channel, ptr_nick);
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ break;
+ /* TODO: remove this obsolete (?) channel flag? */
+ case 'p':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "p", host,
+ (set_flag == '+') ?
+ _("sets private channel flag") :
+ _("removes private channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 's':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "s", host,
+ (set_flag == '+') ?
+ _("sets secret channel flag") :
+ _("removes secret channel flag"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 't':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "t", host,
+ (set_flag == '+') ?
+ _("sets topic protection") :
+ _("removes topic protection"),
+ NULL);
+ /* TODO: change & redraw channel modes */
+ break;
+ case 'v':
+ irc_display_mode (ptr_channel->window,
+ arguments, set_flag, "v", host,
+ (set_flag == '+') ?
+ _("gives voice to") :
+ _("removes voice from"),
+ pos_parm);
+
+ ptr_nick = nick_search (ptr_channel, pos_parm);
+ if (ptr_nick)
+ {
+ ptr_nick->has_voice = (set_flag == '+') ? 1 : 0;
+ nick_resort (ptr_channel, ptr_nick);
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ break;
+ }
+ pos++;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"mode\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ /* nickname modes */
+ gui_printf (server->window, "(TODO!) nickname modes: channel=%s, args=%s\n", arguments, pos);
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_nick: 'nick' message received
+ */
+
+int
+irc_cmd_recv_nick (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ int nick_is_me;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"nick\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ ptr_nick = nick_search (ptr_channel, host);
+ if (ptr_nick)
+ {
+ nick_is_me = (strcmp (ptr_nick->nick, server->nick) == 0);
+ nick_change (ptr_channel, ptr_nick, arguments);
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ if (nick_is_me)
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ _("You are "));
+ else
+ {
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK,
+ "%s", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, " is ");
+ }
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ _("now known as "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK,
+ "%s\n",
+ arguments);
+ if (ptr_channel->window->win_nick)
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ }
+
+ if (strcmp (server->nick, host) == 0)
+ {
+ free (server->nick);
+ server->nick = strdup (arguments);
+ }
+ gui_redraw_window_input (gui_current_window);
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_notice: 'notice' message received
+ */
+
+int
+irc_cmd_recv_notice (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+
+ if (host)
+ {
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s nickname not found for \"notice\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ irc_display_prefix (server->window, PREFIX_SERVER);
+ if (strncmp (pos, "\01VERSION", 8) == 0)
+ {
+ pos += 9;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ gui_printf_color (server->window, COLOR_WIN_CHAT, "CTCP ");
+ gui_printf_color (server->window, COLOR_WIN_CHAT_CHANNEL, "VERSION");
+ gui_printf_color (server->window, COLOR_WIN_CHAT, " reply from ");
+ gui_printf_color (server->window, COLOR_WIN_CHAT_NICK, "%s", host);
+ gui_printf_color (server->window, COLOR_WIN_CHAT, ": %s\n", pos);
+ }
+ else
+ gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_part: 'part' message received
+ */
+
+int
+irc_cmd_recv_part (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos_args;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (!host || !arguments)
+ {
+ gui_printf (server->window,
+ _("%s \"part\" command received without host or channel\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ pos_args = strchr (arguments, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ if (pos_args[0] == ':')
+ pos_args++;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ ptr_nick = nick_search (ptr_channel, host);
+ if (ptr_nick)
+ {
+ if (strcmp (ptr_nick->nick, server->nick) == 0)
+ {
+ /* part request was issued by local client */
+ gui_window_free (ptr_channel->window);
+ channel_free (server, ptr_channel);
+ gui_redraw_window_status (gui_current_window);
+ gui_redraw_window_input (gui_current_window);
+ }
+ else
+ {
+
+ /* remove nick from nick list and display message */
+ nick_free (ptr_channel, ptr_nick);
+ irc_display_prefix (ptr_channel->window, PREFIX_PART);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s ", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_HOST, "%s", pos+1);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _(" has left "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s", ptr_channel->name);
+ if (pos_args && pos_args[0])
+ {
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, " (");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, "%s", pos_args);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ }
+ gui_printf (ptr_channel->window, "\n");
+
+ /* redraw nick list if this is current window */
+ if (ptr_channel->window->win_nick)
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"part\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_ping: 'ping' command received
+ */
+
+int
+irc_cmd_recv_ping (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ (void)host;
+ pos = strrchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+ server_sendf (server, "PONG :%s\r\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_privmsg: 'privmsg' command received
+ */
+
+int
+irc_cmd_recv_privmsg (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2, *host2;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"privmsg\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ {
+ pos[0] = '\0';
+ host2 = pos+1;
+ }
+ else
+ host2 = host;
+
+ /* receiver is a channel ? */
+ if (string_is_channel (arguments))
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+
+ ptr_channel = channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ if (strncmp (pos, "\01ACTION ", 8) == 0)
+ {
+ pos += 8;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ irc_display_prefix (ptr_channel->window, PREFIX_ACTION_ME);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, " %s\n", pos);
+ }
+ else
+ {
+ ptr_nick = nick_search (ptr_channel, host);
+ if (ptr_nick)
+ {
+ irc_display_nick (ptr_channel->window, ptr_nick,
+ MSG_TYPE_NICK, 1, 1, 0);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s nick not found for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+
+ if (strcmp (pos, "\01VERSION\01") == 0)
+ server_sendf (server,
+ "NOTICE %s :\01VERSION "
+ WEECHAT_NAME " v"
+ WEECHAT_VERSION ", compiled on " __DATE__ "\01\r\n",
+ host);
+ else
+ {
+ /* private message received */
+ ptr_channel = channel_search (server, host);
+ if (!ptr_channel)
+ {
+ ptr_channel = channel_new (server, CHAT_PRIVATE, host);
+ if (!ptr_channel)
+ {
+ gui_printf (server->window,
+ _("%s cannot create new private window \"%s\"\n"),
+ WEECHAT_ERROR, host);
+ return -1;
+ }
+ }
+ if (!ptr_channel->topic)
+ {
+ ptr_channel->topic = strdup (host2);
+ gui_redraw_window_title (ptr_channel->window);
+ }
+
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "<");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_NICK_PRIVATE,
+ "%s", host);
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_NICK,
+ COLOR_WIN_CHAT_DARK, "> ");
+ gui_printf_color_type (ptr_channel->window,
+ MSG_TYPE_MSG,
+ COLOR_WIN_CHAT, "%s\n", pos);
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot parse \"privmsg\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_quit: 'quit' command received
+ */
+
+int
+irc_cmd_recv_quit (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (host == NULL)
+ {
+ gui_printf (server->window,
+ _("%s \"quit\" command received without host\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ptr_channel->type == CHAT_PRIVATE)
+ ptr_nick = NULL;
+ else
+ ptr_nick = nick_search (ptr_channel, host);
+
+ if (ptr_nick || (strcmp (ptr_channel->name, host) == 0))
+ {
+ if (ptr_nick)
+ nick_free (ptr_channel, ptr_nick);
+ irc_display_prefix (ptr_channel->window, PREFIX_QUIT);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s ", host);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_HOST, "%s", pos + 1);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _(" has quit "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, "%s",
+ arguments);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")\n");
+ if ((ptr_channel->window == gui_current_window) &&
+ (ptr_channel->window->win_nick))
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_server_msg: command received from server (numeric)
+ */
+
+int
+irc_cmd_recv_server_msg (t_irc_server *server, char *host, char *arguments)
+{
+ /* make gcc happy */
+ (void) host;
+
+ /* skip nickname if at beginning of server message */
+ if (strncmp (server->nick, arguments, strlen (server->nick)) == 0)
+ {
+ arguments += strlen (server->nick) + 1;
+ while (arguments[0] == ' ')
+ arguments++;
+ }
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ /* display server message */
+ irc_display_prefix (server->window, PREFIX_SERVER);
+ gui_printf_color (server->window, COLOR_WIN_CHAT, "%s\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_server_reply: server reply
+ */
+
+int
+irc_cmd_recv_server_reply (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ int first;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_ERROR);
+ first = 1;
+
+ while (pos && pos[0])
+ {
+ pos2 = strchr (pos, ' ');
+ if ((pos[0] == ':') || (!pos2))
+ {
+ if (pos[0] == ':')
+ pos++;
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ "%s%s\n", (first) ? "" : ": ", pos);
+ pos = NULL;
+ }
+ else
+ {
+ pos2[0] = '\0';
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s%s",
+ (first) ? "" : " ", pos);
+ first = 0;
+ pos = pos2 + 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_topic: 'topic' command received
+ */
+
+int
+irc_cmd_recv_topic (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_gui_window *window;
+
+ /* make gcc happy */
+ (void) host;
+
+ /* keep only nick name from host */
+ pos = strchr (host, '!');
+ if (pos)
+ pos[0] = '\0';
+
+ if (string_is_channel (arguments))
+ {
+ gui_printf (server->window,
+ _("%s \"topic\" command received without channel\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+ if (!pos[0])
+ pos = NULL;
+ }
+
+ ptr_channel = channel_search (server, arguments);
+ window = (ptr_channel) ? ptr_channel->window : server->window;
+
+ irc_display_prefix (window, PREFIX_INFO);
+ gui_printf_color (window,
+ COLOR_WIN_CHAT_NICK, "%s",
+ host);
+ if (pos)
+ {
+ gui_printf_color (window,
+ COLOR_WIN_CHAT, _(" has changed topic for "));
+ gui_printf_color (window,
+ COLOR_WIN_CHAT_CHANNEL, "%s",
+ arguments);
+ gui_printf_color (window,
+ COLOR_WIN_CHAT, _(" to: \"%s\"\n"),
+ pos);
+ }
+ else
+ {
+ gui_printf_color (window,
+ COLOR_WIN_CHAT, _(" has unset topic for "));
+ gui_printf_color (window,
+ COLOR_WIN_CHAT_CHANNEL, "%s\n",
+ arguments);
+ }
+
+ if (ptr_channel)
+ {
+ if (ptr_channel->topic)
+ free (ptr_channel->topic);
+ if (pos)
+ ptr_channel->topic = strdup (pos);
+ else
+ ptr_channel->topic = strdup ("");
+ gui_redraw_window_title (ptr_channel->window);
+ }
+
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_004: '004' command (connected to irc server ?????)
+ */
+
+int
+irc_cmd_recv_004 (t_irc_server *server, char *host, char *arguments)
+{
+ /* make gcc happy */
+ (void) host;
+ (void) arguments;
+
+ irc_cmd_recv_server_msg (server, host, arguments);
+
+ /* connection to IRC server is ok! */
+ server->is_connected = 1;
+ gui_redraw_window_status (server->window);
+ gui_redraw_window_input (server->window);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_311: '311' command (away message)
+ */
+
+int
+irc_cmd_recv_301 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (gui_current_window, PREFIX_INFO);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, _(" is away: %s\n"), pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_311: '311' command (whois, user)
+ */
+
+int
+irc_cmd_recv_311 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_user, *pos_host, *pos_realname;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_user = strchr (pos_nick, ' ');
+ if (pos_user)
+ {
+ pos_user[0] = '\0';
+ pos_user++;
+ while (pos_user[0] == ' ')
+ pos_user++;
+ pos_host = strchr (pos_user, ' ');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+ while (pos_host[0] == ' ')
+ pos_host++;
+ pos_realname = strchr (pos_host, ' ');
+ if (pos_realname)
+ {
+ pos_realname[0] = '\0';
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ if (pos_realname[0] == '*')
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ if (pos_realname[0] == ':')
+ pos_realname++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] (");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_HOST, "%s@%s",
+ pos_user, pos_host);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, ")");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, ": %s\n", pos_realname);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_312: '312' command (whois, server)
+ */
+
+int
+irc_cmd_recv_312 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_server, *pos_serverinfo;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_server = strchr (pos_nick, ' ');
+ if (pos_server)
+ {
+ pos_server[0] = '\0';
+ pos_server++;
+ while (pos_server[0] == ' ')
+ pos_server++;
+ pos_serverinfo = strchr (pos_server, ' ');
+ if (pos_serverinfo)
+ {
+ pos_serverinfo[0] = '\0';
+ pos_serverinfo++;
+ while (pos_serverinfo[0] == ' ')
+ pos_serverinfo++;
+ if (pos_serverinfo[0] == ':')
+ pos_serverinfo++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s ", pos_server);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "(");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s", pos_serverinfo);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, ")\n");
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_313: '313' command (whois, operator)
+ */
+
+int
+irc_cmd_recv_313 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s\n", pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_317: '317' command (whois, idle)
+ */
+
+int
+irc_cmd_recv_317 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_idle, *pos_signon, *pos_message;
+ int idle_time, day, hour, min, sec;
+ time_t datetime;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_idle = strchr (pos_nick, ' ');
+ if (pos_idle)
+ {
+ pos_idle[0] = '\0';
+ pos_idle++;
+ while (pos_idle[0] == ' ')
+ pos_idle++;
+ pos_signon = strchr (pos_idle, ' ');
+ if (pos_signon)
+ {
+ pos_signon[0] = '\0';
+ pos_signon++;
+ while (pos_signon[0] == ' ')
+ pos_signon++;
+ pos_message = strchr (pos_signon, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+
+ idle_time = atoi (pos_idle);
+ day = idle_time / (60 * 60 * 24);
+ hour = (idle_time % (60 * 60 * 24)) / (60 * 60);
+ min = ((idle_time % (60 * 60 * 24)) % (60 * 60)) / 60;
+ sec = ((idle_time % (60 * 60 * 24)) % (60 * 60)) % 60;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, _("idle: "));
+ if (day > 0)
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", day);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (day > 1) ? _("days") : _("day"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ }
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%02d ", hour);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (hour > 1) ? _("hours") : _("hour"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ " %02d ", min);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (min > 1) ? _("minutes") : _("minute"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ " %02d ", sec);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ (sec > 1) ? _("seconds") : _("second"));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, _("signon at: "));
+ datetime = (time_t)(atol (pos_signon));
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s", ctime (&datetime));
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_318: '318' command (whois, end)
+ */
+
+int
+irc_cmd_recv_318 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s\n", pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_319: '319' command (whois, end)
+ */
+
+int
+irc_cmd_recv_319 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_channel, *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_channel = strchr (pos_nick, ' ');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ if (pos_channel[0] == ':')
+ pos_channel++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, _("Channels: "));
+
+ while (pos_channel && pos_channel[0])
+ {
+ if (pos_channel[0] == '@')
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_NICK_OP, "@");
+ pos_channel++;
+ }
+ else
+ {
+ if (pos_channel[0] == '%')
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_NICK_HALFOP, "%");
+ pos_channel++;
+ }
+ else
+ if (pos_channel[0] == '+')
+ {
+ gui_printf_color (server->window,
+ COLOR_WIN_NICK_VOICE, "+");
+ pos_channel++;
+ }
+ }
+ pos = strchr (pos_channel, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s%s",
+ pos_channel,
+ (pos && pos[0]) ? " " : "\n");
+ pos_channel = pos;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_320: '320' command (whois, identified user)
+ */
+
+int
+irc_cmd_recv_320 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (server->window,
+ COLOR_WIN_CHAT, "%s\n", pos_message);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_321: '321' command (/list start)
+ */
+
+int
+irc_cmd_recv_321 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_322: '322' command (channel for /list)
+ */
+
+int
+irc_cmd_recv_322 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_323: '323' command (/list end)
+ */
+
+int
+irc_cmd_recv_323 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server->window, PREFIX_INFO);
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_331: '331' command received (no topic for channel)
+ */
+
+int
+irc_cmd_recv_331 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, _("No topic set for "));
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_CHANNEL, "%s\n", arguments);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_332: '332' command received (topic of channel)
+ */
+
+int
+irc_cmd_recv_332 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ t_irc_channel *ptr_channel;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ ptr_channel = channel_search (server, pos);
+ if (ptr_channel)
+ {
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (pos2[0] == ':')
+ pos2++;
+ if (ptr_channel->topic)
+ free (ptr_channel->topic);
+ ptr_channel->topic = strdup (pos2);
+
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _("Topic for "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL, "%s", pos);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _(" is: \"%s\"\n"), pos2);
+
+ gui_redraw_window_title (ptr_channel->window);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"332\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify channel for \"332\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_333: '333' command received (infos about topic (nick / date)
+ */
+
+int
+irc_cmd_recv_333 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos_channel, *pos_nick, *pos_date;
+ t_irc_channel *ptr_channel;
+ time_t datetime;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ pos_nick = strchr (pos_channel, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_date = strchr (pos_nick, ' ');
+ if (pos_date)
+ {
+ pos_date[0] = '\0';
+ pos_date++;
+ while (pos_date[0] == ' ')
+ pos_date++;
+
+ ptr_channel = channel_search (server, pos_channel);
+ if (ptr_channel)
+ {
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _("Topic set by "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_NICK, "%s", pos_nick);
+ datetime = (time_t)(atol (pos_date));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, ", %s", ctime (&datetime));
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s channel not found for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify date/time for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify nickname for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot identify channel for \"333\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_351: '351' command received (server version)
+ */
+
+int
+irc_cmd_recv_351 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+
+ /* make gcc happy */
+ (void) server;
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ pos2 = strstr (pos, " :");
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2 += 2;
+ }
+
+ irc_display_prefix (server->window, PREFIX_SERVER);
+ if (pos2)
+ gui_printf (server->window, "%s %s\n", pos, pos2);
+ else
+ gui_printf (server->window, "%s\n", pos);
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_353: '353' command received (list of users on a channel)
+ */
+
+int
+irc_cmd_recv_353 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos_nick;
+ int is_op, is_halfop, has_voice;
+ t_irc_channel *ptr_channel;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strstr (arguments, " = ");
+ if (pos)
+ arguments = pos + 3;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+
+ ptr_channel = channel_search (server, arguments);
+ if (!ptr_channel)
+ return 0;
+
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] != ':')
+ {
+ gui_printf (server->window,
+ _("%s cannot parse \"353\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ pos++;
+ if (pos[0])
+ {
+ while (pos && pos[0])
+ {
+ is_op = 0;
+ is_halfop = 0;
+ has_voice = 0;
+ while ((pos[0] == '@') || (pos[0] == '%') || (pos[0] == '+'))
+ {
+ if (pos[0] == '@')
+ is_op = 1;
+ if (pos[0] == '%')
+ is_halfop = 1;
+ if (pos[0] == '+')
+ has_voice = 1;
+ pos++;
+ }
+ pos_nick = pos;
+ pos = strchr (pos, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ }
+ if (!nick_new (ptr_channel, pos_nick, is_op, is_halfop, has_voice))
+ gui_printf (server->window,
+ _("%s cannot create nick \"%s\" for channel \"%s\"\n"),
+ WEECHAT_ERROR, pos_nick, ptr_channel->name);
+ }
+ }
+ gui_redraw_window_nick (ptr_channel->window);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _("%s cannot parse \"353\" command\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_366: '366' command received (end of /names list)
+ */
+
+int
+irc_cmd_recv_366 (t_irc_server *server, char *host, char *arguments)
+{
+ char *pos, *pos2;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ int num_nicks, num_op, num_halfop, num_voice, num_normal;
+
+ /* make gcc happy */
+ (void) host;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (pos2[0] == ':')
+ pos2++;
+
+ ptr_channel = channel_search (server, pos);
+ if (ptr_channel)
+ {
+
+ /* display users on channel */
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT,
+ _("Nicks "));
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_CHANNEL,
+ "%s", ptr_channel->name);
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT, ": ");
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "[");
+
+ for (ptr_nick = ptr_channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ irc_display_nick (ptr_channel->window, ptr_nick,
+ MSG_TYPE_INFO, 0, 0, 1);
+ if (ptr_nick != ptr_channel->last_nick)
+ gui_printf (ptr_channel->window, " ");
+ }
+ gui_printf_color (ptr_channel->window, COLOR_WIN_CHAT_DARK, "]\n");
+
+ /* display number of nicks, ops, halfops & voices on the channel */
+ nick_count (ptr_channel, &num_nicks, &num_op, &num_halfop, &num_voice,
+ &num_normal);
+ irc_display_prefix (ptr_channel->window, PREFIX_INFO);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, _("Channel "));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%s", ptr_channel->name);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT, ": ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_nicks);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_nicks > 1) ? _("nicks") : _("nick"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, " (");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_op);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_op > 1) ? _("ops") : _("op"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_halfop);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_halfop > 1) ? _("halfops") : _("halfop"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_voice);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ (num_voice > 1) ? _("voices") : _("voice"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ ", ");
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_CHANNEL,
+ "%d ", num_normal);
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT,
+ _("normal"));
+ gui_printf_color (ptr_channel->window,
+ COLOR_WIN_CHAT_DARK, ")\n");
+ }
+ else
+ {
+ irc_display_prefix (gui_current_window, PREFIX_INFO);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT_CHANNEL, pos);
+ gui_printf_color (gui_current_window,
+ COLOR_WIN_CHAT, ": %s\n", pos2);
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_recv_433: '433' command received (nickname already in use)
+ */
+
+int
+irc_cmd_recv_433 (t_irc_server *server, char *host, char *arguments)
+{
+ char hostname[128];
+
+ if (!server->is_connected)
+ {
+ if (strcmp (server->nick, server->nick1) == 0)
+ {
+ gui_printf (server->window,
+ _(WEECHAT_NAME
+ ": nickname \"%s\" is already in use, "
+ "trying 2nd nickname \"%s\"\n"),
+ server->nick, server->nick2);
+ free (server->nick);
+ server->nick = strdup (server->nick2);
+ }
+ else
+ {
+ if (strcmp (server->nick, server->nick2) == 0)
+ {
+ gui_printf (server->window,
+ _(WEECHAT_NAME
+ ": nickname \"%s\" is already in use, "
+ "trying 3rd nickname \"%s\"\n"),
+ server->nick, server->nick3);
+ free (server->nick);
+ server->nick = strdup (server->nick3);
+ }
+ else
+ {
+ gui_printf (server->window,
+ _(WEECHAT_NAME
+ ": all declared nicknames are already in use, "
+ "closing connection with server!\n"));
+ server_disconnect (server);
+ return 0;
+ }
+ }
+
+ gethostname (hostname, sizeof (hostname) - 1);
+ hostname[sizeof (hostname) - 1] = '\0';
+ if (!hostname[0])
+ strcpy (hostname, _("unknown"));
+ server_sendf (server,
+ "NICK %s\r\n",
+ server->nick);
+ }
+ else
+ return irc_cmd_recv_error (server, host, arguments);
+ return 0;
+}
diff --git a/weechat/src/irc/irc-display.c b/weechat/src/irc/irc-display.c
new file mode 100644
index 000000000..2f2f9931b
--- /dev/null
+++ b/weechat/src/irc/irc-display.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-display.c: display functions for IRC */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../weechat.h"
+#include "irc.h"
+#include "../config.h"
+#include "../gui/gui.h"
+
+
+/*
+ * irc_display_prefix: display prefix for action or info message
+ * prefix must be 3 chars length
+ */
+
+void
+irc_display_prefix (t_gui_window *window, char *prefix)
+{
+ if (prefix[0] == prefix[2])
+ {
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c", prefix[0]);
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX2, "%c", prefix[1]);
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%c ", prefix[2]);
+ }
+ else
+ gui_printf_color (window, COLOR_WIN_CHAT_PREFIX1, "%s ", prefix);
+}
+
+/*
+ * irc_display_nick: display nick in chat window
+ */
+
+void
+irc_display_nick (t_gui_window *window, t_irc_nick *nick, int message_type,
+ int display_around, int color_nick, int no_nickmode)
+{
+ if (display_around)
+ gui_printf_color_type (window,
+ message_type, COLOR_WIN_CHAT_DARK, "<");
+ if (cfg_look_nickmode)
+ {
+ if (nick->is_op)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_NICK_OP, "@");
+ else
+ {
+ if (nick->is_halfop)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_NICK_HALFOP, "%%");
+ else
+ {
+ if (nick->has_voice)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_NICK_VOICE, "+");
+ else
+ if (cfg_look_nickmode_empty && !no_nickmode)
+ gui_printf_color_type (window,
+ message_type,
+ COLOR_WIN_CHAT, " ");
+ }
+ }
+ }
+ gui_printf_color_type (window,
+ message_type,
+ (color_nick) ?
+ ((cfg_look_color_nicks) ?
+ nick->color : COLOR_WIN_CHAT) :
+ COLOR_WIN_CHAT,
+ "%s", nick->nick);
+
+ if (display_around)
+ gui_printf_color_type (window,
+ message_type, COLOR_WIN_CHAT_DARK, "> ");
+}
+
+/*
+ * irc_display_mode: display IRC message for mode change
+ */
+
+void
+irc_display_mode (t_gui_window *window, char *channel_name, char set_flag,
+ char *symbol, char *nick_host, char *message, char *param)
+{
+ irc_display_prefix (window, PREFIX_INFO);
+ gui_printf_color (window, COLOR_WIN_CHAT_DARK, "[");
+ gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%s", channel_name);
+ gui_printf_color (window, COLOR_WIN_CHAT, "/");
+ gui_printf_color (window, COLOR_WIN_CHAT_CHANNEL, "%c%s", set_flag, symbol);
+ gui_printf_color (window, COLOR_WIN_CHAT_DARK, "] ");
+ gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s", nick_host);
+ if (param)
+ {
+ gui_printf_color (window, COLOR_WIN_CHAT, " %s ", message);
+ gui_printf_color (window, COLOR_WIN_CHAT_NICK, "%s\n", param);
+ }
+ else
+ gui_printf_color (window, COLOR_WIN_CHAT, " %s\n", message);
+}
diff --git a/weechat/src/irc/irc-nick.c b/weechat/src/irc/irc-nick.c
new file mode 100644
index 000000000..1f9faf3b3
--- /dev/null
+++ b/weechat/src/irc/irc-nick.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-nick.c: manages nick list for channels */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "../weechat.h"
+#include "irc.h"
+
+
+/*
+ * nick_find_color: find a color for a nick (less used will be better!)
+ */
+
+int
+nick_find_color (t_irc_channel *channel)
+{
+ int i, color_less_used, min_used;
+ int count_used[COLOR_WIN_NICK_NUMBER];
+ t_irc_nick *ptr_nick;
+
+ /* initialize array for counting usage of color */
+ for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++)
+ count_used[i] = 0;
+
+ /* summarize each color usage */
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ count_used[ptr_nick->color - COLOR_WIN_NICK_FIRST]++;
+
+ /* look for color less used on channel */
+ color_less_used = -1;
+ min_used = INT_MAX;
+ for (i = 0; i < COLOR_WIN_NICK_NUMBER; i++)
+ {
+ if (count_used[i] < min_used)
+ {
+ color_less_used = i;
+ min_used = count_used[i];
+ }
+ }
+
+ return (color_less_used < 0) ?
+ COLOR_WIN_NICK_FIRST : COLOR_WIN_NICK_FIRST + color_less_used;
+}
+
+/*
+ * nick_compare: compare two nicks
+ * return: -1 is nick1 < nick2
+ * 0 if nick1 = nick2
+ * +1 if nick1 > nick2
+ * status sort: operator > voice > normal nick
+ */
+
+int
+nick_compare (t_irc_nick *nick1, t_irc_nick *nick2)
+{
+ int score1, score2, comp;
+
+ score1 = - ( (nick1->is_op * 3) + (nick1->is_halfop * 2) + nick1->has_voice );
+ score2 = - ( (nick2->is_op * 3) + (nick2->is_halfop * 2) + nick2->has_voice );
+
+ comp = strcasecmp(nick1->nick, nick2->nick);
+ if (comp > 0)
+ score1++;
+ else
+ if (comp < 0)
+ score2++;
+
+ /* nick1 > nick2 */
+ if (score1 > score2)
+ return 1;
+ /* nick1 < nick2 */
+ if (score1 < score2)
+ return -1;
+ /* nick1 == nick2 */
+ return 0;
+}
+
+/*
+ * nick_find_pos: find position for a nick (for sorting nick list)
+ */
+
+t_irc_nick *
+nick_find_pos (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *ptr_nick;
+
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ if (nick_compare (nick, ptr_nick) < 0)
+ return ptr_nick;
+ }
+ return NULL;
+}
+
+/*
+ * nick_insert_sorted: insert nick into sorted list
+ */
+
+void
+nick_insert_sorted (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *pos_nick;
+
+ if (channel->nicks)
+ {
+ pos_nick = nick_find_pos (channel, nick);
+
+ if (pos_nick)
+ {
+ /* insert nick into the list (before nick found) */
+ nick->prev_nick = pos_nick->prev_nick;
+ nick->next_nick = pos_nick;
+ if (pos_nick->prev_nick)
+ pos_nick->prev_nick->next_nick = nick;
+ else
+ channel->nicks = nick;
+ pos_nick->prev_nick = nick;
+ }
+ else
+ {
+ /* add nick to the end */
+ nick->prev_nick = channel->last_nick;
+ nick->next_nick = NULL;
+ channel->last_nick->next_nick = nick;
+ channel->last_nick = nick;
+ }
+ }
+ else
+ {
+ nick->prev_nick = NULL;
+ nick->next_nick = NULL;
+ channel->nicks = nick;
+ channel->last_nick = nick;
+ }
+}
+
+/*
+ * nick_new: allocate a new nick for a channel and add it to the nick list
+ */
+
+t_irc_nick *
+nick_new (t_irc_channel *channel, char *nick_name,
+ int is_op, int is_halfop, int has_voice)
+{
+ t_irc_nick *new_nick;
+
+ /* nick already exists on this channel? */
+ if ((new_nick = nick_search (channel, nick_name)))
+ {
+ /* update nick */
+ new_nick->is_op = is_op;
+ new_nick->is_halfop = is_halfop;
+ new_nick->has_voice = has_voice;
+ return new_nick;
+ }
+
+ /* alloc memory for new nick */
+ if ((new_nick = (t_irc_nick *) malloc (sizeof (t_irc_nick))) == NULL)
+ {
+ gui_printf (channel->window,
+ _("%s cannot allocate new nick\n"), WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new nick */
+ new_nick->nick = strdup (nick_name);
+ new_nick->is_op = is_op;
+ new_nick->is_halfop = is_halfop;
+ new_nick->has_voice = has_voice;
+ if (strcasecmp (new_nick->nick, SERVER(channel->window)->nick) == 0)
+ new_nick->color = COLOR_WIN_NICK_SELF;
+ else
+ new_nick->color = nick_find_color (channel);
+
+ nick_insert_sorted (channel, new_nick);
+
+ /* all is ok, return address of new nick */
+ return new_nick;
+}
+
+/*
+ * nick_resort: resort nick in the list
+ */
+
+void
+nick_resort (t_irc_channel *channel, t_irc_nick *nick)
+{
+ /* temporarly remove nick from list */
+ if (nick == channel->nicks)
+ channel->nicks = nick->next_nick;
+ else
+ nick->prev_nick->next_nick = nick->next_nick;
+ if (nick->next_nick)
+ nick->next_nick->prev_nick = nick->prev_nick;
+ if (nick == channel->last_nick)
+ channel->last_nick = nick->prev_nick;
+
+ /* insert again nick into sorted list */
+ nick_insert_sorted (channel, nick);
+}
+
+/*
+ * nick_change: change nickname and move it if necessary (list is sorted)
+ */
+
+void
+nick_change (t_irc_channel *channel, t_irc_nick *nick, char *new_nick)
+{
+ /* change nickname */
+ if (nick->nick)
+ free (nick->nick);
+ nick->nick = strdup (new_nick);
+
+ /* insert again nick into sorted list */
+ nick_resort (channel, nick);
+}
+
+/*
+ * nick_free: free a nick and remove it from nicks queue
+ */
+
+void
+nick_free (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *new_nicks;
+
+ /* remove nick from queue */
+ if (channel->last_nick == nick)
+ channel->last_nick = nick->prev_nick;
+ if (nick->prev_nick)
+ {
+ (nick->prev_nick)->next_nick = nick->next_nick;
+ new_nicks = channel->nicks;
+ }
+ else
+ new_nicks = nick->next_nick;
+
+ if (nick->next_nick)
+ (nick->next_nick)->prev_nick = nick->prev_nick;
+
+ /* free data */
+ if (nick->nick)
+ free (nick->nick);
+ free (nick);
+ channel->nicks = new_nicks;
+}
+
+/*
+ * nick_free_all: free all allocated nicks for a channel
+ */
+
+void
+nick_free_all (t_irc_channel *channel)
+{
+ /* remove all nicks for the channel */
+ while (channel->nicks)
+ nick_free (channel, channel->nicks);
+}
+
+/*
+ * nick_search: returns pointer on a nick
+ */
+
+t_irc_nick *
+nick_search (t_irc_channel *channel, char *nickname)
+{
+ t_irc_nick *ptr_nick;
+
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ if (strcasecmp (ptr_nick->nick, nickname) == 0)
+ return ptr_nick;
+ }
+ return NULL;
+}
+
+/*
+ * nick_count: returns number of nicks (total, op, halfop, voice) on a channel
+ */
+
+void
+nick_count (t_irc_channel *channel, int *total, int *count_op,
+ int *count_halfop, int *count_voice, int *count_normal)
+{
+ t_irc_nick *ptr_nick;
+
+ (*total) = 0;
+ (*count_op) = 0;
+ (*count_halfop) = 0;
+ (*count_voice) = 0;
+ (*count_normal) = 0;
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ (*total)++;
+ if (ptr_nick->is_op)
+ (*count_op)++;
+ else
+ {
+ if (ptr_nick->is_halfop)
+ (*count_halfop)++;
+ else
+ {
+ if (ptr_nick->has_voice)
+ (*count_voice)++;
+ else
+ (*count_normal)++;
+ }
+ }
+ }
+}
+
+/*
+ * nick_get_max_length: returns longer nickname on a channel
+ */
+
+int
+nick_get_max_length (t_irc_channel *channel)
+{
+ int length, max_length;
+ t_irc_nick *ptr_nick;
+
+ max_length = 0;
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ length = strlen (ptr_nick->nick);
+ if (length > max_length)
+ max_length = length;
+ }
+ return max_length;
+}
diff --git a/weechat/src/irc/irc-server.c b/weechat/src/irc/irc-server.c
new file mode 100644
index 000000000..b8bacc303
--- /dev/null
+++ b/weechat/src/irc/irc-server.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* irc-server.c: (dis)connection and communication with irc server */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "../weechat.h"
+#include "irc.h"
+#include "../gui/gui.h"
+
+
+t_irc_server *irc_servers = NULL;
+t_irc_server *last_irc_server = NULL;
+t_irc_server *current_irc_server = NULL;
+
+t_irc_message *recv_msgq, *msgq_last_msg;
+
+/* buffer containing beginning of message if not ending with \r\n */
+char *unterminated_message = NULL;
+
+
+/*
+ * server_alloc: allocate a new server and add it to the servers queue
+ */
+
+t_irc_server *
+server_alloc ()
+{
+ t_irc_server *new_server;
+
+ #if DEBUG >= 1
+ log_printf ("allocating new server\n");
+ #endif
+
+ /* alloc memory for new server */
+ if ((new_server = (t_irc_server *) malloc (sizeof (t_irc_server))) == NULL)
+ {
+ fprintf (stderr, _("%s cannot allocate new server"), WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new server */
+ new_server->name = NULL;
+ new_server->address = NULL;
+ new_server->password = NULL;
+ new_server->nick1 = NULL;
+ new_server->nick2 = NULL;
+ new_server->nick3 = NULL;
+ new_server->username = NULL;
+ new_server->realname = NULL;
+ new_server->nick = NULL;
+ new_server->is_connected = 0;
+ new_server->sock4 = -1;
+ new_server->is_away = 0;
+ new_server->server_read = -1;
+ new_server->server_write = -1;
+ new_server->window = NULL;
+ new_server->channels = NULL;
+ new_server->last_channel = NULL;
+
+ /* add new server to queue */
+ new_server->prev_server = last_irc_server;
+ new_server->next_server = NULL;
+ if (irc_servers)
+ last_irc_server->next_server = new_server;
+ else
+ irc_servers = new_server;
+ last_irc_server = new_server;
+
+ /* all is ok, return address of new server */
+ return new_server;
+}
+
+/*
+ * server_create_window: create windows for a server
+ */
+
+void
+server_create_window (t_irc_server *server)
+{
+ if (!SERVER(gui_windows))
+ {
+ server->window = gui_windows;
+ SERVER(gui_windows) = server;
+ }
+ else
+ gui_window_new (server, NULL);
+}
+
+/*
+ * server_free: free a server and remove it from servers queue
+ */
+
+void
+server_free (t_irc_server *server)
+{
+ t_irc_server *new_irc_servers;
+
+ /* remove server from queue */
+ if (server->prev_server)
+ {
+ (server->prev_server)->next_server = server->next_server;
+ new_irc_servers = irc_servers;
+ }
+ else
+ new_irc_servers = server->next_server;
+
+ if (server->next_server)
+ (server->next_server)->prev_server = server->prev_server;
+
+ /* free data */
+ if (server->name)
+ free (server->name);
+ if (server->address)
+ free (server->address);
+ if (server->password)
+ free (server->password);
+ if (server->nick1)
+ free (server->nick1);
+ if (server->nick2)
+ free (server->nick2);
+ if (server->nick3)
+ free (server->nick3);
+ if (server->username)
+ free (server->username);
+ if (server->realname)
+ free (server->realname);
+ if (server->nick)
+ free (server->nick);
+ if (server->channels)
+ channel_free_all (server);
+ /* TODO: free weechat window (???) */
+ /* (...) */
+ free (server);
+ irc_servers = new_irc_servers;
+}
+
+/*
+ * server_free_all: free all allocated servers
+ */
+
+void
+server_free_all ()
+{
+ /* for each server in memory, remove it */
+ while (irc_servers)
+ server_free (irc_servers);
+}
+
+/*
+ * server_new: creates a new server, and initialize it
+ */
+
+t_irc_server *
+server_new (char *name, char *address, int port, char *password,
+ char *nick1, char *nick2, char *nick3,
+ char *username, char *realname)
+{
+ t_irc_server *new_server;
+
+ if (!name || !address || (port < 0) || !nick1 || !nick2 || !nick3
+ || !username || !realname)
+ return NULL;
+
+ #if DEBUG >= 1
+ log_printf ("creating new server (name:%s, address:%s, port:%d, pwd:%s, "
+ "nick1:%s, nick2:%s, nick3:%s, username:%s, realname:%s)\n",
+ name, address, port, password, nick1, nick2, nick3,
+ username, realname);
+ #endif
+
+ if ((new_server = server_alloc ()))
+ {
+ new_server->name = strdup (name);
+ new_server->address = strdup (address);
+ new_server->port = port;
+ new_server->password = (password) ? strdup (password) : strdup ("");
+ new_server->nick1 = (nick1) ? strdup (nick1) : strdup ("weechat_user");
+ new_server->nick2 = (nick2) ? strdup (nick2) : strdup ("weechat2");
+ new_server->nick3 = (nick3) ? strdup (nick3) : strdup ("weechat3");
+ new_server->username =
+ (username) ? strdup (username) : strdup ("weechat");
+ new_server->realname =
+ (realname) ? strdup (realname) : strdup ("realname");
+ new_server->nick = strdup (new_server->nick1);
+ }
+ else
+ return NULL;
+ return new_server;
+}
+
+/*
+ * server_send: send data to irc server
+ */
+
+int
+server_send (t_irc_server * server, char *buffer, int size_buf)
+{
+ if (!server)
+ return -1;
+
+ return send (server->sock4, buffer, size_buf, 0);
+}
+
+/*
+ * server_sendf: send formatted data to irc server
+ */
+
+int
+server_sendf (t_irc_server * server, char *fmt, ...)
+{
+ va_list args;
+ static char buffer[1024];
+ int size_buf;
+
+ if (!server)
+ return -1;
+
+ va_start (args, fmt);
+ size_buf = vsnprintf (buffer, sizeof (buffer) - 1, fmt, args);
+ va_end (args);
+
+ if ((size_buf == 0) || (strcmp (buffer, "\r\n") == 0))
+ return 0;
+
+ buffer[sizeof (buffer) - 1] = '\0';
+ if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1)))
+ size_buf = strlen (buffer);
+ buffer[size_buf - 2] = '\0';
+ #if DEBUG >= 2
+ gui_printf (server->window, "[DEBUG] Sending to server >>> %s\n", buffer);
+ #endif
+ buffer[size_buf - 2] = '\r';
+ return server_send (server, buffer, size_buf);
+}
+
+/*
+ * server_msgq_add_msg: add a message to received messages queue (at the end)
+ */
+
+void
+server_msgq_add_msg (t_irc_server * server, char *msg)
+{
+ t_irc_message *message;
+
+ message = (t_irc_message *) malloc (sizeof (t_irc_message));
+ message->server = server;
+ if (unterminated_message)
+ {
+ message->data = (char *) malloc (strlen (unterminated_message) +
+ strlen (msg) + 1);
+ strcpy (message->data, unterminated_message);
+ strcat (message->data, msg);
+ free (unterminated_message);
+ unterminated_message = NULL;
+ }
+ else
+ message->data = strdup (msg);
+ message->next_message = NULL;
+
+ if (msgq_last_msg)
+ {
+ msgq_last_msg->next_message = message;
+ msgq_last_msg = message;
+ }
+ else
+ {
+ recv_msgq = message;
+ msgq_last_msg = message;
+ }
+}
+
+/*
+ * server_msgq_add_buffer: explode received buffer, creating queued messages
+ */
+
+void
+server_msgq_add_buffer (t_irc_server * server, char *buffer)
+{
+ char *pos;
+
+ while (buffer[0])
+ {
+ pos = strstr (buffer, "\r\n");
+ if (pos)
+ {
+ pos[0] = '\0';
+ server_msgq_add_msg (server, buffer);
+ buffer = pos + 2;
+ }
+ else
+ {
+ pos = strchr (buffer, '\0');
+ if (pos)
+ {
+ unterminated_message =
+ (char *) realloc (unterminated_message,
+ strlen (buffer) + 1);
+ strcpy (unterminated_message, buffer);
+ return;
+ }
+ gui_printf (server->window,
+ _("%s unable to explode received buffer\n"),
+ WEECHAT_ERROR);
+ }
+ }
+}
+
+/*
+ * server_msgq_flush: flush message queue
+ */
+
+void
+server_msgq_flush ()
+{
+ t_irc_message *next;
+ /*char **argv;
+ int argc;*/
+ char *ptr_data, *pos, *pos2;
+ char *host, *command, *args;
+
+ /* TODO: optimize this function, parse only a few messages (for low CPU time!) */
+ while (recv_msgq)
+ {
+ #if DEBUG >= 2
+ gui_printf (gui_current_window, "[DEBUG] %s\n", recv_msgq->data);
+ #endif
+
+ ptr_data = recv_msgq->data;
+
+ while (ptr_data[0] == ' ')
+ ptr_data++;
+
+ if (ptr_data)
+ {
+ #if DEBUG >= 2
+ gui_printf (NULL, "[DEBUG] data received from server: %s\n", ptr_data);
+ #endif
+
+ host = NULL;
+ command = NULL;
+ args = ptr_data;
+
+ if (ptr_data[0] == ':')
+ {
+ pos = strchr(ptr_data, ' ');
+ pos[0] = '\0';
+ host = ptr_data+1;
+ pos++;
+ }
+ else
+ pos = ptr_data;
+
+ if (pos != NULL)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr(pos, ' ');
+ if (pos2 != NULL)
+ {
+ pos2[0] = '\0';
+ command = strdup(pos);
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ args = (pos2[0] == ':') ? pos2+1 : pos2;
+ }
+ }
+
+ switch (irc_recv_command (recv_msgq->server, host, command, args))
+ {
+ case -1:
+ gui_printf (recv_msgq->server->window,
+ _("Command '%s' failed!\n"), command);
+ break;
+ case -2:
+ gui_printf (recv_msgq->server->window,
+ _("No command to execute!\n"));
+ break;
+ case -3:
+ gui_printf (recv_msgq->server->window,
+ _("Unknown command: cmd=%s, args=%s\n"),
+ command, args);
+ break;
+ }
+ }
+
+ free (recv_msgq->data);
+ next = recv_msgq->next_message;
+ free (recv_msgq);
+ recv_msgq = next;
+ if (recv_msgq == NULL)
+ msgq_last_msg = NULL;
+ }
+}
+
+/*
+ * server_recv: receive data from an irc server
+ */
+
+void
+server_recv (t_irc_server *server)
+{
+ static char buffer[4096 + 2];
+ int num_read;
+
+ num_read = recv (server->sock4, buffer, sizeof (buffer) - 2, 0);
+ if (num_read > 0)
+ {
+ buffer[num_read] = '\0';
+ server_msgq_add_buffer (server, buffer);
+ server_msgq_flush ();
+ }
+}
+
+/*
+ * server_connect: connect to an irc server
+ */
+
+int
+server_connect (t_irc_server *server)
+{
+ int set;
+ struct hostent *ip4_hostent;
+ struct sockaddr_in addr;
+ char *ip_address;
+ int error;
+ int server_pipe[2];
+
+ gui_printf (server->window,
+ _(WEECHAT_NAME ": connecting to %s:%d...\n"),
+ server->address, server->port);
+ log_printf ("connecting to server %s:%d...\n",
+ server->address, server->port);
+ server->is_connected = 0;
+
+ /* create pipe */
+ if (pipe (server_pipe) < 0)
+ {
+ gui_printf (server->window,
+ _("%s cannot create pipe\n"), WEECHAT_ERROR);
+ server_free (server);
+ return 0;
+ }
+ server->server_read = server_pipe[0];
+ server->server_write = server_pipe[1];
+
+ /* create socket and set options */
+ server->sock4 = socket (AF_INET, SOCK_STREAM, 0);
+ set = 1;
+ if (setsockopt
+ (server->sock4, SOL_SOCKET, SO_REUSEADDR, (char *) &set,
+ sizeof (set)) == -1)
+ gui_printf (server->window,
+ _("%s cannot set socket option 'SO_REUSEADDR'\n"),
+ WEECHAT_ERROR);
+ set = 1;
+ if (setsockopt
+ (server->sock4, SOL_SOCKET, SO_KEEPALIVE, (char *) &set,
+ sizeof (set)) == -1)
+ gui_printf (server->window,
+ _("%s cannot set socket option \"SO_KEEPALIVE\"\n"),
+ WEECHAT_ERROR);
+
+ /* bind to hostname */
+ ip4_hostent = gethostbyname (server->address);
+ if (!ip4_hostent)
+ {
+ gui_printf (server->window,
+ _("%s address \"%s\" not found\n"),
+ WEECHAT_ERROR, server->address);
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->sock4 = -1;
+ return 0;
+ }
+ memset (&addr, 0, sizeof (addr));
+ memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length);
+ addr.sin_port = htons (server->port);
+ addr.sin_family = AF_INET;
+ /*error = bind(server->sock4, (struct sockaddr *)(&addr), sizeof(addr));
+ if (error != 0)
+ {
+ gui_printf (server->window,
+ WEECHAT_ERORR "server_connect: can't bind to hostname\n");
+ return 0;
+ } */
+ ip_address = inet_ntoa (addr.sin_addr);
+ if (!ip_address)
+ {
+ gui_printf (server->window,
+ _("%s IP address not found\n"), WEECHAT_ERROR);
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->sock4 = -1;
+ return 0;
+ }
+
+ /* connection to server */
+ gui_printf (server->window,
+ _(WEECHAT_NAME ": server IP is: %s\n"), ip_address);
+
+ error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr));
+ if (error != 0)
+ {
+ gui_printf (server->window,
+ _("%s cannot connect to irc server\n"), WEECHAT_ERROR);
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->sock4 = -1;
+ return 0;
+ }
+
+ current_irc_server = server;
+ return 1;
+}
+
+/*
+ * server_disconnect: disconnect from an irc server
+ */
+
+void
+server_disconnect (t_irc_server *server)
+{
+ if (server->is_connected)
+ {
+ close (server->server_read);
+ close (server->server_write);
+ close (server->sock4);
+ server->is_connected = 0;
+ }
+}
+
+/*
+ * server_disconnect_all: disconnect from all irc servers
+ */
+
+void
+server_disconnect_all ()
+{
+ t_irc_server *ptr_server;
+
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ server_disconnect (ptr_server);
+}
+
+/*
+ * server_get_number_connected: returns number of connected server
+ */
+
+int
+server_get_number_connected ()
+{
+ t_irc_server *ptr_server;
+ int number;
+
+ number = 0;
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->is_connected)
+ number++;
+ }
+ return number;
+}
+
+/*
+ * server_name_already_exists: return 1 if server name already exists
+ * otherwise return 0
+ */
+
+int
+server_name_already_exists (char *name)
+{
+ t_irc_server *ptr_server;
+
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ {
+ if (strcmp (ptr_server->name, name) == 0)
+ return 1;
+ }
+ return 0;
+}
diff --git a/weechat/src/irc/irc.h b/weechat/src/irc/irc.h
new file mode 100644
index 000000000..f1f3698be
--- /dev/null
+++ b/weechat/src/irc/irc.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_IRC_H
+#define __WEECHAT_IRC_H 1
+
+#include "../gui/gui.h"
+
+#define PREFIX_SERVER "-@-"
+#define PREFIX_INFO "-=-"
+#define PREFIX_ACTION_ME "-*-"
+#define PREFIX_JOIN "-->"
+#define PREFIX_PART "<--"
+#define PREFIX_QUIT "<--"
+#define PREFIX_ERROR "=!="
+
+#define CHANNEL_PREFIX "#&+!"
+
+/* nick types */
+
+typedef struct t_irc_nick t_irc_nick;
+
+struct t_irc_nick
+{
+ char *nick; /* nickname */
+ int is_op; /* operator privileges? */
+ int is_halfop; /* half operaor privileges? */
+ int has_voice; /* nick has voice? */
+ int color; /* color for nickname */
+ t_irc_nick *prev_nick; /* link to previous nick on the channel */
+ t_irc_nick *next_nick; /* link to next nick on the channel */
+};
+
+/* channel types */
+
+typedef struct t_irc_channel t_irc_channel;
+
+#define CHAT_UNKNOWN -1
+#define CHAT_CHANNEL 0
+#define CHAT_PRIVATE 1
+
+struct t_irc_channel
+{
+ int type; /* channel type */
+ char *name; /* name of channel (exemple: "#abc") */
+ char *topic; /* topic of channel (host for private) */
+ t_irc_nick *nicks; /* nicks on the channel */
+ t_irc_nick *last_nick; /* last nick on the channel */
+ t_gui_window *window; /* GUI window allocated for channel */
+ t_irc_channel *prev_channel; /* link to previous channel */
+ t_irc_channel *next_channel; /* link to next channel */
+};
+
+/* server types */
+
+typedef struct t_irc_server t_irc_server;
+
+struct t_irc_server
+{
+ /* user choices */
+ char *name; /* name of server (only for display) */
+ char *address; /* address of server (IP or name) */
+ int port; /* port for server (6667 by default) */
+ char *password; /* password for server */
+ char *nick1; /* first nickname for the server */
+ char *nick2; /* alternate nickname */
+ char *nick3; /* 2nd alternate nickname */
+ char *username; /* user name */
+ char *realname; /* real name */
+
+ /* internal vars */
+ char *nick; /* current nickname */
+ int is_connected; /* 1 if WeeChat is connected to server */
+ int sock4; /* socket for server */
+ int is_away; /* 1 is user is marker as away */
+ int server_read; /* pipe for reading server data */
+ int server_write; /* pipe for sending data to server */
+ t_gui_window *window; /* GUI window allocated for server */
+ t_irc_channel *channels; /* opened channels on server */
+ t_irc_channel *last_channel; /* last opened channal on server */
+ t_irc_server *prev_server; /* link to previous server */
+ t_irc_server *next_server; /* link to next server */
+};
+
+/* irc commands */
+
+typedef struct t_irc_command t_irc_command;
+
+struct t_irc_command
+{
+ char *command_name; /* command name (internal or IRC cmd) */
+ char *command_description; /* command description */
+ char *arguments; /* command parameters */
+ char *arguments_description; /* parameters description */
+ int min_arg, max_arg; /* min & max number of parameters */
+ int need_connection; /* = 1 if cmd needs server connection */
+ int (*cmd_function_args)(t_irc_server *, int, char **);
+ /* function called when user enters cmd */
+ int (*cmd_function_1arg)(t_irc_server *, char *);
+ /* function called when user enters cmd */
+ int (*recv_function)(t_irc_server *, char *, char *);
+ /* function called when cmd is received */
+};
+
+typedef struct t_irc_message t_irc_message;
+
+struct t_irc_message
+{
+ t_irc_server *server; /* server pointer for received msg */
+ char *data; /* message content */
+ t_irc_message *next_message; /* link to next message */
+};
+
+extern t_irc_command irc_commands[];
+extern t_irc_server *irc_servers, *current_irc_server;
+extern t_irc_message *recv_msgq, *msgq_last_msg;
+extern t_irc_channel *current_channel;
+
+/* server functions (irc-server.c) */
+
+extern t_irc_server *server_alloc ();
+extern void server_create_window (t_irc_server *);
+extern void server_free (t_irc_server *);
+extern void server_free_all ();
+extern t_irc_server *server_new (char *, char *, int, char *, char *, char *,
+ char *, char *, char *);
+extern int server_send (t_irc_server *, char *, int);
+extern int server_sendf (t_irc_server *, char *, ...);
+extern void server_recv (t_irc_server *);
+extern int server_connect ();
+extern void server_disconnect (t_irc_server *);
+extern void server_disconnect_all ();
+extern int server_get_number_connected ();
+extern int server_name_already_exists (char *);
+
+/* channel functions (irc-channel.c) */
+
+extern t_irc_channel *channel_new (t_irc_server *, int, char *);
+extern void channel_free (t_irc_server *, t_irc_channel *);
+extern void channel_free_all (t_irc_server *);
+extern t_irc_channel *channel_search (t_irc_server *, char *);
+extern int string_is_channel (char *);
+
+/* nick functions (irc-nick.c) */
+
+extern t_irc_nick *nick_new (t_irc_channel *, char *, int, int, int);
+extern void nick_resort (t_irc_channel *, t_irc_nick *);
+extern void nick_change (t_irc_channel *, t_irc_nick *, char *);
+extern void nick_free (t_irc_channel *, t_irc_nick *);
+extern void nick_free_all (t_irc_channel *);
+extern t_irc_nick *nick_search (t_irc_channel *, char *);
+extern void nick_count (t_irc_channel *, int *, int *, int *, int *, int *);
+extern int nick_get_max_length (t_irc_channel *);
+
+/* IRC display (irc-diplay.c) */
+
+extern void irc_display_prefix (t_gui_window *, char *);
+extern void irc_display_nick (t_gui_window *, t_irc_nick *, int, int, int, int);
+extern void irc_display_mode (t_gui_window *, char *, char, char *, char *,
+ char *, char *);
+
+/* IRC protocol (irc-commands.c) */
+
+extern int irc_recv_command (t_irc_server *, char *, char *, char *);
+extern void irc_login (t_irc_server *);
+/* IRC commands issued by user */
+extern int irc_cmd_send_away (t_irc_server *, char *);
+extern int irc_cmd_send_ctcp (t_irc_server *, char *);
+extern int irc_cmd_send_deop (t_irc_server *, int, char **);
+extern int irc_cmd_send_devoice (t_irc_server *, int, char **);
+extern int irc_cmd_send_invite (t_irc_server *, char *);
+extern int irc_cmd_send_join (t_irc_server *, char *);
+extern int irc_cmd_send_kick (t_irc_server *, char *);
+extern int irc_cmd_send_kill (t_irc_server *, char *);
+extern int irc_cmd_send_list (t_irc_server *, char *);
+extern int irc_cmd_send_me (t_irc_server *, char *);
+extern int irc_cmd_send_mode (t_irc_server *, char *);
+extern int irc_cmd_send_msg (t_irc_server *, char *);
+extern int irc_cmd_send_names (t_irc_server *, char *);
+extern int irc_cmd_send_nick (t_irc_server *, int, char **);
+extern int irc_cmd_send_notice (t_irc_server *, char *);
+extern int irc_cmd_send_op (t_irc_server *, int, char **);
+extern int irc_cmd_send_oper (t_irc_server *, int, char **);
+extern int irc_cmd_send_part (t_irc_server *, char *);
+extern int irc_cmd_send_ping (t_irc_server *, int, char **);
+extern int irc_cmd_send_pong (t_irc_server *, int, char **);
+extern int irc_cmd_send_quit (t_irc_server *, char *);
+extern int irc_cmd_send_quote (t_irc_server *, char *);
+extern int irc_cmd_send_topic (t_irc_server *, char *);
+extern int irc_cmd_send_version (t_irc_server *, char *);
+extern int irc_cmd_send_voice (t_irc_server *, int, char **);
+extern int irc_cmd_send_whois (t_irc_server *, char *);
+/* IRC commands executed when received from server */
+extern int irc_cmd_recv_error (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_join (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_kick (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_mode (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_nick (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_notice (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_part (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_ping (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_privmsg (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_quit (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_server_msg (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_server_reply (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_topic (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_001 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_004 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_301 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_311 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_312 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_313 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_317 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_318 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_319 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_320 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_321 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_322 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_323 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_331 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_332 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_333 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_351 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_353 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_366 (t_irc_server *, char *, char *);
+extern int irc_cmd_recv_433 (t_irc_server *, char *, char *);
+
+#endif /* irc.h */
diff --git a/weechat/src/plugins/README b/weechat/src/plugins/README
new file mode 100644
index 000000000..978e37655
--- /dev/null
+++ b/weechat/src/plugins/README
@@ -0,0 +1,9 @@
+WeeChat - Wee Enhanced Environment for Chat
+===========================================
+
+This is plugins directory for WeeChat.
+In the future, you'll find there interfaces with many famous languages for
+writing extensions to WeeChat:
+- Perl interface,
+- Python interface,
+- Ruby interface.
diff --git a/weechat/src/weechat.c b/weechat/src/weechat.c
new file mode 100644
index 000000000..25f7a34d6
--- /dev/null
+++ b/weechat/src/weechat.c
@@ -0,0 +1,311 @@
+/* ############################################################################
+ * ### ___ __ ______________ _____ ###
+ * ### __ | / /___________ ____/__ /_______ __ /_ ###
+ * ### __ | /| / /_ _ \ _ \ / __ __ \ __ `/ __/ ###
+ * ### __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ ###
+ * ### ____/|__/ \___/\___/\____/ /_/ /_/\__,_/ \__/ ###
+ * ### ###
+ * ### WeeChat - Wee Enhanced Environment for Chat ###
+ * ### Fast & light environment for Chat ###
+ * ### ###
+ * ### By: FlashCode <flashcode@flashtux.org> ###
+ * ### Bounga <bounga@altern.org> ###
+ * ### Xahlexx <xahlexx@tuxisland.org> ###
+ * ### ###
+ * ### http://weechat.flashtux.org ###
+ * ### ###
+ * ############################################################################
+ *
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* weechat.c: core functions for WeeChat */
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "weechat.h"
+#include "config.h"
+#include "command.h"
+#include "irc/irc.h"
+#include "gui/gui.h"
+
+
+/* char *display_name; */
+int quit_weechat; /* = 1 if quit request from user... why ? :'( */
+
+FILE *log_file; /* WeeChat log file (~/.weechat/weechat.log */
+
+
+/*
+ * log_printf: displays a message in WeeChat log (~/.weechat/weechat.log)
+ */
+
+void
+log_printf (char *message, ...)
+{
+ static char buffer[4096];
+ va_list argptr;
+ static time_t seconds;
+ struct tm *date_tmp;
+
+ if (!log_file)
+ return;
+
+ va_start (argptr, message);
+ vsnprintf (buffer, sizeof (buffer) - 1, message, argptr);
+ va_end (argptr);
+
+ seconds = time (NULL);
+ date_tmp = localtime (&seconds);
+ fprintf (log_file, "[%04d-%02d-%02d %02d:%02d:%02d] %s",
+ date_tmp->tm_year + 1900, date_tmp->tm_mon + 1, date_tmp->tm_mday,
+ date_tmp->tm_hour, date_tmp->tm_min, date_tmp->tm_sec,
+ buffer);
+ fflush (log_file);
+}
+
+/*
+ * wee_parse_args: parse command line args
+ */
+
+void
+wee_parse_args (int argc, char *argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if ((strcmp (argv[i], "-h") == 0)
+ || (strcmp (argv[i], "--help") == 0))
+ {
+ printf ("\n%s%s", WEE_USAGE);
+ exit (0);
+ }
+ else if ((strcmp (argv[i], "-l") == 0)
+ || (strcmp (argv[i], "--license") == 0))
+ {
+ printf ("\n%s%s", WEE_LICENSE);
+ exit (0);
+ }
+ /*else if ((strcmp (argv[i], "-d") == 0)
+ || (strcmp (argv[i], "--display") == 0))
+ {
+ if (i == (argc - 1))
+ fprintf (stderr,
+ _("%s no display specified (parameter '%s'), ignored\n"),
+ WEECHAT_WARNING, argv[i]);
+ else
+ {
+ display_name = argv[i + 1];
+ i++;
+ }
+ }*/
+ else if ((strcmp (argv[i], "-v") == 0)
+ || (strcmp (argv[i], "--version") == 0))
+ {
+ printf (WEECHAT_VERSION "\n");
+ exit (0);
+ }
+ else
+ {
+ fprintf (stderr,
+ _("%s unknown parameter '%s', ignored\n"),
+ WEECHAT_WARNING, argv[i]);
+ }
+ }
+}
+
+/*
+ * wee_create_home_dir: create weechat home directory (if not found)
+ */
+
+void
+wee_create_home_dir ()
+{
+ char *weechat_home_dir;
+ int return_code;
+
+ weechat_home_dir =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (weechat_home_dir, "%s/.weechat", getenv ("HOME"));
+ return_code = mkdir (weechat_home_dir, 0755);
+ if (return_code < 0)
+ {
+ if (errno != EEXIST)
+ {
+ fprintf (stderr, _("%s cannot create directory \"%s\"\n"),
+ WEECHAT_ERROR, weechat_home_dir);
+ free (weechat_home_dir);
+ exit (1);
+ }
+ }
+ free (weechat_home_dir);
+}
+
+/*
+ * wee_init_vars: initialize some variables
+ */
+
+void
+wee_init_vars ()
+{
+ /* GUI not yet initialized */
+ gui_ready = 0;
+
+ /* init received messages queue */
+ recv_msgq = NULL;
+ msgq_last_msg = NULL;
+}
+
+/*
+ * wee_init_log: initialize log file
+ */
+
+void
+wee_init_log ()
+{
+ char *filename;
+
+ filename =
+ (char *) malloc ((strlen (getenv ("HOME")) + 64) * sizeof (char));
+ sprintf (filename, "%s/.weechat/" WEECHAT_LOG_NAME, getenv ("HOME"));
+ if ((log_file = fopen (filename, "wt")) == NULL)
+ {
+ free (filename);
+ fprintf (stderr,
+ _("%s unable to create/append to log file (~/.weechat/"
+ WEECHAT_LOG_NAME), WEECHAT_ERROR);
+ }
+ free (filename);
+}
+
+/*
+ * wee_shutdown: shutdown WeeChat
+ */
+
+void
+wee_shutdown ()
+{
+ gui_end ();
+ server_free_all ();
+ if (log_file)
+ fclose (log_file);
+ exit (0);
+}
+
+/*
+ * main: WeeChat startup
+ */
+
+int
+main (int argc, char *argv[])
+{
+ t_irc_server *ptr_server;
+
+ /* initialize variables */
+ wee_init_vars ();
+
+ /* parse command line args */
+ wee_parse_args (argc, argv);
+
+ /* create weechat home directory */
+ wee_create_home_dir ();
+
+ /* init log file */
+ wee_init_log ();
+
+ /* read configuration */
+ switch (config_read ())
+ {
+ case 0: /* success */
+ break;
+ case -1: /* config file not found */
+ config_create_default ();
+ config_read ();
+ break;
+ default: /* other error (fatal) */
+ server_free_all ();
+ return 1;
+ }
+
+ /* init gui */
+ gui_init ();
+
+ /* build commands index (sorted), for completion */
+ index_command_build ();
+
+ /* Welcome message - yeah! */
+ if (cfg_look_startup_logo)
+ {
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1,
+ " ___ __ ______________ _____ \n"
+ " __ | / /___________ ____/__ /_______ __ /_\n"
+ " __ | /| / /_ _ \\ _ \\ / __ __ \\ __ `/ __/\n"
+ " __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ \n"
+ " ____/|__/ \\___/\\___/\\____/ /_/ /_/\\__,_/ \\__/ \n");
+ }
+ if (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0])
+ {
+ gui_printf_color (NULL, COLOR_WIN_CHAT, _("%sWelcome to "),
+ (cfg_look_startup_logo) ? " " : "");
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2, WEECHAT_NAME);
+ gui_printf_color (NULL, COLOR_WIN_CHAT,
+ ", %s\n", cfg_look_weechat_slogan);
+ }
+ if (cfg_look_startup_version)
+ {
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX2,
+ "%s" WEECHAT_NAME_AND_VERSION,
+ (cfg_look_startup_logo) ? " " : "");
+ gui_printf_color (NULL, COLOR_WIN_CHAT,
+ ", %s %s %s\n",
+ _("compiled on"), __DATE__, __TIME__);
+ }
+ if (cfg_look_startup_logo ||
+ (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0]) ||
+ cfg_look_startup_version)
+ gui_printf_color (NULL, COLOR_WIN_CHAT_PREFIX1,
+ "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
+
+ /* connect to all servers */
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ server_create_window (ptr_server);
+ if (server_connect (ptr_server))
+ irc_login (ptr_server);
+ }
+ gui_main_loop ();
+ server_disconnect_all ();
+
+ /* program ending */
+ wee_shutdown ();
+
+ /* make gcc happy (statement never executed) */
+ return 0;
+}
diff --git a/weechat/src/weechat.h b/weechat/src/weechat.h
new file mode 100644
index 000000000..027d4e743
--- /dev/null
+++ b/weechat/src/weechat.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003 by FlashCode <flashcode@flashtux.org>
+ * Bounga <bounga@altern.org>
+ * Xahlexx <xahlexx@tuxisland.org>
+ * See README for License detail.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __WEECHAT_H
+#define __WEECHAT_H 1
+
+#include <stdio.h>
+#include <libintl.h>
+
+#define _(string) gettext(string)
+#define N_(string) (string)
+
+#define WEECHAT_NAME "WeeChat"
+#define WEECHAT_VERSION "0.0.1"
+
+#define WEECHAT_NAME_AND_VERSION WEECHAT_NAME " " WEECHAT_VERSION
+#define WEECHAT_COPYRIGHT WEECHAT_NAME " (c) 2003 by Wee Team"
+#define WEECHAT_WEBSITE "http://weechat.flashtux.org"
+
+#define WEECHAT_ERROR _(WEECHAT_NAME " Error:")
+#define WEECHAT_WARNING _(WEECHAT_NAME " Warning:")
+
+/* debug mode, 0=normal use, 1=some debug msg, 2=full debug (developers only) */
+#define DEBUG 0
+
+/* log file */
+
+#define WEECHAT_LOG_NAME "weechat.log"
+
+/* license */
+
+#define WEE_LICENSE \
+ WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \
+ "Developed by FlashCode <flashcode@flashtux.org>\n" \
+ " Bounga <bounga@altern.org>\n" \
+ " Xahlexx <xahlexx@tuxisland.org>\n\n" \
+ "This program is free software; you can redistribute it and/or modify\n" \
+ "it under the terms of the GNU General Public License as published by\n" \
+ "the Free Software Foundation; either version 2 of the License, or\n" \
+ "(at your option) any later version.\n" \
+ "\n", \
+ \
+ "This program is distributed in the hope that it will be useful,\n" \
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
+ "GNU General Public License for more details.\n" \
+ "\n" \
+ "You should have received a copy of the GNU General Public License\n" \
+ "along with this program; if not, write to the Free Software\n" \
+ "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n"
+
+#define WEE_USAGE \
+ WEECHAT_NAME_AND_VERSION " (c) Copyright 2003, compiled on " __DATE__ __TIME__ \
+ "Developed by FlashCode <flashcode@flashtux.org>\n" \
+ " Bounga <bounga@altern.org>\n" \
+ " Xahlexx <xahlexx@tuxisland.org>\n\n" \
+ " Bounga <bounga@altern.org>\n" \
+ " Xahlexx <xahlexx@tuxisland.org>\n\n" \
+ " -h, --help this help screen\n", \
+ " -l, --license display WeeChat license\n" \
+ " -v, --version display WeeChat version\n\n"
+
+/* " -d, --display choose X display\n" \*/
+
+
+/*#define DEFAULT_DISPLAY ":0" */
+
+
+/*extern char *display_name; */
+int quit_weechat;
+
+extern int quit_weechat;
+
+extern void log_printf (char *, ...);
+extern void wee_shutdown ();
+
+#endif /* weechat.h */
diff --git a/weechat/weechat.1 b/weechat/weechat.1
new file mode 100644
index 000000000..4d03e5cd0
--- /dev/null
+++ b/weechat/weechat.1
@@ -0,0 +1,44 @@
+.TH WEECHAT 1 "September 2003" "FlashCode"
+
+.SH NAME
+weechat \- wee enhanced environment for chat
+
+.SH SYNOPSIS
+.B weechat
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+Fast, light and extensible IRC client for many operating systems. Everything can be
+done with a keyboard. It is customizable and extensible with scripts.
+
+.SH OPTIONS
+.TP
+.B \-h, \-\-help
+.br
+display summary of options
+.TP
+.B \-l, \-\-license
+.br
+display program license
+.TP
+.B \-v, \-\-version
+.br
+display WeeChat version
+
+.SH FILES
+.TP
+.B $HOME/.weechat/weechat.rc
+configuration file for WeeChat
+
+.SH AUTHOR
+WeeChat is written by:
+.br
+ - FlashCode <flashcode@flashtux.org>
+ - Bounga <bounga@altern.org>
+ - Xahlexx <xahlexx@tuxisland.org>
+.br
+WeeChat on the web:
+.UR
+http://weechat.flashtux.org
+.UE
diff --git a/weechat/weechat.spec b/weechat/weechat.spec
new file mode 100644
index 000000000..6bf1a5f61
--- /dev/null
+++ b/weechat/weechat.spec
@@ -0,0 +1,41 @@
+%define name weechat
+%define version 0.0.1
+%define release 1
+
+Name: %{name}
+Summary: portable, fast, light and extensible IRC client
+Version: %{version}
+Release: %{release}
+Source: http://weechat.flashtux.org/download/%{name}-%{version}.tar.gz
+URL: http://weechat.flashtux.org
+Group: Networking/IRC
+BuildRoot: %{_tmppath}/%{name}-buildroot
+License: GPL
+
+%description
+WeeChat (Wee Enhanced Environment for Chat) is a portable, fast, light and
+extensible IRC client. Everything can be done with a keyboard.
+It is customizable and extensible with scripts.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+%setup
+
+%build
+make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local"
+
+%install
+make DESTDIR="$RPM_BUILD_ROOT" LOCALRPM="local" install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root,0755)
+%doc AUTHORS BUGS ChangeLog COPYING FAQ INSTALL NEWS README TODO
+/usr/share/man/man1/weechat.1*
+/usr/local/bin/weechat
+
+%changelog
+* Thu Sep 27 2003 FlashCode <flashcode@flashtux.org> 0.0.1-1
+- Released version 0.0.1