* 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.
- *
- * $Id$
+ */
+/** @file
+ * @brief Miscellaneous support functions.
+ * @version $Id$
*/
#include "config.h"
#include "hash.h"
#include "ircd.h"
#include "ircd_alloc.h"
-#include "ircd_auth.h"
#include "ircd_features.h"
#include "ircd_log.h"
#include "ircd_reply.h"
#include "parse.h"
#include "querycmds.h"
#include "res.h"
+#include "s_auth.h"
#include "s_bsd.h"
#include "s_conf.h"
#include "s_debug.h"
#include "s_user.h"
#include "send.h"
#include "struct.h"
-#include "support.h"
#include "sys.h"
#include "uping.h"
#include "userload.h"
-#include <assert.h>
+/* #include <assert.h> -- Now using assert in ircd_log.h */
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
-
+/** Array of English month names (0 = January). */
static char *months[] = {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
};
+/** Array of English day names (0 = Sunday). */
static char *weekdays[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
/*
* stats stuff
*/
+/** Global statistics structure. */
static struct ServerStatistics ircst;
+/** Public pointer to global statistics structure. */
struct ServerStatistics* ServerStats = &ircst;
+/** Formats a Unix time as a readable string.
+ * @param clock Unix time to format (0 means #CurrentTime).
+ * @return Pointer to a static buffer containing something like
+ * "Sunday January 1 2000 -- 09:30 +01:00"
+ */
char *date(time_t clock)
{
static char buf[80], plus;
gm = &gmbuf;
lt = localtime(&clock);
+ /* There is unfortunately no clean portable way to extract time zone
+ * offset information, so do ugly things.
+ */
minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min);
if (lt->tm_yday != gm->tm_yday)
{
return buf;
}
-/*
- * myctime
- *
- * This is like standard ctime()-function, but it zaps away
- * the newline from the end of that string. Also, it takes
+/** Like ctime() but with no trailing newline. Also, it takes
* the time value as parameter, instead of pointer to it.
- * Note that it is necessary to copy the string to alternate
- * buffer (who knows how ctime() implements it, maybe it statically
- * has newline there and never 'refreshes' it -- zapping that
- * might break things in other places...)
+ * @param value Unix time to format.
+ * @return Pointer to a static buffer containing formatted time.
*/
char *myctime(time_t value)
{
+ /* Use a secondary buffer in case ctime() would not replace an
+ * overwritten newline.
+ */
static char buf[28];
char *p;
return buf;
}
-/*
- * 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" if 'showip' is false.
- *
- * 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!!!
+/** 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 on any
+ * client structure.
+ * @param sptr Client to operate on.
+ * @param showip If non-zero, append [username\@text-ip] to name.
+ * @return Either cli_name(\a sptr) or a static buffer.
*/
const char* get_client_name(const struct Client* sptr, int showip)
{
static char nbuf[HOSTLEN * 2 + USERLEN + 5];
- if (MyConnect(sptr)) {
- if (showip)
- ircd_snprintf(0, nbuf, sizeof(nbuf), "%s[%s@%s]", cli_name(sptr),
- IsIdented(sptr) ? cli_username(sptr) : "unknown",
- cli_sock_ip(sptr));
- else
- return cli_name(sptr);
- return nbuf;
- }
- return cli_name(sptr);
-}
-
-const char *get_client_host(const struct Client *cptr)
-{
- return get_client_name(cptr, HIDE_IP);
-}
-
-/*
- * Form sockhost such that if the host is of form user@host, only the host
- * portion is copied.
- */
-void get_sockhost(struct Client *cptr, char *host)
-{
- char *s;
- if ((s = strchr(host, '@')))
- s++;
- else
- s = host;
- ircd_strncpy(cli_sockhost(cptr), s, HOSTLEN);
+ if (!MyConnect(sptr) || !showip)
+ return cli_name(sptr);
+ ircd_snprintf(0, nbuf, sizeof(nbuf), "%s[%s@%s]", cli_name(sptr),
+ IsIdented(sptr) ? cli_username(sptr) : "",
+ cli_sock_ip(sptr));
+ return nbuf;
}
-/*
+/**
* Exit one client, local or remote. Assuming for local client that
- * all dependants already have been removed, and socket is closed.
- *
- * Rewritten by Run - 24 sept 94
- *
- * bcptr : client being (s)quitted
- * sptr : The source (prefix) of the QUIT or SQUIT
- *
- * --Run
+ * all dependents already have been removed, and socket is closed.
+ * @param bcptr Client being (s)quitted.
+ * @param comment The QUIT comment to send.
*/
+/* Rewritten by Run - 24 sept 94 */
static void exit_one_client(struct Client* bcptr, const char* comment)
{
struct SLink *lp;
+ struct Ban *bp;
if (cli_serv(bcptr) && cli_serv(bcptr)->client_list) /* Was SetServerYXX called ? */
ClearServerYXX(bcptr); /* Removes server from server_list[] */
* Stop a running /LIST clean
*/
if (MyUser(bcptr) && cli_listing(bcptr)) {
- cli_listing(bcptr)->chptr->mode.mode &= ~MODE_LISTED;
MyFree(cli_listing(bcptr));
cli_listing(bcptr) = NULL;
}
del_invite(bcptr, lp->value.chptr);
/* Clean up silencefield */
- while ((lp = cli_user(bcptr)->silence))
- del_silence(bcptr, lp->value.cp);
+ while ((bp = cli_user(bcptr)->silence)) {
+ cli_user(bcptr)->silence = bp->next;
+ free_ban(bp);
+ }
/* Clean up snotice lists */
if (MyUser(bcptr))
set_snomask(bcptr, ~0, SNO_DEL);
- if (IsInvisible(bcptr))
+ if (IsInvisible(bcptr)) {
+ assert(UserStats.inv_clients > 0);
--UserStats.inv_clients;
- if (IsOper(bcptr))
+ }
+ if (IsOper(bcptr)) {
+ assert(UserStats.opers > 0);
--UserStats.opers;
+ }
if (MyConnect(bcptr))
Count_clientdisconnects(bcptr, UserStats);
- else {
+ else
Count_remoteclientquits(UserStats, bcptr);
- }
}
else if (IsServer(bcptr))
{
assert(!IsServer(bcptr));
/* bcptr->user->server->serv->client_list[IndexYXX(bcptr)] = NULL; */
RemoveYXXClient(cli_user(bcptr)->server, cli_yxx(bcptr));
- if (IsIAuthed(bcptr) || cli_iauth(bcptr))
- iauth_exit_client(bcptr);
}
/* Remove bcptr from the client list */
remove_client_from_list(bcptr);
}
-/*
- * exit_downlinks - added by Run 25-9-94
- *
+/* exit_downlinks - added by Run 25-9-94 */
+/**
* Removes all clients and downlinks (+clients) of any server
* QUITs are generated and sent to local users.
- *
- * cptr : server that must have all dependents removed
- * sptr : source who thought that this was a good idea
- * comment : comment sent as sign off message to local clients
+ * @param cptr server that must have all dependents removed
+ * @param sptr source who thought that this was a good idea
+ * @param comment comment sent as sign off message to local clients
*/
static void exit_downlinks(struct Client *cptr, struct Client *sptr, char *comment)
{
}
}
-/*
- * exit_client, rewritten 25-9-94 by Run
- *
- * This function exits a client of *any* type (user, server, etc)
+/* exit_client, rewritten 25-9-94 by Run */
+/**
+ * Exits a client of *any* type (user, server, etc)
* from this server. Also, this generates all necessary prototol
* messages that this exit may cause.
*
* this connection.
*
* For convenience, this function returns a suitable value for
- * m_funtion return value:
+ * m_function return value:
*
* CPTR_KILLED if (cptr == bcptr)
* 0 if (cptr != bcptr)
*
* This function can be called in two ways:
- * 1) From before or in parse(), exitting the 'cptr', in which case it was
+ * 1) From before or in parse(), exiting the 'cptr', in which case it was
* invoked as exit_client(cptr, cptr, &me,...), causing it to always
* return CPTR_KILLED.
* 2) Via parse from a m_function call, in which case it was invoked as
* sptr->from. And CPTR_KILLED should be returned if cptr got removed (too).
*
* --Run
+ * @param cptr Connection currently being handled by read_message.
+ * @param victim Client being killed.
+ * @param killer Client that made the decision to remove \a victim.
+ * @param comment Reason for the exit.
+ * @return CPTR_KILLED if cptr == bcptr, else 0.
*/
-int exit_client(struct Client *cptr, /* Connection being handled by
- read_message right now */
- struct Client* victim, /* Client being killed */
- struct Client* killer, /* The client that made the decision
- to remove this one, never NULL */
- const char* comment) /* Reason for the exit */
+int exit_client(struct Client *cptr,
+ struct Client* victim,
+ struct Client* killer,
+ const char* comment)
{
struct Client* acptr = 0;
struct DLink *dlp;
on_for = CurrentTime - cli_firsttime(victim);
+ if (IsUser(victim) || IsUserPort(victim))
+ auth_send_exit(victim);
+
if (IsUser(victim))
log_write(LS_USER, L_TRACE, 0, "%Tu %i %s@%s %s %s %s%s %s :%s",
cli_firsttime(victim), on_for,
cli_name(killer), comment);
else
sendrawto_one(victim, MSG_ERROR " :Closing Link: %s by %s (%s)",
- cli_name(victim), IsServer(killer) ? cli_name(&me) :
- cli_name(killer), comment);
+ cli_name(victim),
+ cli_name(IsServer(killer) ? &his : killer),
+ comment);
}
}
if ((IsServer(victim) || IsHandshake(victim) || IsConnecting(victim)) &&
(acptr = findNUser(cli_serv(victim)->by))) {
if (cli_user(acptr) == cli_serv(victim)->user) {
sendcmdto_one(&me, CMD_NOTICE, acptr,
- "%C :Link with %s cancelled: %s", acptr,
+ "%C :Link with %s canceled: %s", acptr,
cli_name(victim), comment);
}
else {
}
}
if (killer == &me)
- sendto_opmask_butone(acptr, SNO_OLDSNO, "Link with %s cancelled: %s",
+ sendto_opmask_butone(acptr, SNO_OLDSNO, "Link with %s canceled: %s",
cli_name(victim), comment);
}
}
/*
* cptr can only have been killed if it was cptr itself that got killed here,
- * because cptr can never have been a dependant of victim --Run
+ * because cptr can never have been a dependent of victim --Run
*/
return (cptr == victim) ? CPTR_KILLED : 0;
}
-/*
- * Exit client with formatted message, added 25-9-94 by Run
+/**
+ * Exit client with formatted va_list message.
+ * Thin wrapper around exit_client().
+ * @param cptr Connection being processed.
+ * @param bcptr Connection being closed.
+ * @param sptr Connection who asked to close the victim.
+ * @param pattern Format string for message.
+ * @param vl Stdargs argument list.
+ * @return Has a tail call to exit_client().
*/
+/* added 25-9-94 by Run */
int vexit_client_msg(struct Client *cptr, struct Client *bcptr, struct Client *sptr,
const char *pattern, va_list vl)
{
return exit_client(cptr, bcptr, sptr, msgbuf);
}
+/**
+ * Exit client with formatted message using a variable-length argument list.
+ * Thin wrapper around exit_client().
+ * @param cptr Connection being processed.
+ * @param bcptr Connection being closed.
+ * @param sptr Connection who asked to close the victim.
+ * @param pattern Format string for message.
+ * @return Has a tail call to exit_client().
+ */
int exit_client_msg(struct Client *cptr, struct Client *bcptr,
struct Client *sptr, const char *pattern, ...)
{
return exit_client(cptr, bcptr, sptr, msgbuf);
}
+/** Initialize global server statistics. */
+/* (Kind of pointless since C guarantees it's already zero'ed, but... */
void initstats(void)
{
memset(&ircst, 0, sizeof(ircst));
}
-void tstats(struct Client *cptr, struct StatDesc *sd, int stat, char *param)
+/** Report server statistics to a client.
+ * @param cptr Client who wants statistics.
+ * @param sd StatDesc structure being looked up (unused).
+ * @param param Extra parameter passed by user (unused).
+ */
+void tstats(struct Client *cptr, const struct StatDesc *sd, char *param)
{
struct Client *acptr;
int i;
{
sp->is_sbs += cli_sendB(acptr);
sp->is_sbr += cli_receiveB(acptr);
- sp->is_sks += cli_sendK(acptr);
- sp->is_skr += cli_receiveK(acptr);
sp->is_sti += CurrentTime - cli_firsttime(acptr);
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 (IsUser(acptr))
{
sp->is_cbs += cli_sendB(acptr);
sp->is_cbr += cli_receiveB(acptr);
- sp->is_cks += cli_sendK(acptr);
- sp->is_ckr += cli_receiveK(acptr);
sp->is_cti += CurrentTime - cli_firsttime(acptr);
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++;
send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Client server");
send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":connected %u %u",
sp->is_cl, sp->is_sv);
- send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":bytes sent %u.%uK %u.%uK",
- sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs);
- send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":bytes recv %u.%uK %u.%uK",
- sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
- send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":time connected %Tu %Tu",
+ send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":bytes sent %Lu %Lu",
+ sp->is_cbs, sp->is_sbs);
+ send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":bytes recv %Lu %Lu",
+ sp->is_cbr, sp->is_sbr);
+ send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":time connected %Lu %Lu",
sp->is_cti, sp->is_sti);
}