diff options
Diffstat (limited to 'ircd/s_misc.c')
-rw-r--r-- | ircd/s_misc.c | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/ircd/s_misc.c b/ircd/s_misc.c new file mode 100644 index 0000000..17c9946 --- /dev/null +++ b/ircd/s_misc.c @@ -0,0 +1,998 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_misc.c (formerly ircd/date.c) + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: s_misc.c,v 1.30 1999/07/21 22:57:39 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_MISC_C +#include "s_externs.h" +#undef S_MISC_C + +static void exit_one_client __P((aClient *,aClient *,aClient *,char *)); + +static char *months[] = { + "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December" +}; + +static char *weekdays[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; + +/* + * stats stuff + */ +struct stats ircst, *ircstp = &ircst; + +char *date(clock) +time_t clock; +{ + static char buf[80], plus; + Reg struct tm *lt, *gm; + struct tm gmbuf; + int minswest; + + if (!clock) + time(&clock); + gm = gmtime(&clock); + bcopy((char *)gm, (char *)&gmbuf, sizeof(gmbuf)); + gm = &gmbuf; + lt = localtime(&clock); + + if (lt->tm_yday == gm->tm_yday) + minswest = (gm->tm_hour - lt->tm_hour) * 60 + + (gm->tm_min - lt->tm_min); + else if (lt->tm_yday > gm->tm_yday) + minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60; + else + minswest = ((lt->tm_hour + 24) - gm->tm_hour) * 60; + + plus = (minswest > 0) ? '-' : '+'; + if (minswest < 0) + minswest = -minswest; + + (void)sprintf(buf, "%s %s %d %d -- %02d:%02d %c%02d:%02d", + weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday, + lt->tm_year + 1900, lt->tm_hour, lt->tm_min, + plus, minswest/60, minswest%60); + + return buf; +} + +/* +** check_registered_user is used to cancel message, if the +** originator is a server or not registered yet. In other +** words, passing this test, *MUST* guarantee that the +** sptr->user exists (not checked after this--let there +** be coredumps to catch bugs... this is intentional --msa ;) +** +** There is this nagging feeling... should this NOT_REGISTERED +** error really be sent to remote users? This happening means +** that remote servers have this user registered, althout this +** one has it not... Not really users fault... Perhaps this +** error message should be restricted to local clients and some +** other thing generated for remotes... +*/ +int check_registered_user(sptr) +aClient *sptr; +{ + if (!IsRegisteredUser(sptr)) + { + sendto_one(sptr, err_str(ERR_NOTREGISTERED, "*")); + return -1; + } + return 0; +} + +/* +** check_registered user cancels message, if 'x' is not +** registered (e.g. we don't know yet whether a server +** or user) +*/ +int check_registered(sptr) +aClient *sptr; +{ + if (!IsRegistered(sptr)) + { + sendto_one(sptr, err_str(ERR_NOTREGISTERED, "*")); + return -1; + } + return 0; +} + +/* +** check_registered_service cancels message, if 'x' is not +** a registered service. +*/ +int check_registered_service(sptr) +aClient *sptr; +{ + if (!IsService(sptr)) + { + sendto_one(sptr, err_str(ERR_NOTREGISTERED, "*")); + return -1; + } + return 0; +} + +/* +** get_client_name +** Return the name of the client for various tracking and +** admin purposes. The main purpose of this function is to +** return the "socket host" name of the client, if that +** differs from the advertised name (other than case). +** But, this can be used to any client structure. +** +** Returns: +** "name[user@ip#.port]" if 'showip' is true; +** "name[username@sockethost]", if name and sockhost are different and +** showip is false; else +** "name". +** +** NOTE 1: +** Watch out the allocation of "nbuf", if either sptr->name +** or sptr->sockhost gets changed into pointers instead of +** directly allocated within the structure... +** +** NOTE 2: +** Function return either a pointer to the structure (sptr) or +** to internal buffer (nbuf). *NEVER* use the returned pointer +** to modify what it points!!! +*/ + +char *get_client_name(sptr, showip) +aClient *sptr; +int showip; +{ + static char nbuf[HOSTLEN * 2 + USERLEN + 5]; + + if (MyConnect(sptr)) + { + if (IsUnixSocket(sptr)) + { + if (showip) + SPRINTF(nbuf, "%s[%s]", + sptr->name, sptr->sockhost); + else + SPRINTF(nbuf, "%s[%s]", + sptr->name, me.sockhost); + } + else + { + if (showip) + (void)sprintf(nbuf, "%s[%.*s@%s]", + sptr->name, USERLEN, + (!(sptr->flags & FLAGS_GOTID)) ? "" : + sptr->auth, +#ifdef INET6 + inetntop(AF_INET6, + (char *)&sptr->ip, + mydummy, MYDUMMY_SIZE)); +#else + inetntoa((char *)&sptr->ip)); +#endif + else + { + if (mycmp(sptr->name, sptr->sockhost)) + /* Show username for clients and + * ident for others. + */ + SPRINTF(nbuf, "%s[%.*s@%s]", + sptr->name, USERLEN, + IsPerson(sptr) ? + sptr->user->username : + sptr->auth, + sptr->sockhost); + else + return sptr->name; + } + } + return nbuf; + } + return sptr->name; +} + +char *get_client_host(cptr) +aClient *cptr; +{ + static char nbuf[HOSTLEN * 2 + USERLEN + 5]; + + if (!MyConnect(cptr)) + return cptr->name; + if (!cptr->hostp) + return get_client_name(cptr, FALSE); + if (IsUnixSocket(cptr)) + SPRINTF(nbuf, "%s[%s]", cptr->name, ME); + else + (void)sprintf(nbuf, "%s[%-.*s@%-.*s]", + cptr->name, USERLEN, + (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->auth, + HOSTLEN, cptr->hostp->h_name); + return nbuf; +} + +/* + * Form sockhost such that if the host is of form user@host, only the host + * portion is copied. + */ +void get_sockhost(cptr, host) +Reg aClient *cptr; +Reg char *host; +{ + Reg char *s; + if ((s = (char *)index(host, '@'))) + s++; + else + s = host; + strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost)); + Debug((DEBUG_DNS,"get_sockhost %s",s)); +} + +/* + * Return wildcard name of my server name according to given config entry + * --Jto + */ +char *my_name_for_link(name, count) +char *name; +Reg int count; +{ + static char namebuf[HOSTLEN]; + Reg char *start = name; + + if (count <= 0 || count > 5) + return start; + + while (count-- && name) + { + name++; + name = (char *)index(name, '.'); + } + if (!name) + return start; + + namebuf[0] = '*'; + (void)strncpy(&namebuf[1], name, HOSTLEN - 1); + namebuf[HOSTLEN - 1] = '\0'; + + return namebuf; +} + +/* + * Goes thru the list of locally connected servers (except cptr), + * check if my neighbours can see the server "name" (or if it is hidden + * by a hostmask) + * Returns the number of marked servers + */ +int +mark_blind_servers (cptr, name) +aClient *cptr; +char *name; +{ + Reg int i, j = 0; + Reg aClient *acptr; + Reg aConfItem *aconf; + + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr)) + continue; + if (acptr == cptr || IsMe(acptr)) + { + acptr->flags &= ~FLAGS_HIDDEN; + continue; + } + if ((aconf = acptr->serv->nline) && + (match(my_name_for_link(ME, aconf->port), name) == 0)) + { + acptr->flags |= FLAGS_HIDDEN; + j++; + } + } + return j; +} + +/* +** 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_funtion return value: +** +** FLUSH_BUFFER if (cptr == sptr) +** 0 if (cptr != sptr) +*/ +int exit_client(cptr, sptr, from, comment) +aClient *cptr; /* + ** The local client originating the exit or NULL, if this + ** exit is generated by this server for internal reasons. + ** This will not get any of the generated messages. + */ +aClient *sptr; /* Client exiting */ +aClient *from; /* Client firing off this Exit, never NULL! */ +char *comment; /* Reason for the exit */ + { + Reg aClient *acptr; + Reg aClient *next; + Reg aServer *asptr; + Reg aService *asvptr; +#if defined(FNAME_USERLOG) || defined(USE_SYSLOG) || defined(USE_SERVICES) + time_t on_for; +#endif + char comment1[HOSTLEN + HOSTLEN + 2]; + int flags = 0; + + if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD)) + { + if (sptr->flags & FLAGS_KILLED) + { + sendto_flag(SCH_LOCAL, "Killed: %s.", + get_client_name(sptr, TRUE)); + sptr->exitc = EXITC_KILL; + } + + sptr->flags |= FLAGS_CLOSING; +#if (defined(FNAME_USERLOG) || defined(FNAME_CONNLOG) \ + || defined(USE_SERVICES)) \ + || (defined(USE_SYSLOG) && (defined(SYSLOG_USERS) || defined(SYSLOG_CONN))) + if (IsPerson(sptr)) + { + /* It's ugly, it's simple, it's not so important */ + on_for = timeofday - sptr->firsttime + 1; +# if defined(USE_SYSLOG) && defined(SYSLOG_USERS) + syslog(LOG_NOTICE, + "%s (%3d:%02d:%02d): %s@%s [%s] %c\n", + myctime(sptr->firsttime), + on_for / 3600, (on_for % 3600)/60, + on_for % 60, + sptr->user->username, sptr->user->host, + sptr->auth, sptr->exitc); +# endif +# if defined(FNAME_USERLOG) || defined(USE_SERVICES) + sendto_flog(sptr, NULL, on_for, sptr->user->username, + sptr->user->host); +# endif + } + else if (sptr->exitc != EXITC_REF && sptr->exitc != EXITC_AREF) + { +# if defined(USE_SYSLOG) && defined(SYSLOG_CONN) + syslog(LOG_NOTICE, + "%s ( Unknown ): <none>@%s [%s] %c\n", + myctime(sptr->firsttime), + (IsUnixSocket(sptr)) ? me.sockhost : + ((sptr->hostp) ? sptr->hostp->h_name : + sptr->sockhost), sptr->auth, sptr->exitc); +# endif +# if defined(FNAME_CONNLOG) || defined(USE_SERVICES) + sendto_flog(sptr, " Unknown ", 0, "<none>", + (IsUnixSocket(sptr)) ? me.sockhost : + ((sptr->hostp) ? sptr->hostp->h_name : + sptr->sockhost)); +# endif + } +#endif + if (MyConnect(sptr)) + { + if (IsPerson(sptr)) + istat.is_myclnt--; + else if (IsServer(sptr)) + istat.is_myserv--; + else if (IsService(sptr)) + istat.is_myservice--; + else + istat.is_unknown--; + + if (cptr != NULL && sptr != cptr) + sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)", + get_client_name(sptr,FALSE), + cptr->name, comment); + else + sendto_one(sptr, "ERROR :Closing Link: %s (%s)", + get_client_name(sptr,FALSE), comment); + + if (sptr->auth != sptr->username) + { + istat.is_authmem -= sizeof(sptr->auth); + istat.is_auth -= 1; + MyFree(sptr->auth); + sptr->auth = sptr->username; + } + } + /* + ** 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... + ** now, I think it harms big client servers... - krys + ** + ** 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. + */ + close_connection(sptr); + + if (IsServer(sptr)) + { + /* + ** First QUIT all NON-servers which are behind this link + ** + ** Note There is no danger of 'cptr' being exited in + ** the following loops. 'cptr' is a *local* client, + ** all dependants are *remote* clients. + */ + + /* This next bit is a a bit ugly but all it does is take the + ** name of us.. me.name and tack it together with the name of + ** the server sptr->name that just broke off and puts this + ** together into exit_one_client() to provide some useful + ** information about where the net is broken. Ian + */ + (void)strcpy(comment1, ME); + (void)strcat(comment1," "); + (void)strcat(comment1, sptr->name); + + /* This will quit all the *users*, without checking the + ** whole list of clients. + */ + for (asptr = svrtop; asptr; asptr = (aServer *)next) + { + next = (aClient *)asptr->nexts; + if ((asptr->bcptr == NULL) || + (asptr->bcptr->from != sptr + && asptr->bcptr != sptr)) + continue; + /* + ** This version doesn't need QUITs to be + ** propagaged unless the remote server is + ** hidden (by a hostmask) + */ + if (mark_blind_servers(NULL, + asptr->bcptr->name)) + flags |= FLAGS_SPLIT | FLAGS_HIDDEN; + else + flags |= FLAGS_SPLIT; + while (GotDependantClient(asptr->bcptr)) + { + acptr = asptr->bcptr->prev; + acptr->flags |= flags; + exit_one_client(NULL, acptr, &me, + comment1); + } + } + /* + ** Second SQUIT all servers behind this link + */ + for (asptr = svrtop; asptr; asptr = (aServer *)next) + { + next = (aClient *)asptr->nexts; + if ((acptr = asptr->bcptr) && + acptr->from == sptr) + { + sendto_flag(SCH_SERVER, + "Sending SQUIT %s (%s)", + acptr->name, comment); + exit_one_client(NULL, acptr, &me, ME); + } + } + } /* If (IsServer(sptr)) */ + } /* if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD)) */ + + if (IsServer(sptr) && GotDependantClient(sptr)) + { + /* + ** generate QUITs locally when receiving a SQUIT + ** check for hostmasking. + */ + if (mark_blind_servers(cptr, sptr->name)) + flags = FLAGS_SPLIT | FLAGS_HIDDEN; + else + flags = FLAGS_SPLIT; + + if (IsServer(from)) + /* this is a guess */ + (void)strcpy(comment1, from->name); + else + /* this is right */ + (void)strcpy(comment1, sptr->serv->up); + (void)strcat(comment1, " "); + (void)strcat(comment1, sptr->name); + + while (GotDependantClient(sptr)) + { + acptr = sptr->prev; + acptr->flags |= flags; + exit_one_client(cptr, acptr, &me, comment1); + } + } + + /* + ** Try to guess from comment if the client is exiting + ** normally (KILL or issued QUIT), or if it is splitting + ** It requires comment for splitting users to be + ** "server.some.where splitting.some.where" + */ + comment1[0] = '\0'; + if (!IsServer(sptr) && ((sptr->flags & FLAGS_KILLED) == 0)) + { + char *c = comment; + int i = 0; + while (*c && *c != ' ') + if (*c++ == '.') + i++; + if (*c++ && i) + { + i = 0; + while (*c && *c != ' ') + if (*c++ == '.') + i++; + if (!i || *c) + sptr->flags |= FLAGS_QUIT; + } + else + sptr->flags |= FLAGS_QUIT; + + if (sptr == cptr && !(sptr->flags & FLAGS_QUIT)) + { + /* + ** This will avoid nick delay to be abused by + ** letting local users put a comment looking + ** like a server split. + */ + strncpyzt(comment1, comment, HOSTLEN + HOSTLEN); + strcat(comment1, " "); + sptr->flags |= FLAGS_QUIT; + } + } + + if (IsServer(sptr) && (cptr == sptr)) + sendto_flag(SCH_SERVER, "Sending SQUIT %s (%s)", + cptr->name, comment); + + exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : comment); + return cptr == sptr ? FLUSH_BUFFER : 0; + } + +/* +** Exit one client, local or remote. Assuming all dependants have +** been already removed, and socket closed for local client. +*/ +static void exit_one_client(cptr, sptr, from, comment) +aClient *sptr; +aClient *cptr; +aClient *from; +char *comment; +{ + Reg aClient *acptr; + Reg int i; + Reg Link *lp; + + /* + ** For a server or user quitting, propagage the information to + ** other servers (except to the one where is came from (cptr)) + */ + if (IsMe(sptr)) + { + sendto_flag(SCH_ERROR, + "ERROR: tried to exit me! : %s", comment); + return; /* ...must *never* exit self!! */ + } + else if (IsServer(sptr)) { + /* + ** Old sendto_serv_but_one() call removed because we now + ** need to send different names to different servers + ** (domain name matching) + */ + istat.is_serv--; + for (i = fdas.highest; i >= 0; i--) + { + Reg aConfItem *aconf; + + if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) || + acptr == cptr || IsMe(acptr)) + continue; + if ((aconf = acptr->serv->nline) && + (match(my_name_for_link(ME, aconf->port), + sptr->name) == 0)) + continue; + sendto_one(acptr, ":%s SQUIT %s :%s", + from->name, sptr->name, comment); + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_SQUIT, sptr->name, sptr, + ":%s SQUIT %s :%s", from->name, + sptr->name, comment); +#endif + (void) del_from_server_hash_table(sptr->serv, cptr ? cptr : + sptr->from); + } else if (!IsPerson(sptr) && !IsService(sptr)) + /* ...this test is *dubious*, would need + ** some thougth.. but for now it plugs a + ** nasty hole in the server... --msa + */ + ; /* Nothing */ + else if (sptr->name[0] && !IsService(sptr)) /* clean with QUIT... */ + { + /* + ** If this exit is generated from "m_kill", then there + ** is no sense in sending the QUIT--KILL's have been + ** sent instead. + */ + if ((sptr->flags & FLAGS_KILLED) == 0) + { + if ((sptr->flags & FLAGS_SPLIT) == 0) + { + sendto_serv_butone(cptr, ":%s QUIT :%s", + sptr->name, comment); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_QUIT| + SERVICE_WANT_RQUIT, + (sptr->user) ? + sptr->user->server + : NULL, cptr, + ":%s QUIT :%s", + sptr->name, comment); +#endif + } + else + { + if (sptr->flags & FLAGS_HIDDEN) + /* joys of hostmasking */ + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr =local[fdas.fd[i]]) + || !IsServer(acptr) + || acptr == cptr + || IsMe(acptr)) + continue; + if (acptr->flags &FLAGS_HIDDEN) + sendto_one(acptr, + ":%s QUIT :%s", + sptr->name, + comment); + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_QUIT, + (sptr->user) ? sptr->user->server + : NULL, cptr, + ":%s QUIT :%s", + sptr->name, comment); +#endif + } + } + /* + ** If a person is on a channel, send a QUIT notice + ** to every client (person) on the same channel (so + ** that the client can show the "**signoff" message). + ** (Note: The notice is to the local clients *only*) + */ + if (sptr->user) + { + if (IsInvisible(sptr)) + istat.is_user[1]--; + else + istat.is_user[0]--; + if (IsAnOper(sptr)) + istat.is_oper--; + sendto_common_channels(sptr, ":%s QUIT :%s", + sptr->name, comment); + + if (!(acptr = cptr ? cptr : sptr->from)) + acptr = sptr; + while ((lp = sptr->user->channel)) + { + /* + ** Mark channels from where remote chop left, + ** this will eventually lock the channel. + ** close_connection() has already been called, + ** it makes MyConnect == False - krys + */ + if (sptr != cptr) + if (*lp->value.chptr->chname == '!') + { + if (!(sptr->flags &FLAGS_QUIT)) + lp->value.chptr->history = timeofday + LDELAYCHASETIMELIMIT; + } + else if ( +#ifndef BETTER_CDELAY + !(sptr->flags & FLAGS_QUIT) && +#endif + is_chan_op(sptr, lp->value.chptr)) + lp->value.chptr->history = timeofday + DELAYCHASETIMELIMIT; + if (IsAnonymous(lp->value.chptr) && + !IsQuiet(lp->value.chptr)) + sendto_channel_butserv(lp->value.chptr, sptr, ":%s PART %s :None", sptr->name, lp->value.chptr->chname); + remove_user_from_channel(sptr,lp->value.chptr); + } + + /* Clean up invitefield */ + while ((lp = sptr->user->invited)) + del_invite(sptr, lp->value.chptr); + /* again, this is all that is needed */ + + /* Add user to history */ +#ifndef BETTER_NDELAY + add_history(sptr, (sptr->flags & FLAGS_QUIT) ? + &me : NULL); +#else + add_history(sptr, (sptr == cptr) ? &me : NULL); +#endif + off_history(sptr); + } + } + else if (sptr->name[0] && IsService(sptr)) + { + /* + ** If this exit is generated from "m_kill", then there + ** is no sense in sending the QUIT--KILL's have been + ** sent instead. + */ + if ((sptr->flags & FLAGS_KILLED) == 0) + { + /* + ** A service quitting is annoying, It has to be sent + ** to connected servers depending on + ** sptr->service->dist + */ + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr = local[fdas.fd[i]]) + || !IsServer(acptr) || acptr == cptr + || IsMe(acptr)) + continue; + if (match(sptr->service->dist, acptr->name)) + continue; + sendto_one(acptr, ":%s QUIT :%s", sptr->name, + comment); + } + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_SERVICE, NULL, NULL, + ":%s QUIT :%s", sptr->name, comment); +#endif + /* MyConnect(sptr) is always FALSE here */ + if (cptr == sptr) + sendto_flag(SCH_NOTICE, "Service %s disconnected", + get_client_name(sptr, TRUE)); + sendto_flag(SCH_SERVICE, "Received QUIT %s from %s (%s)", + sptr->name, from->name, comment); + istat.is_service--; + } + + /* Remove sptr from the client list */ + if (del_from_client_hash_table(sptr->name, sptr) != 1) + Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x", + sptr, sptr->name, + sptr->from ? sptr->from->sockhost : "??host", + sptr->from, sptr->next, sptr->prev, sptr->fd, + sptr->status, sptr->user)); + remove_client_from_list(sptr); + return; +} + +void checklist() +{ + Reg aClient *acptr; + Reg int i,j; + + if (!(bootopt & BOOT_AUTODIE)) + return; + for (j = i = 0; i <= highest_fd; i++) + if (!(acptr = local[i])) + continue; + else if (IsClient(acptr)) + j++; + if (!j) + { +#ifdef USE_SYSLOG + syslog(LOG_WARNING,"ircd exiting: autodie"); +#endif + exit(0); + } + return; +} + +void initstats() +{ + bzero((char *)&istat, sizeof(istat)); + istat.is_serv = 1; + istat.is_remc = 1; /* don't ask me why, I forgot. */ + bzero((char *)&ircst, sizeof(ircst)); +} + +void tstats(cptr, name) +aClient *cptr; +char *name; +{ + Reg aClient *acptr; + Reg int i; + Reg struct stats *sp; + struct stats tmp; + + sp = &tmp; + bcopy((char *)ircstp, (char *)sp, sizeof(*sp)); + for (i = 0; i < MAXCONNECTIONS; i++) + { + if (!(acptr = local[i])) + continue; + if (IsServer(acptr)) + { + sp->is_sbs += acptr->sendB; + sp->is_sbr += acptr->receiveB; + sp->is_sks += acptr->sendK; + sp->is_skr += acptr->receiveK; + sp->is_sti += timeofday - acptr->firsttime; + sp->is_sv++; + if (sp->is_sbs > 1023) + { + sp->is_sks += (sp->is_sbs >> 10); + sp->is_sbs &= 0x3ff; + } + if (sp->is_sbr > 1023) + { + sp->is_skr += (sp->is_sbr >> 10); + sp->is_sbr &= 0x3ff; + } + } + else if (IsClient(acptr)) + { + sp->is_cbs += acptr->sendB; + sp->is_cbr += acptr->receiveB; + sp->is_cks += acptr->sendK; + sp->is_ckr += acptr->receiveK; + sp->is_cti += timeofday - acptr->firsttime; + sp->is_cl++; + if (sp->is_cbs > 1023) + { + sp->is_cks += (sp->is_cbs >> 10); + sp->is_cbs &= 0x3ff; + } + if (sp->is_cbr > 1023) + { + sp->is_ckr += (sp->is_cbr >> 10); + sp->is_cbr &= 0x3ff; + } + } + else if (IsUnknown(acptr)) + sp->is_ni++; + } + + sendto_one(cptr, ":%s %d %s :accepts %u refused %u", + ME, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref); + sendto_one(cptr, ":%s %d %s :unknown: commands %u prefixes %u", + ME, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf); + sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u", + ME, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni); + sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u", + ME, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt); + sendto_one(cptr, ":%s %d %s :users without servers %u ghosts N/A", + ME, RPL_STATSDEBUG, name, sp->is_nosrv); + sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u", + ME, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake); + sendto_one(cptr, ":%s %d %s :auth: successes %u fails %u", + ME, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad); + sendto_one(cptr,":%s %d %s :local connections %u udp packets %u", + ME, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udpok); + sendto_one(cptr,":%s %d %s :udp errors %u udp dropped %u", + ME, RPL_STATSDEBUG, name, sp->is_udperr, sp->is_udpdrop); + sendto_one(cptr, + ":%s %d %s :link checks %u passed %u 15s/%u 30s dropped %uSq/%uYg/%uFl", + ME, RPL_STATSDEBUG, name, sp->is_ckl, sp->is_cklq, + sp->is_cklok, sp->is_cklQ, sp->is_ckly, sp->is_cklno); + if (sp->is_wwcnt) + sendto_one(cptr, ":%s %d %s :whowas turnover %u/%u/%u [%u]", + ME, RPL_STATSDEBUG, name, sp->is_wwmt, + (u_int) (sp->is_wwt / sp->is_wwcnt), sp->is_wwMt, + KILLCHASETIMELIMIT); + if (sp->is_lkcnt) + sendto_one(cptr, ":%s %d %s :ndelay turnover %u/%u/%u [%u]", + ME, RPL_STATSDEBUG, name, sp->is_lkmt, + (u_int) (sp->is_lkt / sp->is_lkcnt), sp->is_lkMt, + DELAYCHASETIMELIMIT); + sendto_one(cptr, ":%s %d %s :abuse protections %u strict %u", ME, + RPL_STATSDEBUG, name, (bootopt & BOOT_PROT) ? 1 : 0, + (bootopt & BOOT_STRICTPROT) ? 1 : 0); + sendto_one(cptr, ":%s %d %s :Client - Server", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, ":%s %d %s :connected %u %u", + ME, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv); + sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK", + ME, RPL_STATSDEBUG, name, + sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs); + sendto_one(cptr, ":%s %d %s :bytes recv %u.%uK %u.%uK", + ME, RPL_STATSDEBUG, name, + sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr); + sendto_one(cptr, ":%s %d %s :time connected %u %u", + ME, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti); +#if defined(USE_IAUTH) + report_iauth_stats(cptr, name); +#endif +} + +#ifdef CACHED_MOTD +aMotd *motd = NULL; +struct tm motd_tm; + +void read_motd(filename) +char *filename; +{ + int fd; + register aMotd *temp, *last; + struct stat Sb; + char line[80]; + register char *tmp; + + if ((fd = open(filename, O_RDONLY)) == -1) + return; + if (fstat(fd, &Sb) == -1) + { + close(fd); + return; + } + for(;motd != NULL;motd=last) + { + last = motd->next; + MyFree(motd->line); + MyFree((char *)motd); + } + motd_tm = *localtime(&Sb.st_mtime); + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + last = NULL; + while (dgets(fd, line, sizeof(line)-1) > 0) + { + if ((tmp = strchr(line, '\n')) != NULL) + *tmp = (char) 0; + if ((tmp = strchr(line, '\r')) != NULL) + *tmp = (char) 0; + temp = (aMotd *)MyMalloc(sizeof(aMotd)); + if (!temp) + outofmemory(); + temp->line = mystrdup(line); + temp->next = NULL; + if (!motd) + motd = temp; + else + last->next = temp; + last = temp; + } + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + close(fd); +} +#endif |