/* * ---------------------------------------------------------------- * Night Light IRC Proxy - Channel Mode * ---------------------------------------------------------------- * 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 (25.11.2007) * */ #define CHAN_MODE_C #define NEED_SYS_TYPES_H 1 /* Extra types */ #define NEED_SYS_PARAM_H 1 /* Some systems need this */ #define NEED_LIMITS_H 1 /* 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.h" #include "conn_sendq.h" #include "chan.h" #include "chan_mode.h" #include "chan_user.h" /* VARIABLES - JONAS (05.07.2000) */ extern struct Conn_Struct *Conn_Head; /* CHAN_ADDMODE FUNCTION - JONAS (31.07.2001) */ struct ChanMode_Struct *chan_addmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const ModePT, const unsigned short int Priority, const unsigned short int Delay) { struct ChanMode_Struct *ChanMode = NULL; struct ChanMode_Struct *ChanMode_NEW = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(ModePT != NULL); assert(ChanUser_IsOP(ChanS->Me)); FAKELOOP { unsigned short int ModeLen = strlen(ModePT); char Mode1[ModeLen+1]; char Mode2[ModeLen+1]; strcpy(Mode1, ModePT); strcpy(Mode2, ModePT); if (Mode1[0] == '+') { Mode2[0] = '-'; } else if (Mode1[0] == '-') { Mode2[0] = '+'; } else { aerrno = AEINVALID; return(NULL); } ChanMode = chan_getmode(ConnS, ChanS, Mode1); if (ChanMode != NULL) { aerrno = AEEXISTS; return(ChanMode); } ChanMode = chan_getmode(ConnS, ChanS, Mode2); if (ChanMode != NULL) { chan_remmode(ConnS, ChanS, ChanMode); aerrno = AESUCCESS; return(NULL); } ChanMode_NEW = malloc(sizeof(struct ChanMode_Struct)); if (ChanMode_NEW == NULL) { aerrno = AEMALLOC; return(NULL); } memset(ChanMode_NEW, 0, sizeof(struct ChanMode_Struct)); chan_initmode(ConnS, ChanS, ChanMode_NEW); ChanMode_NEW->Mode = strdup(Mode1); if (ChanMode_NEW->Mode == NULL) { free(ChanMode_NEW); aerrno = AEMALLOC; return(NULL); } ChanMode_NEW->Priority = Priority; ChanMode_NEW->Delay = Delay; ChanMode_NEW->Time = NOW; } if (ChanS->Mode_Head == NULL) { ChanS->Mode_Head = ChanMode_NEW; ChanS->Mode_Tail = ChanMode_NEW; } else { for (ChanMode = ChanS->Mode_Head ; ChanMode != NULL ; ChanMode = ChanMode->Next) { if (ChanMode->Priority > Priority) { if (ChanMode->Prev == NULL) { /* (NULL | ChanMode_NEW | ChanMode_CUR | ...) */ ChanS->Mode_Head = ChanMode_NEW; ChanMode_NEW->Next = ChanMode; ChanMode->Prev = ChanMode_NEW; } else { /* (... | ChanMode_PRV | ChanMode_NEW | ChanMode_CUR | ...) */ ChanMode->Prev->Next = ChanMode_NEW; ChanMode_NEW->Prev = ChanMode->Prev; ChanMode_NEW->Next = ChanMode; ChanMode->Prev = ChanMode_NEW; } break; } } if (ChanMode == NULL) { /* (... | ChanMode_NEW (TAIL) | NULL) */ ChanMode = ChanS->Mode_Tail; ChanMode->Next = ChanMode_NEW; ChanMode_NEW->Prev = ChanMode; ChanS->Mode_Tail = ChanMode_NEW; } } ChanS->Modes++; aerrno = AESUCCESS; return(ChanMode_NEW); } /* CHAN_REMMODE FUNCTION - JONAS (31.07.2001) */ void chan_remmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanMode_Struct *ChanMode) { assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanMode != NULL); if (ChanMode->Prev == NULL) { ChanS->Mode_Head = ChanMode->Next; } else { ChanMode->Prev->Next = ChanMode->Next; } if (ChanMode->Next == NULL) { ChanS->Mode_Tail = ChanMode->Prev; } else { ChanMode->Next->Prev = ChanMode->Prev; } chan_initmode(ConnS, ChanS, ChanMode); free(ChanMode); ChanS->Modes--; } /* CHAN_GETMODE FUNCTION - JONAS (05.07.2000) */ struct ChanMode_Struct *chan_getmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const ModePT) { struct ChanMode_Struct *ChanMode = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(ModePT != NULL); for (ChanMode = ChanS->Mode_Head ; ChanMode != NULL ; ChanMode = ChanMode->Next) { if (strcasecmp(ChanMode->Mode, ModePT) == FALSE) { aerrno = AESUCCESS; return(ChanMode); } } aerrno = AENOMATCH; return(NULL); } /* CHAN_INITMODE FUNCTION - JONAS (05.07.2000) */ void chan_initmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanMode_Struct *ChanMode) { assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanMode != NULL); FREE(ChanMode->Mode); ChanMode->Time = 0; ChanMode->Priority = 0; ChanMode->Delay = 0; } /* CHAN_DESTROYMODES FUNCTION - JONAS (31.07.2001) */ void chan_destroymodes(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) { assert(ConnS != NULL); assert(ChanS != NULL); while (ChanS->Mode_Head != NULL) { chan_remmode(ConnS, ChanS, ChanS->Mode_Head); } assert(ChanS->Modes == 0); } /* CHAN_ADDSENTMODE FUNCTION - JONAS (31.07.2001) */ struct ChanSentMode_Struct *chan_addsentmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const ModePT) { struct ChanSentMode_Struct *ChanSentMode = NULL; struct ChanSentMode_Struct *ChanSentMode_NEW = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(ModePT != NULL); ChanSentMode = chan_getsentmode(ConnS, ChanS, ModePT); if (ChanSentMode != NULL) { aerrno = AEEXISTS; return(ChanSentMode); } ChanSentMode_NEW = malloc(sizeof(struct ChanSentMode_Struct)); if (ChanSentMode_NEW == NULL) { aerrno = AEMALLOC; return(NULL); } memset(ChanSentMode_NEW, 0, sizeof(struct ChanSentMode_Struct)); chan_initsentmode(ConnS, ChanS, ChanSentMode_NEW); ChanSentMode_NEW->Mode = strdup(ModePT); if (ChanSentMode_NEW->Mode == NULL) { free(ChanSentMode_NEW->Mode); aerrno = AEMALLOC; return(NULL); } ChanSentMode_NEW->Time = NOW; if (ChanS->SentMode_Head == NULL) { ChanS->SentMode_Head = ChanSentMode_NEW; ChanS->SentMode_Tail = ChanSentMode_NEW; } else { ChanSentMode = ChanS->SentMode_Tail; ChanSentMode->Next = ChanSentMode_NEW; ChanSentMode_NEW->Prev = ChanSentMode; ChanS->SentMode_Tail = ChanSentMode_NEW; } ChanS->SentModes++; aerrno = AESUCCESS; return(ChanSentMode_NEW); } /* CHAN_REMSENTMODE FUNCTION - JONAS (31.07.2001) */ void chan_remsentmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanSentMode_Struct *ChanSentMode) { assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanSentMode != NULL); if (ChanSentMode->Prev == NULL) { ChanS->SentMode_Head = ChanSentMode->Next; } else { ChanSentMode->Prev->Next = ChanSentMode->Next; } if (ChanSentMode->Next == NULL) { ChanS->SentMode_Tail = ChanSentMode->Prev; } else { ChanSentMode->Next->Prev = ChanSentMode->Prev; } chan_initsentmode(ConnS, ChanS, ChanSentMode); free(ChanSentMode); ChanS->SentModes--; } /* CHAN_GETSENTMODESTRUCT FUNCTION - JONAS (05.07.2000) */ struct ChanSentMode_Struct *chan_getsentmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const ModePT) { struct ChanSentMode_Struct *ChanSentMode = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(ModePT != NULL); for (ChanSentMode = ChanS->SentMode_Head ; ChanSentMode != NULL ; ChanSentMode = ChanSentMode->Next) { if (strcasecmp(ChanSentMode->Mode, ModePT) == FALSE) { aerrno = AESUCCESS; return(ChanSentMode); } } aerrno = AENOMATCH; return(NULL); } /* CHAN_INITSENTMODE FUNCTION - JONAS (05.07.2000) */ void chan_initsentmode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanSentMode_Struct *ChanSentMode) { assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanSentMode != NULL); FREE(ChanSentMode->Mode); ChanSentMode->Time = 0; } /* CHAN_DESTROYSENTMODES FUNCTION - JONAS (31.07.2001) */ void chan_destroysentmodes(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) { assert(ConnS != NULL); assert(ChanS != NULL); while (ChanS->SentMode_Head != NULL) { chan_remsentmode(ConnS, ChanS, ChanS->SentMode_Head); } assert(ChanS->SentModes == 0); } /* CHAN_EXPIRESENTMODES FUNCTION - JONAS (31.07.2001) */ void chan_expiresentmodes(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) { struct ChanSentMode_Struct *ChanSentMode = NULL; struct ChanSentMode_Struct *ChanSentMode_DEL = NULL; time_t Duration = 0; char *ModePT = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanUser_IsOP(ChanS->Me)); ChanS->CheckSentModesTime = NOW; for (ChanSentMode = ChanS->SentMode_Head ; ChanSentMode != NULL ;) { Duration = (NOW - ChanSentMode->Time); if (Duration >= CHANMODESENTMODETTL) { #if 0 sysprint(BITMASK_BOTCHANMODE, "No response in %s for mode %s on %s: Attempting to resend.", strduration(Duration), ChanSentMode->Mode, ChanS->Chan); #endif ChanSentMode_DEL = ChanSentMode; ChanSentMode = ChanSentMode->Next; ModePT = strdup(ChanSentMode_DEL->Mode); chan_remsentmode(ConnS, ChanS, ChanSentMode_DEL); chan_mode(ConnS, ChanS, ModePT, CHANMODE_PRIOHIGH, 0); free(ModePT); continue; } ChanSentMode = ChanSentMode->Next; } } /* CHAN_MODE FUNCTION - JONAS (05.07.2000) */ signed short int chan_mode(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const ModePT, const unsigned short int Priority, const unsigned short int Delay) { struct Conn_Struct *P_ConnS = NULL; struct Chan_Struct *P_ChanS = NULL; struct ChanMode_Struct *ChanMode = NULL; struct ChanSentMode_Struct *ChanSentMode = NULL; assert(ConnS != NULL); assert(ChanS != NULL); assert(ModePT != NULL); assert(ChanUser_IsOP(ChanS->Me)); for (P_ConnS = Conn_Head ; P_ConnS != NULL ; P_ConnS = P_ConnS->Next) { if (!Conn_IsWelcome(P_ConnS)) { continue; } P_ChanS = chan_get(P_ConnS, ChanS->Chan); if (P_ChanS == NULL) { continue; } if (!ChanUser_IsOP(P_ChanS->Me)) { continue; } ChanSentMode = chan_getsentmode(P_ConnS, P_ChanS, ModePT); if (ChanSentMode != NULL) { return(AEEXISTS); } } ChanSentMode = chan_addsentmode(ConnS, ChanS, ModePT); if (aerrno != AESUCCESS) { return(aerrno); } ChanMode = chan_addmode(ConnS, ChanS, ModePT, Priority, 0); if (aerrno != AESUCCESS) { return(aerrno); } return(SUCCESS); } /* CHAN_FLUSHMODES FUNCTION - JONAS (05.07.2000) */ void chan_flushmodes(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) { struct ChanMode_Struct *ChanMode = NULL; struct ChanMode_Struct *ChanMode_DEL = NULL; unsigned short int Count = 0; time_t Duration; char *ModeCharPT = NULL; char ModeCHR = 0; char ModeCNG = 0; char *ModeParamPT = NULL; char ModePChars[IRCMODECHARSLEN+1] = ""; char ModeMChars[IRCMODECHARSLEN+1] = ""; char ModePParams[IRCMODEPARAMSLEN+1] = ""; char ModeMParams[IRCMODEPARAMSLEN+1] = ""; unsigned short int ModePIndex = 0; unsigned short int ModeMIndex = 0; char Mode[IRCMODELINELEN+1] = ""; assert(ConnS != NULL); assert(ChanS != NULL); assert(ChanUser_IsOP(ChanS->Me)); ChanS->FlushModesTime = NOW; /* Grab the modes for one line but dont delete them from the mode queue until we know they can be flushed by SendQ --Jonas */ for (ChanMode = ChanS->Mode_Head, Count = 0 ; ChanMode != NULL ; ChanMode = ChanMode->Next) { assert(ChanMode->Flushed == FALSE); Duration = (NOW - ChanMode->Time); if (Duration < ChanMode->Delay) { continue; } Count++; ModeCharPT = strtok(ChanMode->Mode, " "); ModeParamPT = strtok(NULL, " "); ModeCNG = ModeCharPT[0]; ModeCHR = ModeCharPT[1]; if (ModeCNG == '+') { ModePChars[ModePIndex] = ModeCHR; ModePIndex++; if (ModeParamPT != NULL) { if (strcmp(ModePParams, "") != FALSE) { strncat(ModePParams, " ", IRCMODEPARAMSLEN - strlen(ModePParams)); } strncat(ModePParams, ModeParamPT, IRCMODEPARAMSLEN - strlen(ModePParams)); } } else if (ModeCNG == '-') { ModeMChars[ModeMIndex] = ModeCHR; ModeMIndex++; if (ModeParamPT != NULL) { if (strcmp(ModeMParams, "") != FALSE) { strncat(ModeMParams, " ", IRCMODEPARAMSLEN - strlen(ModeMParams)); } strncat(ModeMParams, ModeParamPT, IRCMODEPARAMSLEN - strlen(ModeMParams)); } } ChanMode->Flushed = TRUE; if (Count >= ConnS->ISupport.MaxModes) { break; } } /* Compile a MODE-line from the minus and plus modes */ snprintf(Mode, IRCMODELINELEN+1, "MODE %s ", ChanS->Chan); if (strlen(ModeMChars) > 0) { strncat(Mode, "-", IRCMODELINELEN - strlen(Mode)); strncat(Mode, ModeMChars, IRCMODELINELEN - strlen(Mode)); } if (strlen(ModePChars) > 0) { strncat(Mode, "+", IRCMODELINELEN - strlen(Mode)); strncat(Mode, ModePChars, IRCMODELINELEN - strlen(Mode)); } if (strlen(ModeMParams) > 0) { strncat(Mode, " ", IRCMODELINELEN - strlen(Mode)); strncat(Mode, ModeMParams, IRCMODELINELEN - strlen(Mode)); } if (strlen(ModePParams) > 0) { strncat(Mode, " ", IRCMODELINELEN - strlen(Mode)); strncat(Mode, ModePParams, IRCMODELINELEN - strlen(Mode)); } if ((strlen(Mode) > ConnS->SendQMaxFlushBuffer) || (ConnS->SendQMaxFlushLines < 1)) { /* There is no point in flushing ModeQ if SendQ can't flush the data immediately. --Jonas */ for (ChanMode = ChanS->Mode_Head ; ChanMode != NULL ; ChanMode = ChanMode->Next) { ChanMode->Flushed = FALSE; } return; } /* Delete the modes from ModeQ we put in the "Mode" line --Jonas */ for (ChanMode = ChanS->Mode_Head, Count = 1 ; ChanMode != NULL ; Count++) { if (ChanMode->Flushed != TRUE) { continue; } ChanMode_DEL = ChanMode; ChanMode = ChanMode->Next; chan_remmode(ConnS, ChanS, ChanMode_DEL); if (Count >= ConnS->ISupport.MaxModes) { break; } } /* Pass the "Mode" line to SendQ --Jonas */ conn_addsendq(ConnS, "%s", Mode); }