// An IRC analyzer contributed by Roland Gruber. #include #include "IRC.h" #include "DPM.h" #include "ContentLine.h" #include "NetVar.h" #include "Event.h" #include "ZIP.h" IRC_Analyzer::IRC_Analyzer(Connection* conn) : TCP_ApplicationAnalyzer(AnalyzerTag::IRC, conn) { invalid_msg_count = 0; invalid_msg_max_count = 20; orig_status = WAIT_FOR_REGISTRATION; resp_status = WAIT_FOR_REGISTRATION; orig_zip_status = NO_ZIP; resp_zip_status = NO_ZIP; AddSupportAnalyzer(new ContentLine_Analyzer(conn, true)); AddSupportAnalyzer(new ContentLine_Analyzer(conn, false)); } bool IRC_Analyzer::Available() { static bool did_avail = false; static bool avail = false; if ( ! did_avail ) { // It's a lot of events, but for consistency with other // analyzers we need to check for all of them. avail = irc_request || irc_reply || irc_message || irc_quit_message || irc_privmsg_message || irc_notice_message || irc_squery_message || irc_join_message || irc_part_message || irc_nick_message || irc_invalid_nick || irc_network_info || irc_server_info || irc_channel_info || irc_who_line || irc_who_message || irc_whois_message || irc_whois_user_line || irc_whois_operator_line || irc_whois_channel_line || irc_oper_message || irc_oper_response || irc_kick_message || irc_error_message || irc_invite_message || irc_mode_message || irc_squit_message || irc_names_info || irc_dcc_message || irc_global_users || irc_user_message || irc_channel_topic || irc_password_message; did_avail = true; } return avail; } void IRC_Analyzer::Done() { TCP_ApplicationAnalyzer::Done(); } void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { TCP_ApplicationAnalyzer::DeliverStream(length, line, orig); // check line size if ( length > 512 ) { Weird("irc_line_size_exceeded"); return; } if ( length < 2 ) { Weird("irc_line_too_short"); return; } string myline = string((const char*) line); // Check for prefix. string prefix = ""; if ( line[0] == ':' ) { // find end of prefix and extract it unsigned int pos = myline.find(' '); if ( pos > (unsigned int) length ) { Weird("irc_invalid_line"); return; } prefix = myline.substr(1, pos - 1); myline = myline.substr(pos + 1); // remove prefix from line } if ( orig ) ProtocolConfirmation(); int code = 0; string command = ""; // Check if line is long enough to include status code or command. if ( myline.size() < 4 ) { Weird("irc_invalid_line"); ProtocolViolation("line too short"); return; } // Check if this is a server reply. if ( isdigit(myline[0]) ) { if ( isdigit(myline[1]) && isdigit(myline[2]) && myline[3] == ' ') { code = (myline[0] - '0') * 100 + (myline[1] - '0') * 10 + (myline[2] - '0'); myline = myline.substr(4); } else { Weird("irc_invalid_reply_number"); ProtocolViolation("invalid reply number"); return; } } else { // get command unsigned int pos = myline.find(' '); if ( pos > (unsigned int) length ) { Weird("irc_invalid_line"); return; } command = myline.substr(0, pos); for ( unsigned int i = 0; i < command.size(); ++i ) command[i] = toupper(command[i]); myline = myline.substr(pos + 1); } // Extract parameters. string params = myline; // Check for Server2Server - connections with ZIP enabled. if ( orig && orig_status == WAIT_FOR_REGISTRATION ) { if ( command == "PASS" ) { vector p = SplitWords(params,' '); if ( p.size() > 3 && (p[3].find('Z')<=p[3].size() || p[3].find('z')<=p[3].size()) ) orig_zip_status = ACCEPT_ZIP; else orig_zip_status = NO_ZIP; } // We do not check if SERVER command is successful, since // the connection will be terminated by the server if // authentication fails. // // (### This seems not quite prudent to me - VP) if ( command == "SERVER" && prefix == "") { orig_status = REGISTERED; } } if ( ! orig && resp_status == WAIT_FOR_REGISTRATION ) { if ( command == "PASS" ) { vector p = SplitWords(params,' '); if ( p.size() > 3 && (p[3].find('Z')<=p[3].size() || p[3].find('z')<=p[3].size()) ) resp_zip_status = ACCEPT_ZIP; else resp_zip_status = NO_ZIP; } // Again, don't bother checking whether SERVER command // is successful. if ( command == "SERVER" && prefix == "") resp_status = REGISTERED; } // Analyze server reply messages. if ( code > 0 ) { switch ( code ) { // Ignore unimportant messages. case 1: // RPL_WELCOME case 2: // RPL_YOURHOST case 3: // RPL_CREATED case 4: // RPL_MYINFO case 5: // RPL_BOUNCE case 252: // number of ops online case 253: // number of unknown connections case 265: // RPL_LOCALUSERS case 312: // whois server reply case 315: // end of who list case 317: // whois idle reply case 318: // end of whois list case 366: // end of names list case 372: // RPL_MOTD case 375: // RPL_MOTDSTART case 376: // RPL_ENDOFMOTD case 331: // RPL_NOTOPIC break; // Count of users, services and servers in whole network. case 251: if ( ! irc_network_info ) break; { vector parts = SplitWords(params, ' '); int users = 0; int services = 0; int servers = 0; for ( unsigned int i = 1; i < parts.size(); ++i ) { if ( parts[i] == "users" ) users = atoi(parts[i-1].c_str()); else if ( parts[i] == "services" ) services = atoi(parts[i-1].c_str()); else if ( parts[i] == "servers" ) servers = atoi(parts[i-1].c_str()); // else ### } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new Val(users, TYPE_INT)); vl->append(new Val(services, TYPE_INT)); vl->append(new Val(servers, TYPE_INT)); ConnectionEvent(irc_network_info, vl); } break; // List of users in a channel (names command). case 353: if ( ! irc_names_info ) break; { vector parts = SplitWords(params, ' '); // Remove nick name. parts.erase(parts.begin()); if ( parts.size() < 2 ) { Weird("irc_invalid_names_line"); return; } string type = parts[0]; string channel = parts[1]; // Remove type and channel. parts.erase(parts.begin()); parts.erase(parts.begin()); if ( parts.size() > 0 && parts[0][0] == ':' ) parts[0] = parts[0].substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(type.c_str())); vl->append(new StringVal(channel.c_str())); TableVal* set = new TableVal(string_set); for ( unsigned int i = 0; i < parts.size(); ++i ) { if ( parts[i][0] == '@' ) parts[i] = parts[i].substr(1); set->Assign(new StringVal(parts[i].c_str()), 0); } vl->append(set); ConnectionEvent(irc_names_info, vl); } break; // Count of users and services on this server. case 255: if ( ! irc_server_info ) break; { vector parts = SplitWords(params, ' '); int users = 0; int services = 0; int servers = 0; for ( unsigned int i = 1; i < parts.size(); ++i ) { if ( parts[i] == "users," ) users = atoi(parts[i-1].c_str()); else if ( parts[i] == "clients" ) users = atoi(parts[i-1].c_str()); else if ( parts[i] == "services" ) services = atoi(parts[i-1].c_str()); else if ( parts[i] == "servers" ) servers = atoi(parts[i-1].c_str()); // else ### } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new Val(users, TYPE_INT)); vl->append(new Val(services, TYPE_INT)); vl->append(new Val(servers, TYPE_INT)); ConnectionEvent(irc_server_info, vl); } break; // Count of channels. case 254: if ( ! irc_channel_info ) break; { vector parts = SplitWords(params, ' '); int channels = 0; for ( unsigned int i = 1; i < parts.size(); ++i ) if ( parts[i] == ":channels" ) channels = atoi(parts[i - 1].c_str()); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new Val(channels, TYPE_INT)); ConnectionEvent(irc_channel_info, vl); } break; // RPL_GLOBALUSERS case 266: { // FIXME: We should really streamline all this // parsing code ... if ( ! irc_global_users ) break; const char* prefix = params.c_str(); const char* eop = strchr(prefix, ' '); if ( ! eop ) { Weird("invalid_irc_global_users_reply"); break; } const char *msg = strchr(++eop, ':'); if ( ! msg ) { Weird("invalid_irc_global_users_reply"); break; } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(eop - prefix, prefix)); vl->append(new StringVal(++msg)); ConnectionEvent(irc_global_users, vl); break; } // WHOIS user reply line. case 311: if ( ! irc_whois_user_line ) break; { vector parts = SplitWords(params, ' '); if ( parts.size() > 1 ) parts.erase(parts.begin()); if ( parts.size() < 5 ) { Weird("irc_invalid_whois_user_line"); return; } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(parts[0].c_str())); vl->append(new StringVal(parts[1].c_str())); vl->append(new StringVal(parts[2].c_str())); parts.erase(parts.begin(), parts.begin() + 4); string real_name = parts[0]; for ( unsigned int i = 1; i < parts.size(); ++i ) real_name = real_name + " " + parts[i]; if ( real_name[0] == ':' ) real_name = real_name.substr(1); vl->append(new StringVal(real_name.c_str())); ConnectionEvent(irc_whois_user_line, vl); } break; // WHOIS operator reply line. case 313: if ( ! irc_whois_operator_line ) break; { vector parts = SplitWords(params, ' '); if ( parts.size() > 1 ) parts.erase(parts.begin()); if ( parts.size() < 2 ) { Weird("irc_invalid_whois_operator_line"); return; } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(parts[0].c_str())); ConnectionEvent(irc_whois_operator_line, vl); } break; // WHOIS channel reply. case 319: if ( ! irc_whois_channel_line ) break; { vector parts = SplitWords(params, ' '); // Remove nick name. parts.erase(parts.begin()); if ( parts.size() < 2 ) { Weird("irc_invalid_whois_channel_line"); return; } string nick = parts[0]; parts.erase(parts.begin()); if ( parts.size() > 0 && parts[0][0] == ':' ) parts[0] = parts[0].substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(nick.c_str())); TableVal* set = new TableVal(string_set); for ( unsigned int i = 0; i < parts.size(); ++i ) { Val* idx = new StringVal(parts[i].c_str()); set->Assign(idx, 0); Unref(idx); } vl->append(set); ConnectionEvent(irc_whois_channel_line, vl); } break; // RPL_TOPIC reply. case 332: { if ( ! irc_channel_topic ) break; vector parts = SplitWords(params, ' '); if ( parts.size() < 4 ) { Weird("irc_invalid_topic_reply"); return; } unsigned int pos = params.find(':'); if ( pos < params.size() ) { string topic = params.substr(pos + 1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(parts[1].c_str())); const char* t = topic.c_str(); if ( *t == ':' ) ++t; vl->append(new StringVal(t)); ConnectionEvent(irc_channel_topic, vl); } else { Weird("irc_invalid_topic_reply"); return; } break; } // WHO reply line. case 352: if ( ! irc_who_line ) break; { vector parts = SplitWords(params, ' '); if ( parts.size() < 9 ) { Weird("irc_invalid_who_line"); return; } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(parts[0].c_str())); vl->append(new StringVal(parts[1].c_str())); if ( parts[2][0] == '~' ) parts[2] = parts[2].substr(1); vl->append(new StringVal(parts[2].c_str())); vl->append(new StringVal(parts[3].c_str())); vl->append(new StringVal(parts[4].c_str())); vl->append(new StringVal(parts[5].c_str())); vl->append(new StringVal(parts[6].c_str())); if ( parts[7][0] == ':' ) parts[7] = parts[7].substr(1); vl->append(new Val(atoi(parts[7].c_str()), TYPE_INT)); vl->append(new StringVal(parts[8].c_str())); ConnectionEvent(irc_who_line, vl); } break; // Invalid nick name. case 431: case 432: case 433: case 436: if ( irc_invalid_nick ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); ConnectionEvent(irc_invalid_nick, vl); } break; // Operator responses. case 381: // User is operator case 491: // user is not operator if ( irc_oper_response ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new Val(code == 381, TYPE_BOOL)); ConnectionEvent(irc_oper_response, vl); } break; // All other server replies. default: val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new Val(code, TYPE_COUNT)); vl->append(new StringVal(params.c_str())); ConnectionEvent(irc_reply, vl); break; } return; } // Check if command is valid. if ( command.size() > 20 ) { Weird("irc_invalid_command"); if ( ++invalid_msg_count > invalid_msg_max_count ) { Weird("irc_too_many_invalid"); ProtocolViolation("too many long lines"); return; } return; } else if ( irc_privmsg_message || (irc_dcc_message && command == "PRIVMSG") ) { unsigned int pos = params.find(' '); if ( pos >= params.size() ) { Weird("irc_invalid_privmsg_message_format"); return; } string target = params.substr(0, pos); string message = params.substr(pos + 1); if ( message.size() > 0 && message[0] == ':' ) message = message.substr(1); if ( message.size() > 0 && message[0] == 1 ) message = message.substr(1); // DCC // Check for DCC messages. if ( message.size() > 3 && message.substr(0, 3) == "DCC" ) { if ( message.size() > 0 && message[message.size() - 1] == 1 ) message = message.substr(0, message.size() - 1); vector parts = SplitWords(message, ' '); if ( parts.size() < 5 || parts.size() > 6 ) { // Turbo DCC extension appends a "T" at the end of handshake. if ( ! (parts.size() == 7 && parts[6] == "T") ) { Weird("irc_invalid_dcc_message_format"); return; } } // Calculate IP address. uint32 raw_ip = 0; for ( unsigned int i = 0; i < parts[3].size(); ++i ) { string s = parts[3].substr(i, 1); raw_ip = (10 * raw_ip) + atoi(s.c_str()); } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(target.c_str())); vl->append(new StringVal(parts[1].c_str())); vl->append(new StringVal(parts[2].c_str())); vl->append(new AddrVal(htonl(raw_ip))); vl->append(new Val(atoi(parts[4].c_str()), TYPE_COUNT)); if ( parts.size() >= 6 ) vl->append(new Val(atoi(parts[5].c_str()), TYPE_COUNT)); else vl->append(new Val(0, TYPE_COUNT)); ConnectionEvent(irc_dcc_message, vl); } else { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(target.c_str())); vl->append(new StringVal(message.c_str())); ConnectionEvent(irc_privmsg_message, vl); } } else if ( irc_notice_message && command == "NOTICE" ) { unsigned int pos = params.find(' '); if ( pos >= params.size() ) { Weird("irc_invalid_notice_message_format"); return; } string target = params.substr(0, pos); string message = params.substr(pos + 1); if ( message[0] == ':' ) message = message.substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(target.c_str())); vl->append(new StringVal(message.c_str())); ConnectionEvent(irc_notice_message, vl); } else if ( irc_squery_message && command == "SQUERY" ) { unsigned int pos = params.find(' '); if ( pos >= params.size() ) { Weird("irc_invalid_squery_message_format"); return; } string target = params.substr(0, pos); string message = params.substr(pos + 1); if ( message[0] == ':' ) message = message.substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(target.c_str())); vl->append(new StringVal(message.c_str())); ConnectionEvent(irc_squery_message, vl); } else if ( irc_user_message && command == "USER" ) { // extract username and real name vector parts = SplitWords(params, ' '); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); if ( parts.size() > 0 ) vl->append(new StringVal(parts[0].c_str())); else vl->append(new StringVal("")); if ( parts.size() > 1 ) vl->append(new StringVal(parts[1].c_str())); else vl->append(new StringVal("")); if ( parts.size() > 2 ) vl->append(new StringVal(parts[2].c_str())); else vl->append(new StringVal("")); string realname; for ( unsigned int i = 3; i < parts.size(); i++ ) { realname += parts[i]; if ( i > 3 ) realname += " "; } const char* name = realname.c_str(); vl->append(new StringVal(*name == ':' ? name + 1 : name)); ConnectionEvent(irc_user_message, vl); } else if ( irc_oper_message && command == "OPER" ) { // extract username and password vector parts = SplitWords(params, ' '); if ( parts.size() == 2 ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(parts[0].c_str())); vl->append(new StringVal(parts[1].c_str())); ConnectionEvent(irc_oper_message, vl); } else Weird("irc_invalid_oper_message_format"); } else if ( irc_kick_message && command == "KICK" ) { // Extract channels, users and comment. vector parts = SplitWords(params, ' '); if ( parts.size() <= 1 ) { Weird("irc_invalid_kick_message_format"); return; } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(parts[0].c_str())); vl->append(new StringVal(parts[1].c_str())); if ( parts.size() > 2 ) { string comment = parts[2]; for ( unsigned int i = 3; i < parts.size(); ++i ) comment += " " + parts[i]; if ( comment[0] == ':' ) comment = comment.substr(1); vl->append(new StringVal(comment.c_str())); } else vl->append(new StringVal("")); ConnectionEvent(irc_kick_message, vl); } else if ( irc_join_message && command == "JOIN" ) { if ( params[0] == ':' ) params = params.substr(1); vector parts = SplitWords(params, ' '); if ( parts.size() < 1 ) { Weird("irc_invalid_join_line"); return; } string nickname = ""; if ( prefix.size() > 0 ) { unsigned int pos = prefix.find('!'); if ( pos < prefix.size() ) nickname = prefix.substr(0, pos); } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); TableVal* list = new TableVal(irc_join_list); vector channels = SplitWords(parts[0], ','); vector passwords; if ( parts.size() > 1 ) passwords = SplitWords(parts[1], ','); string empty_string = ""; for ( unsigned int i = 0; i < channels.size(); ++i ) { RecordVal* info = new RecordVal(irc_join_info); info->Assign(0, new StringVal(nickname.c_str())); info->Assign(1, new StringVal(channels[i].c_str())); if ( i < passwords.size() ) info->Assign(2, new StringVal(passwords[i].c_str())); else info->Assign(2, new StringVal(empty_string.c_str())); // User mode. info->Assign(3, new StringVal(empty_string.c_str())); list->Assign(info, 0); Unref(info); } vl->append(list); ConnectionEvent(irc_join_message, vl); } else if ( irc_join_message && command == "NJOIN" ) { vector parts = SplitWords(params, ' '); if ( parts.size() != 2 ) { Weird("irc_invalid_njoin_line"); return; } string channel = parts[0]; if ( parts[1][0] == ':' ) parts[1] = parts[1].substr(1); vector users = SplitWords(parts[1], ','); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); TableVal* list = new TableVal(irc_join_list); string empty_string = ""; for ( unsigned int i = 0; i < users.size(); ++i ) { RecordVal* info = new RecordVal(irc_join_info); string nick = users[i]; string mode = "none"; if ( nick[0] == '@' ) { if ( nick[1] == '@' ) { nick = nick.substr(2); mode = "creator"; } else { nick = nick.substr(1); mode = "operator"; } } else if ( nick[0] == '+' ) { nick = nick.substr(1); mode = "voice"; } info->Assign(0, new StringVal(nick.c_str())); info->Assign(1, new StringVal(channel.c_str())); // Password: info->Assign(2, new StringVal(empty_string.c_str())); // User mode: info->Assign(3, new StringVal(mode.c_str())); list->Assign(info, 0); Unref(info); } vl->append(list); ConnectionEvent(irc_join_message, vl); } else if ( irc_part_message && command == "PART" ) { string channels = params; string message = ""; unsigned int pos = params.find(' '); if ( pos < params.size() ) { channels = params.substr(0, pos); if ( params.size() > pos + 1 ) message = params.substr(pos + 1); if ( message[0] == ':' ) message = message.substr(1); } string nick = prefix; pos = nick.find('!'); if ( pos < nick.size() ) nick = nick.substr(0, pos); vector channelList = SplitWords(channels, ','); TableVal* set = new TableVal(string_set); for ( unsigned int i = 0; i < channelList.size(); ++i ) { Val* idx = new StringVal(channelList[i].c_str()); set->Assign(idx, 0); Unref(idx); } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(nick.c_str())); vl->append(set); vl->append(new StringVal(message.c_str())); ConnectionEvent(irc_part_message, vl); } else if ( irc_quit_message && command == "QUIT" ) { string message = params; if ( message[0] == ':' ) message = message.substr(1); string nickname = ""; if ( prefix.size() > 0 ) { unsigned int pos = prefix.find('!'); if ( pos < prefix.size() ) nickname = prefix.substr(0, pos); } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(nickname.c_str())); vl->append(new StringVal(message.c_str())); ConnectionEvent(irc_quit_message, vl); } else if ( irc_nick_message && command == "NICK" ) { string nick = params; if ( nick[0] == ':' ) nick = nick.substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(nick.c_str())); ConnectionEvent(irc_nick_message, vl); } else if ( irc_who_message && command == "WHO" ) { vector parts = SplitWords(params, ' '); if ( parts.size() < 1 || parts.size() > 2 ) { Weird("irc_invalid_who_message_format"); return; } bool oper = false; if ( parts.size() == 2 && parts[1] == "o" ) oper = true; // Remove ":" from mask. if ( parts[0].size() > 0 && parts[0][0] == ':' ) parts[0] = parts[0].substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(parts[0].c_str())); vl->append(new Val(oper, TYPE_BOOL)); ConnectionEvent(irc_who_message, vl); } else if ( irc_whois_message && command == "WHOIS" ) { vector parts = SplitWords(params, ' '); if ( parts.size() < 1 || parts.size() > 2 ) { Weird("irc_invalid_whois_message_format"); return; } string server = ""; string users = ""; if ( parts.size() == 2 ) { server = parts[0]; users = parts[1]; } else users = parts[0]; val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(server.c_str())); vl->append(new StringVal(users.c_str())); ConnectionEvent(irc_whois_message, vl); } else if ( irc_error_message && command == "ERROR" ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); if ( params[0] == ':' ) params = params.substr(1); vl->append(new StringVal(params.c_str())); ConnectionEvent(irc_error_message, vl); } else if ( irc_invite_message && command == "INVITE" ) { vector parts = SplitWords(params, ' '); if ( parts.size() == 2 ) { // remove ":" from channel if ( parts[1].size() > 0 && parts[1][0] == ':' ) parts[1] = parts[1].substr(1); val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(parts[0].c_str())); vl->append(new StringVal(parts[1].c_str())); ConnectionEvent(irc_invite_message, vl); } else Weird("irc_invalid_invite_message_format"); } else if ( irc_mode_message && command == "MODE" ) { if ( params.size() > 0 ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(params.c_str())); ConnectionEvent(irc_mode_message, vl); } else Weird("irc_invalid_mode_message_format"); } else if ( irc_password_message && command == "PASS" ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(params.c_str())); ConnectionEvent(irc_password_message, vl); } else if ( irc_squit_message && command == "SQUIT" ) { string server = params; string message = ""; unsigned int pos = params.find(' '); if ( pos < params.size() ) { server = params.substr(0, pos); message = params.substr(pos + 1); if ( message[0] == ':' ) message = message.substr(1); } val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(server.c_str())); vl->append(new StringVal(message.c_str())); ConnectionEvent(irc_squit_message, vl); } else if ( orig ) { if ( irc_request ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(command.c_str())); vl->append(new StringVal(params.c_str())); ConnectionEvent(irc_request, vl); } } else { if ( irc_message ) { val_list* vl = new val_list; vl->append(BuildConnVal()); vl->append(new Val(orig, TYPE_BOOL)); vl->append(new StringVal(prefix.c_str())); vl->append(new StringVal(command.c_str())); vl->append(new StringVal(params.c_str())); ConnectionEvent(irc_message, vl); } } if ( orig_status == REGISTERED && resp_status == REGISTERED && orig_zip_status == ACCEPT_ZIP && resp_zip_status == ACCEPT_ZIP ) { orig_zip_status = ZIP_LOADED; resp_zip_status = ZIP_LOADED; AddSupportAnalyzer(new ZIP_Analyzer(Conn(), true)); AddSupportAnalyzer(new ZIP_Analyzer(Conn(), false)); } return; } vector IRC_Analyzer::SplitWords(const string input, const char split) { vector words; if ( input.size() < 1 ) return words; unsigned int start = 0; unsigned int split_pos = 0; // Ignore split-characters at the line beginning. while ( input[start] == split ) { ++start; ++split_pos; } string word = ""; while ( (split_pos = input.find(split, start)) < input.size() ) { word = input.substr(start, split_pos - start); if ( word.size() > 0 && word[0] != split ) words.push_back(word); start = split_pos + 1; } // Add line end if needed. if ( start < input.size() ) { word = input.substr(start, input.size() - start); words.push_back(word); } return words; }