void CycleServers() { if (HubSock == NOSOCKET) { if (currenthub) { if (!currenthub->next) currenthub = ServList; else currenthub = currenthub->next; } else currenthub = ServList; SendUmode(OPERUMODE_Y, "*** Cycling server list"); while (currenthub) { /* Begin connection to server */ if ((HubSock = ConnectHost(currenthub->hostname, currenthub->port)) >= 0) { currenthub->sockfd = HubSock; SetHubConnect(currenthub); break; } else { SendUmode(OPERUMODE_Y, "*** Unable to connect to %s:%d (%s)", currenthub->hostname, currenthub->port, strerror(errno)); HubSock = NOSOCKET; currenthub = currenthub->next; } } /* while (currenthub) */ } /* if (HubSock == NOSOCKET) */ } /* CycleServers() */
int CompleteHubConnection(struct Servlist *hubptr) { int errval; socklen_t errlen; assert(hubptr != 0); ClearHubConnect(hubptr); errval = 0; errlen = sizeof(errval); if (getsockopt(HubSock, SOL_SOCKET, SO_ERROR, (void *)&errval, &errlen) == -1) { putlog(LOG1, "getsockopt(SO_ERROR) failed: %s", strerror(errno)); return 0; } if (errval > 0) { putlog(LOG1, "Error connecting to %s tcp/%d: %s", hubptr->hostname, hubptr->port, strerror(errval)); return 0; } signon(); hubptr->connect_ts = current_ts; #ifdef RECORD_RESTART_TS most_recent_sjoin = current_ts; #endif SendUmode(OPERUMODE_Y, "*** Connected to %s tcp/%d", hubptr->hostname, hubptr->port); putlog(LOG1, "Connected to %s tcp/%d", hubptr->hostname, hubptr->port); burst_complete = 0; return 1; } /* CompleteHubConnection() */
void RecordCommand(char *format, ...) { va_list args; char buffer[MAXLINE * 2]; va_start(args, format); vsprintf_irc(buffer, format, args); va_end(args); /* log the command */ stripformatsymbols( buffer ); putlog(LOG2, buffer); /* send it to opers with usermode +s */ SendUmode(OPERUMODE_S, buffer); } /* RecordCommand() */
void DeleteClient(struct Luser *user) { struct UserChannel *chnext; #ifdef NICKSERVICES struct NickInfo *nptr, *realptr; #ifdef CHANNELSERVICES struct aChannelPtr *fnext; #endif #endif /* NICKSERVICES */ if (user == NULL) return; SendUmode(OPERUMODE_CAPE, "*** Client exit: %s!%s@%s [%s]", user->nick, user->username, user->hostname, user->server ? user->server->name : "*unknown*"); #ifdef NICKSERVICES realptr = FindNick(user->nick); nptr = GetMaster(realptr); if (nptr && realptr) { if (LastSeenInfo && (realptr->flags & NS_IDENTIFIED)) { /* * Update last seen user@host info */ if (realptr->lastu) MyFree(realptr->lastu); if (realptr->lasth) MyFree(realptr->lasth); realptr->lastu = MyStrdup(user->username); realptr->lasth = MyStrdup(user->hostname); } /* * they're quitting - unmark them as identified */ realptr->flags &= ~NS_IDENTIFIED; } #ifdef CHANNELSERVICES while (user->founder_channels) { fnext = user->founder_channels->next; RemFounder(user, user->founder_channels->cptr); user->founder_channels = fnext; } #endif #endif /* NICKSERVICES */ #ifdef ALLOW_FUCKOVER /* check if user was a target of o_fuckover() */ CheckFuckoverTarget(user, NULL); #endif if (user->server) user->server->numusers--; while (user->firstchan) { chnext = user->firstchan->next; RemoveFromChannel(user->firstchan->chptr, user); user->firstchan = chnext; } HashDelClient(user, 0); /* keep oper count updated */ if (user->umodes & UMODE_O) { Network->TotalOperators--; if (user->server) user->server->numopers--; } #ifndef BLOCK_ALLOCATION MyFree(user->nick); MyFree(user->username); MyFree(user->hostname); MyFree(user->realname); #endif /* BLOCK_ALLOCATION */ if (user->prev) user->prev->next = user->next; else ClientList = user->next; if (user->next) user->next->prev = user->prev; #ifdef BLOCK_ALLOCATION BlockSubFree(ClientHeap, user); #else MyFree(user); #endif /* BLOCK_ALLOCATION */ Network->TotalUsers--; } /* DeleteClient() */
void UpdateUserModes(struct Luser *user, char *modes) { int PLUS = 1; int umode; unsigned int ii; if (!modes || !user) return; for (ii = 0; ii < strlen(modes); ii++) { if (modes[ii] == '+') { PLUS = 1; continue; } if (modes[ii] == '-') { PLUS = 0; continue; } umode = 0; if (modes[ii] == 'i') umode = UMODE_I; if (modes[ii] == 's') umode = UMODE_S; if (modes[ii] == 'w') umode = UMODE_W; if (modes[ii] == 'o') umode = UMODE_O; #ifdef DANCER if (modes[ii] == 'e') if (PLUS) { struct NickInfo* realptr = FindNick(user->nick); if (realptr) { realptr->flags |= NS_IDENTIFIED; RecordCommand("User %s has +e umode, marking as identified",user->nick); umode = UMODE_E; } else { /* Blech, who is screwing with us? */ toserv(":%s MODE %s -e\r\n", Me.name, user->nick); RecordCommand("User %s has +e umode but is not known to me, setting -e", user->nick); umode = 0; } } #endif /* DANCER */ if (!umode) continue; if (PLUS) { if ((umode == UMODE_O) && (!IsOperator(user))) { #ifdef STATSERVICES char *hostname, *domain; struct HostHash *hosth, *domainh; time_t currtime = current_ts; #endif #ifdef NICKSERVICES CheckOper(user); #endif Network->TotalOperators++; if (SafeConnect) SendUmode(OPERUMODE_O, "*** New Operator: %s (%s@%s) [%s]", user->nick, user->username, user->hostname, user->server ? user->server->name : "*unknown*"); #ifdef STATSERVICES if (Network->TotalOperators > Network->MaxOperators) { Network->MaxOperators = Network->TotalOperators; Network->MaxOperators_ts = current_ts; if ((Network->MaxOperators % 5) == 0) { /* inform +y people of new max oper count */ SendUmode(OPERUMODE_Y, "*** New Max Operator Count: %ld", Network->MaxOperators); putlog(LOG2, "New Max Operator Count: %ld", Network->MaxOperators); } } if (Network->TotalOperators > Network->MaxOperatorsT) { Network->MaxOperatorsT = Network->TotalOperators; Network->MaxOperatorsT_ts = current_ts; } #endif if (user->server) { user->server->numopers++; #ifdef STATSERVICES if (user->server->numopers > user->server->maxopers) { user->server->maxopers = user->server->numopers; user->server->maxopers_ts = current_ts; } #endif } #ifdef STATSERVICES hostname = user->hostname; if ((hosth = FindHost(hostname))) { hosth->curropers++; if (hosth->curropers > hosth->maxopers) { hosth->maxopers = hosth->curropers; hosth->maxopers_ts = currtime; } } if ((domain = GetDomain(hostname))) { if ((domainh = FindDomain(domain))) { domainh->curropers++; if (domainh->curropers > domainh->maxopers) { domainh->maxopers = domainh->curropers; domainh->maxopers_ts = currtime; } } } #endif /* STATSERVICES */ } user->umodes |= umode; } else { if ((umode == UMODE_O) && (IsOperator(user))) { #ifdef STATSERVICES char *hostname, *domain; struct HostHash *hosth, *domainh; #endif Network->TotalOperators--; if (user->server) user->server->numopers--; #ifdef STATSERVICES hostname = user->hostname; if ((hosth = FindHost(hostname))) hosth->curropers--; if ((domain = GetDomain(hostname))) if ((domainh = FindDomain(domain))) domainh->curropers--; #endif } user->umodes &= ~umode; } } } /* UpdateUserModes() */
struct Luser * AddClient(char **line) { char *ch; struct Luser *tempuser, *newptr; #ifdef BLOCK_ALLOCATION tempuser = (struct Luser *) BlockSubAllocate(ClientHeap); if (!tempuser) /* shouldn't happen - but I'm paranoid :) */ return (NULL); memset(tempuser, 0, sizeof(struct Luser)); strlcpy(tempuser->nick, line[1], NICKLEN + 1); strlcpy(tempuser->username, line[5], USERLEN + 1); strlcpy(tempuser->hostname, line[6], HOSTLEN + 1); strlcpy(tempuser->realname, line[8] + 1, REALLEN + 1); #else tempuser = (struct Luser *) MyMalloc(sizeof(struct Luser)); memset(tempuser, 0, sizeof(struct Luser)); tempuser->nick = MyStrdup(line[1]); tempuser->username = MyStrdup(line[5]); tempuser->hostname = MyStrdup(line[6]); tempuser->realname = MyStrdup(line[8] + 1); #endif /* BLOCK_ALLOCATION */ tempuser->since = atol(line[3]); #ifdef NICKSERVICES tempuser->nick_ts = tempuser->since; #if defined SVSNICK || defined FORCENICK tempuser->flags &= ~(UMODE_NOFORCENICK); #endif #endif /* NICKSERVICES */ if ((tempuser->server = FindServer(line[7]))) { tempuser->server->numusers++; #ifdef STATSERVICES if (tempuser->server->numusers > tempuser->server->maxusers) { tempuser->server->maxusers = tempuser->server->numusers; tempuser->server->maxusers_ts = current_ts; } #endif } ch = &line[4][1]; while (*ch) { switch (*ch) { case 'i': case 'I': { tempuser->umodes |= UMODE_I; break; } case 's': case 'S': { tempuser->umodes |= UMODE_S; break; } case 'w': case 'W': { tempuser->umodes |= UMODE_W; break; } case 'o': case 'O': { tempuser->umodes |= UMODE_O; Network->TotalOperators++; #ifdef STATSERVICES if (Network->TotalOperators > Network->MaxOperators) { Network->MaxOperators = Network->TotalOperators; Network->MaxOperators_ts = current_ts; if ((Network->MaxOperators % 5) == 0) { /* inform +y people of new max oper count */ SendUmode(OPERUMODE_Y, "*** New Max Operator Count: %ld", Network->MaxOperators); putlog(LOG2, "New Max Operator Count: %ld", Network->MaxOperators); } } if (Network->TotalOperators > Network->MaxOperatorsT) { Network->MaxOperatorsT = Network->TotalOperators; Network->MaxOperatorsT_ts = current_ts; } #endif if (tempuser->server) { tempuser->server->numopers++; #ifdef STATSERVICES if (tempuser->server->numopers > tempuser->server->maxopers) { tempuser->server->maxopers = tempuser->server->numopers; tempuser->server->maxopers_ts = current_ts; } #endif } break; } /* case 'O' */ #ifdef DANCER case 'e': case 'E': { struct NickInfo *realptr; realptr = FindNick(tempuser->nick); if (realptr) { realptr->flags |= NS_IDENTIFIED; tempuser->umodes |= UMODE_E; RecordCommand("User %s has +e umode, marking as identified", tempuser->nick); } else { /* Is it one of mine? */ int mine = 0; struct aService *sptr; for (sptr = ServiceBots; sptr->name; ++sptr) if (!irccmp(tempuser->nick, *(sptr->name))) { mine = 1; break; } if (!mine) { /* Blech, who is screwing with us? */ toserv(":%s MODE %s -e\r\n", Me.name, tempuser->nick); RecordCommand("User %s has +e umode but is not known to me, setting -e", tempuser->nick); } } break; } #endif /* DANCER */ default: break; } /* switch (*ch) */ ch++; } tempuser->next = ClientList; tempuser->prev = NULL; if (tempuser->next) tempuser->next->prev = tempuser; ClientList = tempuser; /* add client to the hash table */ newptr = HashAddClient(ClientList, 0); Network->TotalUsers++; #ifdef STATSERVICES if (Network->TotalUsers > Network->MaxUsers) { Network->MaxUsers = Network->TotalUsers; Network->MaxUsers_ts = current_ts; if ((Network->MaxUsers % 10) == 0) { /* notify +y people of new max user count */ SendUmode(OPERUMODE_Y, "*** New Max Client Count: %ld", Network->MaxUsers); putlog(LOG2, "New Max Client Count: %ld", Network->MaxUsers); } } if (Network->TotalUsers > Network->MaxUsersT) { Network->MaxUsersT = Network->TotalUsers; Network->MaxUsersT_ts = current_ts; } #endif /* STATSERVICES */ #ifdef ALLOW_GLINES /* * It's possible the client won't exist anymore, because if the user * is a clone and AutoKillClones is enabled, HashAddClient() would * have already killed the user, in which case newptr will be * NULL - CheckGlined() checks for null pointers */ CheckGlined(newptr); /* Check if new user is glined */ #endif return (tempuser); } /* AddClient() */
int main(int argc, char *argv[]) { #if !defined DEBUGMODE && !defined DAEMONTOOLS pid_t pid; /* pid of this process */ #endif /* !DEBUGMODE && !DAEMONTOOLS */ #ifdef GDB_DEBUG int GDBAttached = 0; #endif /* GDB_DEBUG */ #if defined GIMMECORE || defined DEBUGMODE struct rlimit rlim; /* resource limits -kre */ #endif /* GIMMECORE || DEBUGMODE */ FILE *pidfile; /* to write our pid */ uid_t uid; /* real user id */ uid_t euid; /* effective user id */ #if defined HAVE_BOEHM_GC GC_INIT(); #endif /* HAVE_BOEHM_GC */ myargv = argv; /* Initialise current TS for services -kre */ TimeStarted = current_ts = time(NULL); /* Be sure, be paranoid, be safe. -kre */ umask(077); fprintf(stderr, "Hybserv2 TS services version %s by Hybserv2 team\n" #if defined __DATE__ && defined __TIME__ "Compiled at %s, %s\n", #endif hVersion #if defined __DATE__ && defined __TIME__ , __DATE__, __TIME__ #endif ); #ifdef GDB_DEBUG while (!GDBAttached) sleep(1); #endif /* GDB_DEBUG */ /* * Load SETPATH (settings.conf) - this must be done * before the config file is loaded, and before any * putlog() calls are made, since LogFile is specified * in settings.conf */ if (LoadSettings(0) == 0) { fprintf(stderr, "Fatal errors encountered parsing %s, exiting\n" "Check logfile %s/%s\n", SETPATH, LogPath ? LogPath : "", LogFile ? LogFile : "*unknown*"); return (0); } /* * If they run ./shownicks or ./showchans rather than ./hybserv * display nicknames/channels */ if (strstr(argv[0], "shownicks")) { #ifdef NICKSERVICES ShowNicknames(argc, argv); #endif /* NICKSERVICES */ return (0); } else if (strstr(argv[0], "showchans")) { #if defined(NICKSERVICES) && defined(CHANNELSERVICES) ShowChannels(argc, argv); #endif /* defined(NICKSERVICES) && defined(CHANNELSERVICES) */ return 0; } /* Check for running services -kre */ if ((pidfile = fopen(PidFile, "r")) == NULL) fprintf(stderr, "WARNING: Unable to read pid file %s\n", PidFile); else { pid_t mypid; char line[MAXLINE + 1]; if (fgets(line, sizeof(line), pidfile) != NULL) { mypid = atoi(line); if (mypid && !kill(mypid, 0)) { fprintf(stderr, "FATAL: Services are already running!\n"); fclose(pidfile); exit(EXIT_FAILURE); } } fclose(pidfile); } uid = getuid(); /* the user id of the user who ran the process */ euid = geteuid(); /* the effective id (different if setuid) */ if (!uid || !euid) { fprintf(stderr, "FATAL: Please don't run services as root. Now exiting.\n"); exit(EXIT_FAILURE); } if (chdir(HPath) != 0) { fprintf(stderr, "HPath is an invalid directory, please check %s\n", SETPATH); exit(EXIT_FAILURE); } putlog(LOG1, "Hybserv2 TS services version %s started", hVersion); /* Get the offset from GMT (London time) */ gmt_offset = GetTZOffset(TimeStarted); /* * the Network list must be initialized before the config * file is loaded */ InitLists(); /* load server, jupe, gline, user, admin info */ LoadConfig(); /* load nick/chan/memo/stat databases */ LoadData(); #ifdef GLOBALSERVICES if (LogonNews) { Network->LogonNewsFile.filename = LogonNews; ReadMessageFile(&Network->LogonNewsFile); } #endif /* GLOBALSERVICES */ if (LocalHostName) SetupVirtualHost(); #if !defined DEBUGMODE && !defined GDB_DEBUG /* Daemontools compatibility stuff */ #ifndef DAEMONTOOLS pid = fork(); if (pid == -1) { printf("Unable to fork(), exiting.\n"); exit(EXIT_FAILURE); } if (pid != 0) { printf("Running in background (pid: %d)\n", (int)pid); exit(EXIT_SUCCESS); } close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); /* Make current process session leader -kre */ if (setsid() == -1) { exit(EXIT_FAILURE); } #else printf("Entering foreground debug mode\n"); #endif /* DEBUGMODE */ #endif /* DAEMONTOOLS */ #if defined GIMMECORE || defined DEBUGMODE printf("Setting corefile limit... "); /* Set corefilesize to maximum - therefore we ensure that core will be * generated, no matter of shell limits -kre */ getrlimit(RLIMIT_CORE, &rlim); rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); printf("done.\n"); #endif /* GIMMECORE || DEBUGMODE */ /* Signals must be set up after fork(), since the parent exits */ InitSignals(); /* Initialise random number generator -kre */ srandom(current_ts); srandom((unsigned int)random()); /* Write our pid to a file */ if ((pidfile = fopen(PidFile, "w")) == NULL) putlog(LOG1, "Unable to open %s", PidFile); else { char line[MAXLINE + 1]; ircsprintf(line, "%d\n", getpid()); fputs(line, pidfile); fclose(pidfile); } /* initialize tcm/user listening ports */ InitListenPorts(); /* initialize hash tables */ ClearHashes(1); #ifdef BLOCK_ALLOCATION InitHeaps(); #endif HubSock = NOSOCKET; CycleServers(); while (1) { /* enter loop waiting for server info */ ReadSocketInfo(); if (Me.hub) SendUmode(OPERUMODE_Y, "*** Disconnected from %s", Me.hub->name); else SendUmode(OPERUMODE_Y, "*** Disconnected from hub server"); if (currenthub) { if (currenthub->realname) { MyFree(currenthub->realname); currenthub->realname = NULL; } currenthub->connect_ts = 0; } close(HubSock); /* There was an error */ HubSock = NOSOCKET; /* * whenever Hybserv connects/reconnects to a server, clear * users, servers, and chans */ ClearUsers(); ClearChans(); ClearServs(); /* * ClearHashes() must be called AFTER ClearUsers(), * or StatServ's unique client counts will be off since * cloneTable[] would be NULL while it was trying to find * clones */ ClearHashes(0); PostCleanup(); } /* while (1) */ return 0; } /* main() */
void ReadSocketInfo(void) { int SelectResult; struct timeval TimeOut; struct DccUser *dccptr; struct PortInfo *tempport; fd_set readfds, writefds; time_t curr_ts; time_t last_ts = current_ts; spill[0] = '\0'; for (;;) { /* * DoTimer() will be called from this code, and so we need curr_ts * here. And we also need time setup here -kre */ curr_ts = current_ts = time(NULL); #ifdef HIGHTRAFFIC_MODE if (HTM) { int htm_count; if (last_ts != curr_ts) { /* * So DoTimer() doesn't get called a billion times when HTM is * turned off */ last_ts = curr_ts; /* * DoTimer() won't do anything other than update * Network->CheckRecvB since we are in HTM */ DoTimer(curr_ts); } /* if (last_ts != curr_ts) */ /* Check if HTM should be turned off */ if ((curr_ts - HTM_ts) >= HTM_TIMEOUT) { float currload; currload = ((float) (Network->RecvB - Network->CheckRecvB) / (float) 1024) / (float) HTM_INTERVAL; if (currload >= (float) ReceiveLoad) { HTM_ts = curr_ts; putlog(LOG1, "Continuing high-traffic mode (%0.2f K/s)", currload); SendUmode(OPERUMODE_Y, "*** Continuing high-traffic mode (%0.2f K/s)", currload); } else { HTM = HTM_ts = 0; putlog(LOG1, "Resuming standard traffic operations (%0.2f K/s)", currload); SendUmode(OPERUMODE_Y, "*** Resuming standard traffic operations (%0.2f K/s)", currload); } } for (htm_count = 0; htm_count < HTM_RATIO; htm_count++) if (!ReadHub()) { read_socket_done = 1; return; } } /* if (HTM) */ else #endif /* HIGHTRAFFIC_MODE */ if (last_ts != curr_ts) { if (curr_ts > (last_ts + 1)) { time_t delta; /* * we skipped at least 1 time interval - make up for it * by calling DoTimer() how ever many intervals we missed * (ie: if the TS went from 5 to 8, call DoTimer() twice * since we missed 6 and 7) */ for (delta = (last_ts + 1); delta < curr_ts; delta++) DoTimer(delta); } last_ts = curr_ts; DoTimer(curr_ts); } FD_ZERO(&readfds); FD_ZERO(&writefds); TimeOut.tv_sec = 0L; TimeOut.tv_usec = 20000L; if (currenthub && (HubSock != NOSOCKET)) { if (IsHubConnect(currenthub)) FD_SET(HubSock, &writefds); else FD_SET(HubSock, &readfds); } for (dccptr = connections; dccptr; dccptr = dccptr->next) { if (IsDccConnect(dccptr)) FD_SET(dccptr->socket, &writefds); else { FD_SET(dccptr->socket, &readfds); if (dccptr->authfd != NOSOCKET) { FD_SET(dccptr->authfd, &readfds); if (dccptr->flags & SOCK_WRID) FD_SET(dccptr->authfd, &writefds); } } } for (tempport = PortList; tempport; tempport = tempport->next) if (tempport->socket != NOSOCKET) FD_SET(tempport->socket, &readfds); SelectResult = select(FD_SETSIZE, &readfds, &writefds, NULL, &TimeOut); if (SelectResult > 0) { /* something happened */ if (currenthub && (HubSock != NOSOCKET)) { /* This is for info coming from the hub server */ if (IsHubConnect(currenthub) && FD_ISSET(HubSock, &writefds)) { if (!CompleteHubConnection(currenthub)) { close(HubSock); currenthub->sockfd = HubSock = NOSOCKET; } } else if (FD_ISSET(HubSock, &readfds)) { if (!ReadHub()) { read_socket_done = 1; return; /* something bad happened */ } } } /* if (currenthub && (HubSock != NOSOCKET)) */ for (tempport = PortList; tempport; tempport = tempport->next) { if (tempport->socket == NOSOCKET) continue; if (FD_ISSET(tempport->socket, &readfds)) { /* * a client has connected on one of our listening ports * (P: lines) - accept their connection, and perform * ident etc */ ConnectClient(tempport); } } /* this is for info coming from a dcc/telnet/tcm client */ for (dccptr = connections; dccptr != NULL; dccptr = dccnext) { assert(dccptr->socket != NOSOCKET); dccnext = dccptr->next; if (IsDccConnect(dccptr) && FD_ISSET(dccptr->socket, &writefds)) { if (!GreetDccUser(dccptr)) DeleteDccClient(dccptr); continue; } if (dccptr->authfd >= 0) { if (FD_ISSET(dccptr->authfd, &writefds) && (dccptr->flags & SOCK_WRID)) writeauth(dccptr); /* send ident request */ if (FD_ISSET(dccptr->authfd, &readfds)) readauth(dccptr); /* read ident reply */ } if (dccptr->flags & SOCK_NEEDID) continue; if (FD_ISSET(dccptr->socket, &readfds)) { /* read and parse any data from the socket */ if (!ReadSock(dccptr)) { CloseConnection(dccptr); continue; } } /* if (FD_ISSET(dccptr->socket, &readfds)) */ } /* for (dccptr = connections; dccptr; dccptr = dccptr->next) */ dccnext = NULL; /* XXX */ } /* if (SelectResult > 0) */ else { /* Also check whether is errno set at all.. -kre */ if ((SelectResult == (-1)) && errno && (errno != EINTR)) { #ifdef DEBUGMODE fprintf(stderr, "Connection closed: %s\n", strerror(errno)); #endif putlog(LOG1, "Lost connection to %s:%d (%s)", currenthub->hostname, currenthub->port, strerror(errno)); return; } } } /* for (;;) */ } /* ReadSocketInfo() */
void UpdateChanModes(struct Luser *lptr, char *who, struct Channel *cptr, char *modes) { int add; char *tmp, *p; register char ch; struct Luser *userptr; #if defined(NICKSERVICES) && defined(CHANNELSERVICES) int cs_deoped = 0; /* was chanserv deoped? */ #endif char **modeargs; /* arguements to +l/k/o/v modes */ char tempargs[MAXLINE]; int argcnt; /* number of arguements */ int argidx; /* current index in modeargs[] */ #ifndef SAVE_TS char sendstr[MAXLINE]; #endif if (!cptr) return; assert(lptr || who); if (lptr) { SendUmode(OPERUMODE_M, "*** %s: Mode [%s] by %s!%s@%s", cptr->name, modes, lptr->nick, lptr->username, lptr->hostname); putlog(LOG3, "%s: mode change \"%s\" by %s!%s@%s", cptr->name, modes, lptr->nick, lptr->username, lptr->hostname); } else { SendUmode(OPERUMODE_M, "*** %s: Mode [%s] by %s", cptr->name, modes, who); putlog(LOG3, "%s: mode change \"%s\" by %s", cptr->name, modes, who); } if ((tmp = strchr(modes, ' '))) strcpy(tempargs, *(tmp + 1) ? tmp + 1 : ""); else tempargs[0] = '\0'; argcnt = SplitBuf(tempargs, &modeargs); /* * This routine parses the given channel modes and keeps * the corresponding lists correctly updated - also make * sure OperServ and ChanServ remain opped */ add = 0; argidx = (-1); for (tmp = modes; *tmp; ++tmp) { ch = *tmp; if (IsSpace(ch)) break; switch (ch) { case ' ': case '\n': case '\r': break; case '-': { add = 0; break; } case '+': { add = 1; break; } /* * Op/DeOp */ case 'o': { ++argidx; if (argidx >= argcnt) { /* * there are more 'o' flags than there are nicknames, * just break */ break; } if (!(userptr = FindClient(modeargs[argidx]))) break; SetChannelMode(cptr, add, MODE_O, userptr, 0); if (add) { #ifdef STATSERVICES if (lptr) ++lptr->numops; #endif } /* if (add) */ else { if (userptr == Me.osptr) { if (!FloodCheck(cptr, lptr, Me.osptr, 0)) { #ifdef SAVE_TS os_part(cptr); os_join(cptr); #else toserv(":%s MODE %s +o %s\n", n_OperServ, cptr->name, n_OperServ); #endif } if (!lptr) { putlog(LOG1, "%s: %s attempted to deop %s", cptr->name, who, n_OperServ); } else { putlog(LOG1, "%s: %s!%s@%s attempted to deop %s", cptr->name, lptr->nick, lptr->username, lptr->hostname, n_OperServ); } } #if defined(NICKSERVICES) && defined(CHANNELSERVICES) else if (userptr == Me.csptr) { cs_deoped = 1; } #endif /* defined(NICKSERVICES) && defined(CHANNELSERVICES) */ #ifdef STATSERVICES if (lptr) ++lptr->numdops; #endif } /* else if (!add) */ #if defined(NICKSERVICES) && defined(CHANNELSERVICES) cs_CheckModes(lptr, FindChan(cptr->name), !add, MODE_O, userptr); #endif break; } /* case 'o' */ /* * Voice/DeVoice */ case 'v': { ++argidx; if (argidx >= argcnt) break; if (!(userptr = FindClient(modeargs[argidx]))) break; SetChannelMode(cptr, add, MODE_V, userptr, 0); if (add) { #ifdef STATSERVICES if (lptr) ++lptr->numvoices; #endif } else { #ifdef STATSERVICES if (lptr) ++lptr->numdvoices; #endif } /* else if (!add) */ #if defined(NICKSERVICES) && defined(CHANNELSERVICES) cs_CheckModes(lptr, FindChan(cptr->name), !add, MODE_V, userptr); #endif break; } /* case 'v' */ #ifdef HYBRID7 /* HalfOp/DeHalfOp -Janos */ case 'h': { ++argidx; if (argidx >= argcnt) break; if (!(userptr = FindClient(modeargs[argidx]))) break; SetChannelMode(cptr, add, MODE_H, userptr, 0); if (add) { #ifdef STATSERVICES if (lptr) ++lptr->numhops; #endif } else { #ifdef STATSERVICES if (lptr) ++lptr->numdhops; #endif } /* else if (!add) */ #if defined(NICKSERVICES) && defined(CHANNELSERVICES) cs_CheckModes(lptr, FindChan(cptr->name), !add, MODE_H, userptr); #endif break; } /* case 'h'*/ #endif /* HYBRID7 */ /* * Channel limit */ case 'l': { if (add) { ++argidx; if (argidx >= argcnt) break; cptr->limit = atoi(modeargs[argidx]); } else cptr->limit = 0; #if defined(NICKSERVICES) && defined(CHANNELSERVICES) cs_CheckModes(lptr, FindChan(cptr->name), !add, MODE_L, 0); #endif break; } /* case 'l' */ /* * Channel key */ case 'k': { ++argidx; if (argidx >= argcnt) break; #ifndef BLOCK_ALLOCATION if (cptr->key) MyFree(cptr->key); #endif if (add) { #ifdef BLOCK_ALLOCATION strncpy(cptr->key, modeargs[argidx], KEYLEN); cptr->key[KEYLEN] = '\0'; #else cptr->key = MyStrdup(modeargs[argidx]); #endif /* BLOCK_ALLOCATION */ } else { #ifdef BLOCK_ALLOCATION cptr->key[0] = '\0'; #else cptr->key = 0; #endif /* BLOCK_ALLOCATION */ } #if defined(NICKSERVICES) && defined(CHANNELSERVICES) cs_CheckModes(lptr, FindChan(cptr->name), !add, MODE_K, 0); #endif break; } /* case 'k' */ /* * Channel forwarding target */ case 'f': { ++argidx; if (argidx >= argcnt) break; #ifndef BLOCK_ALLOCATION if (cptr->forward) MyFree(cptr->forward); #endif if (add) { #ifdef BLOCK_ALLOCATION strncpy(cptr->forward, modeargs[argidx], CHANNELLEN); cptr->forward[CHANNELLEN] = '\0'; #else cptr->forward = MyStrdup(modeargs[argidx]); #endif /* BLOCK_ALLOCATION */ } else { #ifdef BLOCK_ALLOCATION cptr->forward[0] = '\0'; #else cptr->forward = 0; #endif /* BLOCK_ALLOCATION */ } #if defined(NICKSERVICES) && defined(CHANNELSERVICES) cs_CheckModes(lptr, FindChan(cptr->name), !add, MODE_F, 0); #endif break; } /* case 'f' */ /* * Channel ban */ case 'b': { ++argidx; if (argidx >= argcnt) break; /* if it's a forwarding ban like nick!ident@host!#channel * just drop the forward channel * found by CheeToS -- jilles */ p = strchr(modeargs[argidx], '!'); if (p != NULL) { p = strchr(p + 1, '!'); if (p != NULL) *p = '\0'; } if (add) AddBan(who, cptr, modeargs[argidx]); else DeleteBan(cptr, modeargs[argidx]); if (p != NULL) *p = '!'; break; } /* case 'b' */ #ifdef GECOSBANS /* * Channel deny */ case 'd': { ++argidx; if (argidx >= argcnt) break; if (add) AddGecosBan(who, cptr, modeargs[argidx]); else DeleteGecosBan(cptr, modeargs[argidx]); break; } /* case 'd' */ #endif /* GECOSBANS */ /* * Channel exception */ case 'e': { ++argidx; if (argidx >= argcnt) break; if (add) AddException(who, cptr, modeargs[argidx]); else DeleteException(cptr, modeargs[argidx]); break; } /* case 'e' */ #ifdef HYBRID7 /* Channel invite exception -Janos */ case 'I': { ++argidx; if (argidx >= argcnt) break; if (add) AddInviteException(who, cptr, modeargs[argidx]); else DeleteInviteException(cptr, modeargs[argidx]); break; } /* case 'I' */ #endif /* HYBRID7 */ default: { int modeflag = 0; if (ch == 's') modeflag = MODE_S; else if (ch == 'p') modeflag = MODE_P; else if (ch == 'n') modeflag = MODE_N; else if (ch == 't') modeflag = MODE_T; else if (ch == 'm') modeflag = MODE_M; else if (ch == 'i') modeflag = MODE_I; else if (ch == 'r') modeflag = MODE_R; else if (ch == 'z') modeflag = MODE_Z; else if (ch == 'P') modeflag = MODE_CAPP; #if 0 /* doesn't exist in 1.0.34 */ else if (ch == 'F') modeflag = MODE_CAPF; #endif else if (ch == 'Q') modeflag = MODE_CAPQ; #ifdef HYBRID7 else if (ch == 'a') modeflag = MODE_A; #endif else if (ch == 'c') modeflag = MODE_C; else if (ch == 'g') modeflag = MODE_G; else if (ch == 'L') modeflag = MODE_CAPL; else if (ch == 'R') modeflag = MODE_CAPR; if (modeflag) { if (add) cptr->modes |= modeflag; else cptr->modes &= ~modeflag; } #if defined(NICKSERVICES) && defined(CHANNELSERVICES) if (modeflag) cs_CheckModes(lptr, FindChan(cptr->name), !add, modeflag, 0); #endif break; } /* default: */ } /* switch (*tmp) */ } /* for (tmp = modes; *tmp; ++tmp) */ MyFree(modeargs); #if defined(NICKSERVICES) && defined(CHANNELSERVICES) if ((cs_deoped) && (!FloodCheck(cptr, lptr, Me.csptr, 0))) { /* reop ChanServ */ #ifdef SAVE_TS cs_part(cptr); cs_join(FindChan(cptr->name)); #else toserv(":%s MODE %s +o %s\n", n_ChanServ, cptr->name, n_ChanServ); #endif if (!lptr) putlog(LOG1, "%s: %s attempted to deop %s", cptr->name, who, n_ChanServ); else putlog(LOG1, "%s: %s!%s@%s attempted to deop %s", cptr->name, lptr->nick, lptr->username, lptr->hostname, n_ChanServ); } #endif /* defined(NICKSERVICES) && defined(CHANNELSERVICES) */ } /* UpdateChanModes() */
void RemoveFromChannel(struct Channel *cptr, struct Luser *lptr) { struct UserChannel *tempchan, *prev = NULL; struct ChannelUser *tempuser, *prev2 = NULL; if (!cptr || !lptr) return; SendUmode(OPERUMODE_P, "*** Channel part: %s (%s)", lptr->nick, cptr->name); /* Is this the contact? */ #ifdef CHANNELSERVICES { struct NickInfo *nptr; struct ChanInfo *ciptr; if ((nptr = FindNick(lptr->nick)) && (ciptr = FindChan(cptr->name))) { if (nptr->flags & NS_IDENTIFIED) { if (ciptr->contact && irccmp(lptr->nick, ciptr->contact) == 0) /* That's the contact joining. Update activity timer */ ciptr->last_contact_active = current_ts; if (ciptr->alternate && irccmp(lptr->nick, ciptr->alternate) == 0) ciptr->last_alternate_active = current_ts; } } } #endif /* remove cptr from lptr's chan list */ for (tempchan = lptr->firstchan; tempchan; tempchan = tempchan->next) { if (cptr == tempchan->chptr) { if (prev) prev->next = tempchan->next; else lptr->firstchan = tempchan->next; MyFree(tempchan); tempchan = NULL; break; } prev = tempchan; } /* remove lptr from cptr's nick list */ for (tempuser = cptr->firstuser; tempuser; tempuser = tempuser->next) { if (lptr == tempuser->lptr) { if (prev2) prev2->next = tempuser->next; else cptr->firstuser = tempuser->next; MyFree(tempuser); tempuser = NULL; --cptr->numusers; break; } prev2 = tempuser; } if (cptr->numusers == 0) DeleteChannel(cptr); /* the last nick left the chan, erase it */ } /* RemoveFromChannel() */
struct Channel * AddChannel(char **line, int nickcnt, char **nicks) { char *names; char **anames; char *currnick; char modes[MAXLINE]; struct Channel *chname, *cptr; struct Channel *tempchan; int ii, ncnt, acnt; ncnt = 5; /* default position for channel nicks, if no limit/key */ strcpy(modes, line[4]); while (line[ncnt][0] != ':') { strcat(modes, " "); strcat(modes, line[ncnt]); ncnt++; } if (nickcnt > 0) { acnt = nickcnt; anames = nicks; } else { names = line[ncnt]; names++; /* point past the leading : */ ii = strlen(names); /* kill the \n char on the end */ if (IsSpace(names[ii - 2])) names[ii - 2] = '\0'; else if (IsSpace(names[ii - 1])) names[ii - 1] = '\0'; acnt = SplitBuf(names, &anames); } if (!(cptr = FindChannel(line[3]))) { #ifdef BLOCK_ALLOCATION tempchan = (struct Channel *) BlockSubAllocate(ChannelHeap); memset(tempchan, 0, sizeof(struct Channel)); strncpy(tempchan->name, line[3], CHANNELLEN); #else tempchan = (struct Channel *) MyMalloc(sizeof(struct Channel)); memset(tempchan, 0, sizeof(struct Channel)); tempchan->name = MyStrdup(line[3]); #endif /* BLOCK_ALLOCATION */ tempchan->since = atol(line[2]); tempchan->numusers = acnt; tempchan->next = ChannelList; tempchan->prev = NULL; if (tempchan->next) tempchan->next->prev = tempchan; HashAddChan(tempchan); ChannelList = tempchan; chname = ChannelList; ++Network->TotalChannels; #ifdef STATSERVICES if (Network->TotalChannels > Network->MaxChannels) { Network->MaxChannels = Network->TotalChannels; Network->MaxChannels_ts = current_ts; if ((Network->MaxChannels % 10) == 0) { /* notify +y people about new max channel count */ SendUmode(OPERUMODE_Y, "*** New Max Channel Count: %ld", Network->MaxChannels); } } if (Network->TotalChannels > Network->MaxChannelsT) { Network->MaxChannelsT = Network->TotalChannels; Network->MaxChannelsT_ts = current_ts; } #endif /* STATSERVICES */ } else /* it's an existing channel, but someone has joined it */ { cptr->numusers += acnt; chname = cptr; } /* Add the channel to each nick's channel list */ for (ii = 0; ii < acnt; ii++) { currnick = GetNick(anames[ii]); if (!currnick) continue; if (!IsChannelMember(chname, FindClient(currnick))) { /* * Use anames[ii] instead of currnick here so we get * the @/+ flags */ AddToChannel(chname, anames[ii]); } else chname->numusers--; } /* finally, add the modes for the channel */ UpdateChanModes(0, line[0] + 1, chname, modes); /* * Only free anames[] if there was no nick list * given */ if (!nickcnt) MyFree(anames); return (chname); } /* AddChannel() */