/* * exit_client * This is old "m_bye". Name changed, because this is not a * protocol function, but a general server utility function. * * This function exits a client of *any* type (user, server, etc) * from this server. Also, this generates all necessary prototol * messages that this exit may cause. * * 1) If the client is a local client, then this implicitly exits * all other clients depending on this connection (e.g. remote * clients having 'from'-field that points to this. * * 2) If the client is a remote client, then only this is exited. * * For convenience, this function returns a suitable value for * m_function return value: * * FLUSH_BUFFER if (cptr == sptr) * 0 if (cptr != sptr) */ int exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment) { #ifdef FNAME_USERLOG time_t on_for; #endif if (MyConnect(sptr)) { call_hooks(CHOOK_SIGNOFF, sptr); if (IsUnknown(sptr)) Count.unknown--; if (IsAnOper(sptr)) remove_from_list(&oper_list, sptr, NULL); if (sptr->flags & FLAGS_HAVERECVQ) { /* mark invalid, will be deleted in do_recvqs() */ DLink *lp = find_dlink(recvq_clients, sptr); if (lp) lp->flags = -1; } if (IsClient(sptr)) Count.local--; if (IsNegoServer(sptr)) sendto_realops("Lost server %s during negotiation: %s", sptr->name, comment); if (IsServer(sptr)) { Count.myserver--; if (IsULine(sptr)) Count.myulined--; remove_from_list(&server_list, sptr, NULL); if (server_list == NULL) server_was_split = YES; } sptr->flags |= FLAGS_CLOSING; if (IsPerson(sptr)) { Link *lp, *next; LOpts *lopt = sptr->user->lopt; /* poof goes their watchlist! */ hash_del_watch_list(sptr); /* if they have listopts, axe those, too */ if(lopt != NULL) { remove_from_list(&listing_clients, sptr, NULL); for (lp = lopt->yeslist; lp; lp = next) { next = lp->next; MyFree(lp->value.cp); free_link(lp); } for (lp = lopt->nolist; lp; lp = next) { next = lp->next; MyFree(lp->value.cp); free_link(lp); } MyFree(sptr->user->lopt); sptr->user->lopt = NULL; } sendto_realops_lev(CCONN_LEV, "Client exiting: %s (%s@%s) [%s] [%s]", sptr->name, sptr->user->username, sptr->user->host, (sptr->flags & FLAGS_NORMALEX) ? "Client Quit" : comment, sptr->hostip); } #ifdef FNAME_USERLOG on_for = timeofday - sptr->firsttime; #endif #if defined(USE_SYSLOG) && defined(SYSLOG_USERS) if (IsPerson(sptr)) syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600) / 60, on_for % 60, sptr->name, sptr->user->username, sptr->user->host, sptr->sendK, sptr->receiveK); #endif #if defined(FNAME_USERLOG) { char linebuf[300]; static int logfile = -1; static long lasttime; /* * This conditional makes the logfile active only after it's * been created - thus logging can be turned off by removing * the file. * * stop NFS hangs...most systems should be able to open a file in * 3 seconds. -avalon (curtesy of wumpus) * * Keep the logfile open, syncing it every 10 seconds -Taner */ if (IsPerson(sptr)) { if (logfile == -1) { alarm(3); logfile = open(FNAME_USERLOG, O_WRONLY | O_APPEND); alarm(0); } ircsprintf(linebuf, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600) / 60, on_for % 60, sptr->name, sptr->user->username, sptr->user->host, sptr->sendK, sptr->receiveK); alarm(3); write(logfile, linebuf, strlen(linebuf)); alarm(0); /* Resync the file evey 10 seconds*/ if (timeofday - lasttime > 10) { alarm(3); close(logfile); alarm(0); logfile = -1; lasttime = timeofday; } } } #endif if (sptr->fd >= 0) { if (cptr != NULL && sptr != cptr) sendto_one(&me, sptr, "ERROR :Closing Link: %s %s (%s)", IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", sptr->name, comment); else sendto_one(&me, sptr, "ERROR :Closing Link: %s (%s)", IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", comment); } /* * * Currently only server connections can have * depending * remote clients here, but it does no * harm to check for all * local clients. In * future some other clients than servers * might * have remotes too... * * * Close the Client connection first and mark it * so that no * messages are attempted to send to it. *, The following *must* * make MyConnect(sptr) == FALSE!). * It also makes sptr->from == * NULL, thus it's unnecessary * to test whether "sptr != acptr" * in the following loops. */ if (IsServer(sptr)) { sendto_ops("%s was connected for %lu seconds. %lu/%lu " "sendK/recvK.", sptr->name, (long)(timeofday - sptr->firsttime), sptr->sendK, sptr->receiveK); #ifdef USE_SYSLOG syslog(LOG_NOTICE, "%s was connected for %lu seconds. %lu/%lu " "sendK/recvK.", sptr->name, (u_long) timeofday - sptr->firsttime, sptr->sendK, sptr->receiveK); #endif close_connection(sptr); sptr->sockerr = 0; sptr->flags |= FLAGS_DEADSOCKET; } else { close_connection(sptr); sptr->sockerr = 0; sptr->flags |= FLAGS_DEADSOCKET; } } exit_one_client(cptr, sptr, from, comment); return cptr == sptr ? FLUSH_BUFFER : 0; }
/* * m_watch */ DLLFUNC CMD_FUNC(m_watch) { aClient *acptr; char *s, **pav = parv, *user; char *p = NULL, *def = "l"; int awaynotify = 0; int did_l=0, did_s=0; if (parc < 2) { /* * Default to 'l' - list who's currently online */ parc = 2; parv[1] = def; } for (s = (char *)strtoken(&p, *++pav, " "); s; s = (char *)strtoken(&p, NULL, " ")) { if ((user = (char *)index(s, '!'))) *user++ = '\0'; /* Not used */ if (!strcmp(s, "A") && WATCH_AWAY_NOTIFICATION) awaynotify = 1; /* * Prefix of "+", they want to add a name to their WATCH * list. */ if (*s == '+') { if (!*(s+1)) continue; if (do_nick_name(s + 1)) { if (sptr->watches >= MAXWATCH) { sendto_one(sptr, err_str(ERR_TOOMANYWATCH), me.name, cptr->name, s + 1); continue; } add_to_watch_hash_table(s + 1, sptr, awaynotify); } show_watch(sptr, s + 1, RPL_NOWON, RPL_NOWOFF, awaynotify); continue; } /* * Prefix of "-", coward wants to remove somebody from their * WATCH list. So do it. :-) */ if (*s == '-') { if (!*(s+1)) continue; del_from_watch_hash_table(s + 1, sptr); show_watch(sptr, s + 1, RPL_WATCHOFF, RPL_WATCHOFF, 0); continue; } /* * Fancy "C" or "c", they want to nuke their WATCH list and start * over, so be it. */ if (*s == 'C' || *s == 'c') { hash_del_watch_list(sptr); continue; } /* * Now comes the fun stuff, "S" or "s" returns a status report of * their WATCH list. I imagine this could be CPU intensive if its * done alot, perhaps an auto-lag on this? */ if ((*s == 'S' || *s == 's') && !did_s) { Link *lp; aWatch *anptr; int count = 0; did_s = 1; /* * Send a list of how many users they have on their WATCH list * and how many WATCH lists they are on. */ anptr = hash_get_watch(sptr->name); if (anptr) for (lp = anptr->watch, count = 1; (lp = lp->next); count++) ; sendto_one(sptr, rpl_str(RPL_WATCHSTAT), me.name, parv[0], sptr->watches, count); /* * Send a list of everybody in their WATCH list. Be careful * not to buffer overflow. */ if ((lp = sptr->watch) == NULL) { sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0], *s); continue; } *buf = '\0'; strlcpy(buf, lp->value.wptr->nick, sizeof buf); count = strlen(parv[0]) + strlen(me.name) + 10 + strlen(buf); while ((lp = lp->next)) { if (count + strlen(lp->value.wptr->nick) + 1 > BUFSIZE - 2) { sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name, parv[0], buf); *buf = '\0'; count = strlen(parv[0]) + strlen(me.name) + 10; } strcat(buf, " "); strcat(buf, lp->value.wptr->nick); count += (strlen(lp->value.wptr->nick) + 1); } sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name, parv[0], buf); sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0], *s); continue; } /* * Well that was fun, NOT. Now they want a list of everybody in * their WATCH list AND if they are online or offline? Sheesh, * greedy arn't we? */ if ((*s == 'L' || *s == 'l') && !did_l) { Link *lp = sptr->watch; did_l = 1; while (lp) { if ((acptr = find_person(lp->value.wptr->nick, NULL))) { sendto_one(sptr, rpl_str(RPL_NOWON), me.name, parv[0], acptr->name, acptr->user->username, IsHidden(acptr) ? acptr->user-> virthost : acptr->user->realhost, acptr->lastnick); } /* * But actually, only show them offline if its a capital * 'L' (full list wanted). */ else if (isupper(*s)) sendto_one(sptr, rpl_str(RPL_NOWOFF), me.name, parv[0], lp->value.wptr->nick, "*", "*", lp->value.wptr->lasttime); lp = lp->next; } sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0], *s); continue; } /* * Hmm.. unknown prefix character.. Ignore it. :-) */ } return 0; }