/* * ---------------------------------------------------------------- * Night Light IRC Proxy - Connection Parser Functions * ---------------------------------------------------------------- * Copyright (C) 1997-2007 Jonas Kvinge * All rights reserved. * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Last modified by: * Jonas Kvinge (24.08.2007) * */ #define CONN_PARSER_C #define NEED_SYS_TYPES_H 1 /* Extra types */ #define NEED_SYS_PARAM_H 1 /* Some systems need this */ #define NEED_LIMITS_H 0 /* Kernel limits */ #define NEED_STDARG_H 1 /* va_list, etc */ #define NEED_ERRNO_H 1 /* errno */ #define NEED_CTYPE_H 1 /* isdigit(), etc */ #define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */ #define NEED_ARPA_INET_H 0 /* inet_ntoa(), inet_aton(), etc */ #define NEED_STDIO_H 1 /* Standard C UNIX functions */ #define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */ #define NEED_TIME_H 1 /* time(), etc */ #define NEED_SYSCTL_H 0 /* sysctl(), etc */ #define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */ #define NEED_SYS_UIO_H 0 /* iovec, etc */ #define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */ #define NEED_SYS_IOCTL_H 0 /* ioctl(), etc */ #define NEED_SYS_FILIO_H 0 /* Solaris need this for ioctl(), etc */ #define NEED_UNISTD_H 1 /* Unix standard functions */ #define NEED_STRING_H 1 /* C string functions */ #define NEED_SIGNAL_H 0 /* Signal functions */ #define NEED_SYS_SOCKET_H 0 /* Socket functions */ #define NEED_NETDB_H 0 /* Network database functions */ #define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */ #define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */ #define NEED_ARES 0 /* Functions needed for ares */ #define NEED_SSL 1 /* Needed for SSL support */ #include "includes.h" #include "irc.h" #include "conn_conf.h" #include "client.h" #include "client_connection.h" #include "client_notice.h" #include "conn.h" #include "conn_connection.h" #include "conn_parser.h" #include "conn_sendq.h" #include "conn_log.h" #include "conn_ignore.h" #include "chan.h" #include "chan_user.h" /* VARIABLES - JONAS (31.07.2001) */ extern char *IRCNICK; extern struct Client_Struct *Client_Head; /* CONN_PARSER FUNCTION - JONAS (18.07.2001) */ void conn_parser(struct Conn_Struct *ConnS) { char *BufferPT = NULL; char *LinePT = NULL; char *DumbPT = NULL; unsigned long int Count = 0; unsigned long int Len = 0; char *TempPT = NULL; assert(ConnS != NULL); BufferPT = ConnS->RecvBuffer; for (Count = 1 ; BufferPT != NULL ; Count++) { DumbPT = strchr(BufferPT, '\n'); if (DumbPT == NULL) { if (Count == 1) { return; } Len = strlen(BufferPT) + 1; memmove(ConnS->RecvBuffer, BufferPT, Len); TempPT = realloc(ConnS->RecvBuffer, Len); if (TempPT == NULL) { if (Conn_IsWelcome(ConnS)) { conn_quit(ConnS, "Memory allocation failure: [%d] %s", errno, strerror(errno)); } else { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); } return; } ConnS->RecvBuffer = TempPT; return; } LinePT = strtok(BufferPT, "\n"); BufferPT = strtok(NULL, "\0"); if (LinePT == NULL) { continue; } Len = strlen(LinePT); if (LinePT[Len-1] == '\r') { LinePT[Len-1] = '\0'; } DEBUGPRINT(BITMASK_DEBUG_CONN, "Connection %s: Server: %s: Receive: %s", ConnS->Name, ConnS->ServerHostName, LinePT); conn_parse_message(ConnS, LinePT); if (ConnS->RecvBuffer == NULL) { return; } } FREE(ConnS->RecvBuffer); } /* CONN_PARSE_MESSAGE FUNCTION - JONAS (17.07.2001) */ void conn_parse_message(struct Conn_Struct *ConnS, char *MessagePT) { char *PrefixPT = NULL; char *CommandPT = NULL; char *LinePT = NULL; char **ParamsPT = NULL; char **TempPT = NULL; unsigned short int Index = 0; unsigned short int Params = 0; unsigned short int Numeric = 0; struct Client_Struct *ClientS = NULL; assert(ConnS != NULL); assert(MessagePT != NULL); while (MessagePT[0] == ' ') { MessagePT++; } if (MessagePT[0] == '\0') { return; } LinePT = strdup(MessagePT); if (LinePT == NULL) { if (Conn_IsWelcome(ConnS)) { conn_quit(ConnS, "Memory allocation failure: [%d] %s", errno, strerror(errno)); } else { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); } return; } if (MessagePT[0] == ':') { MessagePT++; PrefixPT = MessagePT; MessagePT = strchr(MessagePT, ' '); if (MessagePT == NULL) { free(LinePT); return; } MessagePT[0] = '\0'; MessagePT++; while (MessagePT[0] == ' ') { MessagePT++; } if (MessagePT[0] == '\0') { free(LinePT); return; } } else { if (ConnS->ServerName == NULL) { if (ConnS->ServerHostName == NULL) { PrefixPT = ConnS->ServerHostIPS; } else { PrefixPT = ConnS->ServerHostName; } } else { PrefixPT = ConnS->ServerName; } } CommandPT = MessagePT; MessagePT = strchr(MessagePT, ' '); if (MessagePT == NULL) { free(LinePT); return; } MessagePT[0] = '\0'; MessagePT++; while (MessagePT[0] == ' ') { MessagePT++; } if (MessagePT[0] == '\0') { free(LinePT); return; } FOREVERLOOP { if (MessagePT[0] == ':') { MessagePT++; ++Params; TempPT = realloc(ParamsPT, (sizeof(char *) * Params)); if (TempPT == NULL) { if (Conn_IsWelcome(ConnS)) { conn_quit(ConnS, "Memory allocation failure: [%d] %s", errno, strerror(errno)); } else { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); } free(LinePT); free(ParamsPT); return; } ParamsPT = TempPT; ParamsPT[Index] = MessagePT; break; } else { ++Params; TempPT = realloc(ParamsPT, (sizeof(char *) * Params)); if (TempPT == NULL) { if (Conn_IsWelcome(ConnS)) { conn_quit(ConnS, "Memory allocation failure: [%d] %s", errno, strerror(errno)); } else { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); } free(LinePT); free(ParamsPT); return; } ParamsPT = TempPT; ParamsPT[Index] = MessagePT; ++Index; MessagePT = strchr(MessagePT, ' '); if (MessagePT == NULL) { break; } MessagePT[0] = '\0'; MessagePT++; while (MessagePT[0] == ' ') { MessagePT++; } if (MessagePT[0] == '\0') { break; } } } if (strdigit(CommandPT) == TRUE) { Numeric = atoi(CommandPT); if (conn_parse_numeric(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params) == FALSE) { free(LinePT); free(ParamsPT); return; } } else { if (conn_parse_event(ConnS, PrefixPT, CommandPT, ParamsPT, Params) == FALSE) { free(LinePT); free(ParamsPT); return; } } for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) { if (ClientS->ConnS == ConnS) { client_addsend(ClientS, "%s", LinePT); } } free(LinePT); free(ParamsPT); } /* CONN_PARSE_NUMERIC FUNCTION - JONAS (17.07.2001) */ unsigned short int conn_parse_numeric(struct Conn_Struct *ConnS, const char *const PrefixPT, const char *const LinePT, const unsigned short int Numeric, char **ParamsPT, const unsigned short int Params) { unsigned short int Result = TRUE; switch(Numeric) { case 1: case 2: case 3: case 4: CONN_PARSE_NUMERIC_CHECKPARAMS(1); Result = conn_parse_numeric_welcome(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_GENERIC_RPL_ISUPPORT: if (!Conn_IsWelcome(ConnS)) { break; } CONN_PARSE_NUMERIC_CHECKPARAMS(1); Result = conn_parse_numeric_isupport(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_RPL_NOWAWAY: if (!Conn_IsWelcome(ConnS)) { break; } Result = conn_parse_numeric_nowaway(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_RPL_UNAWAY: if (!Conn_IsWelcome(ConnS)) { break; } Result = conn_parse_numeric_unaway(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_ERR_NONICKNAMEGIVEN: case IRC_UNDERNET_RPL_NICKTOOFAST: if (!Conn_IsWelcome(ConnS)) { break; } Conn_ClearSentNick(ConnS); Conn_ClearSentAwayNick(ConnS); break; case IRC_RFC1459_ERR_ERRONEUSNICKNAME: case IRC_RFC1459_ERR_NICKCOLLISION: case IRC_RFC1459_ERR_NICKNAMEINUSE: CONN_PARSE_NUMERIC_CHECKPARAMS(3); Result = conn_parse_numeric_nextnick(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_RPL_ISON: if (!Conn_IsWelcome(ConnS)) { break; } CONN_PARSE_NUMERIC_CHECKPARAMS(2); Result = conn_parse_numeric_ison(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_RPL_NAMEREPLY: if (!Conn_IsWelcome(ConnS)) { break; } CONN_PARSE_NUMERIC_CHECKPARAMS(4); Result = conn_parse_numeric_namereply(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_RPL_ENDOFNAMES: if (!Conn_IsWelcome(ConnS)) { break; } CONN_PARSE_NUMERIC_CHECKPARAMS(2); Result = conn_parse_numeric_endofnames(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_RPL_WHOREPLY: if (!Conn_IsWelcome(ConnS)) { break; } CONN_PARSE_NUMERIC_CHECKPARAMS(8); Result = conn_parse_numeric_whoreply(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; case IRC_RFC1459_RPL_ENDOFWHO: if (!Conn_IsWelcome(ConnS)) { break; } CONN_PARSE_NUMERIC_CHECKPARAMS(2); Result = conn_parse_numeric_endofwho(ConnS, PrefixPT, LinePT, Numeric, ParamsPT, Params); break; } return(Result); } /* CONN_PARSE_NUMERIC_WELCOME FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_welcome) { char *TextPT = NULL; char *DumbPT = NULL; unsigned short int TextIndex = 0; unsigned short int TextLen = 1; unsigned short int Len = 0; unsigned short int Count = 0; if (Numeric == 1) { unsigned short int Index = 0; Conn_SetWelcome(ConnS); ConnS->ServerName = CONN_PARSE_STRREALLOC(ConnS->ServerName, PrefixPT); ConnS->IRCNick = CONN_PARSE_STRREALLOC(ConnS->IRCNick, ParamsPT[0]); for (Index = 0 ; Index <= 4 ; Index++) { FREE(ConnS->Welcome[Index]); } if (Conn_IsSentAwayNick(ConnS)) { Conn_SetAwayNick(ConnS); } else { Conn_ClearAwayNick(ConnS); } Conn_ClearSentNick(ConnS); Conn_ClearSentAwayNick(ConnS); conn_addsendq(ConnS, "MODE %s %s", ConnS->IRCNick, ConnS->Mode); conn_addsendq(ConnS, "JOIN %s", ConnS->Chans); client_noticealluser(ConnS->User, "Connection %s: Successfully connected on %s(%s):%ld \"%s\" as %s.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, ConnS->ServerName, ConnS->IRCNick); if ((ConnS->NumClients <= 0) && (ConnConf_IsAutoAway(ConnS)) && (!Conn_IsAway(ConnS))) { conn_addsendq(ConnS, "AWAY :%s", ConnS->AwayMsg); } } for (Count = 1 ; Count < Params ; Count++) { Len = strlen(ParamsPT[Count]); if (Count > 1) { Len++; } if ((Count == (Params - 1)) && (strchr(ParamsPT[Count], ' ') != NULL)) { ++Len; } TextLen += Len; DumbPT = realloc(TextPT, TextLen); if (DumbPT == NULL) { free(TextPT); if (Conn_IsWelcome(ConnS)) { conn_quit(ConnS, "Memory allocation failure: [%d] %s", errno, strerror(errno)); } else { conn_disconnect(ConnS, "Connection %s: Memory allocation failure: [%d] %s", ConnS->Name, errno, strerror(errno)); } return(FALSE); } TextPT = DumbPT; DumbPT += TextIndex; if (Count > 1) { strcpy(DumbPT, " "); DumbPT++; } if ((Count == (Params - 1)) && (strchr(ParamsPT[Count], ' ') != NULL)) { strcpy(DumbPT, ":"); DumbPT++; } strcpy(DumbPT, ParamsPT[Count]); TextIndex += Len; } ConnS->Welcome[Numeric] = CONN_PARSE_STRREALLOC(ConnS->Welcome[Numeric], TextPT); FREE(TextPT); return(TRUE); } /* CONN_PARSE_NUMERIC_ISUPPORT FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_isupport) { char *TextPT = NULL; char *TempPT = NULL; char *ISupportPT = NULL; unsigned short int TextIndex = 0; unsigned short int TextLen = 1; unsigned short int Len = 0; unsigned short int Index = 0; char **ISupportTempPT = NULL; unsigned short int ISupportIndex = 0; for (Index = 1 ; Index < Params ; Index++) { /* Gather ISupport info that can be used internally */ ISupportPT = strdup(ParamsPT[Index]); TempPT = ISupportPT; while (TempPT[0] == ' ') { ++TempPT; } if (TempPT[0] != '\0') { char *OptionPT = NULL; char *ValuePT = NULL; OptionPT = TempPT; TempPT = strchr(TempPT, '='); if (TempPT == NULL) { ValuePT = ""; } else { TempPT[0] = '\0'; ++TempPT; while (TempPT[0] == ' ') { ++TempPT; } if (TempPT == '\0') { ValuePT = ""; } else { ValuePT = TempPT; } } if (strcasecmp(OptionPT, "NETWORK") == FALSE) { if (strcasecmp(ValuePT, "IRCNET") == FALSE) { ConnS->ISupport.Networks |= IRC_NETWORK_IRCNET; } else if (strcasecmp(ValuePT, "EFNET") == FALSE) { ConnS->ISupport.Networks |= IRC_NETWORK_EFNET; } else if (strcasecmp(ValuePT, "UNDERNET") == FALSE) { ConnS->ISupport.Networks |= IRC_NETWORK_UNDERNET; } else if (strcasecmp(ValuePT, "DALNET") == FALSE) { ConnS->ISupport.Networks |= IRC_NETWORK_DALNET; } else if (strcasecmp(ValuePT, "FREENODE") == FALSE) { ConnS->ISupport.Networks |= IRC_NETWORK_FREENODE; } TempPT = strrealloc(ConnS->ISupport.Network, ValuePT); if (TempPT != NULL) { ConnS->ISupport.Network = TempPT; } } else if (strcasecmp(OptionPT, "MODES") == FALSE) { ConnS->ISupport.MaxModes = atoi(ValuePT); } else if (strcasecmp(OptionPT, "MAXCHANNELS") == FALSE) { ConnS->ISupport.MaxChans = atoi(ValuePT); } else if (strcasecmp(OptionPT, "MAXBANS") == FALSE) { ConnS->ISupport.MaxBans = atoi(ValuePT); } else if (strcasecmp(OptionPT, "NICKLEN") == FALSE) { ConnS->ISupport.NickLen = atoi(ValuePT); } else if (strcasecmp(OptionPT, "AWAYLEN") == FALSE) { ConnS->ISupport.AwayMsgLen = atoi(ValuePT); } else if (strcasecmp(OptionPT, "TOPICLEN") == FALSE) { ConnS->ISupport.TopicLen = atoi(ValuePT); } else if (strcasecmp(OptionPT, "KICKLEN") == FALSE) { ConnS->ISupport.KickMsgLen = atoi(ValuePT); } else if (strcasecmp(OptionPT, "CHANMODES") == FALSE) { for (; *ValuePT != '\0' ; ValuePT++) { switch (*ValuePT) { case 'a': /* ANONYMOUS */ ConnISupport_SetAnonymous(ConnS); break; case 'i': /* INVITE-ONLY */ ConnISupport_SetInviteOnly(ConnS); break; case 'm': /* MODERATED */ ConnISupport_SetModerated(ConnS); break; case 'n': /* NO OUTSIDE USER MESSAGES */ ConnISupport_SetNoOutSide(ConnS); break; case 'q': /* QUIET */ ConnISupport_SetQuiet(ConnS); break; case 'p': /* PRIVATE */ ConnISupport_SetPrivate(ConnS); break; case 's': /* SECRET */ ConnISupport_SetSecret(ConnS); break; case 'r': /* REOP */ ConnISupport_SetReOP(ConnS); break; case 't': /* ONLY OP TOPIC */ ConnISupport_SetOnlyOPTopic(ConnS); break; case 'k': /* KEY */ ConnISupport_SetKey(ConnS); break; case 'l': /* LIMIT */ ConnISupport_SetLimit(ConnS); break; case 'b': /* BAN */ ConnISupport_SetBan(ConnS); break; case 'e': /* EXCEPTION */ ConnISupport_SetException(ConnS); break; case 'I': /* INVITATION */ ConnISupport_SetInvitation(ConnS); break; case 'O': /* CREATOR */ ConnISupport_SetCreator(ConnS); break; case 'v': /* VOICE */ ConnISupport_SetVoice(ConnS); break; case 'o': /* OPERATOR */ ConnISupport_SetOperator(ConnS); break; default: break; } } } } free(ISupportPT); /* Create "fake" ISupport lines that can be sent to the IRC client */ Len = strlen(ParamsPT[Index]); if (Index > 1) { Len++; } if ((Index == Params-1) && (strchr(ParamsPT[Index], ' ') != NULL)) { Len++; } TextLen += Len; TempPT = realloc(TextPT, TextLen); if (TempPT == NULL) { free(TextPT); conn_quit(ConnS, "Memory allocation failure: [%d] %s", errno, strerror(errno)); return(FALSE); } TextPT = TempPT; TempPT += TextIndex; if (Index > 1) { strcpy(TempPT, " "); TempPT++; } if ((Index == Params-1) && (strchr(ParamsPT[Index], ' ') != NULL)) { strcpy(TempPT, ":"); TempPT++; } strcpy(TempPT, ParamsPT[Index]); TextIndex += Len; } ++ConnS->ISupportLines; ISupportTempPT = realloc(ConnS->ISupport_String, (sizeof(char *) * ConnS->ISupportLines)); if (ISupportTempPT == NULL) { free(TextPT); conn_quit(ConnS, "Memory allocation failure: [%d] %s", errno, strerror(errno)); return(FALSE); } ConnS->ISupport_String = ISupportTempPT; ISupportIndex = ConnS->ISupportLines - 1; ConnS->ISupport_String[ISupportIndex] = TextPT; DEBUGPRINT(BITMASK_DEBUG_CONN, "Connection: %s ISUPPORT Network: %s MaxModes: %d MaxChans: %d MaxBans: %d, NickLen: %d ChanTypes: %s Prefix: %s ChanModes: %s\n", ConnS->Name, ConnS->ISupport.Network, ConnS->ISupport.MaxModes, ConnS->ISupport.MaxChans, ConnS->ISupport.MaxBans, ConnS->ISupport.NickLen, ConnS->ISupport.ChanTypes, ConnS->ISupport.Prefix, ConnS->ISupport.ChanModes); return(TRUE); } /* CONN_PARSE_NUMERIC_NOWAWAY FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_nowaway) { Conn_SetAway(ConnS); return(TRUE); } /* CONN_PARSE_NUMERIC_UNAWAY FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_unaway) { Conn_ClearAway(ConnS); return(TRUE); } /* CONN_PARSE_NUMERIC_NEXTNICK FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_nextnick) { assert(ConnS->Nick != NULL); FREE(IRCNICK); if ((Conn_IsSentNick(ConnS)) || (Conn_IsSentAwayNick(ConnS))) { if (Conn_IsSentNick(ConnS)) { ConnS->NicksIndex = irc_nextnick(ConnS->Nick, ConnS->NicksIndex, ConnS->ISupport.NickLen); ++ConnS->NicksIndex; } else if (Conn_IsSentAwayNick(ConnS)) { ConnS->NicksIndex = irc_nextnick(ConnS->AwayNick, ConnS->NicksIndex, ConnS->ISupport.NickLen); ++ConnS->NicksIndex; } DEBUGPRINT(BITMASK_DEBUG_CONN, "Connection %s: %s: Server said: %s: Trying new nickname \"%s\".", ConnS->Name, ParamsPT[1], ParamsPT[2], IRCNICK); conn_addsendq(ConnS, "NICK %s", IRCNICK); } return(TRUE); } /* CONN_PARSE_NUMERIC_ISON FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_ison) { if (Conn_IsSentISON(ConnS)) { char *P_NicksPT = ParamsPT[1]; unsigned short int Found = FALSE; Conn_ClearSentISON(ConnS); while (P_NicksPT != NULL) { char *P_NickPT = strtok(P_NicksPT, " "); if (P_NickPT == NULL) { break; } P_NicksPT = strtok(NULL, "\0"); if ((Conn_IsAwayNick(ConnS)) && (strcmp(P_NickPT, ConnS->AwayNick) == FALSE)) { Found = TRUE; } else if (strcmp(P_NickPT, ConnS->Nick) == FALSE) { Found = TRUE; } } if (Found == FALSE) { if (Conn_IsAwayNick(ConnS)) { Conn_SetSentAwayNick(ConnS); ConnS->NicksIndex = 0; conn_addsendq(ConnS, "NICK %s", ConnS->AwayNick); } else { Conn_SetSentNick(ConnS); ConnS->NicksIndex = 0; conn_addsendq(ConnS, "NICK %s", ConnS->Nick); } } return(FALSE); } return(TRUE); } /* CONN_PARSE_NUMERIC_NAMEREPLY FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_namereply) { char *P_ChanPT = ParamsPT[2]; char *P_NicksPT = ParamsPT[3]; char *P_NickPT = NULL; struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; char Mode = 0; ChanS = chan_get(ConnS, P_ChanPT); if (ChanS == NULL) { return(TRUE); } while (P_NicksPT != NULL) { P_NickPT = strtok(P_NicksPT, " "); if (P_NickPT == NULL) { break; } P_NicksPT = strtok(NULL, "\0"); Mode = '\0'; if (P_NickPT[0] == '+') { Mode = 'v'; P_NickPT++; } else if (P_NickPT[0] == '@') { Mode = 'o'; P_NickPT++; } FAKELOOP { unsigned short int NUHLen = strlen(P_NickPT) + 16; char NUH[NUHLen+1]; snprintf(NUH, NUHLen+1, "%s!unknown@unknown", P_NickPT); ChanUser = chan_adduser(ConnS, ChanS, P_NickPT, "unknown", "unknown", NUH); if (ChanUser == NULL) { CONN_PARSE_NUMERIC_ERROR("chan_adduser"); return(FALSE); } } if (Mode == 'v') { ChanUser_SetVoice(ChanUser); } if (Mode == 'o') { ChanUser_SetOP(ChanUser); } } return(TRUE); } /* CONN_PARSE_NUMERIC_ENDOFNAMES FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_endofnames) { char *ChanPT = ParamsPT[1]; struct Chan_Struct *ChanS = NULL; ChanS = chan_get(ConnS, ChanPT); if (ChanS == NULL) { return(TRUE); } Chan_SetNames(ChanS); return(TRUE); } /* CONN_PARSE_NUMERIC_WHOREPLY FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_whoreply) { char *ChanPT = ParamsPT[1]; char *P_UserPT = ParamsPT[2]; char *P_HostPT = ParamsPT[3]; char *P_NickPT = ParamsPT[5]; struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; ChanS = chan_get(ConnS, ChanPT); if (ChanS == NULL) { return(TRUE); } ChanUser = chan_getuser(ConnS, ChanS, P_NickPT); if (ChanUser != NULL) { ChanUser->User = CONN_PARSE_STRREALLOC(ChanUser->User, P_UserPT); ChanUser->Host = CONN_PARSE_STRREALLOC(ChanUser->Host, P_HostPT); FAKELOOP { char NUH[strlen(ChanUser->Nick)+1+strlen(ChanUser->User)+1+strlen(ChanUser->Host)+1]; sprintf(NUH, "%s!%s@%s", ChanUser->Nick, ChanUser->User, ChanUser->Host); ChanUser->NUH = CONN_PARSE_STRREALLOC(ChanUser->NUH, NUH); } if (!ChanUser_IsWho(ChanUser)) { ChanUser_SetWho(ChanUser); ChanS->UserWhos++; } } if (ChanS->Who_Head != NULL) { if (ChanS->Who_Head->ClientS != NULL) { client_addsend(ChanS->Who_Head->ClientS, "%s", LinePT); } return(FALSE); } return(TRUE); } /* CONN_PARSE_NUMERIC_ENDOFWHO FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_NUMERIC(conn_parse_numeric_endofwho) { char *ChanPT = ParamsPT[1]; struct Chan_Struct *ChanS = NULL; ChanS = chan_get(ConnS, ChanPT); if (ChanS == NULL) { return(TRUE); } Chan_ClearSentWho(ChanS); Chan_SetWho(ChanS); if (ChanS->Who_Head) { struct Who_Struct *WhoS = ChanS->Who_Head; ChanS->Who_Head = WhoS->NextForChan; if (WhoS->PrevForClient != NULL) { WhoS->PrevForClient->NextForClient = WhoS->NextForClient; } if (WhoS->NextForClient != NULL) { WhoS->NextForClient->PrevForClient = WhoS->PrevForClient; } if (WhoS->ClientS != NULL) { if (WhoS->ClientS->Who_Head == WhoS) { WhoS->ClientS->Who_Head = WhoS->NextForClient; } client_addsend(WhoS->ClientS, "%s", LinePT); } free(WhoS); return(FALSE); } return(TRUE); } /* CONN_PARSE_EVENT FUNCTION - JONAS (17.07.2001) */ unsigned short int conn_parse_event(struct Conn_Struct *ConnS, const char *PrefixPT, const char *const CommandPT, char **ParamsPT, const unsigned short int Params) { const char *NUHPT = PrefixPT; unsigned short int NUHLen = strlen(NUHPT); char P_NUH[NUHLen+1]; char *P_NUHPT = P_NUH; char *NickPT = NULL; char *UserPT = NULL; char *HostPT = NULL; unsigned short int Result = TRUE; strcpy(P_NUHPT, NUHPT); NickPT = P_NUHPT; if (P_NUHPT != NULL) { P_NUHPT = strchr(P_NUHPT, '!'); if (P_NUHPT != NULL) { *P_NUHPT = '\0'; P_NUHPT++; UserPT = P_NUHPT; if (UserPT == NULL) { UserPT = NickPT; } } else { UserPT = NickPT; } } else { UserPT = NickPT; } if (P_NUHPT != NULL) { P_NUHPT = strchr(P_NUHPT, '@'); if (P_NUHPT != NULL) { *P_NUHPT = '\0'; P_NUHPT++; HostPT = P_NUHPT; if (HostPT == NULL) { HostPT = NickPT; } } else { HostPT = NickPT; } } else { HostPT = NickPT; } if (strcasecmp(CommandPT, "PING") == FALSE) { CONN_PARSE_EVENT_CHECKPARAMS(1); Result = conn_parse_event_ping(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "PONG") == FALSE) { CONN_PARSE_EVENT_CHECKPARAMS(1); Result = conn_parse_event_pong(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "ERROR") == FALSE) { CONN_PARSE_EVENT_CHECKPARAMS(1); Result = conn_parse_event_error(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "NICK") == FALSE) { if (!Conn_IsWelcome(ConnS)) { return(Result); } CONN_PARSE_EVENT_CHECKPARAMS(1); Result = conn_parse_event_nick(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "JOIN") == FALSE) { if (!Conn_IsWelcome(ConnS)) { return(Result); } CONN_PARSE_EVENT_CHECKPARAMS(1); Result = conn_parse_event_join(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "PART") == FALSE) { if (!Conn_IsWelcome(ConnS)) { return(Result); } CONN_PARSE_EVENT_CHECKPARAMS(1); Result = conn_parse_event_part(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "QUIT") == FALSE) { if (!Conn_IsWelcome(ConnS)) { return(Result); } CONN_PARSE_EVENT_CHECKPARAMS(1); Result = conn_parse_event_quit(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "KICK") == FALSE) { if (!Conn_IsWelcome(ConnS)) { return(Result); } CONN_PARSE_EVENT_CHECKPARAMS(2); Result = conn_parse_event_kick(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if (strcasecmp(CommandPT, "MODE") == FALSE) { if (!Conn_IsWelcome(ConnS)) { return(Result); } CONN_PARSE_EVENT_CHECKPARAMS(2); Result = conn_parse_event_mode(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } else if ((strcasecmp(CommandPT, "PRIVMSG") == FALSE) || (strcasecmp(CommandPT, "NOTICE") == FALSE) || (strcasecmp(CommandPT, "TOPIC") == FALSE)) { if (!Conn_IsWelcome(ConnS)) { return(Result); } CONN_PARSE_EVENT_CHECKPARAMS(2); Result = conn_parse_event_privmsg_notice_topic(ConnS, NickPT, UserPT, HostPT, NUHPT, CommandPT, ParamsPT, Params); return(Result); } return(TRUE); } /* CONN_PARSE_EVENT_PING FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_ping) { conn_addsendq(ConnS, "PONG :%s", ParamsPT[0]); return(FALSE); } /* CONN_PARSE_EVENT_PONG FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_pong) { Conn_ClearSentPing(ConnS); ConnS->SentPingTime = 0; return(FALSE); } /* CONN_PARSE_EVENT_ERROR FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_error) { client_noticealluser(ConnS->User, "Connection %s: Received ERROR: \"%s\" from server %s(%s):%ld \"%s\"", ConnS->Name, ParamsPT[0], ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, ConnS->ServerName); return(FALSE); } /* CONN_PARSE_EVENT_NICK FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_nick) { struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; if (ConnS->IRCNick == NULL) { conn_quit(ConnS, "%s: Internal error: ConnS->IRCNick == NULL.", CommandPT); return(FALSE); } if (strcasecmp(ConnS->IRCNick, NickPT) == FALSE) { if (Conn_IsSentAwayNick(ConnS)) { Conn_SetAwayNick(ConnS); } else { Conn_ClearAwayNick(ConnS); } Conn_ClearSentNick(ConnS); Conn_ClearSentAwayNick(ConnS); ConnS->IRCNick = CONN_PARSE_STRREALLOC(ConnS->IRCNick, ParamsPT[0]); } for (ChanS = ConnS->Chan_Head ; ChanS != NULL ; ChanS = ChanS->Next) { ChanUser = chan_getuser(ConnS, ChanS, NickPT); if (ChanUser == NULL) { continue; } chan_changeuser(ConnS, ChanS, ChanUser, ParamsPT[0]); if (aerrno != SUCCESS) { CONN_PARSE_EVENT_ERROR("chan_changeuser"); } ChanUser->User = CONN_PARSE_STRREALLOC(ChanUser->User, UserPT); ChanUser->Host = CONN_PARSE_STRREALLOC(ChanUser->Host, HostPT); if (!ChanUser_IsWho(ChanUser)) { ChanUser_SetWho(ChanUser); ChanS->UserWhos++; } if ((ConnS->NumClients <= 0) && (!ChanUser_IsOP(ChanUser)) && (!ChanUser_IsSentOP(ChanUser)) && (!ChanUser_IsAutoOPCheck(ChanUser))) { chanuser_autoopcheck(ConnS, ChanS, ChanUser); } } return(TRUE); } /* CONN_PARSE_EVENT_JOIN FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_join) { struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; if (ConnS->IRCNick == NULL) { conn_quit(ConnS, "%s: Internal error", CommandPT); return(FALSE); } if (strcasecmp(ConnS->IRCNick, NickPT) == FALSE) { ChanS = chan_add(ConnS, ParamsPT[0]); if (ChanS == NULL) { CONN_PARSE_EVENT_ERROR("chan_add"); } ChanUser = chan_adduser(ConnS, ChanS, NickPT, UserPT, HostPT, NUHPT); if (ChanUser == NULL) { CONN_PARSE_EVENT_ERROR("chan_adduser"); } if (!ChanUser_IsWho(ChanUser)) { ChanUser_SetWho(ChanUser); ChanS->UserWhos++; } ChanS->Me = ChanUser; return(TRUE); } ChanS = chan_get(ConnS, ParamsPT[0]); if (ChanS == NULL) { CONN_PARSE_EVENT_ERROR("chan_get"); } ChanUser = chan_adduser(ConnS, ChanS, NickPT, UserPT, HostPT, NUHPT); if (ChanUser == NULL) { CONN_PARSE_EVENT_ERROR("chan_adduser"); } if (!ChanUser_IsWho(ChanUser)) { ChanUser_SetWho(ChanUser); ChanS->UserWhos++; } if ((ConnS->NumClients <= 0) && (!ChanUser_IsOP(ChanUser)) && (!ChanUser_IsSentOP(ChanUser)) && (!ChanUser_IsAutoOPCheck(ChanUser))) { chanuser_autoopcheck(ConnS, ChanS, ChanUser); } return(TRUE); } /* CONN_PARSE_EVENT_PART FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_part) { struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; ChanS = chan_get(ConnS, ParamsPT[0]); if (ChanS == NULL) { return(TRUE); } ChanUser = chan_getuser(ConnS, ChanS, NickPT); if (ChanUser == NULL) { return(TRUE); } if (ChanUser_IsWho(ChanUser)) { ChanS->UserWhos--; } if (ChanUser == ChanS->Me) { chan_rem(ConnS, ChanS); return(TRUE); } chan_remuser(ConnS, ChanS, ChanUser); if ((ConnConf_IsChanCycle(ConnS)) && (ChanS->Users <= 1) && (ConnS->NumClients <= 0) && (ChanS->Me != NULL) && (!ChanUser_IsOP(ChanS->Me))) { conn_addsendq(ConnS, "PART %s", ChanS->Chan); conn_addsendq(ConnS, "JOIN %s", ChanS->Chan); } return(TRUE); } /* CONN_PARSE_EVENT_QUIT FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_quit) { struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; for (ChanS = ConnS->Chan_Head ; ChanS != NULL ; ChanS = ChanS->Next) { ChanUser = chan_getuser(ConnS, ChanS, NickPT); if (ChanUser == NULL) { continue; } if (ChanUser_IsWho(ChanUser)) { ChanS->UserWhos--; } chan_remuser(ConnS, ChanS, ChanUser); if ((ConnConf_IsChanCycle(ConnS)) && (ChanS->Users <= 1) && (ConnS->NumClients <= 0) && (ChanS->Me != NULL) && (!ChanUser_IsOP(ChanS->Me))) { conn_addsendq(ConnS, "PART %s", ChanS->Chan); conn_addsendq(ConnS, "JOIN %s", ChanS->Chan); } } return(TRUE); } /* CONN_PARSE_EVENT_KICK FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_kick) { struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; ChanS = chan_get(ConnS, ParamsPT[0]); if (ChanS == NULL) { return(TRUE); } ChanUser = chan_getuser(ConnS, ChanS, NickPT); if (ChanUser != NULL) { ChanUser->User = CONN_PARSE_STRREALLOC(ChanUser->User, UserPT); ChanUser->Host = CONN_PARSE_STRREALLOC(ChanUser->Host, HostPT); ChanUser->NUH = CONN_PARSE_STRREALLOC(ChanUser->NUH, NUHPT); if (!ChanUser_IsWho(ChanUser)) { ChanUser_SetWho(ChanUser); ChanS->UserWhos++; } } ChanUser = chan_getuser(ConnS, ChanS, ParamsPT[1]); if (ChanUser == NULL) { return(TRUE); } if (ChanUser_IsWho(ChanUser)) { ChanS->UserWhos--; } if (ChanUser == ChanS->Me) { chan_rem(ConnS, ChanS); return(TRUE); } chan_remuser(ConnS, ChanS, ChanUser); /* This is valid if the only OP on the channel kicks himself */ if ((ConnConf_IsChanCycle(ConnS)) && (ChanS->Users <= 1) && (ConnS->NumClients <= 0) && (ChanS->Me != NULL) && (!ChanUser_IsOP(ChanS->Me))) { conn_addsendq(ConnS, "PART %s", ChanS->Chan); conn_addsendq(ConnS, "JOIN %s", ChanS->Chan); } return(TRUE); } /* CONN_PARSE_EVENT_MODE FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_mode) { char *TargetPT = ParamsPT[0]; char *ModeCharsPT = ParamsPT[1]; char **ModeParamsPT = (ParamsPT + 2); char ModeChar = 0; char *ModeParamPT = NULL; unsigned short int ModeCharNumber = strlen(ModeCharsPT); unsigned short int ModeCharCount = 0; unsigned short int ModeCharIndex = 0; unsigned short int ModeParamNumber = (Params - 2); unsigned short int ModeParamCount = 0; unsigned short int ModeParamIndex = 0; char ModeChange = 0; struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; ChanS = chan_get(ConnS, TargetPT); if (ChanS == NULL) { return(TRUE); } ChanUser = chan_getuser(ConnS, ChanS, NickPT); if (ChanUser != NULL) { ChanUser->User = CONN_PARSE_STRREALLOC(ChanUser->User, UserPT); ChanUser->Host = CONN_PARSE_STRREALLOC(ChanUser->Host, HostPT); ChanUser->NUH = CONN_PARSE_STRREALLOC(ChanUser->NUH, NUHPT); ChanUser_SetWho(ChanUser); } for (ModeCharCount = 1, ModeCharIndex = 0 ; ModeCharCount <= ModeCharNumber ; ModeCharCount++) { struct ChanUser_Struct *P_ChanUser = NULL; ModeChar = ModeCharsPT[ModeCharIndex]; ModeCharIndex++; if ((ModeChar == '+') || (ModeChar == '-')) { ModeChange = ModeChar; continue; } switch (ModeChar) { case 'v': case 'o': case 'O': ModeParamCount++; if (ModeParamCount > ModeParamNumber) { conn_quit(ConnS, "Too few params for %s", CommandPT); return(FALSE); } ModeParamPT = ModeParamsPT[ModeParamIndex]; ModeParamIndex++; P_ChanUser = chan_getuser(ConnS, ChanS, ModeParamPT); if (P_ChanUser == NULL) { break; } if (ModeChange == '+') { switch (ModeChar) { case 'v': ChanUser_SetVoice(P_ChanUser); break; case 'o': ChanUser_SetOP(P_ChanUser); break; case 'O': ChanUser_SetCreator(P_ChanUser); break; default: break; } } else if (ModeChange == '-') { switch (ModeChar) { case 'v': ChanUser_ClearVoice(P_ChanUser); break; case 'o': ChanUser_ClearOP(P_ChanUser); break; case 'O': ChanUser_ClearCreator(P_ChanUser); break; default: break; } } break; case 'I': case 'e': case 'b': ModeParamCount++; ModeParamIndex++; break; default: break; } } return(TRUE); } /* CONN_PARSE_EVENT_PRIVMSG_NOTICE_TOPIC FUNCTION - JONAS (18.07.2001) */ CONN_PARSE_EVENT(conn_parse_event_privmsg_notice_topic) { if (irc_isvalidchan(ParamsPT[0]) == FALSE) { if (*ParamsPT[0] == '@') { return(TRUE); } if (ConnS->NumClients > 0) { return(TRUE); } else { char *MaskPT = NULL; struct Ignore_Struct *IgnoreS = NULL; char *CTCPCmdPT = NULL; char *MessagePT = NULL; signed long int Result = 0; if (ConnConf_IsLogging(ConnS)) { if (Params >= 2) { MessagePT = ParamsPT[1]; } else { MessagePT = ""; } Result = conn_log(ConnS, NUHPT, CommandPT, MessagePT); } MaskPT = irc_nuhmask(NickPT, UserPT, HostPT, CONN_IGNORENICKMASK, CONN_IGNOREUSERMASK, CONN_IGNOREHOSTMASK); assert(MaskPT != NULL); IgnoreS = conn_addignore(ConnS, MaskPT); if (IgnoreS == NULL) { return(TRUE); } IgnoreS->ExpireTime = NOW + CONN_IGNORETTL; if (aerrno == AEEXISTS) { return(TRUE); } if ((ConnS->NickServNUH != NULL) && (strwm(ConnS->NickServNUH, NUHPT) == TRUE)) { conn_addsendq(ConnS, "PRIVMSG %s :IDENTIFY %s", NickPT, ConnS->NickServPass); return(FALSE); } if ((strcmp(CommandPT, "PRIVMSG") == FALSE) && (MessagePT[0] == 1) && (MessagePT[strlen(MessagePT)-1] == 1)) { ++MessagePT; MessagePT[strlen(MessagePT)-1] = '\0'; CTCPCmdPT = strtok(MessagePT, " "); if (CTCPCmdPT == NULL) { return(FALSE); } MessagePT = strtok(NULL, "\0"); if (strcmp(CTCPCmdPT, "VERSION") == FALSE) { conn_addsendq(ConnS, "NOTICE %s :\1VERSION %s v%s - %s %s %s - %s\1", NickPT, SHORTNAME, VERSION, OSNAME, OSRELEASE, PLATFORM, URL); } else if (strcmp(CTCPCmdPT, "PING") == FALSE) { if (MessagePT == NULL) { conn_addsendq(ConnS, "NOTICE %s :\1PING\1", NickPT); } else { conn_addsendq(ConnS, "NOTICE %s :\1PING %s\1", NickPT, MessagePT); } } return(FALSE); } if ((ConnConf_IsLogging(ConnS)) && (Result == SUCCESS)) { conn_addsendq(ConnS, "%s %s :I'm currently not here, your message has been logged.", CommandPT, NickPT); } else { conn_addsendq(ConnS, "%s %s :I'm currently not here, messages are not logged.", CommandPT, NickPT); } } } else { struct Chan_Struct *ChanS = NULL; struct ChanUser_Struct *ChanUser = NULL; ChanS = chan_get(ConnS, ParamsPT[0]); if (ChanS == NULL) { return(TRUE); } ChanUser = chan_getuser(ConnS, ChanS, NickPT); if (ChanUser == NULL) { return(TRUE); } ChanUser->User = CONN_PARSE_STRREALLOC(ChanUser->User, UserPT); ChanUser->Host = CONN_PARSE_STRREALLOC(ChanUser->Host, HostPT); ChanUser->NUH = CONN_PARSE_STRREALLOC(ChanUser->NUH, NUHPT); if (!ChanUser_IsWho(ChanUser)) { ChanUser_SetWho(ChanUser); ChanS->UserWhos++; } if ((ConnS->NumClients <= 0) && (!ChanUser_IsOP(ChanUser)) && (!ChanUser_IsSentOP(ChanUser)) && (!ChanUser_IsAutoOPCheck(ChanUser))) { chanuser_autoopcheck(ConnS, ChanS, ChanUser); } } return(TRUE); }