irc.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           irc.cpp  -  description
00003                              -------------------
00004     begin                : Thu Dec 9 2004
00005     copyright            : (C) 2004 by VooDooMan
00006     email                : vdmfun@hotmail.com
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010 
00011 VooDoo cIRCle - an IRC (ro)bot
00012 Copyright (C) 2004 by Marian VooDooMan Meravy (vdmfun@hotmail.com)
00013 
00014 This program is free software; you can redistribute it and/or
00015 modify it under the terms of the GNU General Public License
00016 as published by the Free Software Foundation; either version 2
00017 of the License, or (at your option) any later version.
00018 
00019 This program is distributed in the hope that it will be useful,
00020 but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License
00025 along with this program; if not, write to the Free Software
00026 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028 ****************************************************************************/
00029 
00030 /*!
00031     \file
00032     \brief Handles core communication with IRC server
00033 */
00034 
00035 //---------------------------------------------------------------------------
00036 
00037 #include <list>
00038 #include <time.h>
00039 #include <vector>
00040 #include <map>
00041 #include <string>
00042 #include <stdlib.h>
00043 
00044 #include "irc.h"
00045 #include "log.h"
00046 #include "sock.h"
00047 #include "logic.h"
00048 #include "dcc.h"
00049 #include "shared.h"
00050 #include "match.h"
00051 #include "filesys.h"
00052 #include "lang.h"
00053 #include "conf.h"
00054 #include "stats.h"
00055 
00056 #pragma hdrstop
00057 
00058 #ifdef _MSC_VER
00059 #   define __FUNC__ __FUNCTION__
00060 #endif
00061 
00062 #ifdef __GNUC__
00063 #define __FUNC__ "<unknown>"
00064 #endif
00065 
00066 #include "irc.h"
00067 
00068 #include "params.h"
00069 
00070 //---------------------------------------------------------------------------
00071 #ifdef __BORLANDC__
00072 #pragma package(smart_init)
00073 #endif
00074 
00075 using namespace std;
00076 
00077 #ifndef _WIN32
00078 #ifndef HAVE_LTOA
00079 extern char *ltoa(long value, char *buffer, int radix);
00080 #endif
00081 #endif
00082 
00083 extern void logic_get_flood_limits(string channel, string user, s_flood& msg_flood, s_flood& notice_flood, s_flood& repeat_flood, s_flood& nick_flood, s_flood& join_flood, s_flood& mode_flood, s_flood& ctcp_flood);
00084 extern bool logic_botnet_get_user(string name, s_user& user);
00085 
00086 extern vector<s_dcc_awaiting_user> dcc_awaiting_users;  //!< Stores users who are waiting for DCC connection
00087 
00088 extern vector<s_channel> r_channels;
00089 extern vector<s_channel_def> r_channel_defs;
00090 
00091 extern vector<s_user> r_users;
00092 
00093 //-------------------
00094 
00095 size_t irc_bot_flood_bytes;             //!< Number of bytes considered as flood from bot
00096 time_t irc_bot_flood_seconds;           //!< Number of seconds to clear flood buffer (from bot)
00097 unsigned int irc_bot_flood_lines;       //!< Number of lines maximum in irc_bot_flood_seconds
00098 time_t irc_bot_flood_other_seconds;     //!< Number of seconds to clear flood buffer for non-PRIVMSG && non-NOTICE messages (from bot)
00099 
00100 bool irc_follow_redirs=false;           //!< Stores "allow_redirect" state from logic.txt (true if bot should follow redirect hints from server)
00101 string irc_recommended_server;          //!< Hint from server: recommended server (together with irc_recommended_port)
00102 unsigned short irc_recommended_port;    //!< Hint from server: recommended port (together with irc_recommended_server)
00103 
00104 s_socket irc_socket;                    //!< Handle of socket connected to server (zero for disconnected state)
00105 time_t irc_last_keepalive_detection;    //!< Used for storing time of last command sent to server (for detection of lost connection)
00106 bool irc_keepalive_sent;                //!< Was WHOIS sent?
00107 
00108 char irc_nick[512];                     //!< Bot's current nick
00109 char irc_fullname[512];                 //!< Bot's current full name
00110 char irc_unique_id[512];                //!< Bot's unique ID
00111 string irc_ident="*";                   //!< Bot's ident username
00112 
00113 string irc_server_host;                 //!< Current IRC server host
00114 unsigned short irc_server_port;         //!< Current IRC server port
00115 
00116 extern void irc_quoted_callback(const char* str, const char* nick, const char* host_mask);
00117 extern void dcc_loop();
00118 
00119 extern vector<s_dcc_request_whois> dcc_request_whois;
00120 
00121 vector<string> irc_nicks;               //!< Bot's nicks available to try them if they are unused (from logic.txt)
00122 vector<s_irc_server> irc_servers;       //!< List of irc servers
00123 vector<s_irc_server>::iterator irc_server_iterator; //!< Current irc server
00124 
00125 time_t filesys_notify_interval;         //!< Interval for filesystem notifications
00126 time_t filesys_last_notify;             //!< Timestam of last filesystem notification
00127 
00128 /*!
00129     \brief Stores data about channel, which is +k, and we are trying all keys in whole history
00130     \author VooDooMan
00131     \version 1
00132     \date 2004
00133 */
00134 struct s_key_chan {
00135     string channel_name;                //!< Name of channel
00136     vector<string> keys;                //!< Keys from history to try them
00137 };
00138 
00139 vector<s_key_chan> irc_key_chans;       //!< List of channels which we are not on, because they are +k and we are trying all keys in the history
00140 
00141 vector<s_online_channel> irc_channels;          //!< List of channels we are on
00142 
00143 vector<s_online_user> tmp_users;                //!< Temporary list of users
00144 
00145 vector<s_online_user> gone_users;               //!< Temporary list of users that have QUIT/PART/been KICK-ed
00146 
00147 vector<s_online_channel> unknown_users_on_channels;     //!< Temporary list of user used ONLY for flood history
00148 
00149 //-------------------
00150 
00151 s_msg_to_server last_msg;                       //!< Last message sent to server
00152 
00153 struct s_awaiting_response {
00154     string message;
00155     time_t time;
00156 };
00157 
00158 vector<s_awaiting_response> waiting_for_response;   //!< Array of last messages to server
00159 
00160 list<s_msg_to_server> msgs_to_server;           //!< Queue of messages that are waiting to be sent to server (for bot's flood control)
00161 list<s_msg_to_server> msgs_to_server2;          //!< Queue of messages that are waiting to be sent to server (for bot's flood control), but these has lower priority (notifies)
00162 list<char*> msgs_from_server;                   //!< Queue of messages from server to be processed
00163 bool irc_socket_error;                          //!< If true, then we have socket error on connection to IRC server
00164 
00165 list<s_flood_history> flood_history;            //!< History of messages sent to server (for bot's flood control)
00166 list<s_flood_history> flood_history_other;      //!< History of other messages sent to server (non-PRIVMSG && non-NOTICE) (for bot's flood protection)
00167 
00168 vector<string> irc_cannot_join_channels;        //!< List of channels that i am banned
00169 time_t irc_last_join_try;                       //!< Timestamp of last try to join because of +b on myself, or +l, or +i
00170 
00171 s_005 irc_isupport;
00172 
00173 /*!
00174     \brief One entry of mode queue (used when "compress_mode_wait" form conf.txt is more than zero)
00175     \author VooDooMan
00176     \version 1
00177     \date 2004
00178 */
00179 struct s_mode_queue_entry {
00180     string channel;                             //!< Name of channel
00181     string mode;                                //!< One mode (+/- prefix + mode char)
00182     string param;                               //!< Parameter of mode
00183     time_t submit;                              //!< Time when mode was wished to post
00184 };
00185 
00186 list<s_mode_queue_entry> mode_queue;            //!< Mode queue used when "compress_mode_wait" form conf.txt is more than zero
00187 list<s_mode_queue_entry> modes_from_server;     //!< Modes that server set
00188 
00189 /*!
00190     \brief If "smart_mode" in conf.txt is non-zero, removes redundant modes from mode_queue
00191     \author VooDooMan
00192     \version 1
00193     \date 2004
00194     \param channel Channel name
00195     \param nick Nick that mode is applied to
00196     \param mode Mode (+o, -v, ...)
00197 */
00198 void irc_remove_redundant_mode(string channel, string nick, string mode)
00199 {
00200     if(atol(conf_getvar("smart_mode").c_str())) {
00201         if(mode.length()!=2)
00202             return;
00203         list<s_mode_queue_entry>::iterator i1;
00204     again:
00205         for(i1=mode_queue.begin(); i1!=mode_queue.end(); i1++) {
00206             if(!cmp_strings_case_insensitive((*i1).channel,channel) && !(*i1).mode.compare(mode) && !cmp_strings_case_insensitive((*i1).param,nick)) {
00207                 mode_queue.erase(i1);
00208                 goto again;
00209             }
00210         }
00211     }
00212 }
00213 
00214 /*!
00215     \brief If "smart_mode" in conf.txt is non-zero, removes redundant modes from mode_queue
00216     \author VooDooMan
00217     \version 1
00218     \date 2004
00219 */
00220 void irc_remove_redundant_mode2()
00221 {
00222     if(atol(conf_getvar("smart_mode").c_str())) {
00223         list<s_mode_queue_entry>::iterator i1;
00224     again:
00225         for(i1=mode_queue.begin(); i1!=mode_queue.end(); i1++) {
00226             list<s_mode_queue_entry>::iterator i2=i1;
00227             i2++;
00228             for(; i2!=mode_queue.end(); i2++) {
00229                 if(!cmp_strings_case_insensitive((*i1).channel,(*i2).channel) &&
00230                     !(*i1).mode.compare((*i2).mode) &&
00231                     !(*i1).param.compare((*i2).param)) {
00232                         mode_queue.erase(i2);
00233                         goto again;
00234                     }
00235             }
00236         }
00237         int compress_mode_wait=atol(conf_getvar("compress_mode_wait").c_str());
00238     again2:
00239         // there is +5 seconds to wait, to ensure that mode from server will not be removed too soon
00240         for(i1=modes_from_server.begin(); i1!=modes_from_server.end(); i1++) {
00241             if((*i1).submit+compress_mode_wait+5<time(NULL)) {
00242                 modes_from_server.erase(i1);
00243                 goto again2;
00244             }
00245         }
00246     again3:
00247         for(i1=mode_queue.begin(); i1!=mode_queue.end(); i1++) {
00248             list<s_mode_queue_entry>::iterator i2;
00249             for(i2=modes_from_server.begin(); i2!=modes_from_server.end(); i2++) {
00250                 if(!cmp_strings_case_insensitive((*i1).channel,(*i2).channel) &&
00251                     !(*i1).mode.compare((*i2).mode) &&
00252                     !(*i1).param.compare((*i2).param)) {
00253                         mode_queue.erase(i1);
00254                         goto again3;
00255                     }
00256             }
00257         }
00258     }
00259 }
00260 
00261 /*!
00262     \brief Converts string to UPPER case (using touppertab[] in match.cpp)
00263     \author VooDooMan
00264     \version 1
00265     \date 2004
00266     \param str Source string
00267     \return Returns UPPERcase string (using touppertab[] in match.cpp)
00268 */
00269 string irc_to_upper(string str)
00270 {
00271     extern unsigned char touppertab[];
00272 
00273     string res;
00274     for(unsigned int i1=0; i1<str.length(); i1++)
00275         res+=touppertab[str[i1]];
00276     return res;
00277 }
00278 
00279 /*!
00280     \brief Compares two strings, case in-sensitive
00281     \author VooDooMan
00282     \version 1
00283     \date 2004
00284     \param s1 String 1
00285     \param s2 String 2
00286     \return Zero if strings are the same (case in-sensitive)
00287     \retval 0 Strings are the same (case in-sensitive)
00288 */
00289 int cmp_strings_case_insensitive(string s1, string s2)
00290 {
00291     s1=irc_to_upper(s1);
00292     s2=irc_to_upper(s2);
00293     if((s1.empty() && !s2.empty()) || (!s1.empty() && s2.empty()))
00294         return -1;
00295     return s1.compare(s2);
00296 }
00297 
00298 /*!
00299     \brief Returns reference to channel that we are on
00300     \author VooDooMan
00301     \version 1
00302     \date 2004
00303     \param channel_name Name of channel
00304     \param chan Returns pointer to channel we are on, or NULL if channel was not found
00305     \return Returns true if found
00306     \retval true Channel found
00307     \retval false Channel not found
00308 */
00309 bool irc_get_online_channel(string channel_name, s_online_channel* &chan)
00310 {
00311     chan=NULL;
00312 
00313     vector<s_online_channel>::iterator i1;
00314     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++)
00315         if(!cmp_strings_case_insensitive((*i1).name,channel_name)) {
00316             chan=&(*i1);
00317             return true;
00318         }
00319 
00320     return false;
00321 }
00322 
00323 /*!
00324     \def IRC_MSG_TOO_LONG
00325     \brief ERROR: msg is longer than 512 bytes
00326 */
00327 #define IRC_MSG_TOO_LONG    0x81234567L
00328 /*!
00329     \def SOCK_SEND_ERROR
00330     \brief ERROR: not all the msg was sent
00331 */
00332 #define SOCK_SEND_ERROR     0x81234568L
00333 
00334 /*!
00335     \brief Imeddiately sends message to server
00336     \author VooDooMan
00337     \version 2
00338     \date 2005
00339     \param socket Socket handle of connection to server
00340     \param msg Message to be sent
00341     \param wait_for_response Set to true if we want to wait for response from IRC server to this command
00342     \return Returns zero for no error, IRC_MSG_TOO_LONG if msg is too long (>512 bytes), SOCK_SEND_ERROR is not all the msg was sent, or OS's socket I/O error
00343     \retval 0 No error
00344     \retval IRC_MSG_TOO_LONG msg is too long (>512 bytes)
00345     \retval SOCK_SEND_ERROR Not all the msg was sent
00346 */
00347 int irc_putserv_immediately(s_socket& socket, const char* msg, bool wait_for_response=false)
00348 {
00349     if(strlen(msg)>512) {
00350         log_debug("in file " __FILE__ " in function " __FUNC__ " occurred error IRC_MSG_TOO_LONG");
00351         return IRC_MSG_TOO_LONG;
00352     }
00353 
00354     // BEGIN: sanity checks
00355     char tmp_msg[1024];
00356     strcpy(tmp_msg,msg);
00357     for(unsigned int ii=0; ii<strlen(tmp_msg); ii++) {
00358         if(tmp_msg[ii]=='\r' && ii!=strlen(tmp_msg)-2) {
00359             tmp_msg[ii]=0;
00360             string log="Warning: in file " __FILE__ " in function " __FUNC__ ": Message to IRC server contained \\r character, truncated message is: \"";
00361             log+=tmp_msg;
00362             log+="\"";
00363             log_debug(log.c_str());
00364             strcat(tmp_msg,"\r\n");
00365             break;
00366         }
00367         if(tmp_msg[ii]=='\n' && ii!=strlen(tmp_msg)-1) {
00368             tmp_msg[ii]=0;
00369             string log="Warning: in file " __FILE__ " in function " __FUNC__ ": Message to IRC server contained \\n character, truncated message is: \"";
00370             log+=tmp_msg;
00371             log+="\"";
00372             log_debug(log.c_str());
00373             strcat(tmp_msg,"\r\n");
00374             break;
00375         }
00376     }
00377     if(tmp_msg[strlen(tmp_msg)-2]!='\r' || tmp_msg[strlen(tmp_msg)-1]!='\n') {
00378         while(strlen(tmp_msg) && (tmp_msg[strlen(tmp_msg)-1]=='\r' || tmp_msg[strlen(tmp_msg)-1]=='\n'))
00379             tmp_msg[strlen(tmp_msg)-1]=0;
00380         string log="Warning: in file " __FILE__ " in function " __FUNC__ ": Message to IRC server doesn't end with \\r\\n sequence, correcting to: \"";
00381         log+=tmp_msg;
00382         log+="\"";
00383         log_debug(log.c_str());
00384         strcat(tmp_msg,"\r\n");
00385     }
00386     if(!strcmp(tmp_msg,"\r\n")) {
00387         string log="Warning: in file " __FILE__ " in function " __FUNC__ ": Message to IRC server is empty!";
00388         log_debug(log.c_str());
00389         return 0;
00390     }
00391     msg=tmp_msg;
00392     // END:   sanity checks
00393 
00394     if(wait_for_response) {
00395         char tmp[128];
00396         unsigned int i1;
00397         for(i1=0; i1<64 && msg[i1]!=0 && msg[i1]!=0x20; i1++)
00398             tmp[i1]=msg[i1];
00399         tmp[i1]=0;
00400         if(strcmp(tmp,"PRIVMSG") && strcmp(tmp,"NOTICE") && strcmp(tmp,"PONG") && strcmp(tmp,"PASS") && strcmp(tmp,"USER")) {
00401             s_awaiting_response r;
00402             r.message=msg;
00403             r.time=time(NULL);
00404             waiting_for_response.push_back(r);
00405         }
00406     }
00407 
00408     char tmp[1024];
00409     strcpy(tmp,msg);
00410     tmp[strlen(tmp)-2]=0; // remove CR/LF
00411     log_irc(false,tmp);
00412 
00413     int ec=0;
00414     size_t sent=sock_send(socket,msg,strlen(msg),ec);
00415     stats_irc_bytes_sent(sent);
00416     //irc_last_keepalive_detection=time(NULL);
00417     if(ec) {
00418         log_socket(ec,sock_error(ec),"in file " __FILE__ " in function " __FUNC__);
00419         return ec;
00420     }
00421     if(sent!=strlen(msg)) {
00422         log_socket(0,"(cannot send all buffer)","in file " __FILE__ " in function " __FUNC__);
00423         return SOCK_SEND_ERROR;
00424     }
00425 
00426     return 0;
00427 }
00428 
00429 /*!
00430     \brief Parses a channel mode
00431     \author VooDooMan
00432     \version 1
00433     \date 2005
00434     \param modes String with modes
00435     \param with_param Returns map of modes with parameter (e.g. "k" -> "channel key")
00436     \param plain Returns string of modes without parameter (e.g. "nt")
00437 */
00438 void irc_parse_modes(string modes, map<char,string>& with_param, string& plain)
00439 {
00440     with_param.clear();
00441     plain="";
00442 
00443     unsigned int i1=0;
00444     unsigned int i2=0;
00445     for(i2=0; i2<modes.length(); i2++) {
00446         if(modes[i2]==0x20) {
00447             i2++;
00448             break;
00449         }
00450     }
00451 
00452     for(;;) {
00453         if(i1>=modes.length())
00454             break;
00455         if(modes[i1]==0x20)
00456             break;
00457         if(modes[i1]=='+') {
00458             i1++;
00459             continue;
00460         }
00461         // however, CLASS A should never occur!
00462         if(irc_isupport.chanmodes_a.find(modes[i1],0)!=string::npos ||
00463            irc_isupport.chanmodes_b.find(modes[i1],0)!=string::npos ||
00464            irc_isupport.chanmodes_c.find(modes[i1],0)!=string::npos) {
00465             if(i2>=modes.length()) {
00466                 i1++;
00467                 continue;
00468             }
00469             pair<char,string> p;
00470             p.first=modes[i1];
00471             p.second="";
00472             for(; i2<modes.length(); i2++) {
00473                 if(modes[i2]==0x20) {
00474                     i2++;
00475                     break;
00476                 }
00477                 p.second+=(string)""+modes[i2];
00478             }
00479             with_param.insert(p);
00480             i1++;
00481             continue;
00482         }
00483         if(irc_isupport.chanmodes_d.find(modes[i1],0)!=string::npos) {
00484             plain+=(string)""+modes[i1];
00485             i1++;
00486             continue;
00487         }
00488         // there it shouldn't go
00489         i1++;
00490     }
00491 }
00492 
00493 /*!
00494     \brief Puts message for server to queue to send
00495     \author VooDooMan
00496     \version 1
00497     \date 2004
00498     \param msg Message
00499     \param wait_for_response Set this to true if message has to be marked as wait for response and then send next message
00500     \param priority CRITICAL_PRIORITY, HIGH_PRIORITY, or LOW_PRIORITY
00501     \return Returns false if socket I/O error occured
00502 */
00503 bool irc_putserv(const char* msg, bool wait_for_response, int priority)
00504 {
00505     if(strlen(msg)+2>512) { /* +2 == CR/LF */
00506         return false;
00507     }
00508 
00509     s_msg_to_server m;
00510 
00511     size_t end;
00512     m.msg=new char[end=(strlen(msg)+2+1)]; // +2 == CR/LF
00513     strcpy(m.msg,msg);
00514     m.msg[end-2-1+0]=0x0D;
00515     m.msg[end-2-1+1]=0x0A;
00516     m.msg[end-2-1+2]=0;
00517 
00518     int compress_mode_wait=atol(conf_getvar("compress_mode_wait").c_str());
00519     if(compress_mode_wait>0 && strstr(msg,"MODE")==msg && priority==LOW_PRIORITY) {
00520         string chan;
00521         string mode;
00522         string param;
00523         unsigned int i1;
00524         int context=0;
00525         for(i1=0; i1<strlen(msg); i1++) {
00526             if(msg[i1]==0x20) {
00527                 context++;
00528                 continue;
00529             }
00530             if(msg[i1]==0x0D || msg[i1]==0x0A)
00531                 break;
00532             if(context==1)
00533                 chan+=msg[i1];
00534             if(context==2)
00535                 mode+=msg[i1];
00536             if(context==3)
00537                 param+=msg[i1];
00538         }
00539         if(context<=3 && mode.length()==2 && (mode[0]=='+' || mode[0]=='-')) {
00540             // process only single mode
00541             int process=0;
00542             /*switch(mode[1]) {
00543                 case 'o':
00544                 case 'O':
00545                 //case 'b':
00546                     // do not precess bans, they should be put immediatelly
00547                 case 'e':
00548                 case 'I':
00549                 case 'v':
00550                     process=1;
00551                     break;
00552                 case 'k':
00553                 case 'l':
00554                     process=2;
00555                     break;
00556                 case 'n':
00557                 case 't':
00558                     process=3;
00559                     break;
00560                 default:
00561                     process=0;
00562                     break;
00563             }*/
00564             if(irc_isupport.get_prefix1(mode[1])!='0') {
00565                 process=1;
00566             }
00567             if(irc_isupport.chanmodes_a.find(mode[1])!=string::npos) {
00568                 if(mode[1]=='b') {
00569                     // do not precess bans, they should be put immediatelly
00570                     process=0;
00571                 } else {
00572                     process=1;
00573                 }
00574             }
00575             if(irc_isupport.chanmodes_b.find(mode[1])!=string::npos || irc_isupport.chanmodes_c.find(mode[1])!=string::npos) {
00576                 process=2;
00577             }
00578             if(irc_isupport.chanmodes_d.find(mode[1])!=string::npos) {
00579                 process=3;
00580             }
00581             if(process==0) {
00582                 // do nothing!
00583             }
00584             if((process==1 || process==2) && !param.empty()) {
00585                 // with parameter
00586                 s_mode_queue_entry e;
00587                 e.channel=chan;
00588                 e.mode=mode;
00589                 e.param=param;
00590                 time(&e.submit);
00591                 mode_queue.push_back(e);
00592                 return true;
00593             }
00594             if(process==3 && param.empty()) {
00595                 // without parameter
00596                 s_mode_queue_entry e;
00597                 e.channel=chan;
00598                 e.mode=mode;
00599                 e.param="";
00600                 time(&e.submit);
00601                 mode_queue.push_back(e);
00602                 return true;
00603             }
00604         }
00605     }
00606 
00607     m.flood_protection=strstr(msg,"PRIVMSG")==msg || strstr(msg,"NOTICE")==msg;
00608 
00609     m.wait_for_response=wait_for_response;
00610     if(wait_for_response)
00611         m.response[0]=0;
00612 
00613     if(priority==HIGH_PRIORITY)
00614         msgs_to_server.push_back(m);
00615     else if(priority==LOW_PRIORITY)
00616         msgs_to_server2.push_back(m);
00617     else if(priority==CRITICAL_PRIORITY)
00618         irc_putserv_immediately(irc_socket,m.msg,wait_for_response);
00619 
00620     return true;
00621 }
00622 
00623 void irc_check_for_filesystem(string user_name, string channel, string nick);
00624 
00625 /*!
00626     \brief This function should be called in a loop to process send and receive to/from server
00627     \author VooDooMan
00628     \version 1
00629     \date 2004
00630     \return Returns true if socket I/O error occured
00631 */
00632 // returns true is socket error occurs
00633 bool irc_loop_putserv()
00634 {
00635     if(!irc_socket.cmp())
00636         return true;
00637 
00638     if(irc_last_keepalive_detection+60*3<time(NULL) && irc_keepalive_sent) {
00639         irc_last_keepalive_detection=time(NULL);
00640         irc_keepalive_sent=false;
00641         irc_disconnect();
00642         logic_exec_from_work();
00643         return false;
00644     }
00645     if(irc_last_join_try+15<time(NULL)) {
00646         time(&irc_last_join_try);
00647         vector<string>::iterator i1;
00648     erase_again:
00649         for(i1=irc_cannot_join_channels.begin(); i1!=irc_cannot_join_channels.end(); i1++) {
00650             vector<s_online_channel>::iterator i;
00651             for(i=irc_channels.begin(); i!=irc_channels.end(); i++)
00652                 if(!cmp_strings_case_insensitive((*i).name,*i1)) {
00653                     irc_cannot_join_channels.erase(i1);
00654                     goto erase_again;
00655                 }
00656 
00657             string msg="JOIN ";
00658             msg+=*i1;
00659             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
00660             msg="MODE ";
00661             msg+=*i1;
00662             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
00663             msg="TOPIC ";
00664             msg+=*i1;
00665             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
00666             msg="WHOIS ";
00667             msg+=irc_nick;
00668             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
00669         }
00670     }
00671 
00672     int compress_mode_wait=atol(conf_getvar("compress_mode_wait").c_str());
00673     if(compress_mode_wait>0) {
00674         time_t now=time(NULL);
00675         list<s_mode_queue_entry> wait_elapsed;
00676         wait_elapsed.clear();
00677     again:
00678         list<s_mode_queue_entry>::iterator i1;
00679         for(i1=mode_queue.begin(); i1!=mode_queue.end(); i1++) {
00680             if((*i1).submit+compress_mode_wait<now) {
00681                 wait_elapsed.push_back(*i1);
00682                 mode_queue.erase(i1);
00683                 goto again;
00684             }
00685         }
00686         string chan="";
00687         list<s_mode_queue_entry> single_channel;
00688         single_channel.clear();
00689     again2:
00690         for(i1=wait_elapsed.begin(); i1!=wait_elapsed.end(); i1++) {
00691             if(chan.empty()) {
00692                 chan=(*i1).channel;
00693                 single_channel.clear();
00694                 single_channel.push_back(*i1);
00695                 wait_elapsed.erase(i1);
00696                 goto again2;
00697             }
00698             if(!cmp_strings_case_insensitive((*i1).channel,chan)) {
00699                 single_channel.push_back(*i1);
00700                 wait_elapsed.erase(i1);
00701                 goto again2;
00702             }
00703         }
00704         {
00705             list<s_mode_queue_entry>::iterator i2;
00706             string cumulative1="MODE "; // chars
00707             cumulative1+=chan;
00708             cumulative1+=" ";
00709             string cumulative2=""; // params
00710             int cum_num=0;
00711         again3:
00712             if(cum_num==irc_isupport.max_modes) {
00713             jump_1:
00714                 if(cumulative2.length() && cumulative2[cumulative2.length()-1]==0x20)
00715                     cumulative2.erase(cumulative2.length()-1,1);
00716                 if(!cumulative2.empty()) {
00717                     cumulative1+=" ";
00718                     cumulative1+=cumulative2;
00719                 }
00720 
00721                 s_msg_to_server m;
00722 
00723                 size_t end;
00724                 m.msg=new char[end=(cumulative1.length()+2+1)]; // +2 == CR/LF
00725                 strcpy(m.msg,cumulative1.c_str());
00726                 m.msg[end-2-1+0]=0x0D;
00727                 m.msg[end-2-1+1]=0x0A;
00728                 m.msg[end-2-1+2]=0;
00729 
00730                 m.flood_protection=false;
00731 
00732                 m.wait_for_response=false;
00733                 if(m.wait_for_response)
00734                     m.response[0]=0;
00735 
00736                 msgs_to_server.push_back(m);
00737 
00738                 cumulative1="MODE "; // chars
00739                 cumulative1+=chan;
00740                 cumulative1+=" ";
00741                 cumulative2="";
00742 
00743                 cum_num=0;
00744             }
00745             for(i2=single_channel.begin(); i2!=single_channel.end(); i2++) {
00746                 if(cum_num<irc_isupport.max_modes) {
00747                     cum_num++;
00748                     cumulative1+=(*i2).mode;
00749                     if(!(*i2).param.empty()) {
00750                         cumulative2+=(*i2).param;
00751                         cumulative2+=" ";
00752                     }
00753                     single_channel.erase(i2);
00754                     goto again3;
00755                 } else
00756                     break;
00757             }
00758             if(cum_num>0)
00759                 goto jump_1;
00760         }
00761         if(!wait_elapsed.empty()) {
00762             chan="";
00763             single_channel.clear();
00764             goto again2;
00765         }
00766     }
00767 
00768     irc_remove_redundant_mode2();
00769 
00770     char* buff2=new char[10240];
00771     int buff2_pos=0;
00772     for(;;) {
00773         char buff[1024];
00774         int ec=0;
00775         bool closed;
00776         size_t size=sock_read(irc_socket,buff,sizeof(buff),ec,closed);
00777         if(closed) {
00778             if(msgs_from_server.empty())
00779                 return true;
00780         }
00781 
00782         if(ec) {
00783             log_socket(ec,sock_error(ec),"while reading from the socket, in file " __FILE__ " in function " __FUNC__);
00784             if(msgs_from_server.empty())
00785                 return true;
00786         }
00787 
00788         if(!size)
00789             break;
00790 
00791         stats_irc_bytes_received(size);
00792 
00793         irc_last_keepalive_detection=time(NULL);
00794         irc_keepalive_sent=false;
00795 
00796         for(size_t i1=0; i1<size; i1++) {
00797             if(buff[i1]==0 || buff[i1]=='\r' || buff[i1]=='\n') {
00798 l2:
00799                 if((buff2_pos==1 && (buff2[0]==0 || buff2[0]=='\r' || buff2[0]=='\n')) || buff2_pos==0)
00800                     buff2_pos=0;
00801                     else {
00802                         buff2[buff2_pos++]=0;
00803                         char* tmp=new char[buff2_pos+16];
00804                         strcpy(tmp,buff2);
00805                         msgs_from_server.push_back(tmp);
00806                         buff2_pos=0;
00807                     }
00808             } else {
00809                 if(buff2_pos>=10240-16) {
00810                     log_debug("one line from IRC server exceeded about 10 KB, in file " __FILE__ " in function " __FUNC__);
00811                     goto l2;
00812                 }
00813                 buff2[buff2_pos++]=buff[i1];
00814             }
00815         }
00816     }
00817     delete[] buff2;
00818     buff2=NULL;
00819 
00820     if(irc_last_keepalive_detection+30<time(NULL) && !irc_keepalive_sent) {
00821         irc_keepalive_sent=true;
00822         string ping="PING :";
00823         char tmp[64];
00824         ltoa((long)time(NULL),tmp,10);
00825         ping+=tmp;
00826         irc_putserv(ping.c_str(),true,HIGH_PRIORITY);
00827     }
00828 
00829     //---
00830     if(last_msg.timestamp+20<time(NULL))
00831         last_msg.wait_for_response=false;
00832 
00833     if(last_msg.wait_for_response && last_msg.response[0]==0)
00834         return false; // still waiting
00835 
00836     if(last_msg.msg) {
00837         delete[] last_msg.msg;
00838         last_msg.msg=NULL;
00839     }
00840     //---
00841 
00842     {
00843         vector<s_awaiting_response>::iterator i1;
00844 _again:
00845         for(i1=waiting_for_response.begin(); i1!=waiting_for_response.end(); i1++) {
00846             if((*i1).time+20<time(NULL)) {
00847                 string msg="Timeout while waiting for response to command: ";
00848                 msg+=(*i1).message;
00849 
00850                 while(msg.length() && msg[msg.length()-1]=='\r')
00851                     msg.erase(msg.length()-1,1);
00852                 while(msg.length() && msg[msg.length()-1]=='\n')
00853                     msg.erase(msg.length()-1,1);
00854                 while(msg.length() && msg[msg.length()-1]=='\r')
00855                     msg.erase(msg.length()-1,1);
00856                 while(msg.length() && msg[msg.length()-1]=='\n')
00857                     msg.erase(msg.length()-1,1);
00858 
00859                 log_debug(msg.c_str());
00860 
00861                 waiting_for_response.erase(i1);
00862                 goto _again;
00863             }
00864         }
00865 
00866         if(waiting_for_response.begin()!=waiting_for_response.end())
00867             return false; // still waiting
00868     }
00869 
00870     //---
00871 
00872     /*time_t now=time(NULL);
00873 
00874     list<s_flood_history>::iterator i;
00875 l1:
00876     for(i=flood_history.begin(); i!=flood_history.end(); i++) {
00877         bool del=false;
00878         if((*i).time>now) // for case of changing system time
00879             del=true;
00880             else
00881             if(((unsigned)now-(*i).time)>irc_bot_flood_seconds)
00882                 del=true;
00883 
00884         if(del) {
00885             flood_history.erase(i);
00886             goto l1;
00887         }
00888     }*/
00889 
00890     size_t bytes=0;
00891     list<s_flood_history>::iterator i;
00892     for(i=flood_history.begin(); i!=flood_history.end(); i++)
00893         bytes+=(*i).bytes;
00894 
00895     size_t all_1=0, all_2=0;
00896     size_t cnt=0;
00897     size_t cnt2=0;
00898     {
00899         list<s_flood_history>::iterator i2;
00900 fl_again1:
00901         for(i2=flood_history.begin(); i2!=flood_history.end(); i2++) {
00902             if((*i2).time+irc_bot_flood_seconds<time(NULL)) {
00903                 flood_history.erase(i2);
00904                 goto fl_again1;
00905             }
00906             all_1+=(*i2).msg.length();
00907             cnt++;
00908         }
00909     }
00910     {
00911         list<s_flood_history>::iterator i2;
00912 fl_again2:
00913         for(i2=flood_history_other.begin(); i2!=flood_history_other.end(); i2++) {
00914             if((*i2).time+irc_bot_flood_other_seconds<time(NULL)) {
00915                 flood_history_other.erase(i2);
00916                 goto fl_again2;
00917             }
00918             all_2+=(*i2).msg.length();
00919             cnt2++;
00920         }
00921     }
00922 
00923     for(;;) {
00924         list<s_msg_to_server>::iterator ii;
00925 
00926         int queue_num=1;
00927 
00928         ii=msgs_to_server.begin();
00929         if(ii==msgs_to_server.end()) {
00930             ii=msgs_to_server2.begin();
00931             if(ii==msgs_to_server2.end())
00932                 break;
00933             queue_num=2;
00934         }
00935 
00936         if(((queue_num==1?all_1:all_1+all_2)<irc_bot_flood_bytes && ((queue_num==1)?cnt<irc_bot_flood_lines:cnt2<1)) && (*ii).flood_protection) {
00937             bytes+=strlen((*ii).msg);
00938 
00939             bool wait_for_response=(*ii).wait_for_response;
00940             if(wait_for_response) {
00941                 last_msg=*ii;
00942                 last_msg.timestamp=time(NULL);
00943             }
00944             // no flood should occur
00945             char* msg=(*ii).msg;
00946             int error=irc_putserv_immediately(irc_socket,msg,wait_for_response);
00947 
00948             if(error==IRC_MSG_TOO_LONG) {
00949                 log_debug("IRC_MSG_TOO_LONG error #1, in file " __FILE__ " in function " __FUNC__);
00950             }
00951 
00952             if(error==SOCK_SEND_ERROR) {
00953                 msgs_to_server.clear();
00954                 flood_history.clear();
00955 
00956                 sock_close(irc_socket);
00957                 irc_socket.clear();
00958 
00959                 log_socket(0,"(socket closed)","in file " __FILE__ " in function " __FUNC__);
00960 
00961                 return true;
00962             }
00963 
00964             bytes+=strlen(msg);
00965 
00966             if((*ii).flood_protection) {
00967                 s_flood_history entry;
00968                 entry.bytes=strlen(msg);
00969                 entry.msg=msg;
00970                 time(&entry.time);
00971                 flood_history.push_back(entry);
00972             } else {
00973                 s_flood_history entry;
00974                 entry.bytes=strlen(msg);
00975                 entry.msg=msg;
00976                 time(&entry.time);
00977                 flood_history_other.push_back(entry);
00978             }
00979             if(queue_num==1)
00980                 msgs_to_server.pop_front();
00981             if(queue_num==2)
00982                 msgs_to_server2.pop_front();
00983 
00984             if(wait_for_response)
00985                 break;
00986         } else {
00987             if(((queue_num==1?all_1:all_1+all_2)<irc_bot_flood_bytes && ((queue_num==1)?cnt<irc_bot_flood_lines:cnt2<1)) && !(*ii).flood_protection) {
00988 
00989                 bytes+=strlen((*ii).msg);
00990 
00991                 bool wait_for_response=(*ii).wait_for_response;
00992                 if(wait_for_response) {
00993                     last_msg=*ii;
00994                     last_msg.timestamp=time(NULL);
00995                 }
00996                 // no flood should occur
00997                 char* msg=(*ii).msg;
00998                 int error=irc_putserv_immediately(irc_socket,msg,wait_for_response);
00999 
01000                 if(error==IRC_MSG_TOO_LONG) {
01001                     log_debug("IRC_MSG_TOO_LONG error #1, in file " __FILE__ " in function " __FUNC__);
01002                 }
01003 
01004                 if(error==SOCK_SEND_ERROR) {
01005                     msgs_to_server.clear();
01006                     flood_history.clear();
01007 
01008                     sock_close(irc_socket);
01009                     irc_socket.clear();
01010 
01011                     log_socket(0,"(socket closed)","in file " __FILE__ " in function " __FUNC__);
01012     
01013                     return true;
01014                 }
01015     
01016                 bytes+=strlen(msg);
01017     
01018                 if((*ii).flood_protection) {
01019                     s_flood_history entry;
01020                     entry.bytes=strlen(msg);
01021                     entry.msg=msg;
01022                     time(&entry.time);
01023                     flood_history.push_back(entry);
01024                 } else {
01025                     s_flood_history entry;
01026                     entry.bytes=strlen(msg);
01027                     entry.msg=msg;
01028                     time(&entry.time);
01029                     flood_history_other.push_back(entry);
01030                 }
01031 
01032                 if(queue_num==1)
01033                     msgs_to_server.pop_front();
01034                 if(queue_num==2)
01035                     msgs_to_server2.pop_front();
01036 
01037                 if(wait_for_response)
01038                     break;
01039             }
01040         }
01041         break;
01042     }
01043 
01044     // notify for files on the filesystem
01045     if(filesys_notify_interval==0) {
01046         filesys_notify_interval=atol(conf_getvar("notify_interval").c_str())*60;
01047         if(filesys_notify_interval==0)
01048             filesys_notify_interval=5*60;
01049     }
01050     if(filesys_last_notify+filesys_notify_interval<=time(NULL)) {
01051         if(filesys_last_notify==0) {
01052             time(&filesys_last_notify);
01053             filesys_last_notify-=filesys_notify_interval;
01054             filesys_last_notify+=20;
01055         } else {
01056             time(&filesys_last_notify);
01057             vector<s_online_channel>::iterator i1;
01058             for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
01059                 vector<s_online_user>::iterator i2;
01060                 for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++)
01061                     irc_check_for_filesystem((*i2).in_logic_as,(*i1).name,(*i2).nick);
01062             }
01063         }
01064     }
01065 
01066     return false;
01067 }
01068 
01069 /*!
01070     \brief Parses the message (scans for new line character) and sends it to the server
01071     \author VooDooMan
01072     \version 1
01073     \date 2004
01074     \param command Command to use (for example "PRIVMSG")
01075     \param nick Whom to send the message?
01076     \param msg Message to parse
01077 */
01078 void irc_put_multiple_lines(string command, string nick, string msg)
01079 {
01080     list<string> cmds;
01081     string m;
01082     unsigned int cnt=0;;
01083     for(unsigned int i1=0; i1<msg.length(); i1++) {
01084         if(msg[i1]=='\\') {
01085             if(!(i1+1<msg.length() && msg[i1+1]=='n')) {
01086                 m+=msg[i1];
01087                 cnt++;
01088             }
01089         } else
01090             if(msg[i1]!='\n') {
01091                 m+=msg[i1];
01092                 cnt++;
01093             }
01094         if((cnt>256 || i1==msg.length()-1) || (i1+1<msg.length() && msg[i1]=='\\' && msg[i1+1]=='n') || msg[i1]=='\n') {
01095             if((i1+1<msg.length() && msg[i1]=='\\' && msg[i1+1]=='n'))
01096                 i1++;
01097 
01098             if(!m.empty()) {
01099                 string cmd=command;
01100                 cmd+=" ";
01101                 cmd+=nick;
01102                 cmd+=" :";
01103 
01104                 // check to avoid bot loops
01105                 while(m.find("\x01",0)!=string::npos)
01106                     m.erase(m.find("\x01",0),1);
01107                 if(m.length()>0 && (m.find(".",0)==0 || m.find("!",0)==0 || m.find("?",0)==0 || m.find("dcc",0)==0 || m.find("getfile",0)==0))
01108                     m=(string)" "+m;
01109 
01110                 cmd+=m;
01111 
01112                 cmds.push_back(cmd);
01113             }
01114             m="";
01115             cnt=0;
01116         }
01117     }
01118 
01119     list<string>::iterator i2;
01120     for(i2=cmds.begin(); i2!=cmds.end(); i2++)
01121         irc_putserv((*i2).c_str(),false,LOW_PRIORITY);
01122 }
01123 
01124 /*!
01125     \brief Check filesystem for new objects and notifies user if needed
01126     \author VooDooMan
01127     \version 1
01128     \date 2004
01129     \param user_name User name from "logic.txt"
01130     \param nick Nick name
01131     \param channel Name of channel that is the user on
01132 */
01133 void irc_check_for_filesystem(string user_name, string channel, string nick)
01134 {
01135     string lang="en"; // TODO: !!!
01136 
01137     vector<s_dcc_notify> notifies;
01138     s_user u;
01139     vector<s_channel> chs;
01140     logic_partyline_get_user(user_name,u,chs);
01141     filesys_dcc_check_for_notifies(user_name,u,chs,channel,notifies,false,lang,"\n");
01142     filesys_dcc_drop_notifies(user_name,true);
01143     vector<s_dcc_notify>::iterator i1;
01144     bool unpublished=false;
01145     bool notified=false;
01146     string incomplete_files;
01147     for(i1=notifies.begin(); i1!=notifies.end(); i1++) {
01148         if(!unpublished && (*i1).unpublished) {
01149             string msg=lang_get_string(1,lang,331);
01150             irc_put_multiple_lines("PRIVMSG",nick,msg);
01151             unpublished=true;
01152         }
01153         if((*i1).notify_owner) {
01154             string msg=(*i1).message;
01155             irc_put_multiple_lines("PRIVMSG",nick,msg);
01156         }
01157         if((*i1).notify_user) {
01158             string msg=(*i1).message;
01159             irc_put_multiple_lines("PRIVMSG",nick,msg);
01160         }
01161         if(!notified && ((*i1).secure_notify_owner || (*i1).secure_notify_user)) {
01162             string msg=lang_get_string(1,lang,332);
01163             irc_put_multiple_lines("PRIVMSG",nick,msg);
01164             notified=true;
01165         }
01166         if((*i1).incomplete) {
01167             if(!incomplete_files.empty())
01168                 incomplete_files+=", ";
01169             incomplete_files+="\"";
01170             incomplete_files+=(*i1).name;
01171             incomplete_files+="\"";
01172         }
01173     }
01174     if(!incomplete_files.empty()) {
01175         string msg=lang_get_string(1,lang,400)+"\n";
01176         msg+=incomplete_files;
01177         irc_put_multiple_lines("PRIVMSG",nick,msg);
01178     }
01179 }
01180 
01181 /*!
01182     \brief Disconnects from server
01183     \author VooDooMan
01184     \version 1
01185     \date 2004
01186     \return Returns zero for no error
01187 */
01188 int irc_disconnect()
01189 {
01190     {
01191         string msg="Disconnecting";
01192         log_irc(false,msg.c_str());
01193     }
01194 
01195     while(irc_channels.begin()!=irc_channels.end())
01196         irc_channels.erase(irc_channels.begin());
01197 
01198     irc_keepalive_sent=false;
01199 
01200     sock_send_cache();
01201     sock_flush_later(irc_socket);
01202     sock_close(irc_socket);
01203     irc_socket.clear();
01204     msgs_to_server.clear();
01205     msgs_to_server2.clear();
01206     mode_queue.clear();
01207     last_msg.wait_for_response=false;
01208     waiting_for_response.clear();
01209     irc_ident="*";
01210     return 0;
01211 }
01212 
01213 /*!
01214     \brief Connects to server
01215     \author VooDooMan
01216     \version 1
01217     \date 2004
01218     \param bind_ip IPv4 address to bind to (client address)
01219     \param host_ DNS host of server
01220     \param port Port of server
01221     \return Returns zero for no error, or OS's socket I/O error code
01222 */
01223 int irc_connect(const char* bind_ip, const char* host_, unsigned short port)
01224 {
01225     char host[1024];
01226     if(strlen(host_)>sizeof(host)-1)
01227         return -1;
01228     strcpy(host,host_);
01229 
01230     irc_socket_error=false;
01231 
01232     irc_bot_flood_bytes=atol(conf_getvar("irc_bot_flood_bytes").c_str());
01233     irc_bot_flood_seconds=atol(conf_getvar("irc_bot_flood_seconds").c_str());
01234     irc_bot_flood_lines=atol(conf_getvar("irc_bot_flood_lines").c_str());
01235     irc_bot_flood_other_seconds=atol(conf_getvar("irc_bot_flood_other_seconds").c_str());
01236 
01237     if(!irc_bot_flood_bytes)
01238         irc_bot_flood_bytes=64;
01239     if(!irc_bot_flood_seconds)
01240         irc_bot_flood_seconds=5;
01241     if(!irc_bot_flood_lines)
01242         irc_bot_flood_lines=2;
01243     if(!irc_bot_flood_other_seconds)
01244         irc_bot_flood_other_seconds=5;
01245 
01246     // do NOT re-set this anymore! - Fixed bug in 1.0.12
01247     //irc_follow_redirs=false;
01248 
01249     irc_recommended_server="";
01250     irc_recommended_port=0;
01251 
01252     irc_socket.clear();
01253     irc_last_keepalive_detection=0;
01254     irc_keepalive_sent=false;
01255 
01256     irc_nick[0]=0;
01257     irc_fullname[0]=0;
01258     irc_unique_id[0]=0;
01259 
01260     irc_nicks.clear();
01261     filesys_notify_interval=0;
01262     filesys_last_notify=0;
01263 
01264     irc_key_chans.clear();
01265     irc_channels.clear();
01266 
01267     tmp_users.clear();
01268 
01269     gone_users.clear();
01270 
01271     unknown_users_on_channels.clear();
01272 
01273     last_msg.wait_for_response=false;
01274     waiting_for_response.clear();
01275 
01276     msgs_to_server.clear();
01277     msgs_to_server2.clear();
01278     msgs_from_server.clear();
01279 
01280     mode_queue.clear();
01281 
01282     flood_history.clear();
01283     flood_history_other.clear();
01284 
01285     irc_cannot_join_channels.clear();
01286     irc_last_join_try=0;
01287 
01288     last_msg.msg=NULL;
01289     last_msg.wait_for_response=false;
01290     last_msg.response[0]=0;
01291 
01292     irc_channels.clear();
01293 
01294     dcc_request_whois.clear();
01295     modes_from_server.clear();
01296 
01297     irc_isupport.clear();
01298 
01299     {
01300         string msg="Connecting to ";
01301         if(strstr(host,":"))
01302             msg+="[";
01303         msg+=host;
01304         if(strstr(host,":"))
01305             msg+="]";
01306         msg+=":";
01307         char tmp[64];
01308         ltoa(port,tmp,10);
01309         msg+=tmp;
01310         msg+="...";
01311         log_irc(false,msg.c_str());
01312     }
01313 
01314     int ec=0;
01315     /*char ip[128];
01316     ip[0]=0;
01317     unsigned long ip_=sock_resolve(host,ip).S_un.S_addr;
01318     if(ip_!=0) {*/
01319         irc_socket=sock_connect((char*)bind_ip,(char*)host,port,ec,true);
01320         irc_last_keepalive_detection=time(NULL);
01321         if(ec) {
01322             irc_socket.clear();
01323             log_socket(ec,sock_error(ec),"while calling sock_connect in file " __FILE__ " in function " __FUNC__);
01324             return ec;
01325         }
01326     /*} else {
01327         irc_socket.clear();
01328         string str="Cannot resolve host \"";
01329         str+=host;
01330         str+="\" to IP address in file " __FILE__ " in function " __FUNC__;
01331         log_socket(-1,"DNS",str.c_str());
01332         return -1;
01333     }*/
01334 
01335     stats_irc_new_connection(host,port);
01336 
01337     return 0;
01338 }
01339 
01340 /*!
01341     \brief Parses and evaluates RPL_ISUPPORT reply (005 numerics)
01342     \author VooDooMan
01343     \version 1
01344     \date 2004
01345     \param str Line of message from server
01346 */
01347 void irc_RPL_ISUPPORT(string str)
01348 {
01349     // BotNick RFC2812 PREFIX=(ov)@+ CHANTYPES=#&!+ MODES=3 CHANLIMIT=#&!+:31 NICKLEN=9 TOPICLEN=160 KICKLEN=160 MAXLIST=beIR:42 CHANNELLEN=50 IDCHAN=!:5 CHANMODES=beIR,k,l,imnpstaqr :are supported by this server
01350 
01351     unsigned int i1;
01352 
01353     for(i1=0; i1<str.length(); i1++)
01354         if(str[i1]==0x20)
01355             break;
01356     str.erase(0,i1+1); // erase my nick
01357 
01358     string feature1, feature2;
01359     while(str.length()>0) {
01360         feature1="";
01361         feature2="";
01362         int context=0;
01363         while(str.length()>0) {
01364             if(str[0]!=0x20) {
01365                 if(str[0]=='=' && context==0) {
01366                     context++;
01367                     str.erase(0,1);
01368                     continue;
01369                 }
01370                 if(context==0)
01371                     feature1+=str[0];
01372                 else
01373                     feature2+=str[0];
01374             } else {
01375                 str.erase(0,1);
01376                 break;
01377             }
01378             str.erase(0,1);
01379         }
01380         if(feature1.length()>0 && feature1[0]==':') {
01381             // end of list - comment found
01382             break;
01383         }
01384         pair<string,string> p;
01385         p.first=feature1;
01386         p.second=feature2;
01387         irc_isupport.raw.insert(p);
01388         if(!feature1.compare("CHANMODES")) {
01389             int context=0;
01390             string str=feature2;
01391             while(str.length()>0) {
01392                 if(str[0]==',') {
01393                     context++;
01394                     str.erase(0,1);
01395                     continue;
01396                 }
01397                 if(context==0)
01398                     irc_isupport.chanmodes_a+=str[0];
01399                 if(context==1)
01400                     irc_isupport.chanmodes_b+=str[0];
01401                 if(context==2)
01402                     irc_isupport.chanmodes_c+=str[0];
01403                 if(context==3)
01404                     irc_isupport.chanmodes_d+=str[0];
01405                 str.erase(0,1);
01406             }
01407         }
01408         if(!feature1.compare("PREFIX")) {
01409             int context=0;
01410             string str=feature2;
01411             string first, second;
01412             while(str.length()>0) {
01413                 if(str[0]=='(') {
01414                     str.erase(0,1);
01415                     continue;
01416                 }
01417                 if(str[0]==')') {
01418                     context++;
01419                     str.erase(0,1);
01420                     continue;
01421                 }
01422                 if(context==0)
01423                     first+=str[0];
01424                 if(context==1)
01425                     second+=str[0];
01426                 str.erase(0,1);
01427             }
01428             for(unsigned int i1=0; i1<first.length() && i1<second.length(); i1++) {
01429                 pair<char,char> p;
01430                 p.first=first[i1];
01431                 p.second=second[i1];
01432                 irc_isupport.prefix.insert(p);
01433             }
01434         }
01435         if(!feature1.compare("MODES")) {
01436             long modes=atol(feature2.c_str());
01437             if(modes==0)
01438                 modes=3;
01439             irc_isupport.max_modes=modes;
01440         }
01441     }
01442 }
01443 
01444 /*!
01445     \brief Parses and evaluates RPL_NAMREPLY reply (reply to NAME command)
01446     \author VooDooMan
01447     \version 1
01448     \date 2004
01449     \param str Line of message from server
01450 */
01451 void irc_RPL_NAMREPLY(string str)
01452 {
01453     unsigned int i1;
01454 
01455     for(i1=0; i1<str.length(); i1++)
01456         if(str[i1]==0x20)
01457             break;
01458     str.erase(0,i1+1); // erase numeric reply
01459 
01460     for(i1=0; i1<str.length(); i1++)
01461         if(str[i1]==0x20)
01462             break;
01463     str.erase(0,i1+1); // erase my nick
01464 
01465     for(i1=0; i1<str.length(); i1++)
01466         if(str[i1]==0x20)
01467             break;
01468     str.erase(0,i1+1); // erase '=' / '*' / '@'
01469 
01470     string channame;
01471     for(i1=0; i1<str.length(); i1++)
01472         if(str[i1]==0x20)
01473             break;
01474             else
01475             channame+=str[i1];
01476     str.erase(0,i1+1); // erase channel name
01477 
01478     for(i1=0; i1<str.length(); i1++)
01479         if(str[i1]==':')
01480             break;
01481     str.erase(0,i1+1); // erase everything before ':'
01482 
01483 l3:
01484     vector<s_online_channel>::iterator i;
01485     bool got_channel=false;
01486     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
01487         if(!cmp_strings_case_insensitive((*i).name,channame)) {
01488             got_channel=true;
01489             break;
01490         }
01491     }
01492     if(!got_channel) {
01493         // we are new on channel, right after JOIN
01494         s_online_channel chan;
01495         chan.name=channame;
01496         chan.modes="";
01497         chan.topic="";
01498         chan.users.clear();
01499         chan.bans.clear();
01500         chan.excepts.clear();
01501         chan.reops.clear();
01502         chan.b_reops_sent=chan.b_excepts_sent=chan.b_invites_sent=chan.b_bans_sent=false;
01503         irc_channels.push_back(chan);
01504         goto l3;
01505     }
01506 
01507     while(str.length()>0) {
01508         while(str.length()>0 && str[0]==0x20)
01509             str.erase(0,1);
01510 
01511         string nick;
01512         for(i1=0; i1<str.length(); i1++)
01513             if(str[i1]==0x20)
01514                 break;
01515                 else
01516                 nick+=str[i1];
01517         str.erase(0,i1); // erase nick
01518 
01519         while(str.length()>0 && str[0]==0x20)
01520             str.erase(0,1);
01521         while(nick.length()>0 && nick[0]==0x20)
01522             str.erase(0,1);
01523 
01524         char prefix='0';
01525         /*if(nick[0]=='+') {
01526             prefix='+';
01527             nick.erase(0,1);
01528         } else
01529             if(nick[0]=='@') {
01530                 prefix='@';
01531                 nick.erase(0,1);
01532             } else
01533                 if(nick[0]=='~') {
01534                     prefix='~';
01535                     nick.erase(0,1);
01536                 } else
01537                     if(nick[0]=='&') {
01538                         prefix='&';
01539                         nick.erase(0,1);
01540                     } else
01541                         if(nick[0]=='%') {
01542                             prefix='%';
01543                             nick.erase(0,1);
01544                         }*/
01545         if(irc_isupport.get_prefix2(nick[0])!='0') {
01546             prefix=nick[0];
01547             nick.erase(0,1);
01548         }
01549 
01550         bool got_user=false;
01551         if(nick.length()>0) {
01552     l4:
01553             vector<s_online_user>::iterator ii;
01554             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
01555                 if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
01556                     got_user=true;
01557                     break;
01558                 }
01559             }
01560             if(!got_user) {
01561                 s_online_user user;
01562                 user.nick=nick;
01563                 user.got_whois=false;
01564                 user.whois_sent=false;
01565                 user.on_join_called=false;
01566                 user.ident="";
01567                 user.host="";
01568                 user.fullname="";
01569                 user.got_mode=true;
01570                 if(prefix!='0')
01571                     user.mode=prefix;
01572                 else
01573                     user.mode="0";
01574                 user.irc_op=false;
01575                 user.just_joined=false;
01576                 user.old_mode="INVALID";
01577                 (*i).users.push_back(user);
01578                 goto l4;
01579             }
01580             if(!(*ii).got_whois) {
01581                 string str="WHOIS ";
01582                 str+=(*ii).nick;
01583                 (*ii).whois_sent=true;
01584                 irc_putserv(str.c_str(),true,HIGH_PRIORITY);
01585             } else {
01586                 if(!nick.compare(irc_nick) && prefix!='0') {
01587                     string source_user=logic_find_user(nick,irc_get_ident(nick),irc_get_host(nick),irc_get_fullname(nick),irc_is_ircop(nick));
01588                     string target_user=source_user;
01589                     logic_validate(channame,source_user,target_user,nick,nick,'+',prefix);
01590                 }
01591             }
01592         }
01593     }
01594 
01595     i1=0;
01596     vector<s_online_user>::iterator i2;
01597     s_online_channel* chan;
01598     if(irc_get_online_channel(channame,chan)) {
01599         i2=chan->users.begin();
01600         for(; i2!=chan->users.end(); i2++)
01601             i1++;
01602         if(i1==1) {
01603             string msg="WHOIS ";
01604             msg+=irc_nick;
01605             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
01606         }
01607 
01608         if(!chan->b_invites_sent && irc_isupport.chanmodes_a.find("I")!=string::npos) {
01609             chan->b_invites_sent=true;
01610             string inv="MODE ";
01611             inv+=channame;
01612             inv+=" +I";
01613             irc_putserv(inv.c_str(),true,HIGH_PRIORITY);
01614         }
01615 
01616         if(!chan->b_reops_sent && irc_isupport.chanmodes_a.find("R")!=string::npos) {
01617             chan->b_reops_sent=true;
01618             string inv="MODE ";
01619             inv+=channame;
01620             inv+=" +R";
01621             irc_putserv(inv.c_str(),true,HIGH_PRIORITY);
01622         }
01623     }
01624 }
01625 
01626 /*!
01627     \brief Checks wheter user is found on channel
01628     \author VooDooMan
01629     \version 1
01630     \date 2004
01631     \param nick Nick name
01632     \param channel Channel name
01633     \retval true If user is on channel
01634     \retval false If user isn't on channel
01635 */
01636 bool irc_check_nick_on_channel(string nick, string channel)
01637 {
01638     vector<s_online_channel>::iterator i1;
01639     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
01640         if(!cmp_strings_case_insensitive((*i1).name,channel)) {
01641             vector<s_online_user>::iterator i2;
01642             for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++) {
01643                 if(!cmp_strings_case_insensitive((*i2).nick,nick))
01644                     return true;
01645             }
01646         }
01647     }
01648     return false;
01649 }
01650 
01651 /*!
01652     \brief Parses and evaluates RPL_WHOISUSER reply (partial reply to WHOIS command)
01653     \author VooDooMan
01654     \version 1
01655     \date 2004
01656     \param str Line of message from server
01657 */
01658 void irc_RPL_WHOISUSER(string str)
01659 {
01660     unsigned int i1;
01661 
01662     for(i1=0; i1<str.length(); i1++)
01663         if(str[i1]==0x20)
01664             break;
01665     str.erase(0,i1+1); // erase numeric reply
01666 
01667     for(i1=0; i1<str.length(); i1++)
01668         if(str[i1]==0x20)
01669             break;
01670     str.erase(0,i1+1); // erase my nick
01671 
01672     string nick;
01673     for(i1=0; i1<str.length(); i1++)
01674         if(str[i1]==0x20)
01675             break;
01676             else
01677             nick+=str[i1];
01678     str.erase(0,i1+1); // erase nick name
01679 
01680     string ident;
01681     for(i1=0; i1<str.length(); i1++)
01682         if(str[i1]==0x20)
01683             break;
01684             else
01685             ident+=str[i1];
01686     str.erase(0,i1+1); // erase ident
01687 
01688     string host;
01689     for(i1=0; i1<str.length(); i1++)
01690         if(str[i1]==0x20)
01691             break;
01692             else
01693             host+=str[i1];
01694     str.erase(0,i1+1); // erase host
01695 
01696     logic_resolve(host);
01697     logic_resolve6(host);
01698 
01699     for(i1=0; i1<str.length(); i1++)
01700         if(str[i1]==':')
01701             break;
01702     str.erase(0,i1+1); // erase everything before ':'
01703 
01704     string fullname;
01705     for(i1=0; i1<str.length(); i1++)
01706         fullname+=str[i1];
01707 
01708     vector<s_online_channel>::iterator i;
01709     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
01710         vector<s_online_user>::iterator ii;
01711         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
01712             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
01713                 (*ii).got_whois=true;
01714                 (*ii).whois_sent=true;
01715                 (*ii).ident=ident;
01716                 (*ii).host=host;
01717                 (*ii).fullname=fullname;
01718 
01719                 (*ii).in_logic_as=logic_find_user((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,(*ii).irc_op);
01720 
01721                 if((*ii).just_joined && !(*ii).on_join_called) {
01722                     (*ii).just_joined=false;
01723                     logic_on_join((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,(*ii).just_joined_channel,(*ii).irc_op);
01724                 } else {
01725                     if(((*ii).mode.compare((*ii).old_mode) && (*ii).old_mode.compare("INVALID")) || (*ii).nick.compare((*ii).old_nick))
01726                         if(!(*ii).on_join_called)
01727                             logic_on_nick_validate((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,(*i).name,(*ii).irc_op,true);
01728                 }
01729                 irc_check_for_filesystem((*ii).in_logic_as,(*i).name,(*ii).nick);
01730                 (*ii).on_join_called=true;
01731                 (*ii).old_mode=(*ii).mode;
01732                 (*ii).old_nick=(*ii).nick;
01733             }
01734         }
01735     }
01736 
01737     vector<s_online_user>::iterator ii;
01738     for(ii=tmp_users.begin(); ii!=tmp_users.end(); ii++) {
01739         if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
01740             (*ii).got_whois=true;
01741             (*ii).whois_sent=true;
01742             (*ii).ident=ident;
01743             (*ii).host=host;
01744             (*ii).fullname=fullname;
01745 
01746             (*ii).in_logic_as=logic_find_user((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,(*ii).irc_op);
01747         }
01748     }
01749 
01750     vector<s_dcc_request_whois>::iterator i2;
01751     for(i2=dcc_request_whois.begin(); i2!=dcc_request_whois.end(); i2++) {
01752         if(!(*i2).nick.compare(nick)) {
01753             (*i2).full_name=fullname;
01754             (*i2).got_whois=true;
01755             (*i2).host=host;
01756             (*i2).ident=ident;
01757             irc_quoted_callback((*i2).str.c_str(),(*i2).nick.c_str(),(*i2).host_mask.c_str());
01758             break;
01759         }
01760     }
01761     
01762     bool irc_op=false; // assume that it is not an irc operator
01763 
01764     if(!cmp_strings_case_insensitive(nick,irc_nick)) {
01765         // after re-JOIN to get op
01766         logic_on_nick_validate(nick,ident,host,fullname,logic_find_user(nick,ident,host,fullname,irc_op),irc_op,true);
01767 
01768         vector<s_online_channel>::iterator i1;
01769         for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
01770             vector<s_online_user>::iterator i2;
01771             for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++) {
01772                 if((*i2).got_whois)
01773                     (*i2).in_logic_as=logic_find_user((*i2).nick,(*i2).ident,(*i2).host,(*i2).fullname,(*i2).irc_op);
01774                 logic_on_nick_validate((*i2).nick,(*i2).ident,(*i2).host,(*i2).fullname,(*i1).name,(*i2).irc_op,true);
01775             }
01776         }
01777     }
01778 }
01779 
01780 /*!
01781     \brief Parses and evaluates RPL_YOURID reply (your unique ID)
01782     \author VooDooMan
01783     \version 1
01784     \date 2004
01785     \param str Line of message from server
01786 */
01787 void irc_RPL_YOURID(string str)
01788 {
01789     unsigned int i1;
01790 
01791     for(i1=0; i1<str.length(); i1++)
01792         if(str[i1]==0x20)
01793             break;
01794     str.erase(0,i1+1); // erase server name
01795 
01796     for(i1=0; i1<str.length(); i1++)
01797         if(str[i1]==0x20)
01798             break;
01799     str.erase(0,i1+1); // erase numeric reply
01800 
01801     for(i1=0; i1<str.length(); i1++)
01802         if(str[i1]==0x20)
01803             break;
01804     str.erase(0,i1+1); // erase my nick
01805 
01806     string id;
01807     for(i1=0; i1<str.length(); i1++)
01808         if(str[i1]==0x20)
01809             break;
01810             else
01811             id+=str[i1];
01812     str.erase(0,i1+1); // erase ID
01813 
01814     if(id.length()<sizeof(irc_unique_id))
01815         strcpy(irc_unique_id,id.c_str());
01816 }
01817 
01818 /*!
01819     \brief Parses and evaluates RPL_WHOISOPERATOR reply (partial reply to WHOIS command)
01820     \author VooDooMan
01821     \version 1
01822     \date 2004
01823     \param str Line of message from server
01824 */
01825 void irc_RPL_WHOISOPERATOR(string str)
01826 {
01827     unsigned int i1;
01828 
01829     for(i1=0; i1<str.length(); i1++)
01830         if(str[i1]==0x20)
01831             break;
01832     str.erase(0,i1+1); // erase numeric reply
01833 
01834     for(i1=0; i1<str.length(); i1++)
01835         if(str[i1]==0x20)
01836             break;
01837     str.erase(0,i1+1); // erase my nick
01838 
01839     string nick;
01840     for(i1=0; i1<str.length(); i1++)
01841         if(str[i1]==0x20)
01842             break;
01843             else
01844             nick+=str[i1];
01845     str.erase(0,i1+1); // erase nick name
01846 
01847     for(i1=0; i1<str.length(); i1++)
01848         if(str[i1]==':')
01849             break;
01850     str.erase(0,i1+1); // erase everything before ':'
01851 
01852     string chan;
01853 
01854     vector<s_online_channel>::iterator i;
01855     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
01856         vector<s_online_user>::iterator ii;
01857         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
01858             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
01859                 if(!(*ii).irc_op) {
01860                     string host_mask=nick;
01861                     host_mask+="!";
01862                     host_mask+=(*ii).ident;
01863                     host_mask+="@";
01864                     host_mask+=(*ii).host;
01865                     log_channel((*i).name.c_str(),TYPE_IRCOP_JOIN,host_mask.c_str(),"","",irc_get_modes_for_log((*i).name,nick).c_str());
01866                 }
01867                 (*ii).irc_op=true;
01868                 chan=(*i).name;
01869             }
01870         }
01871     }
01872 
01873     vector<s_online_user>::iterator ii;
01874     for(ii=tmp_users.begin(); ii!=tmp_users.end(); ii++) {
01875         if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
01876             (*ii).irc_op=true;
01877         }
01878     }
01879 
01880     logic_on_ircop(chan,nick,true);
01881 
01882     vector<s_dcc_request_whois>::iterator i2;
01883     for(i2=dcc_request_whois.begin(); i2!=dcc_request_whois.end(); i2++) {
01884         if(!(*i2).nick.compare(nick)) {
01885             (*i2).irc_op=true;
01886             break;
01887         }
01888     }
01889 }
01890 
01891 /*
01892     \brief Parses and evaluates RPL_WHOISCHANNELS reply (partial reply to WHOIS command)
01893     \author VooDooMan
01894     \version 1
01895     \date 2004
01896     \param str Line of message from server
01897 */
01898 void irc_RPL_WHOISCHANNELS(string str)
01899 {
01900     unsigned int i1;
01901 
01902     for(i1=0; i1<str.length(); i1++)
01903         if(str[i1]==0x20)
01904             break;
01905     str.erase(0,i1+1); // erase numeric reply
01906 
01907     for(i1=0; i1<str.length(); i1++)
01908         if(str[i1]==0x20)
01909             break;
01910     str.erase(0,i1+1); // erase my nick
01911 
01912     string nick;
01913     for(i1=0; i1<str.length(); i1++)
01914         if(str[i1]==0x20)
01915             break;
01916             else
01917             nick+=str[i1];
01918     str.erase(0,i1+1); // erase nick name
01919 
01920     for(i1=0; i1<str.length(); i1++)
01921         if(str[i1]==':')
01922             break;
01923     str.erase(0,i1+1); // erase everything before ':'
01924 
01925     while(str.length()>0) {
01926         string chan;
01927         for(i1=0; i1<str.length(); i1++)
01928             if(str[i1]==0x20)
01929                 break;
01930                 else
01931                 chan+=str[i1];
01932         str.erase(0,i1+1); // erase [@]#channame
01933 
01934         if(chan.length()==0)
01935             continue;
01936 
01937         char prefix='0';
01938         /*if(chan[0]=='@' || /*chan[0]=='+' ||*] chan[0]=='~' || chan[0]=='&' || chan[0]=='%')
01939             prefix=chan[0];
01940         else
01941             if(chan[0]=='+') {
01942                 if(chan.length()>1 && chan[1]!='#' && chan[1]!='!' && chan[1]!='&' && chan[1]!='+')
01943                     // we got +channel = channel name is "+channel" of type '+'
01944                     prefix='0';
01945                 else
01946                     // we got +?channel = channel name is "#channel" or "!channel",..., but with mode of '+' - voice
01947                     prefix='+';
01948             }*/
01949         if(irc_isupport.get_prefix2(chan[0])!='0')
01950             prefix=chan[0];
01951         if(prefix=='+') {
01952             string chantypes;
01953             map<string,string>::iterator iii;
01954             for(iii=irc_isupport.raw.begin(); iii!=irc_isupport.raw.end(); iii++)
01955                 if(!(*iii).first.compare("CHANTYPES")) {
01956                     chantypes=(*iii).second;
01957                     break;
01958                 }
01959             if(chan.length()>1 && chantypes.find(chan[1])==string::npos)
01960                 // we got +channel = channel name is "+channel" of type '+'
01961                 prefix='0';
01962             if(chan.length()>1 && chantypes.find(chan[1])!=string::npos)
01963                 // we got +?channel = channel name is "#channel" or "!channel",..., but with mode of '+' - voice
01964                 prefix='+';
01965             if(chan.length()==1)
01966                 // we got "+" = channel name is "+" of type '+'
01967                 prefix='0';
01968         }
01969         if(prefix!='0')
01970             chan.erase((unsigned int)0,(unsigned int)1);
01971 
01972         vector<s_online_channel>::iterator i;
01973         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
01974             vector<s_online_user>::iterator ii;
01975             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
01976                 if(!cmp_strings_case_insensitive((*ii).nick,nick) && !cmp_strings_case_insensitive((*i).name,chan)) {
01977                     (*ii).got_mode=true;
01978                     if(prefix!='0')
01979                         (*ii).mode=prefix;
01980                     else
01981                         (*ii).mode="0";
01982 
01983                     if((*ii).got_whois && !(*ii).on_join_called) {
01984                         logic_on_join((*ii).nick, (*ii).ident, (*ii).host, (*ii).fullname, chan, (*ii).irc_op);
01985 
01986                         irc_check_for_filesystem((*ii).in_logic_as,(*i).name,(*ii).nick);
01987                     }
01988                     if(!(*ii).nick.compare(irc_nick) && (*ii).mode.compare((*ii).old_mode)) {
01989                         // there it will go on channel cycle
01990                         if((*ii).mode.length() && (*ii).mode.compare("0"))
01991                             logic_validate((*i).name,"",(*ii).in_logic_as,"",(*ii).nick,'+',(*ii).mode[0]);
01992                         (*ii).old_mode=(*ii).mode;
01993                     }
01994                     (*ii).on_join_called=true;
01995                 }
01996             }
01997         }
01998     }
01999 }
02000 
02001 /*!
02002     \brief Finds out if user has access to partyline; adds entry to tmp_users and performs WHOIS command if user is unknown yet
02003     \author VooDooMan
02004     \version 1
02005     \date 2004
02006     \param hostmask Host mask of user ("nick!ident@host")
02007     \param user_name_as_in_logic Returns user's name as defined in logic.txt
02008     \param msg Sets this string to dcc_msg member to tmp_users entry if user is not known yet
02009     \return Returns true if user has access to partyline
02010 */
02011 bool irc_access_to_partyline(const char* hostmask, string& user_name_as_in_logic, string msg)
02012 {
02013     string str=hostmask;
02014 
02015     string nick;
02016     unsigned int i1;
02017     for(i1=0; i1<str.length(); i1++)
02018         if(str[i1]=='!')
02019             break;
02020             else
02021             nick+=str[i1];
02022     str.erase(0,i1+1); // erase nick name
02023 
02024     string ident;
02025     for(i1=0; i1<str.length(); i1++)
02026         if(str[i1]=='@')
02027             break;
02028             else
02029             ident+=str[i1];
02030     str.erase(0,i1+1); // erase ident
02031 
02032     string host;
02033     for(i1=0; i1<str.length(); i1++)
02034         if(str[i1]==0x20)
02035             break;
02036             else
02037             host+=str[i1];
02038     str.erase(0,i1+1); // erase host
02039 
02040     vector<s_online_channel>::iterator i;
02041     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02042         vector<s_online_user>::iterator ii;
02043         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
02044             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
02045                 return logic_access_to_partyline((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,(*ii).irc_op,user_name_as_in_logic);
02046             }
02047         }
02048     }
02049 
02050     vector<s_online_user>::iterator ii;
02051     for(ii=tmp_users.begin(); ii!=tmp_users.end(); ii++) {
02052         if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
02053             return logic_access_to_partyline((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,(*ii).irc_op,user_name_as_in_logic);
02054         }
02055     }
02056 
02057     s_online_user u;
02058     u.nick=nick;
02059     u.got_whois=false;
02060     u.whois_sent=true;
02061     u.on_join_called=false;
02062     u.ident=ident;
02063     u.host=host;
02064     u.fullname="";
02065     u.got_mode=false;
02066     u.mode="0";
02067     u.irc_op=false;
02068     u.in_logic_as="";
02069     time(&u.last_whois);
02070     u.dcc_msg=msg;
02071     u.just_joined=false;
02072     u.old_mode="INVALID";
02073     tmp_users.push_back(u);
02074 
02075     char tmp[1024];
02076     strcpy(tmp,"WHOIS ");
02077     strcat(tmp,nick.c_str());
02078     irc_putserv(tmp,true,HIGH_PRIORITY);
02079 
02080     return false;
02081 }
02082 
02083 /*!
02084     \brief This must be called as RPL_ENDOFWHOIS reply from server - the end of WHOIS list for user
02085     \author VooDooMan
02086     \version 1
02087     \date 2004
02088     \param str Message line from server
02089 */
02090 void irc_RPL_ENDOFWHOIS(string str)
02091 {
02092     unsigned int i1;
02093 
02094     for(i1=0; i1<str.length(); i1++)
02095         if(str[i1]==0x20)
02096             break;
02097     str.erase(0,i1+1); // erase numeric reply
02098 
02099     for(i1=0; i1<str.length(); i1++)
02100         if(str[i1]==0x20)
02101             break;
02102     str.erase(0,i1+1); // erase my nick
02103 
02104     string nick;
02105     for(i1=0; i1<str.length(); i1++)
02106         if(str[i1]==0x20)
02107             break;
02108             else
02109             nick+=str[i1];
02110     str.erase(0,i1+1); // erase nick name
02111 
02112     vector<s_online_user>::iterator ii;
02113     for(ii=tmp_users.begin(); ii!=tmp_users.end(); ii++) {
02114         if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
02115             string hm=(*ii).nick;
02116             hm+="!";
02117             hm+=(*ii).ident;
02118             hm+="@";
02119             hm+=(*ii).host;
02120             string user_name_as_in_logic;
02121             if(irc_access_to_partyline(hm.c_str(),user_name_as_in_logic,(*ii).dcc_msg)) {
02122                 int dcc_group=0;
02123                 string dcc=dcc_get_string((*ii).dcc_msg,dcc_group);
02124                 string dcc_host=logic_get_dcc_host(dcc_group,user_name_as_in_logic);
02125                 if(dcc.compare("")) {
02126                     string str="\x01";
02127                     str+=dcc;
02128                     str+="\x01";
02129                     irc_privmsg(nick.c_str(),str.c_str(),LOW_PRIORITY);
02130                     s_dcc_awaiting_user user;
02131 
02132                     user.nick=nick;
02133                     user.ident=irc_get_ident(nick);
02134                     user.host=irc_get_host(nick);
02135                     user.fullname=irc_get_fullname(nick);
02136 
02137                     size_t n=user_name_as_in_logic.length();
02138                     if(n>128-1)
02139                         n=128-1;
02140                     strncpy(user.user_name_as_in_logic,user_name_as_in_logic.c_str(),n);
02141                     user.user_name_as_in_logic[n]=0;
02142                     in_addr6_ ip6;
02143                     if(inet_pton(AF_INET6,dcc_host.c_str(),&ip6)!=1) {
02144                         user.addr4=sock_resolve(dcc_host.c_str(),NULL);
02145                         user.using_ipv6=false;
02146                     } else {
02147                         memcpy(&user.addr6,&ip6,sizeof(user.addr6));
02148 #ifdef _WIN32
02149                         user.addr4.S_un.S_addr=(unsigned long)-1;
02150 #else
02151                         user.addr4.s_addr=(unsigned long)-1;
02152 #endif
02153                         user.using_ipv6=true;
02154                     }
02155                     time(&user.start_time);
02156                     dcc_awaiting_users.push_back(user);
02157                 }
02158             }
02159             tmp_users.erase(ii);
02160             break;
02161         }
02162     }
02163 }
02164 
02165 /*!
02166     \brief This is called on bot's JOIN, if the bot finds out that some user in logic.txt is banned; it forces on_banned event procedure to be called
02167     \author VooDooMan
02168     \version 1
02169     \date 2004
02170     \param str Partial message from server containing numeric reply, channel name and mask
02171     \warning Must be called after irc_excepted() was called to ensure exceptions (+e) to bans were evaluated
02172 */
02173 void irc_banned(string str)
02174 {
02175     unsigned int i1;
02176 
02177     for(i1=0; i1<str.length(); i1++)
02178         if(str[i1]==0x20)
02179             break;
02180     str.erase(0,i1+1); // erase everything before SPACE
02181 
02182     for(i1=0; i1<str.length(); i1++)
02183         if(str[i1]==0x20)
02184             break;
02185     str.erase(0,i1+1); // erase numeric reply
02186 
02187     for(i1=0; i1<str.length(); i1++)
02188         if(str[i1]==0x20)
02189             break;
02190     str.erase(0,i1+1); // erase my nick
02191 
02192     string channel;
02193     for(i1=0; i1<str.length(); i1++)
02194         if(str[i1]==0x20)
02195             break;
02196             else
02197             channel+=str[i1];
02198     str.erase(0,i1+1); // erase channel_name
02199 
02200     string mask;
02201     for(i1=0; i1<str.length(); i1++)
02202         if(str[i1]==0x20)
02203             break;
02204             else
02205             mask+=str[i1];
02206     str.erase(0,i1+1); // erase mask
02207 
02208     vector<s_online_channel>::iterator i;
02209     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02210         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02211             (*i).bans.push_back(mask);
02212             logic_on_banned(channel, mask,(*i).excepts,(*i).invites,(*i).bans);
02213             break;
02214         }
02215     }
02216 }
02217 
02218 
02219 /*!
02220     \brief Stores informations about user to invite (+I)
02221     \author VooDooMan
02222     \version 1
02223     \date 2004
02224 */
02225 struct s_user_to_invite {
02226     string mask;                    //!< Host mask
02227     string user_name;                //!< Name of user from "logic.txt"
02228 
02229     s_user_to_invite()
02230     {
02231         mask="";
02232         user_name="";
02233     }
02234 };
02235 
02236 /*!
02237     \brief This is called on bot's JOIN, checks wheter some user in logic.txt is not invited; it forces on_not_invited event procedure to be called
02238     \author VooDooMan
02239     \version 1
02240     \date 2004
02241     \warning Must be called after irc_invited() was called to ensure invitations (+I) to override +i mode are in vector
02242 */
02243 void irc_check_for_not_invited(string channel)
02244 {
02245     vector<s_online_channel>::iterator i;
02246     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02247         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02248             vector<s_user_to_invite> invites;
02249             vector<s_channel>::iterator i1;
02250             map<string,string> vars;
02251             for(i1=r_channels.begin(); i1!=r_channels.end(); i1++) {
02252                 if(!cmp_strings_case_insensitive(logic_eval((*i1).channel_name,vars),channel)) {
02253                     if(!(*i1).host_unknown) {
02254                         s_user user;
02255                         if(logic_botnet_get_user((*i1).username,user)) {
02256                             vector<string>::iterator i5;
02257                             for(i5=user.hostmask.begin(); i5!=user.hostmask.end(); i5++) {
02258                                 s_user_to_invite u;
02259                                 u.mask=*i5;
02260                                 if(u.mask.length()>0 && u.mask[0]=='\"')
02261                                     u.mask.erase(0,1);
02262                                 if(u.mask.length()>0 && u.mask[u.mask.length()-1]=='\"')
02263                                     u.mask.erase(u.mask.length()-1,1);
02264                                 u.user_name=user.name;
02265                                 invites.push_back(u);
02266                             }
02267                         }
02268                     }
02269                 }
02270             }
02271             vector<s_user_to_invite>::iterator i4;
02272             for(i4=invites.begin(); i4!=invites.end(); i4++) {
02273                 bool invited=false;
02274                 vector<string>::iterator i3;
02275                 for(i3=(*i).invites.begin(); i3!=(*i).invites.end(); i3++) {
02276                     if(!match((char*)(*i3).c_str(),(char*)(*i4).mask.c_str())) {
02277                         invited=true;
02278                         break;
02279                     }
02280                 }
02281                 if(!invited) {
02282                     logic_on_not_invited(channel,(*i4).mask,(*i4).user_name);
02283                 }
02284             }
02285         }
02286     }
02287 }
02288 
02289 /*!
02290     \brief This is called on bot's JOIN, checks wheter some user in logic.txt is not in +R list; it forces on_not_in_reopped procedure to be called
02291     \author VooDooMan
02292     \version 1
02293     \date 2004
02294 */
02295 void irc_check_for_not_reopped(string channel)
02296 {
02297     vector<s_online_channel>::iterator i;
02298     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02299         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02300             vector<s_user_to_invite> invites;
02301             vector<s_channel>::iterator i1;
02302             map<string,string> vars;
02303             for(i1=r_channels.begin(); i1!=r_channels.end(); i1++) {
02304                 if(!cmp_strings_case_insensitive(logic_eval((*i1).channel_name,vars),channel)) {
02305                     if(!(*i1).host_unknown) {
02306                         s_user user;
02307                         if(logic_botnet_get_user((*i1).username,user)) {
02308                             vector<string>::iterator i5;
02309                             for(i5=user.hostmask.begin(); i5!=user.hostmask.end(); i5++) {
02310                                 s_user_to_invite u;
02311                                 u.mask=*i5;
02312                                 if(u.mask.length()>0 && u.mask[0]=='\"')
02313                                     u.mask.erase(0,1);
02314                                 if(u.mask.length()>0 && u.mask[u.mask.length()-1]=='\"')
02315                                     u.mask.erase(u.mask.length()-1,1);
02316                                 u.user_name=user.name;
02317                                 invites.push_back(u);
02318                             }
02319                         }
02320                     }
02321                 }
02322             }
02323             vector<s_user_to_invite>::iterator i4;
02324             for(i4=invites.begin(); i4!=invites.end(); i4++) {
02325                 bool invited=false;
02326                 vector<string>::iterator i3;
02327                 for(i3=(*i).reops.begin(); i3!=(*i).reops.end(); i3++) {
02328                     if(!match((char*)(*i3).c_str(),(char*)(*i4).mask.c_str())) {
02329                         invited=true;
02330                         break;
02331                     }
02332                 }
02333                 if(!invited) {
02334                     logic_on_not_in_reop(channel,(*i4).mask,(*i4).user_name);
02335                 }
02336             }
02337         }
02338     }
02339 }
02340 
02341 /*!
02342     \brief Called as +e exception mask to ban is found out on channel after bot's JOIN
02343     \author VooDooMan
02344     \version 1
02345     \date 2004
02346     \param str Partial reply from server containing numeric reply, channel name and +e mask
02347 */
02348 void irc_excepted(string str)
02349 {
02350     unsigned int i1;
02351 
02352     for(i1=0; i1<str.length(); i1++)
02353         if(str[i1]==0x20)
02354             break;
02355     str.erase(0,i1+1); // erase everything before SPACE
02356 
02357     for(i1=0; i1<str.length(); i1++)
02358         if(str[i1]==0x20)
02359             break;
02360     str.erase(0,i1+1); // erase numeric reply
02361 
02362     for(i1=0; i1<str.length(); i1++)
02363         if(str[i1]==0x20)
02364             break;
02365     str.erase(0,i1+1); // erase my nick
02366 
02367     string channel;
02368     for(i1=0; i1<str.length(); i1++)
02369         if(str[i1]==0x20)
02370             break;
02371             else
02372             channel+=str[i1];
02373     str.erase(0,i1+1); // erase channel_name
02374 
02375     string mask;
02376     for(i1=0; i1<str.length(); i1++)
02377         if(str[i1]==0x20)
02378             break;
02379             else
02380             mask+=str[i1];
02381     str.erase(0,i1+1); // erase mask
02382 
02383     vector<s_online_channel>::iterator i;
02384     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02385         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02386             (*i).excepts.push_back(mask);
02387             (*i).got_excepts=false;
02388             break;
02389         }
02390     }
02391 }
02392 
02393 /*!
02394     \brief Called as +I invitation mask to +i is found out on channel after bot's JOIN
02395     \author VooDooMan
02396     \version 1
02397     \date 2004
02398     \param str Partial reply from server containing numeric reply, channel name and +I mask
02399 */
02400 void irc_invited(string str)
02401 {
02402     unsigned int i1;
02403 
02404     for(i1=0; i1<str.length(); i1++)
02405         if(str[i1]==0x20)
02406             break;
02407     str.erase(0,i1+1); // erase everything before SPACE
02408 
02409     for(i1=0; i1<str.length(); i1++)
02410         if(str[i1]==0x20)
02411             break;
02412     str.erase(0,i1+1); // erase numeric reply
02413 
02414     for(i1=0; i1<str.length(); i1++)
02415         if(str[i1]==0x20)
02416             break;
02417     str.erase(0,i1+1); // erase my nick
02418 
02419     string channel;
02420     for(i1=0; i1<str.length(); i1++)
02421         if(str[i1]==0x20)
02422             break;
02423             else
02424             channel+=str[i1];
02425     str.erase(0,i1+1); // erase channel_name
02426 
02427     string mask;
02428     for(i1=0; i1<str.length(); i1++)
02429         if(str[i1]==0x20)
02430             break;
02431             else
02432             mask+=str[i1];
02433     str.erase(0,i1+1); // erase mask
02434 
02435     vector<s_online_channel>::iterator i;
02436     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02437         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02438             (*i).invites.push_back(mask);
02439             (*i).got_invites=false;
02440             break;
02441         }
02442     }
02443 }
02444 
02445 /*!
02446     \brief Called as +R reop mask is found out on channel after bot's JOIN
02447     \author VooDooMan
02448     \version 1
02449     \date 2004
02450     \param str Partial reply from server containing numeric reply, channel name and +R mask
02451 */
02452 void irc_in_reop(string str)
02453 {
02454     unsigned int i1;
02455 
02456     for(i1=0; i1<str.length(); i1++)
02457         if(str[i1]==0x20)
02458             break;
02459     str.erase(0,i1+1); // erase everything before SPACE
02460 
02461     for(i1=0; i1<str.length(); i1++)
02462         if(str[i1]==0x20)
02463             break;
02464     str.erase(0,i1+1); // erase numeric reply
02465 
02466     for(i1=0; i1<str.length(); i1++)
02467         if(str[i1]==0x20)
02468             break;
02469     str.erase(0,i1+1); // erase my nick
02470 
02471     string channel;
02472     for(i1=0; i1<str.length(); i1++)
02473         if(str[i1]==0x20)
02474             break;
02475             else
02476             channel+=str[i1];
02477     str.erase(0,i1+1); // erase channel_name
02478 
02479     string mask;
02480     for(i1=0; i1<str.length(); i1++)
02481         if(str[i1]==0x20)
02482             break;
02483             else
02484             mask+=str[i1];
02485     str.erase(0,i1+1); // erase mask
02486 
02487     vector<s_online_channel>::iterator i;
02488     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02489         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02490             (*i).reops.push_back(mask);
02491             (*i).got_reops=false;
02492             break;
02493         }
02494     }
02495 }
02496 
02497 /*!
02498     \brief Checks ban list on channel after bot's JOIN by sending "MODE \#channel +b" command to server
02499     \author VooDooMan
02500     \version 1
02501     \date 2004
02502     \param channel Name of channel
02503 */
02504 void irc_check_bans(string channel)
02505 {
02506     vector<s_online_channel>::iterator i;
02507     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02508         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02509             (*i).got_excepts=true;
02510             s_online_channel* chan;
02511             if(irc_get_online_channel(channel,chan)) {
02512                 if(!chan->b_bans_sent && irc_isupport.chanmodes_a.find("b")!=string::npos) {
02513                     chan->b_bans_sent=true;
02514                     string tmp="MODE ";
02515                     tmp+=channel;
02516                     tmp+=" +b";
02517                     irc_putserv(tmp.c_str(),true,HIGH_PRIORITY);
02518                 }
02519             }
02520             break;
02521         }
02522     }
02523 }
02524 
02525 /*!
02526     \brief Checks invites list on channel after bot's JOIN by sending "MODE \#channel +I" command to server
02527     \author VooDooMan
02528     \version 1
02529     \date 2004
02530     \param channel Name of channel
02531 */
02532 void irc_check_invites(string channel)
02533 {
02534     vector<s_online_channel>::iterator i;
02535     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02536         if(!cmp_strings_case_insensitive((*i).name,channel)) {
02537             (*i).got_invites=true;
02538             s_online_channel* chan;
02539             if(irc_get_online_channel(channel,chan)) {
02540                 if(!chan->b_invites_sent && irc_isupport.chanmodes_a.find("I")!=string::npos) {
02541                     chan->b_invites_sent=true;
02542                     string tmp="MODE ";
02543                     tmp+=channel;
02544                     tmp+=" +I";
02545                     irc_putserv(tmp.c_str(),true,HIGH_PRIORITY);
02546                 }
02547             }
02548             break;
02549         }
02550     }
02551 }
02552 
02553 /*!
02554     \brief Called when bot after JOIN has received message indicating end of +e exceptions / or error, that irc network doesn't support +e exceptions
02555     \author VooDooMan
02556     \version 1
02557     \date 2004
02558     \param str Partial reply from server, also containing channel name
02559 */
02560 void irc_end_of_excepted(string str)
02561 {
02562     unsigned int i1;
02563 
02564     for(i1=0; i1<str.length(); i1++)
02565         if(str[i1]==0x20)
02566             break;
02567     str.erase(0,i1+1); // erase everything before SPACE
02568 
02569     for(i1=0; i1<str.length(); i1++)
02570         if(str[i1]==0x20)
02571             break;
02572     str.erase(0,i1+1); // erase numeric reply
02573 
02574     for(i1=0; i1<str.length(); i1++)
02575         if(str[i1]==0x20)
02576             break;
02577     str.erase(0,i1+1); // erase my nick
02578 
02579     string channel;
02580     for(i1=0; i1<str.length(); i1++)
02581         if(str[i1]==0x20)
02582             break;
02583             else
02584             channel+=str[i1];
02585     str.erase(0,i1+1); // erase channel_name
02586 
02587     irc_check_bans(channel);
02588 }
02589 
02590 /*!
02591     \brief Finds s_online_user record in irc_channel list for user
02592     \author VooDooMan
02593     \version 1
02594     \date 2004
02595     \param nick Nick of user
02596     \return User entry
02597 */
02598 s_online_user irc_find_user(string nick)
02599 {
02600     vector<s_online_channel>::iterator i;
02601     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02602         vector<s_online_user>::iterator ii;
02603         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
02604             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
02605                 return *ii;
02606             }
02607         }
02608     }
02609     s_online_user u;
02610     u.nick=""; // do panic!
02611     return u;
02612 }
02613 
02614 /*!
02615     \brief Adds/remove new mode for user on channel
02616     \author VooDooMan
02617     \version 1
02618     \date 2004
02619     \param channel Name of channel
02620     \param nick Nick name
02621     \param from_nick Which nick set the mode?
02622     \param prefix '-' or '+'
02623     \param mode '@' for +o and or '+' for +v, or '&', '%', etc.
02624 */
02625 void irc_user_mode_change(string channel, string nick, string from_nick, char prefix, char mode)
02626 {
02627     if(!cmp_strings_case_insensitive(nick,irc_nick)) {
02628         logic_validate(channel,irc_find_user(from_nick).in_logic_as,logic_find_user(irc_nick,irc_get_ident(irc_nick),irc_get_host(irc_nick),irc_get_fullname(irc_nick),irc_is_ircop(irc_nick)),from_nick,irc_nick,prefix,mode);
02629 
02630         vector<s_online_channel>::iterator i;
02631         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02632             if(cmp_strings_case_insensitive((*i).name,channel))
02633                 continue;
02634             vector<s_online_user>::iterator ii;
02635             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
02636                 if((*ii).got_whois) {
02637                     if(!(*ii).nick.compare(irc_nick)) {
02638                         while((*ii).mode.find("0",0)!=string::npos)
02639                             (*ii).mode.erase((*ii).mode.find("0",0),1);
02640                         if(prefix=='+') {
02641                             while((*ii).mode.find(mode,0)!=string::npos)
02642                                 (*ii).mode.erase((*ii).mode.find(mode,0),1);
02643                             (*ii).mode+=mode;
02644                         } else {
02645                             while((*ii).mode.find(mode,0)!=string::npos)
02646                                 (*ii).mode.erase((*ii).mode.find(mode,0),1);
02647                         }
02648                         if((*ii).mode.empty())
02649                             (*ii).mode+="0";
02650                     }
02651 
02652                     logic_on_nick_validate((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,channel,(*ii).irc_op,(*ii).on_join_called);
02653                     (*ii).on_join_called=true;
02654                     (*ii).old_mode=(*ii).mode;
02655                 }
02656             }
02657         }
02658     }
02659 
02660     string from_user=irc_find_user(from_nick).in_logic_as;
02661 
02662     vector<s_online_channel>::iterator i1;
02663     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
02664         if(cmp_strings_case_insensitive((*i1).name,channel))
02665             continue;
02666         vector<s_online_user>::iterator i2;
02667         for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++) {
02668             if(!cmp_strings_case_insensitive((*i2).nick,nick)) {
02669                 string m=(*i2).mode;
02670                 while(m.find("0",0)!=string::npos)
02671                     m.erase(m.find("0",0),1);
02672                 if(prefix=='+') {
02673                     while(m.find(mode,0)!=string::npos)
02674                         m.erase(m.find(mode,0),1);
02675                     m+=mode;
02676                 } else {
02677                     while(m.find(mode,0)!=string::npos)
02678                         m.erase(m.find(mode,0),1);
02679                 }
02680                 if(m.empty())
02681                     m+="0";
02682                 (*i2).mode=m;
02683                 (*i2).got_mode=true;
02684 
02685                 logic_set_dynamic((*i2).in_logic_as,from_user,prefix,mode);
02686             }
02687         }
02688     }
02689 }
02690 
02691 /*!
02692     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +O/-O (creator) to user
02693     \author VooDooMan
02694     \version 1
02695     \date 2004
02696     \param channel Name of channel
02697     \param prefix Contains '+' or '-' prefix
02698     \param nick Nick of originator of MODE change
02699     \param ident Ident of originator of MODE change
02700     \param host Host of originator of MODE change
02701     \param whom Nick of target user
02702 */
02703 // +-O nick
02704 void irc_mode_change_creator(string channel, char prefix, string nick, string ident, string host, string whom)
02705 {
02706     irc_user_mode_change(channel,whom,nick,prefix,'@');
02707     s_online_user source=irc_find_user(nick);
02708     s_online_user target=irc_find_user(whom);
02709 
02710     if(!source.nick.compare("")) {
02711         string log;
02712         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #1: unknown nick ";
02713         log+=nick;
02714         log+="!";
02715         log+=ident;
02716         log+="@";
02717         log+=host;
02718         log_debug(log.c_str());
02719         return;
02720     }
02721 
02722     if(!target.nick.compare("")) {
02723         string log;
02724         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #2: unknown nick ";
02725         log+=whom;
02726         log_debug(log.c_str());
02727         return;
02728     }
02729 
02730     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
02731     string target_user=logic_find_user(target.nick,target.ident,target.host,target.fullname,target.irc_op);
02732 
02733     if(cmp_strings_case_insensitive(whom,irc_nick)) // we have already called it above
02734         logic_validate(channel,source_user,target_user,source.nick,target.nick,prefix,'O');
02735 }
02736 
02737 /*!
02738     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +o/-o (op-erator) to user
02739     \author VooDooMan
02740     \version 1
02741     \date 2004
02742     \param channel Name of channel
02743     \param prefix Contains '+' or '-' prefix
02744     \param nick Nick of originator of MODE change
02745     \param ident Ident of originator of MODE change
02746     \param host Host of originator of MODE change
02747     \param whom Nick of target user
02748 */
02749 // +-o nick
02750 void irc_mode_change_op(string channel, char prefix, string nick, string ident, string host, string whom)
02751 {
02752     irc_user_mode_change(channel,whom,nick,prefix,'@');
02753 
02754     if(!nick.compare(irc_nick))
02755         return;
02756 
02757     s_online_user source=irc_find_user(nick);
02758     s_online_user target=irc_find_user(whom);
02759 
02760     if(prefix=='+' && !cmp_strings_case_insensitive(nick,irc_nick)) {
02761         vector<s_online_channel>::iterator i1;
02762         for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
02763             vector<s_online_user>::iterator i2;
02764             for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++)
02765                 if((*i2).got_whois) {
02766                     if((*i2).mode.compare((*i2).old_mode))
02767                         logic_on_nick_validate((*i2).nick,(*i2).ident,(*i2).host,(*i2).fullname,(*i1).name,(*i2).irc_op,(*i2).on_join_called);
02768                     (*i2).on_join_called=true;
02769                     (*i2).old_mode=(*i2).mode;
02770                 }
02771         }
02772     }
02773 
02774     if(!source.nick.compare("")) {
02775         string log;
02776         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #3: unknown nick ";
02777         log+=nick;
02778         log+="!";
02779         log+=ident;
02780         log+="@";
02781         log+=host;
02782         log_debug(log.c_str());
02783         return;
02784     }
02785 
02786     if(!target.nick.compare("")) {
02787         string log;
02788         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #4: unknown nick ";
02789         log+=whom;
02790         log_debug(log.c_str());
02791         return;
02792     }
02793 
02794     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
02795     string target_user=logic_find_user(target.nick,target.ident,target.host,target.fullname,target.irc_op);
02796 
02797     if(cmp_strings_case_insensitive(whom,irc_nick)) // we have already called it above
02798         logic_validate(channel,source_user,target_user,source.nick,target.nick,prefix,'@');
02799 
02800     if(prefix=='+') {
02801         if(!cmp_strings_case_insensitive(target.nick,(string)irc_nick)) {
02802             vector<s_online_channel>::iterator i;
02803             for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02804                 if((*i).got_excepts) {
02805                     irc_check_bans((*i).name);
02806                 }
02807                 irc_check_invites((*i).name);
02808             }
02809         }
02810     }
02811 }
02812 
02813 /*!
02814     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +v/-v (voice) to user
02815     \author VooDooMan
02816     \version 1
02817     \date 2004
02818     \param channel Name of channel
02819     \param prefix Contains '+' or '-' prefix
02820     \param nick Nick of originator of MODE change
02821     \param ident Ident of originator of MODE change
02822     \param host Host of originator of MODE change
02823     \param whom Nick of target user
02824 */
02825 // +-v nick
02826 void irc_mode_change_voice(string channel, char prefix, string nick, string ident, string host, string whom)
02827 {
02828     irc_user_mode_change(channel,whom,nick,prefix,'+');
02829     s_online_user source=irc_find_user(nick);
02830     s_online_user target=irc_find_user(whom);
02831 
02832     if(!source.nick.compare("")) {
02833         string log;
02834         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #5: unknown nick ";
02835         log+=nick;
02836         log+="!";
02837         log+=ident;
02838         log+="@";
02839         log+=host;
02840         log_debug(log.c_str());
02841         return;
02842     }
02843 
02844     if(!target.nick.compare("")) {
02845         string log;
02846         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #6: unknown nick ";
02847         log+=whom;
02848         log_debug(log.c_str());
02849         return;
02850     }
02851 
02852     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
02853     string target_user=logic_find_user(target.nick,target.ident,target.host,target.fullname,target.irc_op);
02854 
02855     if(cmp_strings_case_insensitive(whom,irc_nick)) // we have already called it above
02856         logic_validate(channel,source_user,target_user,source.nick,target.nick,prefix,'+');
02857 }
02858 
02859 /*!
02860     \brief Evaluates, and validates (or accidentally calls specific event) MODE change with other modes to user
02861     \author VooDooMan
02862     \version 1
02863     \date 2004
02864     \param channel Name of channel
02865     \param prefix Contains '+' or '-' prefix
02866     \param mode '~', '&', or '%'
02867     \param nick Nick of originator of MODE change
02868     \param ident Ident of originator of MODE change
02869     \param host Host of originator of MODE change
02870     \param whom Nick of target user
02871 */
02872 void irc_mode_change_other(string channel, char prefix, char mode, string nick, string ident, string host, string whom)
02873 {
02874     irc_user_mode_change(channel,whom,nick,prefix,mode);
02875     s_online_user source=irc_find_user(nick);
02876     s_online_user target=irc_find_user(whom);
02877 
02878     if(!source.nick.compare("")) {
02879         string log;
02880         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #7: unknown nick ";
02881         log+=nick;
02882         log+="!";
02883         log+=ident;
02884         log+="@";
02885         log+=host;
02886         log_debug(log.c_str());
02887         return;
02888     }
02889 
02890     if(!target.nick.compare("")) {
02891         string log;
02892         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #8: unknown nick ";
02893         log+=whom;
02894         log_debug(log.c_str());
02895         return;
02896     }
02897 
02898     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
02899     string target_user=logic_find_user(target.nick,target.ident,target.host,target.fullname,target.irc_op);
02900 
02901     if(cmp_strings_case_insensitive(whom,irc_nick)) // we have already called it above
02902         logic_validate(channel,source_user,target_user,source.nick,target.nick,prefix,mode);
02903 }
02904 
02905 /*!
02906     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/-a,i,m,n,q,p,s,r,t to channel
02907     \author VooDooMan
02908     \version 1
02909     \date 2004
02910     \param channel Name of channel
02911     \param prefix Contains '+' or '-' prefix
02912     \param mode One of followig: 'a', 'i', 'm', 'n', 'q', 'p', 's', 'r', 't'
02913     \param nick Nick of originator of MODE change
02914     \param ident Ident of originator of MODE change
02915     \param host Host of originator of MODE change
02916 */
02917 // +-aimnqpsrt
02918 void irc_mode_change_chan_status(string channel, char prefix, char mode, string nick, string ident, string host)
02919 {
02920     {
02921         vector<s_online_channel>::iterator i;
02922         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02923             if(cmp_strings_case_insensitive((*i).name,channel))
02924                 continue;
02925             while((*i).modes.find(mode,0)!=string::npos)
02926                 (*i).modes.erase((*i).modes.find(mode,0),1);
02927             if(prefix=='+')
02928                 (*i).modes+=(string)""+mode;
02929             break;
02930         }
02931     }
02932 
02933     s_online_user source=irc_find_user(nick);
02934 
02935     if(!source.nick.compare("")) {
02936         string log;
02937         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #9: unknown nick ";
02938         log+=nick;
02939         log+="!";
02940         log+=ident;
02941         log+="@";
02942         log+=host;
02943         log_debug(log.c_str());
02944         return;
02945     }
02946 
02947     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
02948 
02949     logic_validate_chan_mode(channel,source_user,source.nick,prefix,mode);
02950 }
02951 
02952 /*!
02953     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/-k KEY to channel
02954     \author VooDooMan
02955     \version 1
02956     \date 2004
02957     \param channel Name of channel
02958     \param prefix Contains '+' or '-' prefix
02959     \param nick Nick of originator of MODE change
02960     \param ident Ident of originator of MODE change
02961     \param host Host of originator of MODE change
02962     \param key Parameter to +/-k mode (key)
02963 */
02964 // +-k [key]
02965 void irc_mode_change_chan_key(string channel, char prefix, string nick, string ident, string host, string key)
02966 {
02967     {
02968         vector<s_online_channel>::iterator i;
02969         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
02970             if(cmp_strings_case_insensitive((*i).name,channel))
02971                 continue;
02972             if(prefix=='+')
02973                 (*i).key=key;
02974             else
02975                 (*i).key="";
02976             break;
02977         }
02978     }
02979 
02980     s_online_user source=irc_find_user(nick);
02981 
02982     if(!source.nick.compare("")) {
02983         string log;
02984         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #10: unknown nick ";
02985         log+=nick;
02986         log+="!";
02987         log+=ident;
02988         log+="@";
02989         log+=host;
02990         log_debug(log.c_str());
02991         return;
02992     }
02993 
02994     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
02995 
02996     logic_validate_chan_key(channel,source_user,source.nick,prefix,key);
02997 }
02998 
02999 /*!
03000     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/-l NUMBER to channel
03001     \author VooDooMan
03002     \version 1
03003     \date 2004
03004     \param channel Name of channel
03005     \param prefix Contains '+' or '-' prefix
03006     \param nick Nick of originator of MODE change
03007     \param ident Ident of originator of MODE change
03008     \param host Host of originator of MODE change
03009     \param limit Parameter to +/-l mode (limit - number)
03010 */
03011 // +-l [limit]
03012 void irc_mode_change_chan_limit(string channel, char prefix, string nick, string ident, string host, string limit)
03013 {
03014     {
03015         vector<s_online_channel>::iterator i;
03016         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
03017             if(cmp_strings_case_insensitive((*i).name,channel))
03018                 continue;
03019             if(prefix=='+')
03020                 (*i).limit=limit;
03021             else
03022                 (*i).limit="";
03023             break;
03024         }
03025     }
03026 
03027     s_online_user source=irc_find_user(nick);
03028 
03029     if(!source.nick.compare("")) {
03030         string log;
03031         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #11: unknown nick ";
03032         log+=nick;
03033         log+="!";
03034         log+=ident;
03035         log+="@";
03036         log+=host;
03037         log_debug(log.c_str());
03038         return;
03039     }
03040 
03041     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
03042 
03043     logic_validate_chan_limit(channel,source_user,source.nick,prefix,limit);
03044 }
03045 
03046 /*!
03047     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/-b to channel
03048     \author VooDooMan
03049     \version 1
03050     \date 2004
03051     \param channel Name of channel
03052     \param prefix Contains '+' or '-' prefix
03053     \param nick Nick of originator of MODE change
03054     \param ident Ident of originator of MODE change
03055     \param host Host of originator of MODE change
03056     \param mask Parameter to +/-b mode (mask)
03057 */
03058 // +-b mask
03059 void irc_mode_change_ban(string channel, char prefix, string nick, string ident, string host, string mask)
03060 {
03061     {
03062         vector<s_online_channel>::iterator i;
03063         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
03064             if(cmp_strings_case_insensitive((*i).name,channel))
03065                 continue;
03066             vector<string>::iterator i1;
03067         again1:
03068             for(i1=(*i).bans.begin(); i1!=(*i).bans.end(); i1++)
03069                 if(!mask.compare(*i1)) {
03070                     (*i).bans.erase(i1);
03071                     goto again1;
03072                 }
03073             if(prefix=='+')
03074                 (*i).bans.push_back(mask);
03075             break;
03076         }
03077     }
03078 
03079     s_online_user source=irc_find_user(nick);
03080 
03081     if(!source.nick.compare("")) {
03082         string log;
03083         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #12: unknown nick ";
03084         log+=nick;
03085         log+="!";
03086         log+=ident;
03087         log+="@";
03088         log+=host;
03089         log_debug(log.c_str());
03090         return;
03091     }
03092 
03093     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
03094 
03095     logic_validate_by_mask(channel,source_user,nick,mask,prefix,'b');
03096 }
03097 
03098 /*!
03099     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/-e to channel
03100     \author VooDooMan
03101     \version 1
03102     \date 2004
03103     \param channel Name of channel
03104     \param prefix Contains '+' or '-' prefix
03105     \param nick Nick of originator of MODE change
03106     \param ident Ident of originator of MODE change
03107     \param host Host of originator of MODE change
03108     \param mask Parameter to +/-e mode (mask)
03109 */
03110 // +-e mask
03111 void irc_mode_change_ban_exception(string channel, char prefix, string nick, string ident, string host, string mask)
03112 {
03113     {
03114         vector<s_online_channel>::iterator i;
03115         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
03116             if(cmp_strings_case_insensitive((*i).name,channel))
03117                 continue;
03118             vector<string>::iterator i1;
03119         again1:
03120             for(i1=(*i).excepts.begin(); i1!=(*i).excepts.end(); i1++)
03121                 if(!mask.compare(*i1)) {
03122                     (*i).excepts.erase(i1);
03123                     goto again1;
03124                 }
03125             if(prefix=='+')
03126                 (*i).excepts.push_back(mask);
03127             break;
03128         }
03129     }
03130 
03131     s_online_user source=irc_find_user(nick);
03132 
03133     if(!source.nick.compare("")) {
03134         string log;
03135         log="in file " __FILE__ " in function " __FUNC__ " occurred panic #13: unknown nick ";
03136         log+=nick;
03137         log+="!";
03138         log+=ident;
03139         log+="@";
03140         log+=host;
03141         log_debug(log.c_str());
03142         return;
03143     }
03144 
03145     string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
03146 
03147     logic_validate_by_mask(channel,source_user,nick,mask,prefix,'e');
03148 }
03149 
03150 /*!
03151     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/-I to channel
03152     \author VooDooMan
03153     \version 1
03154     \date 2004
03155     \param channel Name of channel
03156     \param prefix Contains '+' or '-' prefix
03157     \param nick Nick of originator of MODE change
03158     \param ident Ident of originator of MODE change
03159     \param host Host of originator of MODE change
03160     \param mask Parameter to +/-I mode (mask)
03161 */
03162 // +-I mask
03163 void irc_mode_change_invitation(string channel, char prefix, string nick, string ident, string host, string mask)
03164 {
03165     vector<s_online_channel>::iterator i1;
03166     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
03167         if(!cmp_strings_case_insensitive((*i1).name,channel)) {
03168             if(prefix=='+') {
03169                 vector<string>::iterator i2;
03170                 for(i2=(*i1).invites.begin(); i2!=(*i1).invites.end(); i2++) {
03171                     if(!(*i2).compare(mask)) {
03172                         // we already got it
03173                         return;
03174                     }
03175                 }
03176                 (*i1).invites.push_back(mask);
03177                 s_online_user source=irc_find_user(nick);
03178                 string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
03179 
03180                 logic_validate_by_mask(channel,source_user,nick,mask,prefix,'I');
03181             }
03182             if(prefix=='-') {
03183                 vector<string>::iterator i2;
03184             l1:
03185                 for(i2=(*i1).invites.begin(); i2!=(*i1).invites.end(); i2++) {
03186                     if(!(*i2).compare(mask)) {
03187                         (*i1).invites.erase(i2);
03188                         goto l1;
03189                     }
03190                 }
03191                 s_online_user source=irc_find_user(nick);
03192                 string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
03193 
03194                 logic_validate_by_mask(channel,source_user,nick,mask,prefix,'I');
03195             }
03196             break;
03197         }
03198     }
03199 }
03200 
03201 /*!
03202     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/-R to channel
03203     \author VooDooMan
03204     \version 1
03205     \date 2004
03206     \param channel Name of channel
03207     \param prefix Contains '+' or '-' prefix
03208     \param nick Nick of originator of MODE change
03209     \param ident Ident of originator of MODE change
03210     \param host Host of originator of MODE change
03211     \param mask Parameter to +/-R mode (mask)
03212 */
03213 // +-R mask
03214 void irc_mode_change_reop(string channel, char prefix, string nick, string ident, string host, string mask)
03215 {
03216     vector<s_online_channel>::iterator i1;
03217     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
03218         if(!cmp_strings_case_insensitive((*i1).name,channel)) {
03219             if(prefix=='+') {
03220                 vector<string>::iterator i2;
03221                 for(i2=(*i1).reops.begin(); i2!=(*i1).reops.end(); i2++) {
03222                     if(!(*i2).compare(mask)) {
03223                         // we already got it
03224                         return;
03225                     }
03226                 }
03227                 (*i1).reops.push_back(mask);
03228                 s_online_user source=irc_find_user(nick);
03229                 string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
03230 
03231                 logic_validate_by_mask(channel,source_user,nick,mask,prefix,'R');
03232             }
03233             if(prefix=='-') {
03234                 vector<string>::iterator i2;
03235             l1:
03236                 for(i2=(*i1).reops.begin(); i2!=(*i1).reops.end(); i2++) {
03237                     if(!(*i2).compare(mask)) {
03238                         (*i1).reops.erase(i2);
03239                         goto l1;
03240                     }
03241                 }
03242                 s_online_user source=irc_find_user(nick);
03243                 string source_user=logic_find_user(source.nick,source.ident,source.host,source.fullname,source.irc_op);
03244 
03245                 logic_validate_by_mask(channel,source_user,nick,mask,prefix,'R');
03246             }
03247             break;
03248         }
03249     }
03250 }
03251 
03252 /*!
03253     \brief Evaluates, and validates (or accidentally calls specific event) MODE change +/- other modes with mask (class A) to channel
03254     \author VooDooMan
03255     \version 1
03256     \date 2004
03257     \param channel Name of channel
03258     \param prefix Contains '+' or '-' prefix
03259     \param nick Nick of originator of MODE change
03260     \param ident Ident of originator of MODE change
03261     \param host Host of originator of MODE change
03262     \param mask Parameter to mode (mask)
03263     \todo Not supported yet.
03264 */
03265 void irc_mode_change_other_mask(string channel, char prefix, string nick, string ident, string host, string mask)
03266 {
03267 }
03268 
03269 /*!
03270     \brief Called after receiving 324 numeric from server (channel modes after MODE \#channel), and calls on_key, on_limit functions after parsing the message
03271     \author VooDooMan
03272     \version 1
03273     \date 2004
03274     \param str Partial message from server
03275 */
03276 void irc_RPL_324(string str)
03277 {
03278     // 324 my_nick #channel +ntlk 20 channel_key
03279 
03280     string log=str;
03281     string old_str=str;
03282     unsigned int i1;
03283 
03284     for(i1=0; i1<str.length(); i1++)
03285         if(str[i1]==' ')
03286             break;
03287     str.erase(0,i1+1); // erase 324
03288 
03289     for(i1=0; i1<str.length(); i1++)
03290         if(str[i1]==' ')
03291             break;
03292     str.erase(0,i1+1); // erase my nick
03293 
03294     string channel;
03295     for(i1=0; i1<str.length(); i1++)
03296         if(str[i1]==0x20)
03297             break;
03298         else
03299             channel+=str[i1];
03300     str.erase(0,i1+1); // erase #channel
03301 
03302     string flags;
03303     for(i1=0; i1<str.length(); i1++)
03304         if(str[i1]==0x20)
03305             break;
03306             else
03307             flags+=str[i1];
03308     str.erase(0,i1+1); // erase flags
03309 
03310     string parameters;
03311     for(i1=0; i1<str.length(); i1++)
03312         parameters+=str[i1];
03313 
03314     multimap<string,string> modes;
03315 
03316     char prefix=0;
03317     unsigned int i2=0;
03318     for(i1=0; i1<flags.length(); i1++) {
03319         if(flags[i1]=='+') {
03320             prefix='+';
03321             continue;
03322         }
03323         if(flags[i1]=='-') {
03324             prefix='-';
03325             continue;
03326         }
03327         string p;
03328         int type=0;
03329 
03330         type=0;
03331         if(irc_isupport.get_prefix1(flags[i1])!='0')
03332             type=1;
03333         if(irc_isupport.chanmodes_d.find(flags[i1])!=string::npos)
03334             type=2;
03335         if(irc_isupport.chanmodes_c.find(flags[i1])!=string::npos)
03336             type=3;
03337         if(irc_isupport.chanmodes_a.find(flags[i1])!=string::npos)
03338             type=4;
03339         if(irc_isupport.chanmodes_b.find(flags[i1])!=string::npos)
03340             type=5;
03341 
03342         if(type==1 || type==4) {
03343             for(; i2<parameters.length(); i2++) {
03344                 if(parameters[i2]==0x20) {
03345                     i2++;
03346                     break;
03347                 }
03348                 p+=parameters[i2];
03349             }
03350         }
03351         if(type==3 && prefix=='+') {
03352             for(; i2<parameters.length(); i2++) {
03353                 if(parameters[i2]==0x20) {
03354                     i2++;
03355                     break;
03356                 }
03357                 p+=parameters[i2];
03358             }
03359         }
03360         if(type==5) {
03361             for(; i2<parameters.length(); i2++) {
03362                 if(parameters[i2]==0x20) {
03363                     i2++;
03364                     break;
03365                 }
03366                 p+=parameters[i2];
03367             }
03368         }
03369         if(type==2)
03370             p="";
03371         if(type==0) {
03372             p="";
03373             log="in file " __FILE__ " in function " __FUNC__ " occurred panic: unknown mode ";
03374             log+=prefix;
03375             log+=flags[i1];
03376             log+=" = string: ";
03377             log+=old_str;
03378             log_debug(log.c_str());
03379         }
03380 
03381         pair<string,string> pr;
03382         pr.first=prefix;
03383         pr.first+=flags[i1];
03384         pr.second=p;
03385         modes.insert(pr);
03386     }
03387 
03388     multimap<string,string>::iterator im;
03389     for(im=modes.begin(); im!=modes.end(); im++) {
03390         char prefix=(*im).first[0];
03391         char mode=(*im).first[1];
03392         string param=(*im).second;
03393 
03394         char class_='0';
03395         if(irc_isupport.chanmodes_a.find(mode)!=string::npos)
03396             class_='A';
03397         if(irc_isupport.chanmodes_b.find(mode)!=string::npos)
03398             class_='B';
03399         if(irc_isupport.chanmodes_c.find(mode)!=string::npos)
03400             class_='C';
03401         if(irc_isupport.chanmodes_d.find(mode)!=string::npos)
03402             class_='D';
03403         if(irc_isupport.get_prefix1(mode)!='0')
03404             class_='x';
03405 
03406         string unknown=""; // name of host_unknown user
03407         {
03408             vector<s_user>::iterator i1;
03409             for(i1=r_users.begin(); i1!=r_users.end(); i1++) {
03410                 if((*i1).host_unknown) {
03411                     unknown=(*i1).name;
03412                     break;
03413                 }
03414             }
03415         }
03416 
03417         bool got=false;
03418 
03419         vector<s_online_channel>::iterator ii;
03420         for(ii=irc_channels.begin(); ii!=irc_channels.end(); ii++)
03421             if(!cmp_strings_case_insensitive(channel,(*ii).name))
03422                 break;
03423         if(ii==irc_channels.end())
03424             continue;
03425 
03426         if(!got && irc_isupport.chanmodes_d.find(mode)!=string::npos) {
03427             got=true;
03428             // these modes were handled elsewhere
03429             logic_validate_chan_mode(channel,unknown,"",prefix,mode);
03430         }
03431         if(!got && mode=='k' && irc_isupport.chanmodes_b.find(mode)!=string::npos) {
03432             got=true;
03433             (*ii).key=param;
03434             logic_validate_chan_key(channel,unknown,"",prefix,param);
03435         }
03436         if(!got && mode=='l' && irc_isupport.chanmodes_c.find(mode)!=string::npos) {
03437             got=true;
03438             (*ii).limit=param;
03439             logic_validate_chan_limit(channel,unknown,"",prefix,param);
03440         }
03441         if(!got) {
03442             log="in file " __FILE__ " in function " __FUNC__ " occurred panic: unsupported mode ";
03443             log+=prefix;
03444             log+=mode;
03445             log+=" ";
03446             log+=param;
03447             log+=" = string: ";
03448             log+=str;
03449             log_debug(log.c_str());
03450         }
03451     }
03452 }
03453 
03454 /*!
03455     \brief Called after receiving RPL_MODE from server (someone has changed MODE for channel), and calls irc_mode_change_XXX functions after parsing the message
03456     \author VooDooMan
03457     \version 1
03458     \date 2004
03459     \param str Partial message from server
03460 */
03461 void irc_RPL_MODE(string str)
03462 {
03463     string log=str;
03464     string old_str=str;
03465     unsigned int i1;
03466 
03467     for(i1=0; i1<str.length(); i1++)
03468         if(str[i1]==':')
03469             break;
03470     str.erase(0,i1+1); // erase everything before ':'
03471 
03472     string nick;
03473     for(i1=0; i1<str.length(); i1++)
03474         if(str[i1]=='!' || str[i1]==0x20)
03475             break;
03476             else
03477             nick+=str[i1];
03478     bool by_server=str[i1]==0x20;
03479     str.erase(0,i1+1); // erase nick name
03480 
03481     string ident;
03482     string host;
03483     if(!by_server) {
03484         for(i1=0; i1<str.length(); i1++)
03485             if(str[i1]=='@')
03486                 break;
03487                 else
03488                 ident+=str[i1];
03489         str.erase(0,i1+1); // erase ident
03490     
03491         for(i1=0; i1<str.length(); i1++)
03492             if(str[i1]==0x20)
03493                 break;
03494                 else
03495                 host+=str[i1];
03496         str.erase(0,i1+1); // erase host name
03497     }
03498 
03499     for(i1=0; i1<str.length(); i1++)
03500         if(str[i1]==0x20)
03501             break;
03502     str.erase(0,i1+1); // erase "MODE"
03503 
03504     string target;
03505     for(i1=0; i1<str.length(); i1++)
03506         if(str[i1]==0x20)
03507             break;
03508             else
03509             target+=str[i1];
03510     str.erase(0,i1+1); // erase target
03511 
03512     if(!cmp_strings_case_insensitive(target,irc_nick)) {
03513         // it is user MODE for me
03514         return;
03515     }
03516 
03517     string flags;
03518     for(i1=0; i1<str.length(); i1++)
03519         if(str[i1]==0x20)
03520             break;
03521             else
03522             flags+=str[i1];
03523     str.erase(0,i1+1); // erase flags
03524 
03525     string parameters;
03526     for(i1=0; i1<str.length(); i1++)
03527         parameters+=str[i1];
03528 
03529     multimap<string,string> modes;
03530 
03531     char prefix=0;
03532     unsigned int i2=0;
03533     for(i1=0; i1<flags.length(); i1++) {
03534         if(flags[i1]=='+') {
03535             prefix='+';
03536             continue;
03537         }
03538         if(flags[i1]=='-') {
03539             prefix='-';
03540             continue;
03541         }
03542         string p;
03543         int type=0;
03544         /*switch(flags[i1]) {
03545             case 'O': // user status: channel creator
03546             case 'o': // user status: channel operator
03547             case 'v': // user status: voice
03548             case 'q': // user status: ~
03549             case 'a': // user status: &
03550             case 'h': // user status: %
03551                 type=1;
03552                 break;
03553 
03554             //case 'a': // channel status: anonymous
03555             case 'i': // channel status: invite-only
03556             case 'm': // channel status: moderated
03557             case 'n': // channel status: no external messages
03558             //case 'q': // channel status: quiet
03559             case 'p': // channel status: private
03560             case 's': // channel status: secret
03561             case 'r': // channel status: server reop
03562             case 't': // channel status: topic settable by channel operator
03563                 type=2;
03564                 break;
03565 
03566             case 'k': // channel property: channel key
03567                 type=5;
03568                 break;
03569             case 'l': // channel property: user limit
03570                 type=3;
03571                 break;
03572 
03573             case 'b': // channel: ban mask
03574             case 'e': // channel: exception mask to override ban mask
03575             case 'I': // channel: invitation mask to override +i flag
03576             case 'R': // channel: reop mask +/-R
03577                 type=4;
03578                 break;
03579 
03580             default:
03581                 type=0;
03582                 str=log;
03583                 log="in file " __FILE__ " in function " __FUNC__ " occurred panic: unknown mode ";
03584                 log+=prefix;
03585                 log+=flags[i1];
03586                 log+=" = string: ";
03587                 log+=str;
03588                 log_debug(log.c_str());
03589                 break;
03590         }*/
03591         type=0;
03592         if(irc_isupport.get_prefix1(flags[i1])!='0')
03593             type=1;
03594         if(irc_isupport.chanmodes_d.find(flags[i1])!=string::npos)
03595             type=2;
03596         if(irc_isupport.chanmodes_c.find(flags[i1])!=string::npos)
03597             type=3;
03598         if(irc_isupport.chanmodes_a.find(flags[i1])!=string::npos)
03599             type=4;
03600         if(irc_isupport.chanmodes_b.find(flags[i1])!=string::npos)
03601             type=5;
03602 
03603         if(type==1 || type==4) {
03604             for(; i2<parameters.length(); i2++) {
03605                 if(parameters[i2]==0x20) {
03606                     i2++;
03607                     break;
03608                 }
03609                 p+=parameters[i2];
03610             }
03611         }
03612         if(type==3 && prefix=='+') {
03613             for(; i2<parameters.length(); i2++) {
03614                 if(parameters[i2]==0x20) {
03615                     i2++;
03616                     break;
03617                 }
03618                 p+=parameters[i2];
03619             }
03620         }
03621         if(type==5) {
03622             for(; i2<parameters.length(); i2++) {
03623                 if(parameters[i2]==0x20) {
03624                     i2++;
03625                     break;
03626                 }
03627                 p+=parameters[i2];
03628             }
03629         }
03630         if(type==2)
03631             p="";
03632         if(type==0) {
03633             p="";
03634             log="in file " __FILE__ " in function " __FUNC__ " occurred panic: unknown mode ";
03635             log+=prefix;
03636             log+=flags[i1];
03637             log+=" = string: ";
03638             log+=old_str;
03639             log_debug(log.c_str());
03640         }
03641 
03642         pair<string,string> pr;
03643         pr.first=prefix;
03644         pr.first+=flags[i1];
03645         pr.second=p;
03646         modes.insert(pr);
03647     }
03648 
03649     multimap<string,string>::iterator im;
03650     for(im=modes.begin(); im!=modes.end(); im++) {
03651         char prefix=(*im).first[0];
03652         char mode=(*im).first[1];
03653         bool got=false;
03654         string param=(*im).second;
03655 
03656         char class_='0';
03657         if(irc_isupport.chanmodes_a.find(mode)!=string::npos)
03658             class_='A';
03659         if(irc_isupport.chanmodes_b.find(mode)!=string::npos)
03660             class_='B';
03661         if(irc_isupport.chanmodes_c.find(mode)!=string::npos)
03662             class_='C';
03663         if(irc_isupport.chanmodes_d.find(mode)!=string::npos)
03664             class_='D';
03665         if(irc_isupport.get_prefix1(mode)!='0')
03666             class_='x';
03667 
03668         if(!got && mode=='O' && irc_isupport.get_prefix1(mode)!='0') {
03669             // +-O - channel creator
03670             got=true;
03671             irc_remove_redundant_mode(target,param,(string)""+prefix+mode);
03672             irc_mode_change_creator(target,prefix,nick,ident,host,param);
03673             if(ident.empty() && host.empty()) {
03674                 s_mode_queue_entry e;
03675                 e.channel=target;
03676                 e.mode=(string)""+prefix+mode;
03677                 e.param=param;
03678                 e.submit=time(NULL);
03679                 modes_from_server.push_back(e);
03680             }
03681         }
03682         if(!got && mode=='o' && irc_isupport.get_prefix1(mode)!='0') {
03683             got=true;
03684             // +-o - channel operator
03685             irc_remove_redundant_mode(target,param,(string)""+prefix+mode);
03686             irc_mode_change_op(target,prefix,nick,ident,host,param);
03687             if(ident.empty() && host.empty()) {
03688                 s_mode_queue_entry e;
03689                 e.channel=target;
03690                 e.mode=(string)""+prefix+mode;
03691                 e.param=param;
03692                 e.submit=time(NULL);
03693                 modes_from_server.push_back(e);
03694             }
03695         }
03696         if(!got && mode=='v' && irc_isupport.get_prefix1(mode)!='0') {
03697             got=true;
03698             // +-v - channel voice
03699             irc_remove_redundant_mode(target,param,(string)""+prefix+mode);
03700             irc_mode_change_voice(target,prefix,nick,ident,host,param);
03701             if(ident.empty() && host.empty()) {
03702                 s_mode_queue_entry e;
03703                 e.channel=target;
03704                 e.mode=(string)""+prefix+mode;
03705                 e.param=param;
03706                 e.submit=time(NULL);
03707                 modes_from_server.push_back(e);
03708             }
03709         }
03710         if(!got && irc_isupport.get_prefix1(mode)!='0') {
03711             got=true;
03712             irc_remove_redundant_mode(target,param,(string)""+prefix+mode);
03713             irc_mode_change_other(target,prefix,irc_isupport.get_prefix1(mode),nick,ident,host,param);
03714             if(ident.empty() && host.empty()) {
03715                 s_mode_queue_entry e;
03716                 e.channel=target;
03717                 e.mode=(string)""+prefix+mode;
03718                 e.param=param;
03719                 e.submit=time(NULL);
03720                 modes_from_server.push_back(e);
03721             }
03722         }
03723         if(!got && irc_isupport.chanmodes_d.find(mode)!=string::npos) {
03724             got=true;
03725             irc_mode_change_chan_status(target,prefix,mode,nick,ident,host);
03726         }
03727         if(!got && mode=='k' && irc_isupport.chanmodes_b.find(mode)!=string::npos) {
03728             got=true;
03729             irc_mode_change_chan_key(target,prefix,nick,ident,host,param);
03730         }
03731         if(!got && mode=='l' && irc_isupport.chanmodes_c.find(mode)!=string::npos) {
03732             got=true;
03733             irc_mode_change_chan_limit(target,prefix,nick,ident,host,param);
03734         }
03735         if(!got && mode=='b' && irc_isupport.chanmodes_a.find(mode)!=string::npos) {
03736             got=true;
03737             irc_mode_change_ban(target,prefix,nick,ident,host,param);
03738         }
03739         if(!got && mode=='e' && irc_isupport.chanmodes_a.find(mode)!=string::npos) {
03740             got=true;
03741             irc_mode_change_ban_exception(target,prefix,nick,ident,host,param);
03742         }
03743         if(!got && mode=='I' && irc_isupport.chanmodes_a.find(mode)!=string::npos) {
03744             got=true;
03745             irc_mode_change_invitation(target,prefix,nick,ident,host,param);
03746         }
03747         if(!got && mode=='R' && irc_isupport.chanmodes_a.find(mode)!=string::npos) {
03748             got=true;
03749             irc_mode_change_reop(target,prefix,nick,ident,host,param);
03750         }
03751         if(!got && irc_isupport.chanmodes_a.find(mode)!=string::npos) {
03752             got=true;
03753             irc_mode_change_other_mask(target,prefix,nick,ident,host,param);
03754         }
03755         if(!got) {
03756             log="in file " __FILE__ " in function " __FUNC__ " occurred panic: unsupported mode ";
03757             log+=prefix;
03758             log+=mode;
03759             log+=" ";
03760             log+=param;
03761             log+=" = string: ";
03762             log+=str;
03763             log_debug(log.c_str());
03764         }
03765     }
03766 }
03767 
03768 /*!
03769     \brief Called after receiving RPL_TOPIC from server (someone has changed TOPIC for channel), and calls logic_validate_topic function after parsing the message
03770     \author VooDooMan
03771     \version 1
03772     \date 2004
03773     \param str Partial message from server
03774 */
03775 void irc_RPL_TOPIC(string str)
03776 {
03777     string log=str;
03778     unsigned int i1;
03779 
03780     for(i1=0; i1<str.length(); i1++)
03781         if(str[i1]==':')
03782             break;
03783     str.erase(0,i1+1); // erase everything before ':'
03784 
03785     string nick;
03786     for(i1=0; i1<str.length(); i1++)
03787         if(str[i1]=='!')
03788             break;
03789             else
03790             nick+=str[i1];
03791     str.erase(0,i1+1); // erase nick name
03792 
03793     string ident;
03794     for(i1=0; i1<str.length(); i1++)
03795         if(str[i1]=='@')
03796             break;
03797             else
03798             ident+=str[i1];
03799     str.erase(0,i1+1); // erase ident
03800 
03801     string host;
03802     for(i1=0; i1<str.length(); i1++)
03803         if(str[i1]==0x20)
03804             break;
03805             else
03806             host+=str[i1];
03807     str.erase(0,i1+1); // erase host name
03808 
03809     for(i1=0; i1<str.length(); i1++)
03810         if(str[i1]==0x20)
03811             break;
03812     str.erase(0,i1+1); // erase "TOPIC"
03813 
03814     string channel;
03815     for(i1=0; i1<str.length(); i1++)
03816         if(str[i1]==0x20)
03817             break;
03818             else
03819             channel+=str[i1];
03820     str.erase(0,i1+1); // erase channel
03821 
03822     for(i1=0; i1<str.length(); i1++)
03823         if(str[i1]==':')
03824             break;
03825     str.erase(0,i1+1); // erase everything before ':'
03826 
03827     string topic;
03828     for(i1=0; i1<str.length(); i1++)
03829         topic+=str[i1];
03830 
03831     s_online_user source_=irc_find_user(nick);
03832     string source_user=logic_find_user(source_.nick,source_.ident,source_.host,source_.fullname,source_.irc_op);
03833 
03834     logic_validate_topic(channel,source_user,nick,topic);
03835 }
03836 
03837 /*!
03838     \brief Called when user was KICKed and validates it (or calls on_kicked event)
03839     \author VooDooMan
03840     \version 1
03841     \date 2004
03842     \param str Partial message from server containing channel name and nick of kicked user
03843 */
03844 void irc_kicked(string str)
03845 {
03846     string log=str;
03847     unsigned int i1;
03848 
03849     str.erase(0,1); // erase first ':'
03850 
03851     string nick;
03852     for(i1=0; i1<str.length(); i1++)
03853         if(str[i1]=='!')
03854             break;
03855             else
03856             nick+=str[i1];
03857     str.erase(0,i1+1); // erase nick name
03858 
03859     string ident;
03860     for(i1=0; i1<str.length(); i1++)
03861         if(str[i1]=='@')
03862             break;
03863             else
03864             ident+=str[i1];
03865     str.erase(0,i1+1); // erase ident
03866 
03867     string host;
03868     for(i1=0; i1<str.length(); i1++)
03869         if(str[i1]==0x20)
03870             break;
03871             else
03872             host+=str[i1];
03873     str.erase(0,i1+1); // erase host name
03874 
03875     for(i1=0; i1<str.length(); i1++)
03876         if(str[i1]==0x20)
03877             break;
03878     str.erase(0,i1+1); // erase "KICK"
03879 
03880     string channel;
03881     for(i1=0; i1<str.length(); i1++)
03882         if(str[i1]==0x20)
03883             break;
03884             else
03885             channel+=str[i1];
03886     str.erase(0,i1+1); // erase channel
03887 
03888     string target;
03889     for(i1=0; i1<str.length(); i1++)
03890         if(str[i1]==0x20)
03891             break;
03892             else
03893             target+=str[i1];
03894     str.erase(0,i1+1); // erase target
03895 
03896     s_online_user source_=irc_find_user(nick);
03897     string source_user=logic_find_user(source_.nick,source_.ident,source_.host,source_.fullname,source_.irc_op);
03898 
03899     s_online_user target_=irc_find_user(target);
03900     string target_user=logic_find_user(target_.nick,target_.ident,target_.host,target_.fullname,target_.irc_op);
03901 
03902     logic_validate_kick(channel,source_user,target_user,nick,target);
03903 }
03904 
03905 /*!
03906     \brief Compares the beginning of message
03907     \author VooDooMan
03908     \version 1
03909     \date 2004
03910     \param start The beginning of the message to be compared with last received message
03911     \return Returns true if it mathes
03912 */
03913 bool irc_check_last_msg(const char* start)
03914 {
03915     if(last_msg.msg==NULL)
03916         return false;
03917     if(strlen(last_msg.msg)<strlen(start))
03918         return false;
03919     bool same=true;
03920     /*for(unsigned int i1=0; i1<strlen(start); i1++)
03921         if(last_msg.msg[i1]!=start[i1]) {
03922             same=false;
03923             break;
03924         }*/
03925     if(strstr(last_msg.msg,start)!=last_msg.msg)
03926         same=false;
03927     return same;
03928 }
03929 
03930 /*!
03931     \brief Clears wait flag for sent message (reply has been received)
03932     \author VooDooMan
03933     \version 1
03934     \date 2004
03935     \param resp Received message from server
03936 */
03937 void irc_kill_last_msg_wait(string resp)
03938 {
03939     size_t n=resp.length();
03940     if(n>sizeof(last_msg.response)-1)
03941         n=sizeof(last_msg.response)-1;
03942     strncpy(last_msg.response,resp.c_str(),n);
03943     last_msg.response[n]=0;
03944     last_msg.wait_for_response=false;
03945 }
03946 
03947 /*!
03948     \brief Clears wait flag for sent command (reply has been received)
03949     \author VooDooMan
03950     \version 1
03951     \date 2005
03952     \param command Command that should be cleared
03953 */
03954 void irc_kill_command_wait(string command)
03955 {
03956     char tmp[128];
03957     unsigned int i1;
03958     for(i1=0; i1<64 && command[i1]!=0 && command[i1]!=0x20; i1++)
03959         tmp[i1]=command[i1];
03960     tmp[i1]=0;
03961 
03962     vector<s_awaiting_response>::iterator i2;
03963     for(i2=waiting_for_response.begin(); i2!=waiting_for_response.end(); i2++) {
03964         string cmd;
03965         for(unsigned int i3=0; i3<(*i2).message.length() && (*i2).message[i3]!=0x20; i3++)
03966             cmd+=(*i2).message[i3];
03967 
03968         if(!cmd.compare(tmp)) {
03969             waiting_for_response.erase(i2);
03970             break;
03971         }
03972     }
03973 }
03974 
03975 /*!
03976     \brief Stores data for repeat flood detection
03977     \author VooDooMan
03978     \version 1
03979     \date 2004
03980 */
03981 struct s_log {
03982     string msg;                 //!< message
03983     unsigned int num;           //!< Number of its occurence
03984     time_t time;                //!< Time of occurence
03985 };
03986 
03987 /*!
03988     \brief Checks flood limits and history for just received message
03989     \author VooDooMan
03990     \version 1
03991     \date 2004
03992     \param type Type of message - one of following: TYPE_PRIVMSG, TYPE_NOTICE, TYPE_QUIT_PART_KICK, TYPE_JOIN, TYPE_NICK, TYPE_MODE, TYPE_CTCP
03993     \param channel Name of channel
03994     \param full_host Host of originator of message ("nick!ident@host")
03995     \param msg Additional "sub-message": for TYPE_PRIVMSG whole message, for TYPE_NOTICE notice message, for TYPE_QUIT_PART_KICK quit message/part message/kick reason (if any), for TYPE_NICK new nick name, and for TYPE_MODE mode string (parameter to MODE command), and for TYPE_MODE, when topic was changed, there is new topic, for TYPE_CTCP - the whole PRIVMSG
03996 */
03997 void irc_check_flood(int type, string channel, string full_host, string msg)
03998 {
03999     string str=full_host;
04000 
04001     string nick;
04002     unsigned int i1;
04003     for(i1=0; i1<str.length(); i1++)
04004         if(str[i1]=='!')
04005             break;
04006             else
04007             nick+=str[i1];
04008     str.erase(0,i1+1); // erase nick name
04009 
04010     if(!cmp_strings_case_insensitive(nick,(string)irc_nick))
04011         // it's me! the bot!
04012         return;
04013 
04014     if(type==TYPE_NICK && !cmp_strings_case_insensitive(msg,(string)irc_nick))
04015         // it's me while changing nick!
04016         return;
04017 
04018     string ident;
04019     for(i1=0; i1<str.length(); i1++)
04020         if(str[i1]=='@')
04021             break;
04022             else
04023             ident+=str[i1];
04024     str.erase(0,i1+1); // erase ident
04025 
04026     string host;
04027     for(i1=0; i1<str.length(); i1++)
04028         if(str[i1]==0x20)
04029             break;
04030             else
04031             host+=str[i1];
04032     str.erase(0,i1+1); // erase host
04033 
04034     // check for myself
04035     {
04036         bool match=false;
04037         vector<s_user>::iterator i1;
04038         map<string,string> vars;
04039         for(i1=r_users.begin(); i1!=r_users.end(); i1++) {
04040             if(!(*i1).host_bot)
04041                 continue;
04042             vector<string>::iterator i2;
04043             for(i2=(*i1).hostmask.begin(); i2!=(*i1).hostmask.end(); i2++)
04044                 if(logic_check_mask(logic_eval(*i2,vars),nick+"!"+ident+"@"+host,"*","*")) {
04045                     match=true;
04046                     break;
04047                 }
04048             break;
04049         }
04050         if(match)
04051             return;
04052     }
04053 
04054 
04055     s_online_user* user=NULL;
04056 
04057     bool got_user=false;
04058     vector<s_online_channel>::iterator i2;
04059     for(i2=irc_channels.begin(); i2!=irc_channels.end(); i2++) {
04060         vector<s_online_user>::iterator i3;
04061         for(i3=(*i2).users.begin(); i3!=(*i2).users.end(); i3++) {
04062             if(!cmp_strings_case_insensitive((*i3).nick,nick) /*&& !(*i3).ident.compare(ident) && !(*i3).host.compare(host)*/) {
04063                 user=&(*i3);
04064                 got_user=true;
04065                 break;
04066             }
04067         }
04068         if(got_user)
04069             break;
04070     }
04071     if(!got_user) {
04072         // type gone users (join/quit flood)
04073         vector<s_online_user>::iterator i3;
04074         for(i3=gone_users.begin(); i3!=gone_users.end(); i3++) {
04075             if(!cmp_strings_case_insensitive((*i3).nick,nick) && !cmp_strings_case_insensitive((*i3).ident,ident) && !cmp_strings_case_insensitive((*i3).host,host)) {
04076                 user=&(*i3);
04077                 got_user=true;
04078                 break;
04079             }
04080         }
04081     }
04082 
04083     time_t now;
04084     time(&now);
04085 
04086     s_flood msg_flood;
04087     s_flood notice_flood;
04088     s_flood repeat_flood;
04089     s_flood nick_flood;
04090     s_flood join_flood;
04091     s_flood mode_flood;
04092     s_flood ctcp_flood;
04093     string username;
04094     if(!got_user || user==NULL || !user->got_whois) {
04095         // we don't got user (host_unknown not defined) or we don't have WHOIS yet
04096         return;
04097     } else {
04098         username=user->in_logic_as;
04099     }
04100     logic_get_flood_limits(channel,username,msg_flood,notice_flood,repeat_flood,nick_flood,join_flood,mode_flood,ctcp_flood);
04101 
04102     // clean up flood buffers
04103     vector<s_flood_history>::iterator i4;
04104 l4:
04105     for(i4=user->msg_flood_hist.begin(); i4!=user->msg_flood_hist.end(); i4++)
04106         if(now-(*i4).time>(time_t)msg_flood.seconds) {
04107             user->msg_flood_hist.erase(i4);
04108             goto l4;
04109         }
04110 l5:
04111     for(i4=user->notice_flood_hist.begin(); i4!=user->notice_flood_hist.end(); i4++)
04112         if(now-(*i4).time>(time_t)notice_flood.seconds) {
04113             user->notice_flood_hist.erase(i4);
04114             goto l5;
04115         }
04116 l6:
04117     for(i4=user->repeat_flood_hist.begin(); i4!=user->repeat_flood_hist.end(); i4++)
04118         if(now-(*i4).time>(time_t)repeat_flood.seconds) {
04119             user->repeat_flood_hist.erase(i4);
04120             goto l6;
04121         }
04122 l7:
04123     for(i4=user->nick_flood_hist.begin(); i4!=user->nick_flood_hist.end(); i4++)
04124         if(now-(*i4).time>(time_t)nick_flood.seconds) {
04125             user->nick_flood_hist.erase(i4);
04126             goto l7;
04127         }
04128 l8:
04129     for(i4=user->join_flood_hist.begin(); i4!=user->join_flood_hist.end(); i4++)
04130         if(now-(*i4).time>(time_t)join_flood.seconds) {
04131             user->join_flood_hist.erase(i4);
04132             goto l8;
04133         }
04134 l9:
04135     for(i4=user->mode_flood_hist.begin(); i4!=user->mode_flood_hist.end(); i4++)
04136         if(now-(*i4).time>(time_t)mode_flood.seconds) {
04137             user->mode_flood_hist.erase(i4);
04138             goto l9;
04139         }
04140 l10:
04141     for(i4=user->ctcp_flood_hist.begin(); i4!=user->ctcp_flood_hist.end(); i4++)
04142         if(now-(*i4).time>(time_t)ctcp_flood.seconds) {
04143             user->ctcp_flood_hist.erase(i4);
04144             goto l10;
04145         }
04146 
04147     s_flood_history entry;
04148     entry.time=now;
04149     entry.bytes=msg.length();
04150     entry.msg=msg;
04151     if(type==TYPE_JOIN)
04152         entry.msg=channel;
04153 
04154     bool got2=false;
04155     if(type==TYPE_PRIVMSG) {
04156         user->msg_flood_hist.push_back(entry);
04157         user->repeat_flood_hist.push_back(entry);
04158         unsigned int entries=0;
04159         time_t low_time=0;
04160         for(i4=user->msg_flood_hist.begin(); i4!=user->msg_flood_hist.end(); i4++) {
04161             entries++;
04162             if(low_time==0 || low_time>(*i4).time)
04163                 low_time=(*i4).time;
04164         }
04165         time_t diff=time(NULL)-low_time;
04166         if(msg_flood.lines!=0 && entries>=msg_flood.lines) {
04167             user->msg_flood_hist.clear();
04168             user->notice_flood_hist.clear();
04169             user->repeat_flood_hist.clear();
04170             user->nick_flood_hist.clear();
04171             user->join_flood_hist.clear();
04172             user->mode_flood_hist.clear();
04173             user->ctcp_flood_hist.clear();
04174             logic_on_flood(channel,username,nick,TYPE_PRIVMSG,entries,diff,msg_flood.seconds);
04175             got2=true;
04176         }
04177     }
04178     if(type==TYPE_NOTICE) {
04179         user->notice_flood_hist.push_back(entry);
04180         user->repeat_flood_hist.push_back(entry);
04181         unsigned int entries=0;
04182         time_t low_time=0;
04183         for(i4=user->notice_flood_hist.begin(); i4!=user->notice_flood_hist.end(); i4++) {
04184             entries++;
04185             if(low_time==0 || low_time>(*i4).time)
04186                 low_time=(*i4).time;
04187         }
04188         time_t diff=time(NULL)-low_time;
04189         if(!got2 && notice_flood.lines!=0 && entries>=notice_flood.lines) {
04190             user->msg_flood_hist.clear();
04191             user->notice_flood_hist.clear();
04192             user->repeat_flood_hist.clear();
04193             user->nick_flood_hist.clear();
04194             user->join_flood_hist.clear();
04195             user->mode_flood_hist.clear();
04196             user->ctcp_flood_hist.clear();
04197             logic_on_flood(channel,username,nick,TYPE_NOTICE,entries,diff,notice_flood.seconds);
04198             got2=true;
04199         }
04200     }
04201     if(type==TYPE_QUIT_PART_KICK) {
04202         user->join_flood_hist.push_back(entry);
04203         //user->repeat_flood_hist.push_back(entry);
04204     }
04205     if(type==TYPE_JOIN) {
04206         user->join_flood_hist.push_back(entry);
04207         unsigned int entries=0;
04208         time_t low_time=0;
04209         for(i4=user->join_flood_hist.begin(); i4!=user->join_flood_hist.end(); i4++) {
04210             if(!cmp_strings_case_insensitive((*i4).msg,channel)) {
04211                 entries++;
04212                 if(low_time==0 || low_time>(*i4).time)
04213                     low_time=(*i4).time;
04214             }
04215         }
04216         time_t diff=time(NULL)-low_time;
04217         if(!got2 && join_flood.lines!=0 && entries>=join_flood.lines) {
04218             user->msg_flood_hist.clear();
04219             user->notice_flood_hist.clear();
04220             user->repeat_flood_hist.clear();
04221             user->nick_flood_hist.clear();
04222             user->join_flood_hist.clear();
04223             user->mode_flood_hist.clear();
04224             user->ctcp_flood_hist.clear();
04225             logic_on_flood(channel,username,nick,TYPE_JOIN,entries,diff,join_flood.seconds);
04226             got2=true;
04227         }
04228     }
04229     if(type==TYPE_NICK) {
04230         user->nick_flood_hist.push_back(entry);
04231         user->repeat_flood_hist.push_back(entry);
04232         unsigned int entries=0;
04233         time_t low_time=0;
04234         for(i4=user->nick_flood_hist.begin(); i4!=user->nick_flood_hist.end(); i4++) {
04235             entries++;
04236             if(low_time==0 || low_time>(*i4).time)
04237                 low_time=(*i4).time;
04238         }
04239         time_t diff=time(NULL)-low_time;
04240         if(!got2 && nick_flood.lines!=0 && entries>=nick_flood.lines) {
04241             user->msg_flood_hist.clear();
04242             user->notice_flood_hist.clear();
04243             user->repeat_flood_hist.clear();
04244             user->nick_flood_hist.clear();
04245             user->join_flood_hist.clear();
04246             user->mode_flood_hist.clear();
04247             user->ctcp_flood_hist.clear();
04248             logic_on_flood(channel,username,nick,TYPE_NICK,entries,diff,nick_flood.seconds);
04249             got2=true;
04250         }
04251     }
04252     if(type==TYPE_MODE) {
04253         user->mode_flood_hist.push_back(entry);
04254         user->repeat_flood_hist.push_back(entry);
04255         unsigned int entries=0;
04256         time_t low_time=0;
04257         for(i4=user->mode_flood_hist.begin(); i4!=user->mode_flood_hist.end(); i4++) {
04258             entries++;
04259             if(low_time==0 || low_time>(*i4).time)
04260                 low_time=(*i4).time;
04261         }
04262         time_t diff=time(NULL)-low_time;
04263         if(mode_flood.lines!=0 && entries>=mode_flood.lines) {
04264             user->msg_flood_hist.clear();
04265             user->notice_flood_hist.clear();
04266             user->repeat_flood_hist.clear();
04267             user->nick_flood_hist.clear();
04268             user->join_flood_hist.clear();
04269             user->mode_flood_hist.clear();
04270             logic_on_flood(channel,username,nick,TYPE_MODE,entries,diff,mode_flood.seconds);
04271             got2=true;
04272         }
04273     }
04274     if(type==TYPE_CTCP) {
04275         user->ctcp_flood_hist.push_back(entry);
04276         user->repeat_flood_hist.push_back(entry);
04277         unsigned int entries=0;
04278         time_t low_time=0;
04279         for(i4=user->ctcp_flood_hist.begin(); i4!=user->ctcp_flood_hist.end(); i4++) {
04280             entries++;
04281             if(low_time==0 || low_time>(*i4).time)
04282                 low_time=(*i4).time;
04283         }
04284         time_t diff=time(NULL)-low_time;
04285         if(ctcp_flood.lines!=0 && entries>=ctcp_flood.lines) {
04286             user->msg_flood_hist.clear();
04287             user->notice_flood_hist.clear();
04288             user->repeat_flood_hist.clear();
04289             user->nick_flood_hist.clear();
04290             user->join_flood_hist.clear();
04291             user->mode_flood_hist.clear();
04292             user->ctcp_flood_hist.clear();
04293             logic_on_flood(channel,username,nick,TYPE_CTCP,entries,diff,ctcp_flood.seconds);
04294             got2=true;
04295         }
04296     }
04297     // evaluate repeat
04298     if(type==TYPE_PRIVMSG || type==TYPE_NOTICE || /*type==TYPE_QUIT_PART_KICK ||*/ type==TYPE_NICK || type==TYPE_CTCP) {
04299         vector<s_log> repeat_log;
04300         vector<s_log>::iterator i5;
04301         time_t low_time=0;
04302         for(i4=user->repeat_flood_hist.begin(); i4!=user->repeat_flood_hist.end(); i4++) {
04303             bool got=false;
04304             for(i5=repeat_log.begin(); i5!=repeat_log.end(); i5++)
04305                 if(!(*i5).msg.compare((*i4).msg)) {
04306                     got=true;
04307                     (*i5).num++;
04308                     if(low_time==0 || low_time>(*i5).time)
04309                         low_time=(*i5).time;
04310                     break;
04311                 }
04312             if(!got) {
04313                 s_log e;
04314                 e.msg=(*i4).msg;
04315                 e.num=1;
04316                 e.time=(*i4).time;
04317                 repeat_log.push_back(e);
04318             }
04319         }
04320         time_t diff=time(NULL)-low_time;
04321         for(i5=repeat_log.begin(); i5!=repeat_log.end(); i5++)
04322             if(!got2 && repeat_flood.lines!=0 && (*i5).num>=repeat_flood.lines) {
04323                 user->msg_flood_hist.clear();
04324                 user->notice_flood_hist.clear();
04325                 user->repeat_flood_hist.clear();
04326                 user->nick_flood_hist.clear();
04327                 user->join_flood_hist.clear();
04328                 user->mode_flood_hist.clear();
04329                 user->ctcp_flood_hist.clear();
04330                 logic_on_flood(channel,username,nick,TYPE_REPEAT,(*i5).num,diff,repeat_flood.seconds);
04331                 got2=true;
04332                 break;
04333             }
04334     }
04335 
04336     // clean up gone_users
04337     vector<s_online_user>::iterator i3;
04338 l1:
04339     for(i3=gone_users.begin(); i3!=gone_users.end(); i3++) {
04340         if((*i3).quit_time+120<now) {
04341             // 120 seconds ought be enough!
04342             gone_users.erase(i3);
04343             goto l1;
04344         }
04345     }
04346     if(type==TYPE_QUIT_PART_KICK) {
04347         bool got=false;
04348         for(i3=gone_users.begin(); i3!=gone_users.end(); i3++)
04349             if(!(*i3).nick.compare(nick)) {
04350                 got=true;
04351                 break;
04352             }
04353         if(!got) {
04354             time(&user->quit_time);
04355             gone_users.push_back(*user);
04356         }
04357     }
04358 }
04359 
04360 /*!
04361     \brief Raises on_privmsg event if defined for specific user and channel
04362     \author VooDooMan
04363     \version 1
04364     \date 2004
04365     \param channel Name of channel
04366     \param full_host Host of originator ("nick!ident@host")
04367     \param msg The message (PRIVMSG message)
04368 */
04369 void irc_on_privmsg(string channel, string full_host, string msg)
04370 {
04371     string str=full_host;
04372 
04373     string nick;
04374     unsigned int i1;
04375     for(i1=0; i1<str.length(); i1++)
04376         if(str[i1]=='!')
04377             break;
04378             else
04379             nick+=str[i1];
04380     str.erase(0,i1+1); // erase nick name
04381 
04382     if(!cmp_strings_case_insensitive(nick,(string)irc_nick)) // it's me! the bot!
04383         return;
04384 
04385     string ident;
04386     for(i1=0; i1<str.length(); i1++)
04387         if(str[i1]=='@')
04388             break;
04389             else
04390             ident+=str[i1];
04391     str.erase(0,i1+1); // erase ident
04392 
04393     string host;
04394     for(i1=0; i1<str.length(); i1++)
04395         if(str[i1]==0x20)
04396             break;
04397             else
04398             host+=str[i1];
04399     str.erase(0,i1+1); // erase host
04400 
04401     s_online_user* user=NULL;
04402 
04403     bool got_user=false;
04404     vector<s_online_channel>::iterator i2;
04405     for(i2=irc_channels.begin(); i2!=irc_channels.end(); i2++) {
04406         vector<s_online_user>::iterator i3;
04407         for(i3=(*i2).users.begin(); i3!=(*i2).users.end(); i3++) {
04408             if(!cmp_strings_case_insensitive((*i3).nick,nick) && !cmp_strings_case_insensitive((*i3).ident,ident) && !cmp_strings_case_insensitive((*i3).host,host)) {
04409                 user=&(*i3);
04410                 got_user=true;
04411                 break;
04412             }
04413         }
04414         if(got_user)
04415             break;
04416     }
04417 
04418     time_t now;
04419     time(&now);
04420 
04421     string username;
04422     if(!got_user) {
04423         // assume unknown user
04424         username="";
04425 
04426         vector<s_online_channel>::iterator i1;
04427     l3:
04428         bool got_channel=false;
04429         for(i1=unknown_users_on_channels.begin(); i1!=unknown_users_on_channels.end(); i1++)
04430             if(!cmp_strings_case_insensitive((*i1).name,channel)) {
04431                 user=&(*(*i1).users.begin()); // just first record only
04432                 got_channel=true;
04433                 break;
04434             }
04435         if(!got_channel) {
04436             s_online_channel ch;
04437             ch.name=channel;
04438             ch.b_excepts_sent=ch.b_invites_sent=ch.b_bans_sent=false;
04439             s_online_user u;
04440             u.old_mode="INVALID";
04441             ch.users.push_back(u);
04442             unknown_users_on_channels.push_back(ch);
04443             goto l3;
04444         }
04445     } else {
04446         username=user->in_logic_as;
04447     }
04448 
04449     if(!channel.empty())
04450         logic_on_privmsg(channel,username,nick,msg);
04451     else
04452         logic_on_privmsg_query(username,nick,msg);
04453 }
04454 
04455 /*!
04456     \brief Raises on_broadcast event
04457     \author VooDooMan
04458     \version 1
04459     \date 2005-04-22
04460     \param bcast_mask Broadcast mask ("$$irc.someserver.net")
04461     \param type Type: TYPE_PRIVMSG, TYPE_NOTICE
04462     \param full_host Host of originator ("nick!ident@host")
04463     \param msg The message
04464     \param server IRC server host we are on
04465     \param port IRC server port we are on
04466 */
04467 void irc_on_broadcast(string bcast_mask, int type, string full_host, string msg, string server, unsigned short port)
04468 {
04469     string str=full_host;
04470 
04471     string nick;
04472     unsigned int i1;
04473     for(i1=0; i1<str.length(); i1++)
04474         if(str[i1]=='!')
04475             break;
04476             else
04477             nick+=str[i1];
04478     str.erase(0,i1+1); // erase nick name
04479 
04480     string ident;
04481     for(i1=0; i1<str.length(); i1++)
04482         if(str[i1]=='@')
04483             break;
04484             else
04485             ident+=str[i1];
04486     str.erase(0,i1+1); // erase ident
04487 
04488     string host;
04489     for(i1=0; i1<str.length(); i1++)
04490         if(str[i1]==0x20)
04491             break;
04492             else
04493             host+=str[i1];
04494     str.erase(0,i1+1); // erase host
04495 
04496     s_online_user* user=NULL;
04497 
04498     bool got_user=false;
04499     vector<s_online_channel>::iterator i2;
04500     for(i2=irc_channels.begin(); i2!=irc_channels.end(); i2++) {
04501         vector<s_online_user>::iterator i3;
04502         for(i3=(*i2).users.begin(); i3!=(*i2).users.end(); i3++) {
04503             if(!cmp_strings_case_insensitive((*i3).nick,nick) && !cmp_strings_case_insensitive((*i3).ident,ident) && !cmp_strings_case_insensitive((*i3).host,host)) {
04504                 user=&(*i3);
04505                 got_user=true;
04506                 break;
04507             }
04508         }
04509         if(got_user)
04510             break;
04511     }
04512 
04513     time_t now;
04514     time(&now);
04515 
04516     string username;
04517     if(!got_user) {
04518         // assume unknown user
04519         username="";
04520     } else {
04521         username=user->in_logic_as;
04522     }
04523 
04524     logic_on_broadcast(username,nick,ident,host,bcast_mask,type,msg,server,port);
04525 }
04526 
04527 /*!
04528     \brief Raises on_notice event if defined for specific user and channel
04529     \author VooDooMan
04530     \version 1
04531     \date 2004
04532     \param channel Name of channel
04533     \param full_host Host of originator ("nick!ident@host")
04534     \param msg The message (NOTICE message)
04535 */
04536 void irc_on_notice(string channel, string full_host, string msg)
04537 {
04538     string str=full_host;
04539 
04540     string nick;
04541     unsigned int i1;
04542     for(i1=0; i1<str.length(); i1++)
04543         if(str[i1]=='!')
04544             break;
04545             else
04546             nick+=str[i1];
04547     str.erase(0,i1+1); // erase nick name
04548 
04549     if(!cmp_strings_case_insensitive(nick,(string)irc_nick)) // it's me! the bot!
04550         return;
04551 
04552     string ident;
04553     for(i1=0; i1<str.length(); i1++)
04554         if(str[i1]=='@')
04555             break;
04556             else
04557             ident+=str[i1];
04558     str.erase(0,i1+1); // erase ident
04559 
04560     string host;
04561     for(i1=0; i1<str.length(); i1++)
04562         if(str[i1]==0x20)
04563             break;
04564             else
04565             host+=str[i1];
04566     str.erase(0,i1+1); // erase host
04567 
04568     s_online_user* user=NULL;
04569 
04570     bool got_user=false;
04571     vector<s_online_channel>::iterator i2;
04572     for(i2=irc_channels.begin(); i2!=irc_channels.end(); i2++) {
04573         vector<s_online_user>::iterator i3;
04574         for(i3=(*i2).users.begin(); i3!=(*i2).users.end(); i3++) {
04575             if(!cmp_strings_case_insensitive((*i3).nick,nick) && !cmp_strings_case_insensitive((*i3).ident,ident) && !cmp_strings_case_insensitive((*i3).host,host)) {
04576                 user=&(*i3);
04577                 got_user=true;
04578                 break;
04579             }
04580         }
04581         if(got_user)
04582             break;
04583     }
04584 
04585     time_t now;
04586     time(&now);
04587 
04588     string username;
04589     if(!got_user) {
04590         // assume unknown user
04591         username="";
04592 
04593         vector<s_online_channel>::iterator i1;
04594     l3:
04595         bool got_channel=false;
04596         for(i1=unknown_users_on_channels.begin(); i1!=unknown_users_on_channels.end(); i1++)
04597             if(!cmp_strings_case_insensitive((*i1).name,channel)) {
04598                 user=&(*(*i1).users.begin()); // just first record only
04599                 got_channel=true;
04600                 break;
04601             }
04602         if(!got_channel) {
04603             s_online_channel ch;
04604             ch.name=channel;
04605             ch.b_excepts_sent=ch.b_invites_sent=ch.b_bans_sent=false;
04606             s_online_user u;
04607             u.old_mode="INVALID";
04608             ch.users.push_back(u);
04609             unknown_users_on_channels.push_back(ch);
04610             goto l3;
04611         }
04612     } else {
04613         username=user->in_logic_as;
04614     }
04615 
04616     logic_on_notice(channel,username,nick,msg);
04617 }
04618 
04619 extern void sleep(int ms);
04620 
04621 /*!
04622     \brief This is called in loop to process messages from server
04623     \author VooDooMan
04624     \version 1
04625     \date 2004
04626     \retval 0 Okay
04627     \retval 1 Error occured and bot should reconnect to server
04628     \retval 2 Throttled - should be sleep for a couple of seconds
04629 */
04630 int irc_loop_process_input()
04631 {
04632     time_t now;
04633     time(&now);
04634     vector<s_online_user>::iterator ii;
04635 _label_1:
04636     for(ii=tmp_users.begin(); ii!=tmp_users.end(); ii++) {
04637         if((*ii).last_whois+10<=now) {
04638             tmp_users.erase(ii);
04639             goto _label_1;
04640         }
04641     }
04642 
04643     list<char*>::iterator i;
04644 
04645 l1:
04646     i=msgs_from_server.begin();
04647     if(i!=msgs_from_server.end()) {
04648         irc_last_keepalive_detection=time(NULL);
04649 
04650         log_irc(true,*i);
04651 
04652         {
04653             string resp=*i;
04654             //bool b=false;
04655             if(resp.length()>=4) {
04656                 if(resp[0]=='P' && resp[1]=='I' && resp[2]=='N' && resp[3]=='G') {
04657                     string pong="PONG :";
04658                     for(unsigned int i1=6; i1<resp.length(); i1++)
04659                         pong+=resp[i1];
04660                     pong+="\r\n";
04661 
04662                     delete[] (*i);
04663                     msgs_from_server.pop_front();
04664 
04665                     irc_putserv_immediately(irc_socket,pong.c_str());
04666 
04667                     goto l1;
04668                 }
04669 
04670                 if(resp[0]=='E' && resp[1]=='R' && resp[2]=='R' && resp[3]=='O' && resp[4]=='R') {
04671                     if(strstr(resp.c_str(),"Throttled") ||
04672                         strstr(resp.c_str(),"throttled") ||
04673                         strstr(resp.c_str(),"too fast") ||
04674                         strstr(resp.c_str(),"Overridden") ||
04675                         strstr(resp.c_str(),"overridden")
04676                         ) {
04677                             irc_disconnect();
04678                             return 2;
04679                         }
04680                     irc_disconnect();
04681                     sleep(60);
04682 
04683                     return 1;
04684                 }
04685 
04686                 unsigned int i1;
04687                 for(i1=0; i1<resp.length(); i1++)
04688                     if(resp[i1]==0x20)
04689                         break;
04690                 i1++;
04691 
04692                 size_t len=resp.length()-i1;
04693                 if(len>4*1024-1) {
04694                     log_debug("one line from IRC server exceeded about 4 KB, in file " __FILE__ " in function ");
04695                     goto l2;
04696                 }
04697 
04698                 char tmp[4*1024];
04699                 strcpy(tmp,(char*)&((resp.c_str())[i1]));
04700                 if(tmp[strlen(tmp)-1]=='\r' || tmp[strlen(tmp)-1]=='\n')
04701                     tmp[strlen(tmp)-1]=0;
04702                 if(tmp[strlen(tmp)-1]=='\r' || tmp[strlen(tmp)-1]=='\n')
04703                     tmp[strlen(tmp)-1]=0;
04704 
04705                 string str=tmp;
04706                 len=str.length();
04707 
04708                 string hm;
04709                 string nick, ident, host;
04710                 string channel;
04711                 string whom; // only for KICK
04712                 string topic; // only for topic
04713                 string notice; // only for NOTICE from server
04714                 if(resp.length()>0 && resp[0]==':') {
04715                     unsigned int i1;
04716                     for(i1=1; i1<resp.length(); i1++) {
04717                         if(resp[i1]==0x20)
04718                             break;
04719                         hm+=resp[i1];
04720                     }
04721                     if(hm.find("!")!=string::npos && hm.find("@")!=string::npos) {
04722                         i1++;
04723                         int pos=0;
04724                         for(i1=1; i1<resp.length(); i1++) {
04725                             if(pos==0 && resp[i1]=='!') {
04726                                 pos++;
04727                                 continue;
04728                             }
04729                             if(pos==1 && resp[i1]=='@') {
04730                                 pos++;
04731                                 continue;
04732                             }
04733                             if(pos==2 && resp[i1]==0x20) {
04734                                 pos++;
04735                                 continue;
04736                             }
04737                             if(pos==3 && resp[i1]==0x20) {
04738                                 pos++;
04739                                 continue;
04740                             }
04741                             if(pos==4 && resp[i1]==0x20) {
04742                                 pos++;
04743                                 continue;
04744                             }
04745                             if(pos==5 && resp[i1]==':') {
04746                                 pos++;
04747                                 continue;
04748                             }
04749                             if(pos==0)
04750                                 nick+=resp[i1];
04751                             if(pos==1)
04752                                 ident+=resp[i1];
04753                             if(pos==2)
04754                                 host+=resp[i1];
04755                             if(pos==3) {
04756                                 // command
04757                             }
04758                             if(pos==4)
04759                                 channel+=resp[i1];
04760                             if(pos==5)
04761                                 whom+=resp[i1];
04762                             if(pos==6)
04763                                 topic+=resp[i1];
04764                         }
04765                     } else {
04766                         // message from server
04767                         nick="";
04768                         ident="";
04769                         host="";
04770                         whom="";
04771                         channel="";
04772                         topic="";
04773                         notice="";
04774                         if(resp.length()>=i1+6 && resp[i1+1]=='M' && resp[i1+2]=='O' && resp[i1+3]=='D' &&
04775                             resp[i1+4]=='E' && resp[i1+5]==0x20) {
04776                                 channel=resp;
04777                                 channel.erase(0,i1+1+strlen("MODE "));
04778                                 whom=channel;
04779                                 if(channel.find("\x20",0)!=string::npos)
04780                                     channel.erase(channel.find(0x20,0),channel.length()-channel.find(0x20,0));
04781                                 if(whom.find(0x20,0)!=string::npos)
04782                                     whom.erase(0,whom.find(0x20,0)+1);
04783                             }
04784                         if(resp.length()>=i1+7 && resp[i1+1]=='T' && resp[i1+2]=='O' && resp[i1+3]=='P' &&
04785                             resp[i1+4]=='I' && resp[i1+5]=='C' && resp[i1+6]==0x20) {
04786                                 channel=resp;
04787                                 channel.erase(0,i1+1+strlen("TOPIC "));
04788                                 whom=channel;
04789                                 if(channel.find("\x20",0)!=string::npos)
04790                                     channel.erase(channel.find(0x20,0),channel.length()-channel.find(0x20,0));
04791                                 if(whom.find(0x20,0)!=string::npos)
04792                                     whom.erase(0,whom.find(0x20,0)+1);
04793                                 whom.erase(0,1);
04794                                 topic=whom;
04795                                 whom="";
04796                             }
04797                         if(resp.length()>=i1+8 && resp[i1+1]=='N' && resp[i1+2]=='O' && resp[i1+3]=='T' &&
04798                             resp[i1+4]=='I' && resp[i1+5]=='C' && resp[i1+6]=='E' && resp[i1+7]==0x20) {
04799                                 channel=resp;
04800                                 channel.erase(0,i1+1+strlen("NOTICE "));
04801                                 whom=channel;
04802                                 if(channel.find("\x20",0)!=string::npos)
04803                                     channel.erase(channel.find(0x20,0),channel.length()-channel.find(0x20,0));
04804                                 if(whom.find(0x20,0)!=string::npos)
04805                                     whom.erase(0,whom.find(0x20,0)+1);
04806                                 whom.erase(0,1);
04807                                 notice=whom;
04808                                 whom="";
04809                             }
04810                     }
04811                     while(whom.length()>0 && whom[whom.length()-1]==0x20)
04812                         whom.erase(whom.length()-1,1);
04813                 }
04814                 string quoted;
04815                 string msg;
04816                 bool sometihng=false;
04817                 bool after_colon=false;
04818                 for(i1=0; i1<len; i1++) {
04819                     if(after_colon)
04820                         msg+=str[i1];
04821                     if(str[i1]==':')
04822                         after_colon=true;
04823                     if(sometihng && str[i1]==0x01)
04824                         break;
04825                     if(!sometihng && str[i1]==0x01) {
04826                         sometihng=true;
04827                         continue;
04828                     }
04829                     if(sometihng)
04830                         quoted+=str[i1];
04831                 }
04832                 if(channel.length()>0 && channel[0]==':')
04833                     channel.erase(0,1);
04834 
04835                 if(len>=4 && str[0]=='P' && str[1]=='O' && str[2]=='N' && str[3]=='G') {
04836                     irc_kill_command_wait("PING");
04837                 }
04838 
04839                 if(len>=7 && str[0]=='P' && str[1]=='R' && str[2]=='I' && str[3]=='V' && str[4]=='M' && str[5]=='S' && str[6]=='G' && str[7]==' ') {
04840                     string tmp=nick;
04841                     tmp+="!";
04842                     tmp+=ident;
04843                     tmp+="@";
04844                     tmp+=host;
04845                     if(channel.find("$")!=-1 || channel.find("%")!=-1) {
04846                         // we got broadcast PRIVMSG message
04847                         log_broadcast(channel.c_str(),TYPE_PRIVMSG,tmp.c_str(),msg.c_str(),irc_server_host,irc_server_port);
04848                         irc_on_broadcast(channel,TYPE_PRIVMSG,tmp,msg,irc_server_host,irc_server_port);
04849                     } else if(!nick.empty()) {
04850                         if(cmp_strings_case_insensitive(channel,irc_nick)) {
04851                             log_channel(channel.c_str(),TYPE_PRIVMSG,tmp.c_str(),"",msg.c_str(),irc_get_modes_for_log(channel,nick).c_str());
04852                             if(msg.find('\x01',0)!=-1 && msg.find("\x01" "ACTION ",0)==-1)
04853                                 irc_check_flood(TYPE_CTCP,channel,tmp,msg);
04854                             else
04855                                 irc_check_flood(TYPE_PRIVMSG,channel,tmp,msg);
04856                             irc_on_privmsg(channel,tmp,msg);
04857                         } else {
04858                             log_channel("private",TYPE_PRIVMSG,tmp.c_str(),"",msg.c_str(),"");
04859                             irc_on_privmsg("",tmp,msg);
04860                         }
04861                     } else {
04862                         // PRIVMSG from server
04863                         if(cmp_strings_case_insensitive(channel,irc_nick)) {
04864                             // it is for channel
04865                             log_channel(channel.c_str(),TYPE_PRIVMSG,hm.c_str(),channel.c_str(),msg.c_str(),"");
04866                             // we really don't want to check for flood now, since it is not likely
04867                             //   when server begins to flood channel, and there is a fact that we
04868                             //   cannot ban server ;-)
04869                             //   -- quote of VooDooMan on 2005-04-22 @ 14:30 GMT +01:00 (zopiclonum 7.5 mg per oral)
04870 
04871                             logic_on_server_msg(channel,hm,TYPE_PRIVMSG,msg,irc_server_host,irc_server_port);
04872                         } else {
04873                             // it is privately for bot
04874                             log_channel("private",TYPE_PRIVMSG,hm.c_str(),channel.c_str(),msg.c_str(),"");
04875 
04876                             logic_on_server_msg("",hm,TYPE_PRIVMSG,msg,irc_server_host,irc_server_port);
04877                         }
04878                     }
04879 
04880                     if(!cmp_strings_case_insensitive(channel,irc_nick) && msg.length()>=3 && msg[0]=='d' && msg[1]=='c' && msg[2]=='c') {
04881                         string user_name_as_in_logic;
04882                         if(irc_access_to_partyline(hm.c_str(),user_name_as_in_logic,msg)) {
04883                             int dcc_group=0;
04884                             string dcc=dcc_get_string(msg,dcc_group);
04885                             string dcc_host=logic_get_dcc_host(dcc_group,user_name_as_in_logic);
04886                             if(!dcc.empty()) {
04887                                 string str="\x01";
04888                                 str+=dcc;
04889                                 str+="\x01";
04890                                 irc_privmsg(nick.c_str(),str.c_str(),LOW_PRIORITY);
04891                                 s_dcc_awaiting_user user;
04892 
04893                                 user.nick=nick;
04894                                 user.ident=irc_get_ident(nick);
04895                                 user.host=irc_get_host(nick);
04896                                 user.fullname=irc_get_fullname(nick);
04897 
04898                                 size_t n=user_name_as_in_logic.length();
04899                                 if(n>128-1)
04900                                     n=128-1;
04901                                 strncpy(user.user_name_as_in_logic,user_name_as_in_logic.c_str(),n);
04902                                 user.user_name_as_in_logic[n]=0;
04903 
04904                                 in_addr6_ ip6;
04905                                 if(inet_pton(AF_INET6,host.c_str(),&ip6)!=1) {
04906                                     user.using_ipv6=false;
04907 #ifdef _WIN32
04908                                     user.addr4.S_un.S_addr=0;
04909 #else
04910                                     user.addr4.s_addr=0;
04911 #endif
04912                                     user.addr4=sock_resolve(host.c_str(),NULL);
04913 #ifdef _WIN32
04914                                     if(!user.addr4.S_un.S_addr) {
04915                                         user.addr4.S_un.S_addr=(unsigned long)-1;
04916 #else
04917                                     if(!user.addr4.s_addr) {
04918                                         user.addr4.s_addr=(unsigned long)-1;
04919 #endif
04920                                         user.addr6=sock_resolve6((char*)host.c_str());
04921                                         user.using_ipv6=true;
04922                                     }
04923                                 } else {
04924                                     memcpy(&user.addr6,&ip6,sizeof(user.addr6));
04925 #ifdef _WIN32
04926                                     user.addr4.S_un.S_addr=(unsigned long)-1;
04927 #else
04928                                     user.addr4.s_addr=(unsigned long)-1;
04929 #endif
04930                                     user.using_ipv6=true;
04931                                 }
04932 
04933                                 time(&user.start_time);
04934 
04935                                 // security issue (two users from the same IP (proxy) connecting at the same time)
04936                                 vector<s_dcc_awaiting_user>::iterator i;
04937 again_:
04938                                 bool ignore=false;
04939                                 for(i=dcc_awaiting_users.begin(); i!=dcc_awaiting_users.end(); i++) {
04940                                     if((*i).start_time+20<time(NULL)) {
04941                                         dcc_awaiting_users.erase(i);
04942                                         goto again_;
04943                                     }
04944                                     if(!(*i).using_ipv6 && !user.using_ipv6) {
04945 #ifdef _WIN32
04946                                         if((*i).addr4.S_un.S_addr==user.addr4.S_un.S_addr)
04947 #else
04948                                         if((*i).addr4.s_addr==user.addr4.s_addr)
04949 #endif
04950                                             ignore=true;
04951                                     }
04952                                     if((*i).using_ipv6 && user.using_ipv6) {
04953                                         if((*i).addr6.bytes[0]==user.addr6.bytes[0] &&
04954                                            (*i).addr6.bytes[1]==user.addr6.bytes[1] &&
04955                                            (*i).addr6.bytes[2]==user.addr6.bytes[2] &&
04956                                            (*i).addr6.bytes[3]==user.addr6.bytes[3] &&
04957                                            (*i).addr6.bytes[4]==user.addr6.bytes[4] &&
04958                                            (*i).addr6.bytes[5]==user.addr6.bytes[5] &&
04959                                            (*i).addr6.bytes[6]==user.addr6.bytes[6] &&
04960                                            (*i).addr6.bytes[7]==user.addr6.bytes[7] &&
04961                                            (*i).addr6.bytes[8]==user.addr6.bytes[8] &&
04962                                            (*i).addr6.bytes[9]==user.addr6.bytes[9] &&
04963                                            (*i).addr6.bytes[10]==user.addr6.bytes[10] &&
04964                                            (*i).addr6.bytes[11]==user.addr6.bytes[11] &&
04965                                            (*i).addr6.bytes[12]==user.addr6.bytes[12] &&
04966                                            (*i).addr6.bytes[13]==user.addr6.bytes[13] &&
04967                                            (*i).addr6.bytes[14]==user.addr6.bytes[14] &&
04968                                            (*i).addr6.bytes[15]==user.addr6.bytes[15])
04969                                            ignore=true;
04970                                     }
04971                                 }
04972 
04973                                 if(!ignore)
04974                                     dcc_awaiting_users.push_back(user);
04975                             }
04976                         }
04977                     }
04978 
04979                     if((msg.length()>=7 && msg[0]=='g' && msg[1]=='e' && msg[2]=='t' && msg[3]=='f' && msg[4]=='i' && msg[5]=='l' && msg[6]=='e' && msg[7]==' ')
04980                         ||
04981                         (msg.length()>=8 && msg[0]=='.' && msg[1]=='g' && msg[2]=='e' && msg[3]=='t' && msg[4]=='f' && msg[5]=='i' && msg[6]=='l' && msg[7]=='e' && msg[8]==' ')
04982                         ) {
04983                         string cmd=msg;
04984                         while(cmd[0]!=' ')
04985                             cmd.erase(0,1);
04986                         string fn;
04987                         string dcc_gr="0";
04988                         int pos=0;
04989                         while(cmd.length()>0) {
04990                             if(cmd[0]==' ') {
04991                                 cmd.erase(0,1);
04992                                 pos++;
04993                                 continue;
04994                             }
04995                             if(pos==1) {
04996                                 fn+=cmd[0];
04997                                 cmd.erase(0,1);
04998                                 continue;
04999                             }
05000                             if(pos==2) {
05001                                 dcc_gr+=cmd[0];
05002                                 cmd.erase(0,1);
05003                                 continue;
05004                             }
05005                         }
05006                         int dcc_group=atol(dcc_gr.c_str());
05007                         int res=dcc_send_file(false,fn,nick,dcc_group);
05008                         string disp;
05009                         switch(res) {
05010                             case DCC_NO_SUCH_FILE:
05011                                 disp=lang_get_string(1,"en",334);
05012                                 break;
05013                             case DCC_ACCESS_DENIED:
05014                                 disp=lang_get_string(1,"en",335);
05015                                 break;
05016                             case DCC_IO_ERROR:
05017                                 disp=lang_get_string(1,"en",336);
05018                                 break;
05019                         }
05020 
05021                         if(!disp.empty()) {
05022                             string m="PRIVMSG ";
05023                             m+=nick;
05024                             m+=" :";
05025                             m+=disp;
05026                             irc_putserv(m.c_str(),false,LOW_PRIORITY);
05027                         } else {
05028                             dcc_file_has_been_read(fn,nick);
05029                         }
05030                     }
05031 
05032                     if(!quoted.empty()) {
05033                         irc_quoted_callback(quoted.c_str(), nick.c_str(), hm.c_str());
05034                     }
05035 
05036                     delete[] (*i);
05037                     msgs_from_server.pop_front();
05038 
05039                     goto l1;
05040                 }
05041 
05042                 if(len>=6 && str[0]=='N' && str[1]=='O' && str[2]=='T' && str[3]=='I' && str[4]=='C' && str[5]=='E' && str[6]==' ') {
05043                     string tmp=nick;
05044                     tmp+="!";
05045                     tmp+=ident;
05046                     tmp+="@";
05047                     tmp+=host;
05048                     if(channel.find("$")!=-1 || channel.find("%")!=-1) {
05049                         // we got broadcast NOTICE message
05050                         log_broadcast(channel,TYPE_NOTICE,tmp,msg,irc_server_host,irc_server_port);
05051                         irc_on_broadcast(channel,TYPE_NOTICE,tmp,msg,irc_server_host,irc_server_port);
05052                     } else if(!nick.empty()) {
05053                         if(cmp_strings_case_insensitive(channel,irc_nick)) {
05054                             log_channel(channel.c_str(),TYPE_NOTICE,hm.c_str(),channel.c_str(),msg.c_str(),irc_get_modes_for_log(channel,nick).c_str());
05055                             if(msg.find('\x01',0)!=-1 && msg.find("\x01" "ACTION ",0)==-1)
05056                                 irc_check_flood(TYPE_CTCP,channel,tmp,msg);
05057                             else
05058                                 irc_check_flood(TYPE_NOTICE,channel,tmp,msg);
05059                             irc_on_notice(channel,tmp,msg);
05060                         } else {
05061                             log_channel("private",TYPE_NOTICE,hm.c_str(),channel.c_str(),msg.c_str(),"");
05062                             irc_on_notice("",tmp,msg);
05063                         }
05064                     } else {
05065                         // NOTICE from server
05066                         if(cmp_strings_case_insensitive(channel,irc_nick)) {
05067                             // it is for channel
05068                             log_channel(channel.c_str(),TYPE_NOTICE,hm.c_str(),channel.c_str(),msg.c_str(),"");
05069                             // we really don't want to check for flood now, since it is not likely
05070                             //   when server begins to flood channel, and there is a fact that we
05071                             //   cannot ban server ;-)
05072                             //   -- quote of VooDooMan on 2005-04-22 @ 14:30 GMT +01:00 (zopiclonum 7.5 mg per oral)
05073 
05074                             logic_on_server_msg(channel,hm,TYPE_NOTICE,msg,irc_server_host,irc_server_port);
05075                         } else {
05076                             // it is privately for bot
05077                             log_channel("private",TYPE_NOTICE,hm.c_str(),channel.c_str(),msg.c_str(),"");
05078 
05079                             logic_on_server_msg("",hm,TYPE_NOTICE,msg,irc_server_host,irc_server_port);
05080                         }
05081                     }
05082                 }
05083 
05084                 if(len>4 && str[0]=='J' && str[1]=='O' && str[2]=='I' && str[3]=='N') {
05085                     if(!nick.empty()) {
05086                         string tmp=nick;
05087                         tmp+="!";
05088                         tmp+=ident;
05089                         tmp+="@";
05090                         tmp+=host;
05091                         log_channel(channel.c_str(),TYPE_JOIN,tmp.c_str(),"","",irc_get_modes_for_log(channel,nick).c_str());
05092 
05093                         irc_check_flood(TYPE_JOIN,channel,tmp,""); // !!! we (maybe) don't know who "tmp" is here!
05094                     }
05095 
05096                     if(!nick.compare(irc_nick)) {
05097                         irc_kill_command_wait("JOIN");
05098 
05099                         vector<s_key_chan>::iterator i2;
05100                     label_b:
05101                         for(i2=irc_key_chans.begin(); i2!=irc_key_chans.end(); i2++) {
05102                             if(!cmp_strings_case_insensitive((*i2).channel_name,channel)) {
05103                                 irc_key_chans.erase(i2);
05104                                 goto label_b;
05105                             }
05106                         }
05107 
05108                         vector<string>::iterator i1;
05109                     erase_again:
05110                         for(i1=irc_cannot_join_channels.begin(); i1!=irc_cannot_join_channels.end(); i1++) {
05111                             if(!cmp_strings_case_insensitive(*i1,channel)) {
05112                                 irc_cannot_join_channels.erase(i1);
05113                                 goto erase_again;
05114                             }
05115                         }
05116                     }
05117 
05118                     str.erase(0,5);
05119                     unsigned int i1;
05120                     for(i1=0; i1<str.length(); i1++)
05121                         if(str[i1]==0x20)
05122                             break;
05123                     if(str.length()-i1>0)
05124                         str.erase(i1,str.length()-i1);
05125 
05126                     for(i1=0; i1<str.length(); i1++)
05127                         if(str[i1]==':')
05128                             break;
05129                     if(str[i1]==':')
05130                         str.erase(0,i1+1); // erase everything before ':'
05131 
05132                     bool got_user=false;
05133                     bool got_channel=false;
05134                 l5:
05135                     vector<s_online_channel>::iterator i2;
05136                     vector<s_online_user>::iterator ii;
05137                     for(i2=irc_channels.begin(); i2!=irc_channels.end(); i2++) {
05138                         if(!cmp_strings_case_insensitive((*i2).name,str)) {
05139                             got_channel=true;
05140                             for(ii=(*i2).users.begin(); ii!=(*i2).users.end(); ii++) {
05141                                 if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
05142                                     (*i2).users.erase(ii);
05143                                     got_user=false;
05144                                     goto l5;
05145                                 }
05146                             }
05147                             if(got_user)
05148                                 break;
05149                         }
05150                     }
05151 
05152                 l10:
05153                     vector<s_online_channel>::iterator i;
05154                     got_channel=false;
05155                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05156                         if(!cmp_strings_case_insensitive((*i).name,str)) {
05157                             got_channel=true;
05158                             break;
05159                         }
05160                     }
05161                     if(!got_channel) {
05162                         s_online_channel chan;
05163                         chan.b_excepts_sent=chan.b_invites_sent=chan.b_bans_sent=false;
05164                         chan.name=str;
05165                         chan.modes="";
05166                         chan.topic="";
05167                         chan.users.clear();
05168                         chan.bans.clear();
05169                         chan.got_excepts=false;
05170                         chan.got_invites=false;
05171                         chan.excepts.clear();
05172                         chan.invites.clear();
05173                         irc_channels.push_back(chan);
05174 
05175                         goto l10;
05176                     }
05177 
05178                     if(!nick.compare(irc_nick)) {
05179                         // we are new on channel, right after JOIN
05180                     }
05181 
05182                     if(got_channel && !irc_check_nick_on_channel(nick,channel)) {
05183                         for(i2=irc_channels.begin(); i2!=irc_channels.end(); i2++)
05184                             if(!cmp_strings_case_insensitive((*i2).name,str))
05185                                 break;
05186 
05187                         s_online_user u;
05188                         u.nick=nick;
05189                         u.got_whois=false;
05190                         u.on_join_called=false;
05191                         u.old_mode="INVALID";
05192 
05193                         bool got_nick=false;
05194                         vector<s_online_channel>::iterator ii1;
05195                         vector<s_online_user>::iterator ii2;
05196                         for(ii1=irc_channels.begin(); ii1!=irc_channels.end(); ii1++) {
05197                             for(ii2=(*ii1).users.begin(); ii2!=(*ii1).users.end(); ii2++) {
05198                                 if(!(*ii2).nick.compare(nick)) {
05199                                     got_nick=true;
05200                                     break;
05201                                 }
05202                             }
05203                             if(got_nick)
05204                                 break;
05205                         }
05206 
05207                         if(!got_nick) {
05208 hard_whois:
05209                             string str="WHOIS ";
05210                             str+=nick;
05211                             irc_putserv(str.c_str(),true,HIGH_PRIORITY);
05212 
05213                             u.whois_sent=true;
05214 
05215                             u.ident=ident;
05216                             u.host=host;
05217                             u.fullname="";
05218                             u.got_mode=false;
05219                             u.mode="0";
05220                             u.irc_op=false;
05221                             u.in_logic_as="";
05222 
05223                             u.just_joined=true;
05224                             u.just_joined_channel=channel;
05225                         } else {
05226                             if(!(*ii2).got_whois)
05227                                 goto hard_whois;
05228                             u.fullname=(*ii2).fullname;
05229                             u.got_mode=true;
05230                             u.got_whois=true;
05231                             u.host=(*ii2).host;
05232                             u.ident=(*ii2).ident;
05233                             u.in_logic_as=(*ii2).in_logic_as;
05234                             u.irc_op=(*ii2).irc_op;
05235                             u.mode="0";
05236                             u.nick=(*ii2).nick;
05237                             u.old_nick=u.nick;
05238                             u.old_mode=u.mode;
05239                             u.on_join_called=true;
05240                             u.whois_sent=true;
05241                             u.just_joined_channel=channel;
05242 
05243                             u.just_joined=true;
05244                             if(nick.compare(irc_nick)) // only call if it is not me myself!
05245                                 logic_on_join(u.nick,u.ident,u.host,u.fullname,u.just_joined_channel,u.irc_op);
05246                             if(u.irc_op) {
05247                                 logic_on_ircop(channel,u.nick,true);
05248                                 string host_mask=u.nick;
05249                                 host_mask+="!";
05250                                 host_mask+=u.ident;
05251                                 host_mask+="@";
05252                                 host_mask+=u.host;
05253                                 log_channel(channel.c_str(),TYPE_IRCOP_JOIN,host_mask.c_str(),"","",irc_get_modes_for_log(channel,nick).c_str());
05254                             }
05255                         }
05256                         (*i2).users.push_back(u);
05257                     }
05258 
05259                     if(irc_check_last_msg("JOIN"))
05260                         irc_kill_last_msg_wait(resp);
05261 
05262                     irc_kill_command_wait("JOIN");
05263                 }
05264                 str=tmp;
05265 
05266                 if(len>4 && str[0]=='Q' && str[1]=='U' && str[2]=='I' && str[3]=='T') {
05267                     string host_mask;
05268                     if(!nick.empty()) {
05269                         string tmp=nick;
05270                         tmp+="!";
05271                         tmp+=ident;
05272                         tmp+="@";
05273                         tmp+=host;
05274                         host_mask=tmp;
05275                         vector<s_online_channel>::iterator i1;
05276                         for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
05277                             vector<s_online_user>::iterator i2;
05278                             for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++)
05279                                 if(!cmp_strings_case_insensitive((*i2).nick,nick)) {
05280                                     log_channel((*i1).name.c_str(),TYPE_QUIT,tmp.c_str(),"",msg.c_str(),irc_get_modes_for_log(channel,nick).c_str());
05281                                     if((*i2).irc_op) {
05282                                         logic_on_ircop((*i1).name,nick,false);
05283                                         log_channel((*i1).name.c_str(),TYPE_IRCOP_LEFT,host_mask.c_str(),"","",irc_get_modes_for_log((*i1).name,nick).c_str());
05284                                     }
05285                                     irc_check_flood(TYPE_QUIT_PART_KICK,(*i1).name,tmp,msg);
05286 
05287                                     logic_on_part((*i1).name,nick,msg,TYPE_QUIT);
05288                                 }
05289                         }
05290                     }
05291 
05292                     vector<s_online_channel>::iterator i;
05293                 l6:
05294                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05295                         vector<s_online_user>::iterator ii;
05296                         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
05297                             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
05298                                 time(&(*ii).quit_time);
05299                                 gone_users.push_back(*ii);
05300                                 (*i).users.erase(ii);
05301                                 goto l6;
05302                             }
05303                         }
05304                     }
05305                 cycle1:
05306                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05307                         string my_modes=irc_get_mode((*i).name,irc_nick);
05308                         if(my_modes.find('@',0)==-1 && cmp_strings_case_insensitive(nick,irc_nick)) {
05309                             int users=0;
05310                             vector<s_online_user>::iterator ii;
05311                             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++, users++)
05312                                 ;
05313                             if(users==1) {
05314                                 // try to get op
05315                                 string m=(*i).name;
05316                                 irc_kill_last_msg_wait(resp);
05317                                 string msg="PART ";
05318                                 msg+=m;
05319                                 irc_putserv(msg.c_str(),false,HIGH_PRIORITY);
05320                                 msg="JOIN ";
05321                                 msg+=m;
05322                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05323                                 msg="MODE ";
05324                                 msg+=m;
05325                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05326                                 msg="TOPIC ";
05327                                 msg+=m;
05328                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05329                                 msg="WHOIS ";
05330                                 msg+=irc_nick;
05331                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05332 
05333                                 irc_channels.erase(i);
05334                                 goto cycle1;
05335                             }
05336                         }
05337                     }
05338                 }
05339                 str=tmp;
05340 
05341                 if(len>4 && str[0]=='P' && str[1]=='A' && str[2]=='R' && str[3]=='T') {
05342                     string host_mask;
05343                     if(!nick.empty()) {
05344                         string tmp=nick;
05345                         tmp+="!";
05346                         tmp+=ident;
05347                         tmp+="@";
05348                         tmp+=host;
05349                         host_mask=tmp;
05350                         log_channel(channel.c_str(),TYPE_PART,tmp.c_str(),"",msg.c_str(),irc_get_modes_for_log(channel,nick).c_str());
05351 
05352                         irc_check_flood(TYPE_QUIT_PART_KICK,channel,tmp,msg);
05353                     }
05354 
05355                     str.erase(0,5);
05356                     unsigned int i1;
05357                     for(i1=0; i1<str.length(); i1++)
05358                         if(str[i1]==0x20)
05359                             break;
05360                     if(str.length()-i1>0)
05361                         str.erase(i1,str.length()-i1);
05362 
05363                 l8:
05364                     vector<s_online_channel>::iterator i;
05365                     bool got_channel=false;
05366                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05367                         if(!cmp_strings_case_insensitive((*i).name,str)) {
05368                             got_channel=true;
05369                             break;
05370                         }
05371                     }
05372                     if(!got_channel /*&& nick.compare(irc_nick)*/) {
05373                         // we are new on channel, right after JOIN
05374                         // assume that irc server will send names reply
05375                         s_online_channel chan;
05376                         chan.b_excepts_sent=chan.b_invites_sent=chan.b_bans_sent=false;
05377                         chan.name=str;
05378                         chan.modes="";
05379                         chan.topic="";
05380                         chan.users.clear();
05381                         chan.bans.clear();
05382                         chan.got_excepts=false;
05383                         chan.excepts.clear();
05384                         chan.got_invites=false;
05385                         chan.invites.clear();
05386                         irc_channels.push_back(chan);
05387 
05388                         goto l8;
05389                     }
05390 
05391                 l7:
05392                     vector<s_online_user>::iterator ii;
05393                     for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
05394                         if(!cmp_strings_case_insensitive((*ii).nick,nick) && !cmp_strings_case_insensitive((*i).name,str)) {
05395                             logic_on_part(channel,nick,msg,TYPE_PART);
05396                             if((*ii).irc_op) {
05397                                 logic_on_ircop(channel,nick,false);
05398                                 log_channel(channel.c_str(),TYPE_IRCOP_LEFT,host_mask.c_str(),"","",irc_get_modes_for_log((*i).name,nick).c_str());
05399                             }
05400 
05401                             if(cmp_strings_case_insensitive((*ii).ident,ident) || cmp_strings_case_insensitive((*ii).host,host)) {
05402                                 time(&(*ii).quit_time);
05403                                 gone_users.push_back(*ii);
05404                                 (*i).users.erase(ii);
05405 
05406                                 goto l7;
05407                             }
05408                             (*i).users.erase(ii);
05409                             goto l7;
05410                         }
05411                     }
05412                 cycle2:
05413                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05414                         string my_modes=irc_get_mode((*i).name,irc_nick);
05415                         if(my_modes.find('@',0)==-1 && cmp_strings_case_insensitive(nick,irc_nick)) {
05416                             int users=0;
05417                             vector<s_online_user>::iterator ii;
05418                             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++, users++)
05419                                 ;
05420                             // if someone else has PART-ed, try to get op
05421                             if(users==1 && cmp_strings_case_insensitive(nick,irc_nick)) {
05422                                 // try to get op
05423                                 string m=(*i).name;
05424                                 irc_kill_last_msg_wait(resp);
05425                                 string msg="PART ";
05426                                 msg+=m;
05427                                 irc_putserv(msg.c_str(),false,HIGH_PRIORITY);
05428                                 msg="JOIN ";
05429                                 msg+=m;
05430                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05431                                 msg="MODE ";
05432                                 msg+=m;
05433                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05434                                 msg="TOPIC ";
05435                                 msg+=m;
05436                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05437                                 msg="WHOIS ";
05438                                 msg+=irc_nick;
05439                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05440 
05441                                 irc_channels.erase(i);
05442                                 goto cycle2;
05443                             }
05444                         }
05445                     }
05446                     if(!cmp_strings_case_insensitive(nick,irc_nick)) {
05447                         // if I PART-ed
05448                         irc_kill_last_msg_wait(resp);
05449 
05450                         irc_kill_command_wait("PART");
05451 
05452                 again_e_chan2:
05453                         vector<s_online_channel>::iterator i;
05454                         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05455                             if(!cmp_strings_case_insensitive((*i).name,channel)) {
05456                                 irc_channels.erase(i);
05457                                 goto again_e_chan2;
05458                             }
05459                         }
05460                     }
05461                 }
05462                 str=tmp;
05463 
05464                 if(len>4 && str[0]=='K' && str[1]=='I' && str[2]=='C' && str[3]=='K') {
05465                     irc_kill_command_wait("KICK");
05466 
05467                     string host_mask;
05468                     if(!nick.empty()) {
05469                         string tmp=nick;
05470                         tmp+="!";
05471                         tmp+=ident;
05472                         tmp+="@";
05473                         tmp+=host;
05474                         host_mask=tmp;
05475                         log_channel(channel.c_str(),TYPE_KICK,tmp.c_str(),whom.c_str(),msg.c_str(),irc_get_modes_for_log(channel,nick).c_str());
05476 
05477                         irc_check_flood(TYPE_QUIT_PART_KICK,channel,tmp,msg);
05478 
05479                         irc_kicked(resp);
05480                     }
05481 
05482                     vector<s_online_channel>::iterator i;
05483                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05484                         if(!cmp_strings_case_insensitive((*i).name,channel)) {
05485                             vector<s_online_user>::iterator ii;
05486                             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
05487                                 if(!cmp_strings_case_insensitive((*ii).nick,whom)) {
05488                                     logic_on_part(channel,whom,msg,TYPE_KICK);
05489                                     if((*ii).irc_op) {
05490                                         logic_on_ircop(channel,whom,false);
05491                                         log_channel(channel.c_str(),TYPE_IRCOP_LEFT,host_mask.c_str(),"","",irc_get_modes_for_log((*i).name,nick).c_str());
05492                                     }
05493 
05494                                     time(&(*ii).quit_time);
05495                                     gone_users.push_back(*ii);
05496                                     (*i).users.erase(ii);
05497                                     break;
05498                                 }
05499                             }
05500                         }
05501                     }
05502                 cycle3:
05503                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05504                         string my_modes=irc_get_mode((*i).name,irc_nick);
05505                         if(my_modes.find('@',0)==-1 && cmp_strings_case_insensitive(nick,irc_nick)) {
05506                             int users=0;
05507                             vector<s_online_user>::iterator ii;
05508                             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++, users++)
05509                                 ;
05510                             // if not KICK-ed me, but someone else, try to get op
05511                             if(users==1 && cmp_strings_case_insensitive(whom,irc_nick)) {
05512                                 // try to get op
05513                                 string m=(*i).name;
05514                                 irc_kill_last_msg_wait(resp);
05515 
05516                                 irc_kill_command_wait("KICK");
05517 
05518                                 string msg="PART ";
05519                                 msg+=m;
05520                                 irc_putserv(msg.c_str(),false,HIGH_PRIORITY);
05521                                 msg="JOIN ";
05522                                 msg+=m;
05523                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05524                                 msg="MODE ";
05525                                 msg+=m;
05526                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05527                                 msg="TOPIC ";
05528                                 msg+=m;
05529                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05530                                 msg="WHOIS ";
05531                                 msg+=irc_nick;
05532                                 irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
05533 
05534                                 irc_channels.erase(i);
05535                                 goto cycle3;
05536                             }
05537                         }
05538                     }
05539                     if(!cmp_strings_case_insensitive(whom,irc_nick)) {
05540                 again_e_chan1:
05541                         vector<s_online_channel>::iterator i;
05542                         for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05543                             if(!cmp_strings_case_insensitive((*i).name,channel)) {
05544                                 irc_channels.erase(i);
05545                                 goto again_e_chan1;
05546                             }
05547                         }
05548                     }
05549                     irc_kill_last_msg_wait(resp);
05550                 }
05551                 str=tmp;
05552 
05553                 if(len>4 && str[0]=='N' && str[1]=='I' && str[2]=='C' && str[3]=='K') {
05554                     irc_kill_command_wait("NICK");
05555 
05556             forced_nick_change:
05557                     if(!nick.empty()) {
05558                         string tmp=nick;
05559                         tmp+="!";
05560                         tmp+=ident;
05561                         tmp+="@";
05562                         tmp+=host;
05563                         vector<s_online_channel>::iterator i1;
05564                         for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
05565                             vector<s_online_user>::iterator ii;
05566                             for(ii=(*i1).users.begin(); ii!=(*i1).users.end(); ii++) {
05567                                 if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
05568                                     // msg contains new nick
05569                                     log_channel((*i1).name.c_str(),TYPE_NICK,tmp.c_str(),"",msg.c_str(),irc_get_modes_for_log((*i1).name,nick).c_str());
05570                                     if(nick.compare(irc_nick)) {
05571                                         irc_check_flood(TYPE_NICK,(*i1).name,tmp,msg);
05572                                         // do NOT perform next line! we got it later
05573                                         //(*ii).nick=msg;
05574                                         char tmp[1024];
05575                                         strcpy(tmp,"WHOIS ");
05576                                         strcat(tmp,msg.c_str());
05577                                         irc_putserv(tmp,true,HIGH_PRIORITY);
05578                                     } else {
05579                                         if(msg.length()<sizeof(irc_nick)) {
05580                                             strcpy(irc_nick,msg.c_str());
05581                                             char tmp[1024];
05582                                             strcpy(tmp,"WHOIS ");
05583                                             strcat(tmp,irc_nick);
05584                                             irc_putserv(tmp,true,HIGH_PRIORITY);
05585                                         }
05586                                     }
05587                                 }
05588                             }
05589                         }
05590                         if(!cmp_strings_case_insensitive(nick,irc_nick)) {
05591                             if(msg.length()<sizeof(irc_nick))
05592                                 strcpy(irc_nick,msg.c_str());
05593                         }
05594                     }
05595 
05596                     vector<s_online_channel>::iterator i;
05597                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05598                         vector<s_online_user>::iterator ii;
05599                         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
05600                             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
05601                                 string old_nick=(*ii).nick;
05602                                 (*ii).nick=msg;
05603 
05604                                 // validate new nick
05605                                 logic_on_nick_change((*ii).nick,(*ii).ident,(*ii).host,(*ii).fullname,(*ii).just_joined_channel,(*ii).irc_op,old_nick);
05606                             }
05607                         }
05608                     }
05609                 }
05610                 str=tmp;
05611 
05612                 // 433: nickname already in use
05613                 if(len>4 && str[0]=='4' && str[1]=='3' && str[2]=='3' && str[3]==' ') {
05614                     if(irc_check_last_msg("NICK"))
05615                         irc_kill_last_msg_wait(resp);
05616 
05617                     irc_kill_command_wait("NICK");
05618                 }
05619 
05620                 if(len>4 && str[0]=='0' && str[1]=='0' && str[2]=='1' && str[3]==' ') {
05621                     if(irc_check_last_msg("USER"))
05622                         irc_kill_last_msg_wait(resp);
05623 
05624                     irc_kill_command_wait("USER");
05625                 }
05626                 if(len>4 && str[0]=='0' && str[1]=='0' && str[2]=='2' && str[3]==' ') {
05627                     if(irc_check_last_msg("USER"))
05628                         irc_kill_last_msg_wait(resp);
05629 
05630                     irc_kill_command_wait("USER");
05631                 }
05632                 if(len>4 && str[0]=='0' && str[1]=='0' && str[2]=='3' && str[3]==' ') {
05633                     if(irc_check_last_msg("USER"))
05634                         irc_kill_last_msg_wait(resp);
05635 
05636                     irc_kill_command_wait("USER");
05637                 }
05638                 if(len>4 && str[0]=='0' && str[1]=='0' && str[2]=='4' && str[3]==' ') {
05639                     if(irc_check_last_msg("USER"))
05640                         irc_kill_last_msg_wait(resp);
05641 
05642                     irc_kill_command_wait("USER");
05643                 }
05644                 if(len>4 && str[0]=='0' && str[1]=='0' && str[2]=='5' && str[3]==' ') {
05645                     if(irc_check_last_msg("USER"))
05646                         irc_kill_last_msg_wait(resp);
05647 
05648                     irc_kill_command_wait("USER");
05649 
05650                     // check for string "Try server <server name>, port <port number>"
05651                     str.erase(0,4);
05652                     size_t len=str.length();
05653                     if(len>11 && str[1]=='r' && str[2]=='y' && str[3]==0x20 &&  str[4]=='s' && str[5]=='e' &&
05654                         str[6]=='r' &&  str[7]=='v' &&  str[8]=='e' &&  str[9]=='r' &&  str[10]==0x20) {
05655                             str.erase(0,11);
05656                             string p;
05657                             p=str;
05658 
05659                             while(p.length()>0 && p[0]!=',')
05660                                 p.erase(0,1);
05661                             while(p.length()>0 && (p[0]<'0' || p[0]>'9'))
05662                                 p.erase(0,1);
05663 
05664                             unsigned int i1;
05665                             for(i1=0; i1<str.length(); i1++)
05666                                 if(str[i1]==',' || str[i1]==0x20)
05667                                     break;
05668                             str.erase(0,i1+1);
05669 
05670                             unsigned short port=(unsigned short)atol(p.c_str());
05671                             if(irc_follow_redirs) {
05672                                 irc_recommended_server=str;
05673                                 irc_recommended_port=port;
05674                             }
05675                         } else {
05676                             irc_RPL_ISUPPORT(str);
05677                         }
05678                 }
05679 
05680                 // NAMES reply
05681                 if(len>4 && str[0]=='3' && str[1]=='5' && str[2]=='3' && str[3]==' ') {
05682                     irc_RPL_NAMREPLY(str);
05683                 }
05684 
05685                 // RPL_ENDOFNAMES
05686                 if(len>4 && str[0]=='3' && str[1]=='6' && str[2]=='6' && str[3]==' ') {
05687                     if(irc_check_last_msg("NAMES"))
05688                         irc_kill_last_msg_wait(resp);
05689 
05690                     irc_kill_command_wait("NAMES");
05691                 }
05692 
05693                 // RPL_WHOISUSER
05694                 // WHOIS reply
05695                 if(len>4 && str[0]=='3' && str[1]=='1' && str[2]=='1' && str[3]==' ') {
05696                     irc_RPL_WHOISUSER(str);
05697                 }
05698 
05699                 // RPL_WHOISOPERATOR
05700                 // user is an IRC operator
05701                 if(len>4 && str[0]=='3' && str[1]=='1' && str[2]=='3' && str[3]==' ') {
05702                     irc_RPL_WHOISOPERATOR(str);
05703                 }
05704 
05705                 // RPL_ENDOFWHOIS
05706                 if(len>4 && str[0]=='3' && str[1]=='1' && str[2]=='8' && str[3]==' ') {
05707                     irc_RPL_ENDOFWHOIS(str);
05708                     if(irc_check_last_msg("WHOIS"))
05709                         irc_kill_last_msg_wait(resp);
05710 
05711                     irc_kill_command_wait("WHOIS");
05712                 }
05713 
05714                 // RPL_WHOISCHANNELS
05715                 if(len>4 && str[0]=='3' && str[1]=='1' && str[2]=='9' && str[3]==' ') {
05716                     irc_RPL_WHOISCHANNELS(str);
05717                 }
05718 
05719                 // 471: Cannot join channel (+l) - limit
05720                 // 473: Cannot join channel (+i) - invite only
05721                 // 474: Cannot join channel (+b) - banned
05722                 // 437: Channel/nick is temporarily unavailable (!!! also can be not channel, but nick!!!)
05723                 if(len>4 && (
05724                     (str[0]=='4' && str[1]=='7' && str[2]=='1' && str[3]==' ') ||
05725                     (str[0]=='4' && str[1]=='7' && str[2]=='3' && str[3]==' ') ||
05726                     (str[0]=='4' && str[1]=='7' && str[2]=='4' && str[3]==' ') ||
05727                     (str[0]=='4' && str[1]=='3' && str[2]=='7' && str[3]==' ')))
05728                 {
05729                     irc_kill_command_wait("JOIN");
05730                     irc_kill_command_wait("MODE");
05731                     irc_kill_command_wait("TOPIC");
05732 
05733                     string s=str;
05734                     int i1=0;
05735                     while(i1<2 && s.length()>0) {
05736                         if(s[0]==0x20)
05737                             i1++;
05738                         s.erase(0,1);
05739                     }
05740                     string chan;
05741                     while(s.length()>0 && s[0]!=0x20) {
05742                         chan+=s[0];
05743                         s.erase(0,1);
05744                     }
05745 
05746                     bool got=false;
05747                     vector<string>::iterator i2;
05748                     for(i2=irc_cannot_join_channels.begin(); i2!=irc_cannot_join_channels.end(); i2++)
05749                         if(!cmp_strings_case_insensitive(*i2,chan)) {
05750                             got=true;
05751                             break;
05752                         }
05753 
05754                     /*if(!got && chan.length()>0 && chan[0]!='#' && chan[0]!='&' && chan[0]!='+' && chan[0]!='!')
05755                         got=true; // it is just a "437 nick teporarily unavailable" (not channel)
05756                         */
05757                     string chantypes;
05758                     map<string,string>::iterator iii;
05759                     for(iii=irc_isupport.raw.begin(); iii!=irc_isupport.raw.end(); iii++)
05760                         if(!(*iii).first.compare("CHANTYPES")) {
05761                             chantypes=(*iii).second;
05762                             break;
05763                         }
05764                     if(!got && chan.length()>0 && chantypes.find(chan[0])==-1)
05765                         got=true; // it is just a "437 nick teporarily unavailable" (not channel)
05766 
05767                     if(!got)
05768                         irc_cannot_join_channels.push_back(chan);
05769 
05770                     vector<s_online_channel>::iterator i;
05771                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++)
05772                         if(!cmp_strings_case_insensitive((*i).name,chan)) {
05773                             irc_channels.erase(i);
05774                             break;
05775                         }
05776 
05777                     irc_kill_last_msg_wait(resp);
05778                 }
05779 
05780                 //IRC IN  :irc.server.com 442 BOT #channel :You're not on that channel
05781                 if(len>4 && str[0]=='4' && str[1]=='4' && str[2]=='2' && str[3]==' ') {
05782                     irc_kill_command_wait("MODE");
05783                     irc_kill_command_wait("TOPIC");
05784 
05785                     irc_kill_last_msg_wait(resp);
05786                 }
05787 
05788                 // IRC IN  :irc.server.com 324 BOT #channel +nt
05789                 // channel mode after JOIN
05790                 if(len>4 && str[0]=='3' && str[1]=='2' && str[2]=='4' && str[3]==' ') {
05791                     irc_RPL_324(str);
05792 
05793                     if(str.find(" ",0)!=string::npos)
05794                         str.erase(0,str.find(" ")+1); // erase everything before and inclusive trailing SPACE - numeric reply
05795                     if(str.find(" ",0)!=string::npos)
05796                         str.erase(0,str.find(" ")+1); // erase everything before SPACE inclusive - my nick
05797                     string chan;
05798                     if(str.find(" ",0)!=string::npos)
05799                         while(str.length() && str[0]!=0x20) {
05800                             chan+=str[0];
05801                             str.erase(0,1);
05802                         }
05803                     str.erase(0,1); // erase space
05804                     if(str.length() && str[0]=='+')
05805                         str.erase(0,1); // erase leading '+'
05806                     if(str.find(" ",0)!=string::npos)
05807                         str.erase(str.find(" ",0),str.length()-str.find(" ",0)); // erase everything after SAPCE inclusive (possibly the topic)
05808                     // in "str" we have channel modes now
05809                     vector<s_online_channel>::iterator i;
05810                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05811                         if(cmp_strings_case_insensitive((*i).name,chan))
05812                             continue;
05813                         (*i).modes=str;
05814                         break;
05815                     }
05816                     irc_kill_last_msg_wait(resp);
05817 
05818                     irc_kill_command_wait("MODE");
05819                 }
05820                 str=tmp;
05821 
05822                 // IRC IN  :irc.server.com 332 BOT #channel :topic
05823                 // topic after join
05824                 if(len>4 && str[0]=='3' && str[1]=='3' && str[2]=='2' && str[3]==' ') {
05825                     irc_kill_command_wait("TOPIC");
05826 
05827                     if(str.find(" ",0)!=string::npos)
05828                         str.erase(0,str.find(" ")+1); // erase everything before and inclusive trailing SPACE - numeric reply
05829                     if(str.find(" ",0)!=string::npos)
05830                         str.erase(0,str.find(" ")+1); // erase everything before SPACE inclusive - my nick
05831                     string chan;
05832                     if(str.find(" ",0)!=string::npos)
05833                         while(str.length() && str[0]!=0x20) {
05834                             chan+=str[0];
05835                             str.erase(0,1);
05836                         }
05837                     str.erase(0,1); // erase space
05838 
05839                     if(str.find(":",0)!=string::npos)
05840                         str.erase(0,str.find(":")+1); // erase everything before ':' inclusive
05841 
05842                     // in str we have topic
05843                     vector<s_online_channel>::iterator i;
05844                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05845                         if(cmp_strings_case_insensitive((*i).name,chan))
05846                             continue;
05847                         (*i).topic=str;
05848                         break;
05849                     }
05850                     irc_kill_last_msg_wait(resp);
05851 
05852                     irc_kill_command_wait("TOPIC");
05853                 }
05854                 str=tmp;
05855 
05856                 // IRC IN  :irc.server.com 331 BOT #channel :No topic is set.
05857                 // NO topic after join
05858                 if(len>4 && str[0]=='3' && str[1]=='3' && str[2]=='1' && str[3]==' ') {
05859                     irc_kill_command_wait("TOPIC");
05860 
05861                     if(str.find(" ",0)!=string::npos)
05862                         str.erase(0,str.find(" ")+1); // erase everything before and inclusive trailing SPACE - numeric reply
05863                     if(str.find(" ",0)!=string::npos)
05864                         str.erase(0,str.find(" ")+1); // erase everything before SPACE inclusive - my nick
05865                     string chan;
05866                     if(str.find(" ",0)!=string::npos)
05867                         while(str.length() && str[0]!=0x20) {
05868                             chan+=str[0];
05869                             str.erase(0,1);
05870                         }
05871                     str.erase(0,1); // erase space
05872 
05873                     if(str.find(":",0)!=string::npos)
05874                         str.erase(0,str.find(":")+1); // erase everything before ':' inclusive
05875 
05876                     vector<s_online_channel>::iterator i;
05877                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05878                         if(cmp_strings_case_insensitive((*i).name,chan))
05879                             continue;
05880                         (*i).topic="";
05881                         break;
05882                     }
05883                     irc_kill_last_msg_wait(resp);
05884 
05885                     irc_kill_command_wait("TOPIC");
05886                 }
05887                 str=tmp;
05888 
05889                 if(len>4 && str[0]=='M' && str[1]=='O' && str[2]=='D' && str[3]=='E') {
05890                     if(!nick.empty()) {
05891                         string tmp=nick;
05892                         tmp+="!";
05893                         tmp+=ident;
05894                         tmp+="@";
05895                         tmp+=host;
05896                         irc_check_flood(TYPE_MODE,channel,tmp,whom);
05897                     }
05898 
05899                     if(!channel.length()) {
05900                         whom=str;
05901                         if(whom.find(":",0)!=string::npos)
05902                             whom.erase(0,whom.find(":",0)+1);
05903                     }
05904                     log_channel(channel.c_str(),TYPE_MODE,hm.c_str(),"",whom.c_str(),irc_get_modes_for_log(channel,nick).c_str());
05905 
05906                     if(irc_check_last_msg("MODE"))
05907                         irc_kill_last_msg_wait(resp);
05908 
05909                     irc_kill_command_wait("MODE");
05910 
05911                     irc_RPL_MODE(resp);
05912                 }
05913 
05914                 if(len>4 && str[0]=='T' && str[1]=='O' && str[2]=='P' && str[3]=='I' && str[4]=='C') {
05915                     if(!nick.empty()) {
05916                         string tmp=nick;
05917                         tmp+="!";
05918                         tmp+=ident;
05919                         tmp+="@";
05920                         tmp+=host;
05921                         irc_check_flood(TYPE_MODE,channel,tmp,topic);
05922                     }
05923 
05924                     vector<s_online_channel>::iterator i;
05925                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05926                         if(cmp_strings_case_insensitive((*i).name,channel))
05927                             continue;
05928                         (*i).topic=topic;
05929                         break;
05930                     }
05931 
05932                     log_channel(channel.c_str(),TYPE_TOPIC,hm.c_str(),"TOPIC",topic.c_str(),irc_get_modes_for_log(channel,nick).c_str());
05933 
05934                     if(irc_check_last_msg("TOPIC"))
05935                         irc_kill_last_msg_wait(resp);
05936 
05937                     irc_kill_command_wait("TOPIC");
05938 
05939                     irc_RPL_TOPIC(resp);
05940                 }
05941 
05942                 // 472: unknown mode
05943                 if(len>4 && str[0]=='4' && str[1]=='7' && str[2]=='2' && str[3]==' ') {
05944                     if(irc_check_last_msg("MODE"))
05945                         irc_kill_last_msg_wait(resp);
05946 
05947                     irc_kill_command_wait("MODE");
05948 
05949                     // assume that error is on MODE #chan +e (some irc networks doesn't support +e exceptions to bans)
05950                     vector<s_online_channel>::iterator i;
05951                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05952                         (*i).got_excepts=true;
05953                         irc_check_bans((*i).name);
05954                     }
05955 
05956                     // assume that error is on MODE #chan +I (some irc networks doesn't support +I invitations)
05957                     //vector<s_online_channel>::iterator i;
05958                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05959                         (*i).got_invites=true;
05960                         //irc_check_invites((*i).name);
05961                     }
05962 
05963                     //vector<s_online_channel>::iterator i;
05964                     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
05965                         (*i).got_reops=true;
05966                     }
05967 
05968                     s_online_channel* chan;
05969                     if(irc_get_online_channel(channel,chan)) {
05970                         if(!chan->b_excepts_sent && irc_isupport.chanmodes_a.find("e")!=string::npos) {
05971                             chan->b_excepts_sent=true;
05972                             string excepts="MODE ";
05973                             excepts+=channel;
05974                             excepts+=" +e";
05975                             irc_putserv(excepts.c_str(),true,HIGH_PRIORITY);
05976                         }
05977     
05978                         if(!chan->b_bans_sent && irc_isupport.chanmodes_a.find("b")!=string::npos) {
05979                             chan->b_bans_sent=true;
05980                             string bans="MODE ";
05981                             bans+=channel;
05982                             bans+=" +b";
05983                             irc_putserv(bans.c_str(),true,HIGH_PRIORITY);
05984                         }
05985                     }
05986 
05987                     irc_end_of_excepted(resp);
05988                 }
05989 
05990                 // 475: cannot join channel (+k)
05991                 if(len>4 && str[0]=='4' && str[1]=='7' && str[2]=='5' && str[3]==' ') {
05992                     irc_kill_command_wait("JOIN");
05993                     irc_kill_command_wait("MODE");
05994                     irc_kill_command_wait("TOPIC");
05995 
05996                     string s=str;
05997                     int i1=0;
05998                     while(i1<2 && s.length()>0) {
05999                         if(s[0]==0x20)
06000                             i1++;
06001                         s.erase(0,1);
06002                     }
06003                     string chan;
06004                     while(s.length()>0 && s[0]!=0x20) {
06005                         chan+=s[0];
06006                         s.erase(0,1);
06007                     }
06008 
06009                     bool got=false;
06010 label_a:
06011                     vector<s_key_chan>::iterator i2;
06012                     for(i2=irc_key_chans.begin(); i2!=irc_key_chans.end(); i2++) {
06013                         if(!cmp_strings_case_insensitive((*i2).channel_name,chan)) {
06014                             if((*i2).keys.begin()==(*i2).keys.end()) {
06015                                 // :-(
06016                                 string log="Cannot join channel ";
06017                                 log+=chan;
06018                                 log+=" because it is +k, and I have tried all keys that I have in the history. Next retry is scheduled.";
06019                                 log_bot(log.c_str());
06020                                 irc_key_chans.erase(i2);
06021 
06022                                 {
06023                                     bool got=false;
06024                                     vector<string>::iterator ii;
06025                                     for(ii=irc_cannot_join_channels.begin(); ii!=irc_cannot_join_channels.end(); ii++)
06026                                         if(!chan.compare(*ii)) {
06027                                             got=true;
06028                                         }
06029                                     if(!got)
06030                                         irc_cannot_join_channels.push_back(chan);
06031                                 }
06032 
06033                                 got=true;
06034                                 break;
06035                             }
06036                             string key=*((*i2).keys.begin());
06037                             (*i2).keys.erase((*i2).keys.begin());
06038 
06039                             string msg="JOIN ";
06040                             msg+=chan;
06041                             msg+=" ";
06042                             msg+=key;
06043                             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
06044                             msg="MODE ";
06045                             msg+=chan;
06046                             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
06047                             msg="TOPIC ";
06048                             msg+=chan;
06049                             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
06050                             msg="WHOIS ";
06051                             msg+=irc_nick;
06052                             irc_putserv(msg.c_str(),true,HIGH_PRIORITY);
06053 
06054                             irc_kill_last_msg_wait(resp);
06055 
06056                             got=true;
06057                         }
06058                     }
06059                     if(!got) {
06060                         s_key_chan kch;
06061                         kch.channel_name=chan;
06062                         kch.keys.clear();
06063                         vector<s_channel_def>::iterator i2;
06064                         for(i2=r_channel_defs.begin(); i2!=r_channel_defs.end(); i2++)
06065                             if(!cmp_strings_case_insensitive((*i2).channel_name,chan)) {
06066                                 vector<string>::iterator i3;
06067                                 for(i3=(*i2).keys.begin(); i3!=(*i2).keys.end(); i3++)
06068                                     kch.keys.push_back(*i3);
06069                                 irc_key_chans.push_back(kch);
06070                             }
06071                         got=true; // for case that we don't have a channel definition
06072                         goto label_a;
06073                     }
06074                 }
06075 
06076                 // 348: exceptions
06077                 if(len>4 && str[0]=='3' && str[1]=='4' && str[2]=='8' && str[3]==' ') {
06078                     if(irc_check_last_msg("MODE"))
06079                         irc_kill_last_msg_wait(resp);
06080                     irc_excepted(resp);
06081                 }
06082 
06083                 // 349: end of exceptions
06084                 if(len>4 && str[0]=='3' && str[1]=='4' && str[2]=='9' && str[3]==' ') {
06085                     if(irc_check_last_msg("MODE"))
06086                         irc_kill_last_msg_wait(resp);
06087                     irc_kill_command_wait("MODE");
06088                     irc_end_of_excepted(resp);
06089                 }
06090 
06091                 // 367: ban list
06092                 if(len>4 && str[0]=='3' && str[1]=='6' && str[2]=='7' && str[3]==' ') {
06093                     irc_banned(resp);
06094                 }
06095 
06096                 // 368: end of +b list
06097                 if(len>4 && str[0]=='3' && str[1]=='6' && str[2]=='8' && str[3]==' ') {
06098                     if(irc_check_last_msg("MODE"))
06099                         irc_kill_last_msg_wait(resp);
06100                     irc_kill_command_wait("MODE");
06101                 }
06102 
06103                 // 346: invited
06104                 if(len>4 && str[0]=='3' && str[1]=='4' && str[2]=='6' && str[3]==' ') {
06105                     irc_invited(resp);
06106                 }
06107 
06108                 // 347: end of +I list
06109                 if(len>4 && str[0]=='3' && str[1]=='4' && str[2]=='7' && str[3]==' ') {
06110                     if(irc_check_last_msg("MODE"))
06111                         irc_kill_last_msg_wait(resp);
06112                     irc_kill_command_wait("MODE");
06113 
06114                     string s=str;
06115                     string channel;
06116                     int pos=0;
06117                     for(unsigned int i1=0; i1<len; i1++) {
06118                         if(str[i1]==0x20) {
06119                             pos++;
06120                             continue;
06121                         }
06122                         if(pos==2)
06123                             channel+=str[i1];
06124                         if(pos>2)
06125                             break;
06126                     }
06127                     irc_check_for_not_invited(channel);
06128 
06129                     s_online_channel* chan;
06130                     if(irc_get_online_channel(channel,chan)) {
06131                         if(!chan->b_excepts_sent && irc_isupport.chanmodes_a.find("e")!=string::npos) {
06132                             chan->b_excepts_sent=true;
06133                             string excepts="MODE ";
06134                             excepts+=channel;
06135                             excepts+=" +e";
06136                             irc_putserv(excepts.c_str(),true,HIGH_PRIORITY);
06137                         }
06138                     }
06139                 }
06140 
06141                 // 344: in reop list +R
06142                 if(len>4 && str[0]=='3' && str[1]=='4' && str[2]=='4' && str[3]==' ') {
06143                     irc_in_reop(resp);
06144                 }
06145 
06146                 // 345: end of +R list
06147                 if(len>4 && str[0]=='3' && str[1]=='4' && str[2]=='5' && str[3]==' ') {
06148                     if(irc_check_last_msg("MODE"))
06149                         irc_kill_last_msg_wait(resp);
06150                     irc_kill_command_wait("MODE");
06151 
06152                     string s=str;
06153                     string channel;
06154                     int pos=0;
06155                     for(unsigned int i1=0; i1<len; i1++) {
06156                         if(str[i1]==0x20) {
06157                             pos++;
06158                             continue;
06159                         }
06160                         if(pos==2)
06161                             channel+=str[i1];
06162                         if(pos>2)
06163                             break;
06164                     }
06165                     irc_check_for_not_reopped(channel);
06166                 }
06167 
06168                 // :%s 042 %s %s :your unique ID
06169                 if(len>4 && str[0]=='0' && str[1]=='4' && str[2]=='2' && str[3]==' ') {
06170                     irc_RPL_YOURID(resp);
06171                 }
06172 
06173                 // :%s 043 %s %s :nickname collision, forcing nick change to your unique ID.
06174                 if(len>4 && str[0]=='0' && str[1]=='4' && str[2]=='3' && str[3]==' ') {
06175                     static bool got=false;
06176                     if(!got) {
06177                         got=true;
06178                         
06179                         nick=irc_nick;
06180                         ident=irc_get_ident(nick);
06181                         host=irc_get_host(nick);
06182                         msg=irc_unique_id;
06183                         logic_fnc(nick,irc_unique_id);
06184                         goto forced_nick_change;
06185                     } else
06186                         got=false;
06187                 }
06188 
06189                 // 482: you are not a channel operator
06190                 if(len>4 && str[0]=='4' && str[1]=='8' && str[2]=='2' && str[3]==' ') {
06191                     if(irc_check_last_msg("MODE"))
06192                         irc_kill_last_msg_wait(resp);
06193                     irc_kill_command_wait("MODE");
06194 
06195                     if(irc_check_last_msg("KICK"))
06196                         irc_kill_last_msg_wait(resp);
06197                     irc_kill_command_wait("KICK");
06198                 }
06199 
06200                 if(last_msg.wait_for_response && last_msg.timestamp+20<time(NULL))
06201                     irc_kill_last_msg_wait(resp);
06202             }
06203         }
06204 
06205         l2:
06206 
06207         memset(last_msg.response,0,sizeof(last_msg.response));
06208         strncpy(last_msg.response,*i,sizeof(last_msg.response)-1);
06209 
06210         delete[] (*i);
06211 
06212         msgs_from_server.pop_front();
06213 
06214         //goto l1;
06215     }
06216 
06217     dcc_loop();
06218 
06219     return 0;
06220 }
06221 
06222 /*!
06223     \brief Resets user's old_mode atribute
06224     \author VooDooMan
06225     \version 2
06226     \date 2005
06227     \param channel Name of channel
06228     \param nick Nick name
06229     \param prefix '-' or '+'
06230     \param mode '@' or '+'
06231     \warning Behaviour of this function changed in version 1.0.40: Now it just resets old_mode
06232 */
06233 void irc_internal_set_mode(string channel, string nick, char prefix, char mode)
06234 {
06235     vector<s_online_channel>::iterator i1;
06236     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
06237         if(cmp_strings_case_insensitive((*i1).name,channel))
06238             continue;
06239         vector<s_online_user>::iterator i2;
06240         for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++)
06241             if(!cmp_strings_case_insensitive((*i2).nick,nick)) {
06242                 /*while((*i2).mode.find("0",0)!=string::npos)
06243                     (*i2).mode.erase((*i2).mode.find("0",0),1);
06244                 while((*i2).mode.find(mode,0)!=string::npos)
06245                     (*i2).mode.erase((*i2).mode.find(mode,0),1);
06246                 if(prefix=='+')
06247                     (*i2).mode+=mode;
06248                 if((*i2).mode.empty())
06249                     (*i2).mode="0";*/
06250                 (*i2).old_mode=(*i2).mode;
06251             }
06252     }
06253 }
06254 
06255 /*!
06256     \brief Sets +o (chan op) status to nick on channel
06257     \author VooDooMan
06258     \version 1
06259     \date 2004
06260     \param channel Channel name
06261     \param nick Nick name
06262     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06263     \return Returns false if socket I/O error occured
06264 */
06265 bool irc_op(const char* channel, const char* nick, int priority)
06266 {
06267     if(strlen(channel)>128)
06268         return false;
06269     if(strlen(nick)>128)
06270         return false;
06271 
06272     irc_internal_set_mode(channel,nick,'+','@');
06273 
06274     char msg[4096];
06275     strcpy(msg,"MODE ");
06276     strcat(msg,channel);
06277     strcat(msg," +o ");
06278     strcat(msg,nick);
06279 
06280     return irc_putserv(msg,true,priority);
06281 }
06282 
06283 /*!
06284     \brief Sets -o (chan op) status to nick on channel
06285     \author VooDooMan
06286     \version 1
06287     \date 2004
06288     \param channel Channel name
06289     \param nick Nick name
06290     \return Returns false if socket I/O error occured
06291     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06292 */
06293 bool irc_deop(const char* channel, const char* nick, int priority)
06294 {
06295     if(strlen(channel)>128)
06296         return false;
06297     if(strlen(nick)>128)
06298         return false;
06299 
06300     irc_internal_set_mode(channel,nick,'-','@');
06301 
06302     char msg[4096];
06303     strcpy(msg,"MODE ");
06304     strcat(msg,channel);
06305     strcat(msg," -o ");
06306     strcat(msg,nick);
06307 
06308     return irc_putserv(msg,true,priority);
06309 }
06310 
06311 /*!
06312     \brief Sets +v (voice) status to nick on channel
06313     \author VooDooMan
06314     \version 1
06315     \date 2004
06316     \param channel Channel name
06317     \param nick Nick name
06318     \return Returns false if socket I/O error occured
06319     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06320 */
06321 bool irc_voice(const char* channel, const char* nick, int priority)
06322 {
06323     if(strlen(channel)>128)
06324         return false;
06325     if(strlen(nick)>128)
06326         return false;
06327 
06328     irc_internal_set_mode(channel,nick,'+','+');
06329 
06330     char msg[4096];
06331     strcpy(msg,"MODE ");
06332     strcat(msg,channel);
06333     strcat(msg," +v ");
06334     strcat(msg,nick);
06335 
06336     return irc_putserv(msg,true,priority);
06337 }
06338 
06339 /*!
06340     \brief Sets -v (voice) status to nick on channel
06341     \author VooDooMan
06342     \version 1
06343     \date 2004
06344     \param channel Channel name
06345     \param nick Nick name
06346     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06347     \return Returns false if socket I/O error occured
06348 */
06349 bool irc_devoice(const char* channel, const char* nick, int priority)
06350 {
06351     if(strlen(channel)>128)
06352         return false;
06353     if(strlen(nick)>128)
06354         return false;
06355 
06356     irc_internal_set_mode(channel,nick,'-','+');
06357 
06358     char msg[4096];
06359     strcpy(msg,"MODE ");
06360     strcat(msg,channel);
06361     strcat(msg," -v ");
06362     strcat(msg,nick);
06363 
06364     return irc_putserv(msg,true,priority);
06365 }
06366 
06367 /*!
06368     \brief Kicks nick on channel
06369     \author VooDooMan
06370     \version 1
06371     \date 2004
06372     \param channel Channel name
06373     \param nick Nick name
06374     \param reason Kick message (reason of kick)
06375     \return Returns false if socket I/O error occured
06376 */
06377 bool irc_kick(const char* channel, const char* nick, const char* reason)
06378 {
06379     if(strlen(channel)>128)
06380         return false;
06381     if(strlen(nick)>128)
06382         return false;
06383     if(strlen(reason)>128)
06384         return false;
06385 
06386     char msg[4096];
06387     strcpy(msg,"KICK ");
06388     strcat(msg,channel);
06389     strcat(msg," ");
06390     strcat(msg,nick);
06391     if(reason!=NULL && strlen(reason)>0) {
06392         strcat(msg," :");
06393         strcat(msg,reason);
06394     }
06395 
06396     return irc_putserv(msg,false,HIGH_PRIORITY);
06397 }
06398 
06399 /*!
06400     \brief JOINs channel
06401     \author VooDooMan
06402     \version 1
06403     \date 2004
06404     \param channel Channel name
06405     \param key Key to channel (can be empty)
06406     \return Returns false if socket I/O error occured
06407 */
06408 bool irc_join(const char* channel, const char* key)
06409 {
06410     if(strlen(channel)>128)
06411         return false;
06412 
06413     char msg[4096];
06414     strcpy(msg,"JOIN ");
06415     strcat(msg,channel);
06416     if(key[0]!=0) {
06417         strcat(msg," ");
06418         strcat(msg,key);
06419     }
06420     bool ok=irc_putserv(msg,false,HIGH_PRIORITY);
06421     strcpy(msg,"MODE ");
06422     strcat(msg,channel);
06423     ok&=irc_putserv(msg,true,HIGH_PRIORITY);
06424     strcpy(msg,"TOPIC ");
06425     strcat(msg,channel);
06426     ok&=irc_putserv(msg,true,HIGH_PRIORITY);
06427     strcpy(msg,"WHOIS ");
06428     strcat(msg,irc_nick);
06429     ok&=irc_putserv(msg,true,HIGH_PRIORITY);
06430 
06431     return ok;
06432 }
06433 
06434 /*!
06435     \brief PARTs channel
06436     \author VooDooMan
06437     \version 1
06438     \date 2004
06439     \param channel Channel name
06440     \param reason PART message (reason of PART)
06441     \return Returns false if socket I/O error occured
06442 */
06443 bool irc_part(const char* channel, const char* reason)
06444 {
06445     if(strlen(channel)>128)
06446         return false;
06447     if(strlen(reason)>128)
06448         return false;
06449 
06450     char msg[4096];
06451     strcpy(msg,"PART ");
06452     strcat(msg,channel);
06453     if(reason[0]) {
06454         strcat(msg," :");
06455         strcat(msg,reason);
06456     }
06457 
06458     return irc_putserv(msg,false,HIGH_PRIORITY);
06459 }
06460 
06461 /*!
06462     \brief Sends PRIVMSG to user/channel
06463     \author VooDooMan
06464     \version 1
06465     \date 2004
06466     \param target Nick name / channel name of target
06467     \param msg Whole message
06468     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06469     \return Returns false if socket I/O error occured
06470 */
06471 bool irc_privmsg(const char* target, const char* msg, int priority)
06472 {
06473     if(strlen(target)>128)
06474         return false;
06475     if(strlen(msg)>512-1)
06476         return false;
06477 
06478     char tmp[4096];
06479     strcpy(tmp,"PRIVMSG ");
06480     strcat(tmp,target);
06481     strcat(tmp," :");
06482     strcat(tmp,msg);
06483 
06484     return irc_putserv(tmp,false,priority);
06485 }
06486 
06487 /*!
06488     \brief Sends NOTICE to user/channel
06489     \author VooDooMan
06490     \version 1
06491     \date 2004
06492     \param target Nick name / channel name of target
06493     \param msg Whole message
06494     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06495     \return Returns false if socket I/O error occured
06496 */
06497 bool irc_notice(const char* target, const char* msg, int priority)
06498 {
06499     if(strlen(target)>128)
06500         return false;
06501     if(strlen(msg)>512-1)
06502         return false;
06503 
06504     char tmp[4096];
06505     strcpy(tmp,"NOTICE ");
06506     strcat(tmp,target);
06507     strcat(tmp," :");
06508     strcat(tmp,msg);
06509 
06510     return irc_putserv(tmp,false,priority);
06511 }
06512 
06513 /*!
06514     \brief Looks-up user from name in logic.txt to nick name (if online)
06515     \author VooDooMan
06516     \version 1
06517     \date 2004
06518     \param user User name as in logic.txt
06519     \return If user is online, returns its nick name, if not, returns user parameter
06520 */
06521 string irc_get_nick(string user)
06522 {
06523     vector<s_online_channel>::iterator i;
06524     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06525         vector<s_online_user>::iterator ii;
06526         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
06527             if(!cmp_strings_case_insensitive((*ii).in_logic_as,user)) {
06528                 return (*ii).nick;
06529             }
06530         }
06531     }
06532 
06533     return user;
06534 }
06535 
06536 /*!
06537     \brief Looks-up user from name in logic.txt to nick name (if online)
06538     \author VooDooMan
06539     \version 1
06540     \date 2004
06541     \param user User name as in logic.txt
06542     \return If user is online, returns its nick name, if not, returns empty string
06543 */
06544 string irc_is_online(string user)
06545 {
06546     vector<s_online_channel>::iterator i;
06547     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06548         vector<s_online_user>::iterator ii;
06549         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
06550             if(!cmp_strings_case_insensitive((*ii).in_logic_as,user)) {
06551                 return (*ii).nick;
06552             }
06553         }
06554     }
06555 
06556     return "";
06557 }
06558 
06559 /*!
06560     \brief Looks-up user from name in logic.txt  and checks if it is an irc operator (if online)
06561     \author VooDooMan
06562     \version 1
06563     \date 2004
06564     \param nick Nick name
06565     \return If user is online, returns true for irc operator, if it is not online, returns false
06566 */
06567 bool irc_is_ircop(string nick)
06568 {
06569     vector<s_online_channel>::iterator i;
06570     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06571         vector<s_online_user>::iterator ii;
06572         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
06573             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
06574                 return (*ii).irc_op;
06575             }
06576         }
06577     }
06578 
06579     return false;
06580 }
06581 
06582 /*!
06583     \brief Looks-up user from nick name and checks its mode on channel
06584     \author VooDooMan
06585     \version 1
06586     \date 2004
06587     \param channel Channel name
06588     \param nick Nick name
06589     \return Returns mode (i.e. "+", "@", "~", "@+", "+@", or "0")
06590     \retval "+" User has voice
06591     \retval "@" User is channel operator
06592     \retval "0" Normal user
06593     \retval "@+" both +o and +v
06594 */
06595 string irc_get_mode(string channel, string nick)
06596 {
06597     vector<s_online_channel>::iterator i;
06598     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06599         if(!cmp_strings_case_insensitive((*i).name,channel)) {
06600             vector<s_online_user>::iterator ii;
06601             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
06602                 if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
06603                     if(!(*ii).got_mode)
06604                         return "0";
06605                     return (*ii).mode;
06606                 }
06607             }
06608         }
06609     }
06610 
06611     return "0";
06612 }
06613 
06614 /*!
06615     \brief Looks-up user from nick name and returns their mode(s) for logging purposes to channel log
06616     \author VooDooMan
06617     \version 1
06618     \date 2005
06619     \param channel Channel name
06620     \param nick Nick name
06621     \return Returns mode(s) (i.e. "o", "v", "a", "ov", or "" - an empty string for none, or "?" for not-got-WHOIS-yet/unknown nick)
06622     \retval '?' if we don't have WHOIS yet, or nick is unknown
06623 */
06624 string irc_get_modes_for_log(string channel, string nick)
06625 {
06626     vector<s_online_channel>::iterator i;
06627     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06628         if(!cmp_strings_case_insensitive((*i).name,channel)) {
06629             vector<s_online_user>::iterator ii;
06630             for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
06631                 if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
06632                     if(!(*ii).got_mode)
06633                         return "?";
06634                     string res;
06635                     if((*ii).irc_op)
06636                         res+="!";
06637                     for(unsigned int i1=0; i1<(*ii).mode.length(); i1++)
06638                         if((*ii).mode[i1]!='0')
06639                             res+=(string)""+irc_isupport.get_prefix2((*ii).mode[i1]);
06640                     return res;
06641                 }
06642             }
06643         }
06644     }
06645 
06646     return "?";
06647 }
06648 
06649 /*!
06650     \brief Looks-up user from nick name and checks its full name
06651     \author VooDooMan
06652     \version 1
06653     \date 2004
06654     \param nick Nick name
06655     \return Returns full name if online, if not, empty string
06656 */
06657 string irc_get_fullname(string nick)
06658 {
06659     vector<s_online_channel>::iterator i;
06660     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06661         vector<s_online_user>::iterator ii;
06662         for(ii=(*i).users.begin(); ii!=(*i).users.end(); ii++) {
06663             if(!cmp_strings_case_insensitive((*ii).nick,nick)) {
06664                 if(!(*ii).got_whois)
06665                     return "";
06666                 return (*ii).fullname;
06667             }
06668         }
06669     }
06670 
06671     return "";
06672 }
06673 
06674 /*!
06675     \brief Unbans (MODE \#channel -b mask) host mask on channel
06676     \author VooDooMan
06677     \version 1
06678     \date 2004
06679     \param channel Channel name
06680     \param mask Ban mask
06681     \return Returns false if socket I/O error occured, or channel is longer than 128 chars, or mask is longer than 511 bytes
06682 */
06683 bool irc_unban(const char* channel, const char* mask)
06684 {
06685     if(strlen(channel)>128)
06686         return false;
06687     if(strlen(mask)>512-1)
06688         return false;
06689 
06690     vector<s_online_channel>::iterator i;
06691     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06692         if(!cmp_strings_case_insensitive((*i).name,(string)channel)) {
06693             vector<string>::iterator i2;
06694             for(i2=(*i).bans.begin(); i2!=(*i).bans.end(); i2++) {
06695                 if(!cmp_strings_case_insensitive((*i2),(string)mask)) {
06696                     (*i).bans.erase(i2);
06697                     break;
06698                 }
06699             }
06700         }
06701     }
06702 
06703     char tmp[4096];
06704     strcpy(tmp,"MODE ");
06705     strcat(tmp,channel);
06706     strcat(tmp," -b ");
06707     strcat(tmp,mask);
06708 
06709     return irc_putserv(tmp,true,HIGH_PRIORITY);
06710 }
06711 
06712 /*!
06713     \brief Bans (MODE \#channel +b mask) host mask on channel
06714     \author VooDooMan
06715     \version 1
06716     \date 2004
06717     \param channel Channel name
06718     \param mask Ban mask
06719     \return Returns false if socket I/O error occured, or channel is longer than 128 chars, or mask is longer than 511 bytes
06720 */
06721 bool irc_ban(const char* channel, const char* mask)
06722 {
06723     if(strlen(channel)>128)
06724         return false;
06725     if(strlen(mask)>512-1)
06726         return false;
06727 
06728      if(irc_isupport.chanmodes_a.find("b")==string::npos)
06729          return true;
06730 
06731     char tmp[4096];
06732     strcpy(tmp,"MODE ");
06733     strcat(tmp,channel);
06734     strcat(tmp," +b ");
06735     strcat(tmp,mask);
06736 
06737     return irc_putserv(tmp,false,HIGH_PRIORITY);
06738 }
06739 
06740 /*!
06741     \brief Sets value of irc_follow_redirs flag
06742     \author VooDooMan
06743     \version 1
06744     \date 2004
06745     \param follow_redirs flag to set
06746 */
06747 void irc_set_redir(bool follow_redirs)
06748 {
06749     irc_follow_redirs=follow_redirs;
06750 }
06751 
06752 /*!
06753     \brief Looks-up ident of online user
06754     \author VooDooMan
06755     \version 1
06756     \date 2004
06757     \param nick Nick name of user
06758     \return Returns ident of user, or empty string if there's no such nick online
06759 */
06760 string irc_get_ident(string nick)
06761 {
06762     vector<s_online_channel>::iterator i1;
06763     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
06764         vector<s_online_user>::iterator i2;
06765         for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++) {
06766             if(!cmp_strings_case_insensitive((*i2).nick,nick)) {
06767                 if(!(*i2).got_whois)
06768                     break;
06769                 return (*i2).ident;
06770             }
06771         }
06772     }
06773     vector<s_online_user>::iterator i2;
06774     for(i2=gone_users.begin(); i2!=gone_users.end(); i2++) {
06775         if(!cmp_strings_case_insensitive((*i2).nick,nick)) {
06776             if(!(*i2).got_whois)
06777                 break;
06778             return (*i2).ident;
06779         }
06780     }
06781     return "";
06782 }
06783 
06784 /*!
06785     \brief Looks-up host of online user
06786     \author VooDooMan
06787     \version 1
06788     \date 2004
06789     \param nick Nick name of user
06790     \return Returns host of user, or empty string if there's no such nick online
06791 */
06792 string irc_get_host(string nick)
06793 {
06794     vector<s_online_channel>::iterator i1;
06795     for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
06796         vector<s_online_user>::iterator i2;
06797         for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++) {
06798             if(!cmp_strings_case_insensitive((*i2).nick,nick)) {
06799                 if(!(*i2).got_whois)
06800                     break;
06801                 return (*i2).host;
06802             }
06803         }
06804     }
06805     vector<s_online_user>::iterator i2;
06806     for(i2=gone_users.begin(); i2!=gone_users.end(); i2++) {
06807         if(!cmp_strings_case_insensitive((*i2).nick,nick)) {
06808             if(!(*i2).got_whois)
06809                 break;
06810             return (*i2).host;
06811         }
06812     }
06813     return "";
06814 }
06815 
06816 /*!
06817     \brief Raw-ly puts message to queue to send to server
06818     \author VooDooMan
06819     \version 1
06820     \date 2004
06821     \param data Raw message (i.e. "PRIVMSG nick hello!")
06822     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06823 */
06824 void irc_put(string data, int priority)
06825 {
06826     irc_putserv(data.c_str(),false,priority);
06827 }
06828 
06829 /*!
06830     \brief Sets mode of channel
06831     \author VooDooMan
06832     \version 1
06833     \date 2004
06834     \param channel Channel name
06835     \param mode Mode to set
06836     \param priority Priority class (LOW_PRIORITY, HIGH_PRIORITY, or CRITICAL_PRIORITY)
06837     \return Returns irc_putserv() result
06838 */
06839 bool irc_chan_mode(const char* channel, const char* mode,int priority)
06840 {
06841     string msg="MODE ";
06842     msg+=channel;
06843     msg+=" ";
06844     msg+=mode;
06845     return !irc_putserv(msg.c_str(),false,priority);
06846 }
06847 
06848 /*!
06849     \brief Quits the IRC
06850     \author VooDooMan
06851     \version 1
06852     \date 2004
06853     \param reason Quit message
06854 */
06855 void irc_quit(const char* reason)
06856 {
06857     string tmp="QUIT :";
06858     tmp+=reason;
06859     tmp+=(string)"\r\n";
06860     irc_putserv_immediately(irc_socket,tmp.c_str(),true);
06861     sock_send_cache();
06862     sock_flush_later(irc_socket);
06863     //sleep(1000);
06864 }
06865 
06866 /*!
06867     \brief Called to await DCC connection from user
06868     \author VooDooMan
06869     \version 1
06870     \date 2004
06871     \param nick Nick of user
06872     \param dcc_group DCC-group ID
06873     \param user_name_as_in_logic User name from "logic.txt"
06874 */
06875 void irc_await_dcc_chat(string nick, string user_name_as_in_logic, int dcc_group)
06876 {
06877     string dcc_host=logic_get_dcc_host(dcc_group,user_name_as_in_logic);
06878 
06879     s_dcc_awaiting_user user;
06880 
06881     user.nick=nick;
06882     user.ident=irc_get_ident(nick);
06883     user.host=irc_get_host(nick);
06884     user.fullname=irc_get_fullname(nick);
06885 
06886     size_t n=user_name_as_in_logic.length();
06887     if(n>128-1)
06888         n=128-1;
06889     strncpy(user.user_name_as_in_logic,user_name_as_in_logic.c_str(),n);
06890     user.user_name_as_in_logic[n]=0;
06891 
06892     in_addr6_ ip6;
06893     if(inet_pton(AF_INET6,dcc_host.c_str(),&ip6)!=1) {
06894         user.addr4=sock_resolve(dcc_host.c_str(),NULL);
06895         user.using_ipv6=false;
06896     } else {
06897         memcpy(&user.addr6,&ip6,sizeof(user.addr6));
06898 #ifdef _WIN32
06899         user.addr4.S_un.S_addr=(unsigned long)-1;
06900 #else
06901         user.addr4.s_addr=(unsigned long)-1;
06902 #endif
06903         user.using_ipv6=true;
06904     }
06905     time(&user.start_time);
06906     dcc_awaiting_users.push_back(user);
06907 }
06908 
06909 /*!
06910     \brief Called from logic.cpp after rehashing. Deletes all online users and so applies new configuration
06911     \author VooDooMan
06912     \version 1
06913     \date 2004
06914 */
06915 void irc_rehashed()
06916 {
06917     irc_bot_flood_bytes=atol(conf_getvar("irc_bot_flood_bytes").c_str());
06918     irc_bot_flood_seconds=atol(conf_getvar("irc_bot_flood_seconds").c_str());
06919     irc_bot_flood_lines=atol(conf_getvar("irc_bot_flood_lines").c_str());
06920 
06921     {
06922         vector<s_online_channel>::iterator i1;
06923         for(i1=irc_channels.begin(); i1!=irc_channels.end(); i1++) {
06924             vector<s_online_user>::iterator i2;
06925             for(i2=(*i1).users.begin(); i2!=(*i1).users.end(); i2++) {
06926                 if((*i2).got_whois)
06927                     (*i2).in_logic_as=logic_find_user((*i2).nick,(*i2).ident,(*i2).host,(*i2).fullname,(*i2).irc_op);
06928                 logic_on_nick_validate((*i2).nick,(*i2).ident,(*i2).host,(*i2).fullname,(*i1).name,(*i2).irc_op,true);
06929             }
06930         }
06931     }
06932 }
06933 
06934 /*!
06935     \brief Checks if bot has op (+o) on channel
06936     \author VooDooMan
06937     \version 1
06938     \date 2004
06939     \param channel Channel to check
06940     \retval true If bot got +o
06941     \retval false If bot got -o
06942 */
06943 bool irc_got_op(string channel)
06944 {
06945     string m=irc_get_mode(channel,irc_nick);
06946     return m.find(irc_isupport.get_prefix1('o'),0)!=string::npos;
06947 }
06948 
06949 /*!
06950     \brief Returns channel mode
06951     \author VooDooMan
06952     \version 1
06953     \date 2004
06954     \param channel Channel name
06955     \param topic Returns topic of channel
06956     \return Returns mode (i.e. "", "nt", "nts", "ntp", "n",..)
06957 */
06958 string irc_get_chan_mode(string channel, string& topic)
06959 {
06960     topic="";
06961     vector<s_online_channel>::iterator i;
06962     for(i=irc_channels.begin(); i!=irc_channels.end(); i++) {
06963         if(!cmp_strings_case_insensitive((*i).name,channel)) {
06964             topic=(*i).topic;
06965             return (*i).modes;
06966         }
06967     }
06968 
06969     return "";
06970 }
06971 
06972 /*!
06973     \brief Gets information from parsed RPL_ISUPPORT message (005 numeric)
06974     \author VooDooMan
06975     \version 1
06976     \date 2004
06977     \param raw Assiciative array with all features
06978     \param prefix Associative array with prefixes (user modes: 'o'=='@', 'v'=='+', etc.)
06979     \param chm_a Channel modes class A - +b, +e, ...
06980     \param chm_b Channel modes class B - +k
06981     \param chm_c Channel modes class C - +l
06982     \param chm_d Channel modes class D - +n, +t, ...
06983 */
06984 void irc_get_005(map<string,string>& raw, map<char,char>& prefix, string& chm_a, string& chm_b, string& chm_c, string& chm_d)
06985 {
06986     raw=irc_isupport.raw;
06987     prefix=irc_isupport.prefix;
06988     chm_a=irc_isupport.chanmodes_a;
06989     chm_b=irc_isupport.chanmodes_b;
06990     chm_c=irc_isupport.chanmodes_c;
06991     chm_d=irc_isupport.chanmodes_d;
06992 }
06993 

Generated on Sun Jul 10 03:22:54 2005 for VooDoo cIRCle by doxygen 1.4.3

Hosted by SourceForge.net Logo