?? handle_irc.c
字號:
/* * Copyright (C) 2001 Marco Ziech (mmz@gmx.net) * Copyright (C) 2005 Bryan Biedenkapp (gatekeep@gmail.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define CONNECTION_INTERNAL_ACCESS#include "common/setup_before.h"#include "common/util.h"#ifdef STDC_HEADERS# include <stdlib.h>#else# ifdef HAVE_MALLOC_H# include <malloc.h># endif#endif#ifdef HAVE_STRING_H# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif# ifdef HAVE_MEMORY_H# include <memory.h># endif#endif#include "compat/strdup.h"#include "compat/strcasecmp.h"#include <errno.h>#include "compat/strerror.h"#include "common/irc_protocol.h"#include "common/packet.h"#include "common/eventlog.h"#include "connection.h"#include "common/bn_type.h"#include "common/field_sizes.h"#include "common/addr.h"#include "common/version.h"#include "common/queue.h"#include "common/list.h"#include "common/bnethash.h"#include "common/bnethashconv.h"#include "message.h"#include "account.h"#include "account_wrap.h"#include "channel.h"#include "irc.h"#include "prefs.h"#include "tick.h"#include "timer.h"#include "server.h"#include "command.h"#include "handle_irc.h"#include "topic.h"#include "command_groups.h"#include "common/tag.h"#include "common/xalloc.h"#include "ctype.h"#include "common/setup_after.h"typedef int (* t_irc_command)(t_connection * conn, int numparams, char ** params, char * text);typedef struct { const char * irc_command_string; t_irc_command irc_command_handler;} t_irc_command_table_row;static int _handle_nick_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_user_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_ping_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_pong_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_pass_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_privmsg_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_notice_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_quit_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_who_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_list_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_topic_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_join_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_names_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_mode_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_userhost_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_ison_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_whois_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_part_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_cvers_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_verchk_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_lobcount_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_whereto_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_apgar_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_serial_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_squadinfo_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_setopt_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_setcodepage_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_setlocale_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_getcodepage_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_getlocale_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_joingame_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_gameopt_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_finduserex_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_page_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_startg_command(t_connection * conn, int numparams, char ** params, char * text);static int _handle_listsearch_command(t_connection * conn, int numparams, char ** params, char * text);/* state "connected" handlers */static const t_irc_command_table_row irc_con_command_table[] ={ { "NICK" , _handle_nick_command }, { "USER" , _handle_user_command }, { "PING" , _handle_ping_command }, { "PONG" , _handle_pong_command }, { "PASS" , _handle_pass_command }, { "PRIVMSG" , _handle_privmsg_command }, { "NOTICE" , _handle_notice_command }, { "QUIT" , _handle_quit_command }, { "CVERS" , _handle_cvers_command }, { "VERCHK" , _handle_verchk_command }, { "LOBCOUNT" , _handle_lobcount_command }, { "WHERETO" , _handle_whereto_command }, { "APGAR" , _handle_apgar_command }, { "SERIAL" , _handle_serial_command }, { NULL , NULL }};/* state "logged in" handlers */static const t_irc_command_table_row irc_log_command_table[] ={ { "WHO" , _handle_who_command }, { "LIST" , _handle_list_command }, { "TOPIC" , _handle_topic_command }, { "JOIN" , _handle_join_command }, { "NAMES" , _handle_names_command }, { "MODE" , _handle_mode_command }, { "USERHOST" , _handle_userhost_command }, { "ISON" , _handle_ison_command }, { "WHOIS" , _handle_whois_command }, { "PART" , _handle_part_command }, { "SQUADINFO" , _handle_squadinfo_command }, { "SETOPT" , _handle_setopt_command }, { "SETCODEPAGE" , _handle_setcodepage_command }, { "SETLOCALE" , _handle_setlocale_command }, { "GETCODEPAGE" , _handle_getcodepage_command }, { "GETLOCALE" , _handle_getlocale_command }, { "JOINGAME" , _handle_joingame_command }, { "GAMEOPT" , _handle_gameopt_command }, { "FINDUSEREX" , _handle_finduserex_command }, { "PAGE" , _handle_page_command }, { "STARTG" , _handle_startg_command }, { "LISTSEARCH" , _handle_listsearch_command }, { NULL , NULL }};static int handle_irc_con_command(t_connection * conn, char const * command, int numparams, char ** params, char * text){ t_irc_command_table_row const *p; for (p = irc_con_command_table; p->irc_command_string != NULL; p++) { if (strcasecmp(command, p->irc_command_string)==0) { if (p->irc_command_handler != NULL) return ((p->irc_command_handler)(conn,numparams,params,text)); } } return -1;}static int handle_irc_log_command(t_connection * conn, char const * command, int numparams, char ** params, char * text){ t_irc_command_table_row const *p; for (p = irc_log_command_table; p->irc_command_string != NULL; p++) { if (strcasecmp(command, p->irc_command_string)==0) { if (p->irc_command_handler != NULL) return ((p->irc_command_handler)(conn,numparams,params,text)); } } return -1;}static int handle_irc_line(t_connection * conn, char const * ircline){ /* [:prefix] <command> [[param1] [param2] ... [paramN]] [:<text>] */ char * line; /* copy of ircline */ char * prefix = NULL; /* optional; mostly NULL */ char * command; /* mandatory */ char ** params = NULL; /* optional (array of params) */ char * text = NULL; /* optional */ char * bnet_command = NULL; /* amadeo: used for battle.net.commands */ int unrecognized_before = 0; int linelen; /* amadeo: counter for stringlenghts */ int numparams = 0; char * tempparams; int i; char paramtemp[MAX_IRC_MESSAGE_LEN*2]; int first = 1; if (!conn) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return -1; } if (!ircline) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL ircline"); return -1; } if (ircline[0] == '\0') { eventlog(eventlog_level_error,__FUNCTION__,"got empty ircline"); return -1; } //amadeo: code was sent by some unknown fellow of pvpgn, prevents buffer-overflow for // too long irc-lines if (strlen(ircline)>254) { char * tmp = (char *)ircline; eventlog(eventlog_level_warn,__FUNCTION__,"line to long, truncation..."); tmp[254]='\0'; } line = xstrdup(ircline); /* split the message */ if (line[0] == ':') { /* The prefix is optional and is rarely provided */ prefix = line; if (!(command = strchr(line,' '))) { eventlog(eventlog_level_warn,__FUNCTION__,"got malformed line (missing command)"); xfree(line); return -1; } *command++ = '\0'; } else { /* In most cases command is the first thing on the line */ command = line; } tempparams = strchr(command,' '); if (tempparams) { *tempparams++ = '\0'; if (tempparams[0]==':') { text = tempparams+1; /* theres just text, no params. skip the colon */ } else { for (i=0;tempparams[i]!='\0';i++) { if ((tempparams[i]==' ')&&(tempparams[i+1]==':')) { text = tempparams+i; *text++ = '\0'; text++; /* skip the colon */ break; /* text found, stop search */ } } params = irc_get_paramelems(tempparams); } } if (params) { /* count parameters */ for (numparams=0;params[numparams];numparams++); } memset(paramtemp,0,sizeof(paramtemp)); for (i=0;((numparams>0)&&(params[i]));i++) { if (!first) strcat(paramtemp," "); strcat(paramtemp,"\""); strcat(paramtemp,params[i]); strcat(paramtemp,"\""); first = 0; } eventlog(eventlog_level_debug,__FUNCTION__,"[%d] got \"%s\" \"%s\" [%s] \"%s\"",conn_get_socket(conn),((prefix)?(prefix):("")),command,paramtemp,((text)?(text):(""))); if (conn_get_state(conn)==conn_state_connected) { t_timer_data temp; conn_set_state(conn,conn_state_bot_username); temp.n = prefs_get_irc_latency(); conn_test_latency(conn,time(NULL),temp); } if (handle_irc_con_command(conn, command, numparams, params, text)!=-1) {} else if (conn_get_state(conn)!=conn_state_loggedin) { char temp[MAX_IRC_MESSAGE_LEN+1]; if ((38+strlen(command)+16+1)<sizeof(temp)) { sprintf(temp,":Unrecognized command \"%s\" (before login)",command); irc_send(conn,ERR_UNKNOWNCOMMAND,temp); } else { irc_send(conn,ERR_UNKNOWNCOMMAND,":Unrecognized command (before login)"); } } else { /* command is handled later */ unrecognized_before = 1; } /* --- The following should only be executable after login --- */ if ((conn_get_state(conn)==conn_state_loggedin)&&(unrecognized_before)) { if (handle_irc_log_command(conn, command, numparams, params, text)!=-1) {} else if ((strstart(command,"LAG")!=0)&&(strstart(command,"JOIN")!=0)){ linelen = strlen (ircline); bnet_command = xmalloc(linelen + 2); bnet_command[0]='/'; strcpy(bnet_command + 1, ircline); handle_command(conn,bnet_command); xfree((void*)bnet_command); } } /* loggedin */ if (params) irc_unget_paramelems(params); xfree(line); return 0;}extern int handle_irc_packet(t_connection * conn, t_packet const * const packet){ unsigned int i; char ircline[MAX_IRC_MESSAGE_LEN]; int ircpos; char const * data; if (!packet) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet"); return -1; } if ((conn_get_class(conn) != conn_class_irc) && (conn_get_class(conn) != conn_class_wol)) { eventlog(eventlog_level_error,__FUNCTION__,"FIXME: handle_irc_packet without any reason (conn->class != conn_class_irc)"); return -1; } /* eventlog(eventlog_level_debug,__FUNCTION__,"got \"%s\"",packet_get_raw_data_const(packet,0)); */ memset(ircline,0,sizeof(ircline)); data = conn_get_ircline(conn); /* fetch current status */ if (data) strcpy(ircline,data); ircpos = strlen(ircline); data = packet_get_raw_data_const(packet,0); for (i=0; i < packet_get_size(packet); i++) { if ((data[i] == '\r')||(data[i] == '\0')) { /* kindly ignore \r and NUL ... */ } else if (data[i] == '\n') { /* end of line */ handle_irc_line(conn,ircline); memset(ircline,0,sizeof(ircline)); ircpos = 0; } else { if (ircpos < MAX_IRC_MESSAGE_LEN-1) ircline[ircpos++] = data[i]; else { ircpos++; /* for the statistic :) */ eventlog(eventlog_level_warn,__FUNCTION__,"[%d] client exceeded maximum allowed message length by %d characters",conn_get_socket(conn),ircpos-MAX_IRC_MESSAGE_LEN); if ((ircpos-MAX_IRC_MESSAGE_LEN)>100) { /* automatic flood protection */ eventlog(eventlog_level_error,__FUNCTION__,"[%d] excess flood",conn_get_socket(conn)); return -1; } } } } conn_set_ircline(conn,ircline); /* write back current status */ return 0;}static int _handle_nick_command(t_connection * conn, int numparams, char ** params, char * text){ /* FIXME: more strict param checking */ if ((conn_get_loggeduser(conn))&& (conn_get_state(conn)!=conn_state_bot_password && conn_get_state(conn)!=conn_state_bot_username)) { irc_send(conn,ERR_RESTRICTED,":You can't change your nick after login"); } else { if ((params)&&(params[0])) { if (conn_get_loggeduser(conn)) irc_send_cmd2(conn,conn_get_loggeduser(conn),"NICK","",params[0]); conn_set_loggeduser(conn,params[0]); } else if (text) { if (conn_get_loggeduser(conn)) irc_send_cmd2(conn,conn_get_loggeduser(conn),"NICK","",text); conn_set_loggeduser(conn,text); } else irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to NICK"); if ((conn_get_user(conn))&&(conn_get_loggeduser(conn)))
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -