X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/a6a4707efec425579538e4591381924408044411..8536ac6b661fa261bad7de981045401f514fb6b7:/src/proto-p10.c diff --git a/src/proto-p10.c b/src/proto-p10.c index 264c858..4a4dbb9 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -5,7 +5,7 @@ * * x3 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -20,12 +20,16 @@ #include "nickserv.h" #include "chanserv.h" +#include "hash.h" +#include "helpfile.h" #include "hosthiding.h" #include "proto-common.c" +#include "opserv.h" /* Full commands. */ #define CMD_ACCOUNT "ACCOUNT" #define CMD_ADMIN "ADMIN" +#define CMD_ALIST "ALIST" #define CMD_ASLL "ASLL" #define CMD_AWAY "AWAY" #define CMD_BURST "BURST" @@ -85,12 +89,20 @@ #define CMD_SERVSET "SERVSET" #define CMD_SET "SET" #define CMD_SETTIME "SETTIME" +#define CMD_SGLINE "SGLINE" #define CMD_SHUN "SHUN" #define CMD_SILENCE "SILENCE" +#define CMD_SMO "SMO" +#define CMD_SNO "SNO" +#define CMD_SSHUN "SSHUN" +#define CMD_SPAMFILTER "SPAMFILTER" #define CMD_SQUERY "SQUERY" #define CMD_SQUIT "SQUIT" #define CMD_STATS "STATS" +#define CMD_SVSJOIN "SVSJOIN" #define CMD_SVSNICK "SVSNICK" +#define CMD_SVSPART "SVSPART" +#define CMD_SVSQUIT "SVSQUIT" #define CMD_SWHOIS "SWHOIS" #define CMD_TIME "TIME" #define CMD_TOPIC "TOPIC" @@ -113,6 +125,7 @@ /* Tokenized commands. */ #define TOK_ACCOUNT "AC" #define TOK_ADMIN "AD" +#define TOK_ALIST "AL" #define TOK_ASLL "LL" #define TOK_AWAY "A" #define TOK_BURST "B" @@ -173,12 +186,20 @@ #define TOK_SERVSET "SERVSET" #define TOK_SET "SET" #define TOK_SETTIME "SE" +#define TOK_SGLINE "SGL" #define TOK_SHUN "SU" #define TOK_SILENCE "U" +#define TOK_SMO "SMO" +#define TOK_SNO "SNO" +#define TOK_SSHUN "SSU" +#define TOK_SPAMFILTER "SF" #define TOK_SQUERY "SQUERY" #define TOK_SQUIT "SQ" #define TOK_STATS "R" +#define TOK_SVSJOIN "SJ" #define TOK_SVSNICK "SN" +#define TOK_SVSPART "SP" +#define TOK_SVSQUIT "SX" #define TOK_SWHOIS "SW" #define TOK_TIME "TI" #define TOK_TOPIC "T" @@ -271,12 +292,20 @@ #define P10_SERVSET TYPE(SERVSET) #define P10_SET TYPE(SET) #define P10_SETTIME TYPE(SETTIME) +#define P10_SGLINE TYPE(SGLINE) #define P10_SHUN TYPE(SHUN) #define P10_SILENCE TYPE(SILENCE) +#define P10_SMO TYPE(SMO) +#define P10_SNO TYPE(SNO) +#define P10_SSHUN TYPE(SSHUN) +#define P10_SPAMFILTER TYPE(SPAMFILTER) #define P10_SQUERY TYPE(SQUERY) #define P10_SQUIT TYPE(SQUIT) #define P10_STATS TYPE(STATS) +#define P10_SVSJOIN TYPE(SVSJOIN) #define P10_SVSNICK TYPE(SVSNICK) +#define P10_SVSPART TYPE(SVSPART) +#define P10_SVSQUIT TYPE(SVSQUIT) #define P10_SWHOIS TYPE(SWHOIS) #define P10_TIME TYPE(TIME) #define P10_TOPIC TYPE(TOPIC) @@ -302,22 +331,32 @@ */ #define PREHISTORY 780000000 +#define MODELEN 40 + KEYLEN + static struct server *servers_num[64*64]; static privmsg_func_t *privmsg_funcs; static unsigned int num_privmsg_funcs; static privmsg_func_t *notice_funcs; static unsigned int num_notice_funcs; static struct dict *unbursted_channels; -static char *his_servername; -static char *his_servercomment; +static const char *his_servername; +static const char *his_servercomment; static int extended_accounts; +/* These correspond to 1 << X: 012345678901234567 */ +const char irc_user_mode_chars[] = "o iw dkgn I"; + static struct userNode *AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip); extern int off_channel; +extern int DefConLevel; +extern int DefConTimeOut; +extern char *DefConChanModes; static int parse_oplevel(char *str); +char privbuf[512] = ""; + /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the * server and Y's indentifying the client on that server. */ struct server* @@ -364,6 +403,32 @@ GetUserN(const char *numeric) /* using numeric */ return un; } +extern struct userNode *opserv; +static void +check_ctcp(struct userNode *user, struct userNode *bot, char *text, UNUSED_ARG(int server_qualified)) +{ + char *cmd; + /* if its a version reply, do an alert check (only alerts with version=something) */ + if(bot == opserv) { + if(text[0] == '\001') { + text++; + cmd = mysep(&text, " "); + if(!irccasecmp(cmd, "VERSION")) { + char *version = mysep(&text, "\n"); + if(!version) + version = ""; + /* opserv_debug("Opserv got CTCP VERSION Notice from %s: %s", user->nick, version); */ + /* TODO: setup a ctcp_funcs thing to handle this and other CTCPS properly */ + user->version_reply = strdup(version); + /* TODO: put this in the db */ + if(match_ircglob(version, "WebTV;*")) + user->no_notice = true; /* webbies cant see notices */ + } + } + } +} + + static void privmsg_user_helper(struct userNode *un, void *data) { @@ -375,11 +440,49 @@ privmsg_user_helper(struct userNode *un, void *data) } } else { if ((num < num_notice_funcs) && notice_funcs[num]) { + check_ctcp(pd->user, un, pd->text, pd->is_qualified); notice_funcs[num](pd->user, un, pd->text, pd->is_qualified); } } } +/* equiv to user doing /connect server port target */ +void irc_connect(struct userNode *user, char *server, unsigned int port, struct server *target) +{ + putsock("%s " P10_CONNECT " %s %d %s", user->numeric, server, port, target->numeric); +} + +void +irc_squit_route(struct server *srv, const char *message, ...) +{ + va_list arg_list; + char buffer[MAXLEN]; + va_start(arg_list, message); + vsnprintf(buffer, MAXLEN-2, message, arg_list); + buffer[MAXLEN-1] = 0; + + /* When would we squit ourselves exactly?? -Rubin */ + if(srv == self && cManager.uplink->state == CONNECTED ) { + unsigned int i; + + /* Quit all clients linked to me. */ + for(i = 0; i <= self->num_mask; i++) { + if(!self->users[i]) + continue; + irc_quit(self->users[i], buffer); + } + } + + putsock("%s " P10_SQUIT " %s %d :%s", self->numeric, srv->name, 0, buffer); + + if(srv == self) { + /* Force a reconnect to the currently selected server. */ + cManager.uplink->tries = 0; + log_module(MAIN_LOG, LOG_INFO, "Squitting from uplink: %s", buffer); + close_socket(); + } +} + void irc_server(struct server *srv) { @@ -387,15 +490,15 @@ irc_server(struct server *srv) inttobase64(extranum, srv->num_mask, (srv->numeric[1] || (srv->num_mask >= 64*64)) ? 3 : 2); if (srv == self) { - putsock(P10_SERVER " %s %d %li %li J10 %s%s +s6 :%s", - srv->name, srv->hops+1, srv->boot, srv->link, srv->numeric, extranum, srv->description); + putsock(P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " J10 %s%s +s6 :%s", + srv->name, srv->hops+1, srv->boot, srv->link_time, srv->numeric, extranum, srv->description); } else { - putsock("%s " P10_SERVER " %s %d %li %li %c10 %s%s +s6 :%s", - self->numeric, srv->name, srv->hops+1, srv->boot, srv->link, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description); + putsock("%s " P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " %c10 %s%s +s6 :%s", + self->numeric, srv->name, srv->hops+1, srv->boot, srv->link_time, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description); } } -static void +void irc_p10_pton(irc_in_addr_t *ip, const char *input) { if (strlen(input) == 6) { @@ -422,7 +525,7 @@ irc_p10_pton(irc_in_addr_t *ip, const char *input) } } -static void +void irc_p10_ntop(char *output, const irc_in_addr_t *ip) { if (!irc_in_addr_is_valid(*ip)) { @@ -474,43 +577,18 @@ void irc_user(struct userNode *user) { char b64ip[25]; - if (!user) + if (!user || IsDummy(user)) return; irc_p10_ntop(b64ip, &user->ip); if (user->modes) { - int modelen; char modes[32]; - modelen = 0; - if (IsOper(user)) - modes[modelen++] = 'o'; - if (IsInvisible(user)) - modes[modelen++] = 'i'; - if (IsWallOp(user)) - modes[modelen++] = 'w'; - if (IsService(user)) - modes[modelen++] = 'k'; - if (IsServNotice(user)) - modes[modelen++] = 's'; - if (IsDeaf(user)) - modes[modelen++] = 'd'; - if (IsGlobal(user)) - modes[modelen++] = 'g'; - // sethost - reed/apples - // if (IsHelperIrcu(user)) - if (IsSetHost(user)) - modes[modelen++] = 'h'; - if (IsFakeHost(user)) - modes[modelen++] = 'f'; - if (IsHiddenHost(user)) - modes[modelen++] = 'x'; - modes[modelen] = 0; - + irc_user_modes(user, modes, sizeof(modes)); /* we don't need to put the + in modes because it's in the format string. */ - putsock("%s " P10_NICK " %s %d %li %s %s +%s %s %s :%s", + putsock("%s " P10_NICK " %s %d " FMT_TIME_T " %s %s +%s %s %s :%s", user->uplink->numeric, user->nick, user->uplink->hops+1, user->timestamp, user->ident, user->hostname, modes, b64ip, user->numeric, user->info); } else { - putsock("%s " P10_NICK " %s %d %li %s %s %s %s :%s", + putsock("%s " P10_NICK " %s %d " FMT_TIME_T " %s %s %s %s :%s", user->uplink->numeric, user->nick, user->uplink->hops+1, user->timestamp, user->ident, user->hostname, b64ip, user->numeric, user->info); } } @@ -533,9 +611,9 @@ void irc_account(struct userNode *user, const char *stamp, time_t timestamp) { if(extended_accounts) - putsock("%s " P10_ACCOUNT " %s R %s %lu", self->numeric, user->numeric, stamp, timestamp); + putsock("%s " P10_ACCOUNT " %s R %s "FMT_TIME_T, self->numeric, user->numeric, stamp, timestamp); else - putsock("%s " P10_ACCOUNT " %s %s %lu", self->numeric, user->numeric, stamp, timestamp); + putsock("%s " P10_ACCOUNT " %s %s "FMT_TIME_T, self->numeric, user->numeric, stamp, timestamp); } void @@ -598,22 +676,71 @@ irc_wallchops(struct userNode *from, const char *to, const char *message) putsock("%s " P10_WALLCHOPS " %s :%s", from->numeric, to, message); } +void +irc_wallops(const char *format, ...) +{ + va_list arg_list; + char buffer[MAXLEN]; + va_start(arg_list, format); + vsnprintf(buffer, MAXLEN-2, format, arg_list); + buffer[MAXLEN-1] = 0; + putsock("%s " P10_WALLOPS " :%s", self->numeric, buffer); +} + +static int +deliver_to_dummy(struct userNode *source, struct userNode *dest, const char *message, int type) +{ + unsigned int num; + + if (!dest || !IsDummy(dest) || !IsLocal(dest)) + return 0; + num = dest->num_local; + switch (type) { + default: + if ((num < num_notice_funcs) && notice_funcs[num]) + notice_funcs[num](source, dest, message, 0); + break; + case 1: + if ((num < num_privmsg_funcs) && privmsg_funcs[num]) + privmsg_funcs[num](source, dest, message, 0); + break; + } + return 1; +} + void irc_notice(struct userNode *from, const char *to, const char *message) { - putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message); + if (to[0] == '#' || to[0] == '$' + || !deliver_to_dummy(from, GetUserN(to), message, 0)) + putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message); } void irc_notice_user(struct userNode *from, struct userNode *to, const char *message) { - putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message); + if (!deliver_to_dummy(from, to, message, 0)) + putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message); } void irc_privmsg(struct userNode *from, const char *to, const char *message) { - putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message); + if (to[0] == '#' || to[0] == '$' + || !deliver_to_dummy(from, GetUserN(to), message, 1)) + putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message); +} + +void +irc_privmsg_user(struct userNode *from, struct userNode *to, const char *message) +{ + putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to->numeric, message); +} + +void +irc_version_user(struct userNode *from, struct userNode *to) +{ + irc_privmsg_user(from, to, "\001VERSION\001"); } void @@ -626,6 +753,24 @@ void irc_eob_ack(void) { putsock("%s " P10_EOB_ACK, self->numeric); + + char *nick; + const char *str; + str = conf_get_data("services/opserv/nick", RECDB_QSTRING); + nick = strdup(str); + + if (nick && (DefConLevel < 5)) { + DefConProcess(GetUserH(nick)); + + if (DefConTimeOut > 0) + timeq_add(now + DefConTimeOut, defcon_timeout, NULL); + } +} + +void +irc_rpong(const char *from1, const char *from2, const char *pingtime, const char *clientinfo) +{ + putsock("%s " P10_RPONG " %s %s %s :%s", self->numeric, from1, from2, pingtime, clientinfo); } void @@ -645,14 +790,14 @@ irc_pong_asll(const char *who, const char *orig_ts) { char *delim; struct timeval orig; - struct timeval now; + struct timeval sys_now; int diff; orig.tv_sec = strtoul(orig_ts, &delim, 10); orig.tv_usec = (*delim == '.') ? strtoul(delim + 1, NULL, 10) : 0; - gettimeofday(&now, NULL); - diff = (now.tv_sec - orig.tv_sec) * 1000 + (now.tv_usec - orig.tv_usec) / 1000; - putsock("%s " P10_PONG " %s %s %d " FMT_TIME_T ".%06u", self->numeric, who, orig_ts, diff, now.tv_sec, (unsigned)now.tv_usec); + gettimeofday(&sys_now, NULL); + diff = (sys_now.tv_sec - orig.tv_sec) * 1000 + (sys_now.tv_usec - orig.tv_usec) / 1000; + putsock("%s " P10_PONG " %s %s %d %lu.%06lu", self->numeric, who, orig_ts, diff, (unsigned long)sys_now.tv_sec, (unsigned long)sys_now.tv_usec); } void @@ -676,14 +821,14 @@ irc_introduce(const char *passwd) void irc_gline(struct server *srv, struct gline *gline, int silent) { - putsock("%s " P10_GLINE " %s +%s %ld :%s<%s> %s", - self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, silent ? "AUTO " : "", gline->issuer, gline->reason); + putsock("%s " P10_GLINE " %s +%s " FMT_TIME_T " " FMT_TIME_T " :%s<%s> %s", + self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, now, silent ? "AUTO " : "", gline->issuer, gline->reason); } void irc_shun(struct server *srv, struct shun *shun) { - putsock("%s " P10_SHUN " %s +%s %ld :<%s> %s", + putsock("%s " P10_SHUN " %s +%s " FMT_TIME_T " :<%s> %s", self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, shun->issuer, shun->reason); } @@ -708,7 +853,7 @@ irc_unshun(const char *mask) putsock("%s " P10_SHUN " * -%s", self->numeric, mask); } -static void +void irc_burst(struct chanNode *chan) { char burst_line[512]; @@ -717,15 +862,19 @@ irc_burst(struct chanNode *chan) struct banNode *bn; struct exemptNode *en; long last_mode=-1; + unsigned int first_ban; + unsigned int first_exempt; unsigned int n; base_len = sprintf(burst_line, "%s " P10_BURST " %s " FMT_TIME_T " ", self->numeric, chan->name, chan->timestamp); len = irc_make_chanmode(chan, burst_line+base_len); pos = base_len + len; - if (len) + if (len > 0 && chan->members.used > 0) burst_line[pos++] = ' '; + if(chan->members.used < 1) + return; /* dont burst empty channels (created by discrims) */ /* dump the users */ for (n=0; nmembers.used; n++) { mn = chan->members.list[n]; @@ -735,6 +884,7 @@ irc_burst(struct chanNode *chan) pos = base_len; last_mode = -1; } + memcpy(burst_line+pos, mn->user->numeric, strlen(mn->user->numeric)); pos += strlen(mn->user->numeric); if (mn->modes && (mn->modes != last_mode)) { @@ -752,55 +902,53 @@ irc_burst(struct chanNode *chan) } if (chan->banlist.used) { /* dump the bans */ - if (pos+2+strlen(chan->banlist.list[0]->ban) > 505) { - burst_line[pos-1] = 0; - putsock("%s", burst_line); - pos = base_len; - } else { - burst_line[pos++] = ' '; - } + first_ban = 1; - burst_line[pos++] = ':'; - burst_line[pos++] = '%'; - base_len = pos; - for (n=0; nbanlist.used; n++) { + for (n=0; nbanlist.used; ) { + if (first_ban && (pos < 500)) { + burst_line[pos++] = ':'; + burst_line[pos++] = '%'; + } bn = chan->banlist.list[n]; len = strlen(bn->ban); - if (pos+len+1 > 510) { - burst_line[pos-1] = 0; /* -1 to back up over the space or comma */ + if (pos + 2 + len < 505) { + memcpy(burst_line + pos, bn->ban, len); + pos += len; + burst_line[pos++] = ' '; + first_ban = 0; + n++; + } else { + burst_line[pos-1] = 0; putsock("%s", burst_line); pos = base_len; + first_ban = 1; } - memcpy(burst_line+pos, bn->ban, len); - pos += len; - burst_line[pos++] = ' '; } } if (chan->exemptlist.used) { - /* dump the exempt */ - if (pos+2+strlen(chan->exemptlist.list[0]->exempt) > 505) { - burst_line[pos-1] = 0; - putsock("%s", burst_line); - pos = base_len; - } else { - burst_line[pos++] = ' '; - } - - burst_line[pos++] = ' '; - burst_line[pos++] = '~'; - burst_line[pos++] = ' '; - base_len = pos; - for (n=0; nexemptlist.used; n++) { + /* dump the exempts */ + first_exempt = 1; + + for (n=0; nexemptlist.used; ) { + if (first_exempt && (pos < 500)) { + burst_line[pos++] = ' '; + burst_line[pos++] = '~'; + burst_line[pos++] = ' '; + } en = chan->exemptlist.list[n]; len = strlen(en->exempt); - if (pos+len+1 > 510) { - burst_line[pos-1] = 0; /* -1 to back up over the space or comma */ + if (pos + 2 + len < 505) { + memcpy(burst_line + pos, en->exempt, len); + pos += len; + burst_line[pos++] = ' '; + first_exempt = 0; + n++; + } else { + burst_line[pos-1] = 0; putsock("%s", burst_line); pos = base_len; + first_exempt = 1; } - memcpy(burst_line+pos, en->exempt, len); - pos += len; - burst_line[pos++] = ' '; } } /* print the last line */ @@ -871,13 +1019,31 @@ void irc_join(struct userNode *who, struct chanNode *what) { if (what->members.used == 1) { - putsock("%s " P10_CREATE " %s %lu", + putsock("%s " P10_CREATE " %s "FMT_TIME_T, who->numeric, what->name, what->timestamp); } else { - putsock("%s " P10_JOIN " %s %lu", who->numeric, what->name, what->timestamp); + putsock("%s " P10_JOIN " %s "FMT_TIME_T, who->numeric, what->name, what->timestamp); } } +void +irc_svsjoin(struct userNode *from, struct userNode *who, struct chanNode *to) +{ + putsock("%s " P10_SVSJOIN " %s %s "FMT_TIME_T, from->uplink->numeric, who->numeric, to->name, now); +} + +void +irc_svspart(struct userNode *from, struct userNode *who, struct chanNode *to) +{ + putsock("%s " P10_SVSPART " %s %s", from->uplink->numeric, who->numeric, to->name); +} + +void +irc_svsquit(struct userNode *from, struct userNode *who, char const *reason) +{ + putsock("%s " P10_SVSQUIT " %s :%s", from->uplink->numeric, who->numeric, reason); +} + void irc_kick(struct userNode *who, struct userNode *target, struct chanNode *channel, const char *msg) { @@ -922,16 +1088,46 @@ void irc_topic(struct userNode *service, struct userNode *who, struct chanNode *what, const char *topic) { - int type = 4; - const char *str; - str = conf_get_data("server/type", RECDB_QSTRING); - if(str) - type = atoi(str); + int type = 4, host_in_topic = 0, hasident = 0; + const char *hstr, *tstr; + char *host, *hostmask; + char shost[MAXLEN]; + char sident[MAXLEN]; + + tstr = conf_get_data("server/type", RECDB_QSTRING); + hstr = conf_get_data("server/host_in_topic", RECDB_QSTRING); + if(tstr) + type = atoi(tstr); else type = 4;/* default to 040 style topics */ - if (type == 5) { - putsock("%s " P10_TOPIC " %s %s " FMT_TIME_T " " FMT_TIME_T " :%s", service->numeric, what->name, who->nick, what->timestamp, now, topic); + if (hstr) { + if (IsFakeHost(who)) + safestrncpy(shost, who->fakehost, sizeof(shost)); + else if (IsSetHost(who)) { + hostmask = strdup(who->sethost); + if ((host = (strrchr(hostmask, '@')))) { + hasident = 1; + *host++ = '\0'; + } else + host = hostmask; + + if (hasident) + safestrncpy(sident, hostmask, sizeof(shost)); + else + safestrncpy(sident, who->ident, sizeof(shost)); + + safestrncpy(shost, host, sizeof(shost)); + } else + safestrncpy(shost, who->hostname, sizeof(shost)); + + host_in_topic = atoi(hstr); + } + + if (type >= 5) { + putsock("%s " P10_TOPIC " %s %s%s%s%s%s " FMT_TIME_T " " FMT_TIME_T " :%s", service->numeric, what->name, + who->nick, host_in_topic ? "!" : "", host_in_topic ? (IsSetHost(who) ? sident : who->ident) : "", + host_in_topic ? "@" : "", host_in_topic ? shost : "", what->timestamp, now, topic); } else { who = service; putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic); @@ -955,6 +1151,57 @@ irc_numeric(struct userNode *user, unsigned int num, const char *format, ...) putsock(":%s %03d %s %s", self->name, num, user->nick, buffer); } +void +irc_mark(struct userNode *user, char *mark) +{ + char *host = user->hostname; + + /* TODO: Allow mark overwrite. If they are marked, and their fakehost is oldmark.hostname, update it to newmark.hostname so mark can be called multiple times. Probably requires ircd modification also */ + if(user->mark) + return; + + /* if the mark will put us over the host length, clip some off the left hand side + * to make room... + */ + if(strlen(host) + 1 + strlen(mark) > HOSTLEN) + host += 1 + ( (strlen(host) + 1 + strlen(mark)) - HOSTLEN ); + putsock("%s " CMD_MARK " %s DNSBL +m %s.%s", self->numeric, user->nick, mark, host); + putsock("%s " CMD_MARK " %s DNSBL_DATA %s", self->numeric, user->nick, mark); + + /* Save it in the user */ + user->mark = strdup(mark); + + /* If they are not otherwise marked, mark their host with fakehost */ + if(!IsFakeHost(user) && !IsSetHost(user) && !(IsHiddenHost(user) && user->handle_info) ) + { + struct modeNode *mn = NULL; + char fakehost[HOSTLEN]; + unsigned int count = 0; + unsigned int n = 0; + + putsock("%s " CMD_FAKEHOST " %s %s.%s", self->numeric, user->numeric, mark, host); + putsock("%s " CMD_MODE " %s +x", self->numeric, user->nick); + + snprintf(fakehost, sizeof(fakehost), "%s.%s", mark, host); + safestrncpy(user->fakehost, fakehost, sizeof(user->fakehost)); + + for (n=count=0; nchannels.used; n++) { + mn = user->channels.list[n]; + if (strlen(mn->channel->name) >= 1) /* Sanity */ + check_bans(user, mn->channel->name); + } + } +} + +void irc_sno(unsigned int mask, char const* format, ...) { + va_list arg_list; + char buffer[MAXLEN]; + va_start(arg_list, format); + vsnprintf(buffer, MAXLEN-2, format, arg_list); + buffer[MAXLEN-1] = 0; + putsock("%s " CMD_SNO " %d :%s", self->numeric, mask, buffer); +} + static void send_burst(void); static void @@ -979,6 +1226,8 @@ static CMD_FUNC(cmd_whois) { struct userNode *from; struct userNode *who; + char buf[MAXLEN]; + unsigned int i, mlen, len; if (argc < 3) return 0; @@ -986,21 +1235,75 @@ static CMD_FUNC(cmd_whois) log_module(MAIN_LOG, LOG_ERROR, "Could not find WHOIS origin user %s", origin); return 0; } - if(!(who = GetUserH(argv[2]))) { + if (!(who = GetUserH(argv[2]))) { irc_numeric(from, ERR_NOSUCHNICK, "%s@%s :No such nick", argv[2], self->name); return 1; } - if (IsHiddenHost(who) && !IsOper(from)) { - /* Just stay quiet. */ - return 1; + + if (IsFakeHost(who) && IsHiddenHost(who)) + irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->fakehost, who->info); + else if (IsHiddenHost(who) && who->handle_info && hidden_host_suffix) + irc_numeric(from, RPL_WHOISUSER, "%s %s %s.%s * :%s", who->nick, who->ident, who->handle_info->handle, hidden_host_suffix, who->info); + else + irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info); + + if (IsService(who) || (from == who)) { + struct modeNode *mn; + mlen = strlen(self->name) + strlen(from->nick) + 12 + strlen(who->nick); + len = 0; + *buf = '\0'; + for (i = who->channels.used; i > 0; ) + { + mn = who->channels.list[--i]; + + if (!IsOper(from) && (mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from)) + continue; + + if (len + strlen(mn->channel->name) + mlen > MAXLEN - 5) + { + irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf); + *buf = '\0'; + len = 0; + } + + if (IsDeaf(who)) + *(buf + len++) = '-'; + if ((mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from)) + *(buf + len++) = '*'; + if (mn->modes & MODE_CHANOP) + *(buf + len++) = '@'; + else if (mn->modes & MODE_HALFOP) + *(buf + len++) = '%'; + else if (mn->modes & MODE_VOICE) + *(buf + len++) = '+'; + + if (len) + *(buf + len) = '\0'; + strcpy(buf + len, mn->channel->name); + len += strlen(mn->channel->name); + strcat(buf + len, " "); + len++; + } + if (buf[0] != '\0') + irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf); } - irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info); - if (his_servername && his_servercomment) + + if (his_servername && his_servercomment && !IsOper(from) && from != who) irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment); else irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description); + + if (IsAway(who)) + irc_numeric(from, RPL_AWAY, "%s :Away", who->nick); if (IsOper(who)) - irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick); + irc_numeric(from, RPL_WHOISOPERATOR, "%s :%s", who->nick, IsLocal(who) ? "is a megalomaniacal power hungry tyrant" : "is an IRC Operator"); + if (who->handle_info) + irc_numeric(from, RPL_WHOISACCOUNT, "%s %s :is logged in as", who->nick, who->handle_info->handle); + if (IsHiddenHost(who) && who->handle_info && (IsOper(from) || from == who)) + irc_numeric(from, RPL_WHOISACTUALLY, "%s %s@%s %s :Actual user@host, Actual IP", who->nick, who->ident, who->hostname, irc_ntoa(&who->ip)); + if (IsLocal(who) && !IsService(who) && (IsOper(from) || from == who)) + irc_numeric(from, RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time", who->nick, now - who->idle_since, who->timestamp); + irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick); return 1; } @@ -1047,7 +1350,8 @@ static CMD_FUNC(cmd_server) * Alternately, we are same age, but we accept their time * since we are linking to them. */ self->boot = srv->boot; - ioset_set_time(srv->link); + ioset_set_time(srv->link_time +); } } if (srv == self->uplink) { @@ -1057,11 +1361,11 @@ static CMD_FUNC(cmd_server) return 1; } + static CMD_FUNC(cmd_eob) { struct server *sender; dict_iterator_t it; - unsigned int ii; if (!(sender = GetServerH(origin))) return 0; @@ -1073,11 +1377,21 @@ static CMD_FUNC(cmd_eob) unbursted_channels = NULL; irc_eob(); irc_eob_ack(); + + /* now that we know who our uplink is, + * we can center the routing map and activate auto-routing. + */ + //activate_routing(NULL, NULL, NULL); + routing_init(); } sender->self_burst = 0; recalc_bursts(sender); - for (ii=0; iiuplink != self) + routing_handle_connect(sender->name, sender->uplink->name); return 1; } @@ -1093,6 +1407,19 @@ static CMD_FUNC(cmd_eob_ack) return 1; } +static CMD_FUNC(cmd_rping) +{ + struct server *dest; + + if (!(dest = GetServerN(argv[1]))) + return 1; /* if its a jupe or something, return 1 so its silently ignored */ + + if (dest == self) + irc_rpong(argv[2], argv[3], argv[4], argv[5]); + + return 1; +} + static CMD_FUNC(cmd_ping) { struct server *srv; @@ -1177,6 +1504,22 @@ static CMD_FUNC(cmd_join) return 1; } +static CMD_FUNC(cmd_svsjoin) +{ + struct create_desc cd; + + if (!(cd.user = GetUserH(argv[1]))) + return 0; + if (argc < 3) + return 0; + else if (argc < 4) + cd.when = now; + else + cd.when = atoi(argv[3]); + parse_foreach(argv[2], join_helper, create_helper, NULL, NULL, &cd); + return 1; +} + static CMD_FUNC(cmd_pong) { if (argc < 3) @@ -1200,6 +1543,7 @@ static CMD_FUNC(cmd_nick) NickChange(user, argv[1], 1); } else { struct server *serv; + struct userNode *nuser; char modes[MAXLEN]; /* new nick */ if (argc < 9) @@ -1209,7 +1553,7 @@ static CMD_FUNC(cmd_nick) unsplit_string(argv+6, argc-9, modes); else strcpy(modes, "+"); - AddUser(serv, argv[1], argv[4], argv[5], modes, argv[argc-2], argv[argc-1], atoi(argv[3]), argv[argc-3]); + nuser = AddUser(serv, argv[1], argv[4], argv[5], modes, argv[argc-2], argv[argc-1], atoi(argv[3]), argv[argc-3]); } return 1; } @@ -1233,11 +1577,40 @@ static CMD_FUNC(cmd_account) if(!strcmp(argv[2],"C")) { - if((hi = loc_auth(argv[4], argv[5]))) + if((hi = loc_auth(NULL, argv[4], argv[5], NULL))) { /* Return a AC A */ - putsock("%s " P10_ACCOUNT " %s A %s %lu", self->numeric, server->numeric , argv[3], hi->registered); + putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered); + log_module(MAIN_LOG, LOG_DEBUG, "loc_auth: %s\n", user->nick); + } + else + { + /* Return a AC D */ + putsock("%s " P10_ACCOUNT " %s D %s", self->numeric, server->numeric , argv[3]); + } + return 1; + } + else if(!strcmp(argv[2],"H")) /* New enhanced (host) version of C */ + { + if((hi = loc_auth(NULL, argv[5], argv[6], argv[4] ))) + { + /* Return a AC A */ + putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered); + } + else + { + /* Return a AC D */ + putsock("%s " P10_ACCOUNT " %s D %s", self->numeric, server->numeric , argv[3]); + } + return 1; + } + else if(!strcmp(argv[2],"S")) + { + if((hi = loc_auth(argv[5], argv[6], argv[7], argv[4]))) + { + /* Return a AC A */ + putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered); } else { @@ -1265,6 +1638,150 @@ static CMD_FUNC(cmd_fakehost) return 1; } +static struct { + char *name; + unsigned int priv; +} privtab[] = { +#define P(priv) { #priv, PRIV_ ## priv } + P(CHAN_LIMIT), P(MODE_LCHAN), P(WALK_LCHAN), P(DEOP_LCHAN), + P(SHOW_INVIS), P(SHOW_ALL_INVIS), P(UNLIMIT_QUERY), P(KILL), + P(LOCAL_KILL), P(REHASH), P(RESTART), P(DIE), + P(GLINE), P(LOCAL_GLINE), P(JUPE), P(LOCAL_JUPE), + P(OPMODE), P(LOCAL_OPMODE), P(SET), P(WHOX), + P(BADCHAN), P(LOCAL_BADCHAN), P(SEE_CHAN), P(PROPAGATE), + P(DISPLAY), P(SEE_OPERS), P(WIDE_GLINE), P(FORCE_OPMODE), + P(FORCE_LOCAL_OPMODE), P(REMOTEREHASH), P(CHECK), P(SEE_SECRET_CHAN), + P(SHUN), P(LOCAL_SHUN), P(WIDE_SHUN), P(ZLINE), + P(LOCAL_ZLINE), P(WIDE_ZLINE), P(LIST_CHAN), P(WHOIS_NOTICE), + P(HIDE_IDLE), P(XTRAOP), P(HIDE_CHANNELS), P(DISPLAY_MODE), + P(FREEFORM), P(REMOVE), P(SPAMFILTER), +#undef P + { 0, 0 } +}; + +char *client_report_privs(struct userNode *client) +{ + int i; + + privbuf[0] = '\0'; + for (i = 0; privtab[i].name; i++) { + if (HasPriv(client, privtab[i].priv)) { + strcat(privbuf, privtab[i].name); + strcat(privbuf, " "); + } + } + + privbuf[strlen(privbuf)] = 0; + + return privbuf; +} + +int clear_privs(struct userNode *who) { + int i = 0; + assert(0 != who); + + for (i = 0; privtab[i].name; i++) + RevokePriv(who, privtab[i].priv); + + return 0; +} + +int client_modify_priv_by_name(struct userNode *who, char *priv, int what) { + int i = 0; + assert(0 != priv); + assert(0 != who); + + for (i = 0; privtab[i].name; i++) { + if (0 == strcmp(privtab[i].name, priv)) { + if (what == PRIV_ADD) + GrantPriv(who, privtab[i].priv); + else if (what == PRIV_DEL) { + RevokePriv(who, privtab[i].priv); + } + } + } + return 0; +} + +int check_priv(char *priv) +{ + int i; + + for (i = 0; privtab[i].name; i++) { + if (0 == strcmp(privtab[i].name, priv)) { + return 1; + } + } + return 0; +} + +void +irc_privs(struct userNode *target, char *flag, int add) +{ + client_modify_priv_by_name(target, flag, add); + putsock("%s " P10_PRIVS " %s %s%s", self->numeric, target->numeric, (add == PRIV_ADD) ? "+" : "-", flag); +} + +void +irc_raw_privs(struct userNode *target, const char *privs) +{ + putsock("%s " P10_PRIVS " %s %s", self->numeric, target->numeric, privs); +} + +static CMD_FUNC(cmd_privs) +{ + char *tstr = NULL; + char buf[512] = ""; + char *p = 0; + char *tmp; + + int what = PRIV_ADD; + int type = 0; + + unsigned int i; + + struct server *sender; + struct userNode *user; + + + tstr = conf_get_data("server/type", RECDB_QSTRING); + if(tstr) + type = atoi(tstr); + + + if (!(sender = GetServerH(origin))) { /* from oper */ + return 1; /* ignore as no services have privs set */ + } else { /* from server */ + if (type < 5) + return 1; /* silently ignore */ + + user = argc > 1 ? GetUserN(argv[1]) : NULL; + + if (!user) + return 0; + + for (i=1; i user->timestamp+5) + clear_privs(user); + break; + } else + client_modify_priv_by_name(user, tmp, what); + } + } + } + return 1; +} + static CMD_FUNC(cmd_burst) { extern int rel_age; @@ -1272,6 +1789,7 @@ static CMD_FUNC(cmd_burst) static char exemptlist[MAXLEN], banlist[MAXLEN]; unsigned int next = 3, res = 1; int ctype = 0, echeck = 0, bcheck = 0; + struct chanData *cData; struct chanNode *cNode; struct userNode *un; struct modeNode *mNode; @@ -1297,6 +1815,8 @@ static CMD_FUNC(cmd_burst) if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A') || (*pos == 'U')) n_modes++; + if (next + n_modes > argc) + n_modes = argc - next; unsplit_string(argv+next, n_modes, modes); next += n_modes; break; @@ -1355,6 +1875,15 @@ static CMD_FUNC(cmd_burst) irc_burst(cNode); } cNode = AddChannel(argv[1], in_timestamp, modes, banlist, exemptlist); + cData = cNode->channel_info; + + if (!cData) { + if (cNode->modes & MODE_REGISTERED) { + irc_join(opserv, cNode); + irc_mode(opserv, cNode, "-z"); + irc_part(opserv, cNode, ""); + } + } /* Burst channel members in now. */ for (user = members, sep = *members, mode = 0; sep; user = end) { @@ -1398,6 +1927,73 @@ static CMD_FUNC(cmd_burst) return res; } +/* TODO: + * This is a stub that doesn't actually do anything. It should be completed + * so that bans on *!*@markname.* match users as it does in nefarious + */ +static CMD_FUNC(cmd_mark) +{ + struct userNode *target; + /* + * log_module(MAIN_LOG, LOG_ERROR, "DEBUG: mark, user %s, type %s, arg %s", argv[1], argv[2], argv[3]); + */ + + if(argc < 4) + return 0; + if(!strcasecmp(argv[2], "DNSBL")) { + /* DNSBL */ + return 1; + } + else if(!strcasecmp(argv[2], "DNSBL_DATA")) { + /* DNSBL_DATA name */ + target = GetUserH(argv[1]); + if(!target) { + log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose dnsbl mark is changing.", argv[1]); + return 0; + } + target->mark = strdup(argv[3]); + return 1; + + } + else if(!strcasecmp(argv[2], "CVERSION")) { + /* CTCP VERSION mark */ + target = GetUserH(argv[1]); + if(!target) { + log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose version mark is changing.", argv[1]); + return 0; + } + + char *version = unsplit_string(argv + 3, argc - 3, NULL); + if(!version) + version = ""; + + target->version_reply = strdup(version); + + if(match_ircglob(version, "WebTV;*")) + target->no_notice = true; /* webbies cant see notices */ + + return 1; + } + else if(!strcasecmp(argv[2], "SSLCLIFP")) { + /* SSL fingerprint mark */ + target = GetUserH(argv[1]); + if(!target) { + log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose SSL fingerprint mark is changing.", argv[1]); + return 0; + } + + char *sslfp = unsplit_string(argv + 3, argc - 3, NULL); + if(!sslfp) + sslfp = ""; + + target->sslfp = strdup(sslfp); + + return 1; + } + /* unknown type of mark */ + return 1; +} + static CMD_FUNC(cmd_mode) { struct chanNode *cn; @@ -1443,6 +2039,22 @@ static CMD_FUNC(cmd_mode) cn->timestamp = atoi(argv[argc-1]); } + if (checkDefCon(DEFCON_NO_MODE_CHANGE) && !IsOper(un)) { + const char *str; + str = conf_get_data("services/opserv/nick", RECDB_QSTRING); + if (str) { + char modes[MODELEN]; + struct userNode *opserv = GetUserH(str); + + send_message_type(4, un, opserv, "Channel modes cannot be changed due to DefCon level %d in effect, please try again soon", DefConLevel); + irc_make_chanmode(cn, modes); + irc_mode(opserv, cn, modes); + irc_mode(opserv, cn, DefConChanModes); + } + return 1; + } + + return mod_chanmode(un, cn, argv+2, argc-2, MCP_ALLOW_OVB|MCP_FROM_SERVER|(un ? MC_NOTIFY : 0)); } @@ -1567,17 +2179,29 @@ static CMD_FUNC(cmd_num_topic) static CMD_FUNC(cmd_num_gline) { - if (argc < 6) - return 0; - gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0, 0); + if (argc < 7) { + if (argc < 6) + return 0; + else + gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0, 0); + } else { + if (!strcmp(argv[5], "+")) + gline_add(origin, argv[3], atoi(argv[4])-now, argv[6], now, 0, 0); + } return 1; } static CMD_FUNC(cmd_num_shun) { - if (argc < 6) - return 0; - shun_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0); + if (argc < 7) { + if (argc < 6) + return 0; + else + shun_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0); + } else { + if (!strcmp(argv[5], "+")) + shun_add(origin, argv[3], atoi(argv[4])-now, argv[6], now, 0); + } return 1; } @@ -1619,16 +2243,16 @@ static CMD_FUNC(cmd_kill) return 1; } -static CMD_FUNC(cmd_part) +static CMD_FUNC(cmd_svspart) { struct userNode *user; - if (argc < 2) + if (argc < 3) return 0; - user = GetUserH(origin); + user = GetUserN(argv[1]); if (!user) return 0; - parse_foreach(argv[1], part_helper, NULL, NULL, NULL, user); + parse_foreach(argv[2], part_helper, NULL, NULL, NULL, user); return 1; } @@ -1636,6 +2260,7 @@ static CMD_FUNC(cmd_silence) { struct userNode *user; char *mask; + char *new_mask; unsigned int i; if (argc < 2) @@ -1655,7 +2280,7 @@ static CMD_FUNC(cmd_silence) if (!user->handle_info) return 1; - mask = strdup(argv[2]); + mask = argv[2]; if (*mask == '-') { for (i=0; ihandle_info->ignores->used; i++) { @@ -1668,9 +2293,9 @@ static CMD_FUNC(cmd_silence) return 1; /* Already on the users NickServ ignore list, safely ignore */ } - string_list_append(user->handle_info->ignores, mask+1); + new_mask = strdup(mask+1); + string_list_append(user->handle_info->ignores, new_mask); } - return 1; } @@ -1685,6 +2310,7 @@ static CMD_FUNC(cmd_kick) static CMD_FUNC(cmd_squit) { struct server *server; + char *uplink; if (argc < 4) return 0; @@ -1699,35 +2325,86 @@ static CMD_FUNC(cmd_squit) return 1; } + uplink = strdup(server->uplink->name); DelServer(server, 0, argv[3]); + /* if its a pingout and pingout connecting is enabled + or its a read error and readerror connecting is enabled + or were doing a "N" and i need to connect that server somewhere */ + routing_handle_squit(argv[1], uplink, argv[3]); + free(uplink); return 1; } static CMD_FUNC(cmd_privmsg) { struct privmsg_desc pd; - if (argc != 3) + if (argc < 3) return 0; pd.user = GetUserH(origin); if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user))) return 1; + + if (checkDefCon(DEFCON_OPER_ONLY) && !IsOper(pd.user)) { + const char *str; + str = conf_get_data("services/opserv/nick", RECDB_QSTRING); + if (str) + send_message_type(4, pd.user, GetUserH(str), "Services are currently not available, please try again soon"); + return 1; + } + + if (checkDefCon(DEFCON_SILENT_OPER_ONLY) && !IsOper(pd.user)) + return 1; /* Silently Ignore */ + pd.is_notice = 0; - pd.text = argv[2]; + pd.text = argv[argc - 1]; parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd); + return 1; } static CMD_FUNC(cmd_notice) { struct privmsg_desc pd; + struct server *srv; + int nuser = 0; + if (argc != 3) return 0; + pd.user = GetUserH(origin); - if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user))) - return 1; - pd.is_notice = 1; - pd.text = argv[2]; - parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd); + if(!pd.user) + nuser = 1; + if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user))) { + } + else { + pd.is_notice = 1; + pd.text = argv[2]; + parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd); + } + + srv = GetServerH(origin); + if(srv) { + char *sargv[MAXNUMPARAMS]; + int sargc; + + sargc = split_line(argv[2], true, MAXNUMPARAMS, sargv); + + if(!strcasecmp(sargv[0], "Connect:")) { + /* :Connect: Host shoe.loxxin.net not listed in ircd.conf */ + if(!strcasecmp(sargv[3], "not") && !strcasecmp(sargv[4], "listed")) { + routing_handle_connect_failure(srv, sargv[2], unsplit_string(sargv+3, sargc-3, NULL)); + } + } + else if(!strcasecmp(sargv[0], "Link")) { + /* :Link with mephisto.etheria.cx cancelled: Server mephisto.etheria.cx[216.46.33.71] + * + * :Link with laptop.afternet.org cancelled: Connection refused + */ + if(!strcasecmp(sargv[3], "cancelled:")) { + routing_handle_connect_failure(srv, sargv[2], unsplit_string(sargv+4, sargc-4, NULL)); + } + } + } return 1; } @@ -1761,6 +2438,34 @@ static CMD_FUNC(cmd_gline) return 0; } +static CMD_FUNC(cmd_sgline) +{ + struct server *sender; + + if (argc < 4) + return 0; + + if (!(sender = GetServerH(origin))) + return 0; + + gline_add(origin, argv[1], strtoul(argv[2], NULL, 0), argv[argc-1], now, 1, 0); + return 1; +} + +static CMD_FUNC(cmd_sshun) +{ + struct server *sender; + + if (argc < 4) + return 0; + + if (!(sender = GetServerH(origin))) + return 0; + + shun_add(origin, argv[1], strtoul(argv[2], NULL, 0), argv[argc-1], now, 1); + return 1; +} + static CMD_FUNC(cmd_shun) { if (argc < 3) @@ -1789,9 +2494,6 @@ static CMD_FUNC(cmd_svsnick) return 1; } -static oper_func_t *of_list; -static unsigned int of_size = 0, of_used = 0; - void free_user(struct userNode *user) { @@ -1800,12 +2502,15 @@ free_user(struct userNode *user) } static void -parse_cleanup(void) +parse_cleanup(UNUSED_ARG(void *extra)) { unsigned int nn; free(of_list); + free(of_list_extra); free(privmsg_funcs); + num_privmsg_funcs = 0; free(notice_funcs); + num_notice_funcs = 0; free(mcf_list); dict_delete(irc_func_dict); for (nn=0; nnname); } @@ -1855,11 +2562,6 @@ init_parse(void) else inttobase64(numer, (numnick << 18) + (usermask & 0x3ffff), 5); - str = conf_get_data("server/his_servername", RECDB_QSTRING); - his_servername = str ? strdup(str) : NULL; - str = conf_get_data("server/his_servercomment", RECDB_QSTRING); - his_servercomment = str ? strdup(str) : NULL; - str = conf_get_data("server/hostname", RECDB_QSTRING); desc = conf_get_data("server/description", RECDB_QSTRING); if (!str || !desc) { @@ -1880,6 +2582,8 @@ init_parse(void) dict_insert(irc_func_dict, TOK_EOB_ACK, cmd_eob_ack); dict_insert(irc_func_dict, CMD_MODE, cmd_mode); dict_insert(irc_func_dict, TOK_MODE, cmd_mode); + dict_insert(irc_func_dict, CMD_MARK, cmd_mark); + dict_insert(irc_func_dict, TOK_MARK, cmd_mark); dict_insert(irc_func_dict, CMD_NICK, cmd_nick); dict_insert(irc_func_dict, TOK_NICK, cmd_nick); dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account); @@ -1920,16 +2624,24 @@ init_parse(void) dict_insert(irc_func_dict, TOK_NOTICE, cmd_notice); dict_insert(irc_func_dict, CMD_STATS, cmd_stats); dict_insert(irc_func_dict, TOK_STATS, cmd_stats); + dict_insert(irc_func_dict, CMD_SVSJOIN, cmd_svsjoin); + dict_insert(irc_func_dict, TOK_SVSJOIN, cmd_svsjoin); dict_insert(irc_func_dict, CMD_SVSNICK, cmd_svsnick); dict_insert(irc_func_dict, TOK_SVSNICK, cmd_svsnick); + dict_insert(irc_func_dict, CMD_SVSPART, cmd_svspart); + dict_insert(irc_func_dict, TOK_SVSPART, cmd_svspart); dict_insert(irc_func_dict, CMD_SWHOIS, cmd_dummy); dict_insert(irc_func_dict, TOK_SWHOIS, cmd_dummy); dict_insert(irc_func_dict, CMD_WHOIS, cmd_whois); dict_insert(irc_func_dict, TOK_WHOIS, cmd_whois); dict_insert(irc_func_dict, CMD_GLINE, cmd_gline); dict_insert(irc_func_dict, TOK_GLINE, cmd_gline); + dict_insert(irc_func_dict, CMD_SGLINE, cmd_sgline); + dict_insert(irc_func_dict, TOK_SGLINE, cmd_sgline); dict_insert(irc_func_dict, CMD_SHUN, cmd_shun); dict_insert(irc_func_dict, TOK_SHUN, cmd_shun); + dict_insert(irc_func_dict, CMD_SSHUN, cmd_sshun); + dict_insert(irc_func_dict, TOK_SSHUN, cmd_sshun); dict_insert(irc_func_dict, CMD_OPMODE, cmd_opmode); dict_insert(irc_func_dict, TOK_OPMODE, cmd_opmode); dict_insert(irc_func_dict, CMD_CLEARMODE, cmd_clearmode); @@ -1938,6 +2650,15 @@ init_parse(void) dict_insert(irc_func_dict, TOK_VERSION, cmd_version); dict_insert(irc_func_dict, CMD_ADMIN, cmd_admin); dict_insert(irc_func_dict, TOK_ADMIN, cmd_admin); + dict_insert(irc_func_dict, CMD_SMO, cmd_dummy); + dict_insert(irc_func_dict, TOK_SMO, cmd_dummy); + dict_insert(irc_func_dict, CMD_SNO, cmd_dummy); + dict_insert(irc_func_dict, TOK_SNO, cmd_dummy); + + dict_insert(irc_func_dict, CMD_RPING, cmd_rping); + dict_insert(irc_func_dict, TOK_RPING, cmd_rping); + dict_insert(irc_func_dict, CMD_RPONG, cmd_dummy); + dict_insert(irc_func_dict, TOK_RPONG, cmd_dummy); /* In P10, DESTRUCT doesn't do anything except be broadcast to servers. * Apparently to obliterate channels from any servers that think they @@ -1966,9 +2687,14 @@ init_parse(void) dict_insert(irc_func_dict, TOK_WALLUSERS, cmd_dummy); /* Ignore dnsbl exemptions */ dict_insert(irc_func_dict, TOK_EXEMPT, cmd_dummy); - dict_insert(irc_func_dict, TOK_MARK, cmd_dummy); - /* Ignore privs */ - dict_insert(irc_func_dict, TOK_PRIVS, cmd_dummy); + dict_insert(irc_func_dict, CMD_PRIVS, cmd_privs); + dict_insert(irc_func_dict, TOK_PRIVS, cmd_privs); + /* ignore ALIST for now */ + dict_insert(irc_func_dict, TOK_ALIST, cmd_dummy); + dict_insert(irc_func_dict, CMD_ALIST, cmd_dummy); + /* ignore SPAMFILTER */ + dict_insert(irc_func_dict, TOK_SPAMFILTER, cmd_dummy); + dict_insert(irc_func_dict, CMD_SPAMFILTER, cmd_dummy); /* Ignore remote luser */ dict_insert(irc_func_dict, TOK_LUSERS, cmd_dummy); /* We have reliable clock! Always! Wraaa! */ @@ -1978,6 +2704,7 @@ init_parse(void) /* ignore /trace and /motd commands targetted at us */ dict_insert(irc_func_dict, TOK_TRACE, cmd_dummy); dict_insert(irc_func_dict, TOK_MOTD, cmd_dummy); + dict_insert(irc_func_dict, TOK_UPING, cmd_dummy); /* handle topics */ dict_insert(irc_func_dict, "331", cmd_num_topic); @@ -1987,6 +2714,7 @@ init_parse(void) dict_insert(irc_func_dict, "432", cmd_error_nick); /* Erroneus [sic] nickname */ /* ban list resetting */ /* "stats g" responses */ + dict_insert(irc_func_dict, "230", cmd_dummy); /* ignore stats headers */ dict_insert(irc_func_dict, "247", cmd_num_gline); dict_insert(irc_func_dict, "542", cmd_num_shun); dict_insert(irc_func_dict, "219", cmd_dummy); /* "End of /STATS report" */ @@ -2010,8 +2738,9 @@ init_parse(void) memset(notice_funcs, 0, sizeof(privmsg_func_t)*num_notice_funcs); userList_init(&dead_users); - reg_del_channel_func(remove_unbursted_channel); - reg_exit_func(parse_cleanup); + reg_del_channel_func(remove_unbursted_channel, NULL); + reg_exit_func(parse_cleanup, NULL); + // reg_notice_func(opserv, check_ctcp); } int @@ -2138,7 +2867,7 @@ make_numeric(struct server *svr, int local_num, char *outbuf) } struct server * -AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t link, const char *numeric, const char *description) +AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t link_time, const char *numeric, const char *description) { struct server* sNode; int slen, mlen; @@ -2170,7 +2899,7 @@ AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t sNode->num_mask = base64toint(numeric+slen, mlen); sNode->hops = hops; sNode->boot = boot; - sNode->link = link; + sNode->link_time = link_time; strncpy(sNode->numeric, numeric, slen); safestrncpy(sNode->description, description, sizeof(sNode->description)); sNode->users = calloc(sNode->num_mask+1, sizeof(*sNode->users)); @@ -2221,13 +2950,16 @@ void DelServer(struct server* serv, int announce, const char *message) } struct userNode * -AddService(const char *nick, const char *modes, const char *desc, const char *hostname) +AddLocalUser(const char *nick, const char *ident, const char *hostname, const char *desc, const char *modes) { char numeric[COMBO_NUMERIC_LEN+1]; int local_num = get_local_numeric(); time_t timestamp = now; struct userNode *old_user = GetUserH(nick); + if (!modes) + modes = "+oik"; + if (old_user) { if (IsLocal(old_user)) return old_user; @@ -2240,8 +2972,7 @@ AddService(const char *nick, const char *modes, const char *desc, const char *ho if (!hostname) hostname = self->name; make_numeric(self, local_num, numeric); - /* TODO: Make these modes part of the conf file */ - return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA"); + return AddUser(self, nick, ident, hostname, modes, numeric, desc, now, "AAAAAA"); } struct userNode * @@ -2284,36 +3015,47 @@ static struct userNode* AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip) { struct userNode *oldUser, *uNode; - unsigned int n, ignore_user; + unsigned int ignore_user, dummy; + char *tstr; + int type; if ((strlen(numeric) < 3) || (strlen(numeric) > 5)) { - log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink, nick, numeric); + log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", (void*)uplink, nick, numeric); return NULL; } if (!uplink) { - log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s doesn't exist!", uplink, nick, numeric); + log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s doesn't exist!", (void*)uplink, nick, numeric); return NULL; } if (uplink != GetServerN(numeric)) { - log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s differs from nominal uplink %s.", uplink, nick, numeric, uplink->name); + log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s differs from nominal uplink %s.", (void*)uplink, nick, numeric, uplink->name); return NULL; } - if (!is_valid_nick(nick)) { - log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", uplink, nick); + dummy = modes && modes[0] == '*'; + if (dummy) { + ++modes; + } else if (!is_valid_nick(nick)) { + log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", (void*)uplink, nick); return NULL; } ignore_user = 0; if ((oldUser = GetUserH(nick))) { - if (IsLocal(oldUser) && (IsService(oldUser) || IsPersistent(oldUser))) { - /* The service should collide the new user off. */ + if (IsLocal(oldUser) + && (IsService(oldUser) || IsPersistent(oldUser))) { + /* The service should collide the new user off - but not + * if the new user is coming in during a burst. (During a + * burst, the bursting server will kill either our user -- + * triggering a ReintroduceUser() -- or its own.) + */ oldUser->timestamp = timestamp - 1; - irc_user(oldUser); - } - if (oldUser->timestamp > timestamp) { + ignore_user = 1; + if (!uplink->burst) + irc_user(oldUser); + } else if (oldUser->timestamp > timestamp) { /* "Old" user is really newer; remove them */ DelUser(oldUser, 0, 1, "Overruled by older nick"); } else { @@ -2333,13 +3075,20 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric)); irc_p10_pton(&uNode->ip, realip); - if (irc_in_addr_is_ipv4(uNode->ip)) { - make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip); - make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost); - } else if (irc_in_addr_is_ipv6(uNode->ip)) { - make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost); + tstr = conf_get_data("server/type", RECDB_QSTRING); + type = atoi(tstr); + if (type == 7) { + if (irc_in_addr_is_ipv4(uNode->ip)) { + make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip); + make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost); + } else if (irc_in_addr_is_ipv6(uNode->ip)) { + make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost); + } } + if (!uNode->crypthost && uNode->cryptip) + snprintf(uNode->crypthost, sizeof(uNode->crypthost), "%s", strdup(uNode->cryptip)); + uNode->idle_since = timestamp; uNode->timestamp = timestamp; modeList_init(&uNode->channels); uNode->uplink = uplink; @@ -2349,6 +3098,11 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * uNode->num_local = base64toint(numeric+strlen(uNode->uplink->numeric), 3) & uNode->uplink->num_mask; uNode->uplink->users[uNode->num_local] = uNode; mod_usermode(uNode, modes); + if (dummy) + uNode->modes |= FLAGS_DUMMY; + + set_geoip_info(uNode); + if (ignore_user) return uNode; @@ -2359,9 +3113,7 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * } if (IsLocal(uNode)) irc_user(uNode); - for (n=0; nloc == 1) && (uNode->handle_info)) send_func_list(uNode); @@ -2373,7 +3125,6 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * void DelUser(struct userNode* user, struct userNode *killer, int announce, const char *why) { - unsigned int n; verify(user); @@ -2385,12 +3136,11 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char /* remove user from all channels */ while (user->channels.used > 0) - DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, false, 0); + DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, NULL, 0); /* Call these in reverse order so ChanServ can update presence information before NickServ nukes the handle_info. */ - for (n = duf_used; n > 0; ) - duf_list[--n](user, killer, why); + call_del_user_funcs(user, killer, why); user->uplink->clients--; user->uplink->users[user->num_local] = NULL; @@ -2410,7 +3160,40 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char irc_kill(killer, user, why); } + if (IsLocal(user)) { + unsigned int num = user->num_local; + if (num < num_privmsg_funcs) + privmsg_funcs[num] = NULL; + if (num < num_notice_funcs) + notice_funcs[num] = NULL; + } + modeList_clean(&user->channels); + + /* Clean up version data */ + if(user->version_reply) { + free(user->version_reply); + user->version_reply = NULL; + } + + /* Clean up SSL fingerprint data */ + if(user->sslfp) { + free(user->sslfp); + user->sslfp = NULL; + } + + /* clean up mark */ + if(user->mark) { + free(user->mark); + user->mark = NULL; + } + + /* clean up geoip data if any */ + if(user->country_code) free(user->country_code); + if(user->city) free(user->city); + if(user->region) free(user->region); + if(user->postal_code) free(user->postal_code); + /* We don't free them, in case we try to privmsg them or something * (like when a stupid oper kills themself). We just put them onto * a list of clients that get freed after processing each line. @@ -2441,15 +3224,13 @@ void mod_usermode(struct userNode *user, const char *mode_change) { case '+': add = 1; break; case '-': add = 0; break; case 'o': - if (add) { - if(!IsOper(user)) { /* Dont re-oper an oper */ - userList_append(&curr_opers, user); - call_oper_funcs(user); - } - } else { - userList_remove(&curr_opers, user); - } do_user_mode(FLAGS_OPER); + if (!add) { + userList_remove(&curr_opers, user); + } else if (!userList_contains(&curr_opers, user)) { + userList_append(&curr_opers, user); + call_oper_funcs(user); + } break; case 'O': do_user_mode(FLAGS_LOCOP); break; case 'i': do_user_mode(FLAGS_INVISIBLE); @@ -2459,10 +3240,37 @@ void mod_usermode(struct userNode *user, const char *mode_change) { invis_clients--; break; case 'w': do_user_mode(FLAGS_WALLOP); break; - case 's': do_user_mode(FLAGS_SERVNOTICE); break; case 'd': do_user_mode(FLAGS_DEAF); break; case 'k': do_user_mode(FLAGS_SERVICE); break; case 'g': do_user_mode(FLAGS_GLOBAL); break; + case 'B': do_user_mode(FLAGS_BOT); break; + case 'n': do_user_mode(FLAGS_HIDECHANS); break; + case 'I': do_user_mode(FLAGS_HIDEIDLE); break; + case 'X': do_user_mode(FLAGS_XTRAOP); break; + case 'C': do_user_mode(FLAGS_CLOAKHOST); + if (*word) { + char cloakhost[MAXLEN]; + unsigned int ii; + for (ii=0; (*word != ' ') && (*word != '\0'); ) + cloakhost[ii++] = *word++; + cloakhost[ii] = 0; + while (*word == ' ') + word++; + safestrncpy(user->crypthost, cloakhost, sizeof(user->crypthost)); + } + break; + case 'c': do_user_mode(FLAGS_CLOAKIP); + if (*word) { + char cloakip[MAXLEN]; + unsigned int ii; + for (ii=0; (*word != ' ') && (*word != '\0'); ) + cloakip[ii++] = *word++; + cloakip[ii] = 0; + while (*word == ' ') + word++; + safestrncpy(user->cryptip, cloakip, sizeof(user->cryptip)); + } + break; // sethost - reed/apples // case 'h': do_user_mode(FLAGS_HELPER); break; // I check if there's an 'h' in the first part, and if there, @@ -2509,6 +3317,26 @@ void mod_usermode(struct userNode *user, const char *mode_change) { } } +static int +keyncpy(char output[], char input[], size_t output_size) +{ + size_t ii; + + if (input[0] == ':') + { + output[0] = '\0'; + return 1; + } + + for (ii = 0; (ii + 1 < output_size) && (input[ii] != '\0'); ++ii) + { + output[ii] = input[ii]; + } + + output[ii] = '\0'; + return 0; +} + struct mod_chanmode * mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags, short base_oplevel) { @@ -2547,14 +3375,15 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un case 'Q': do_chan_mode(MODE_NOQUITMSGS); break; case 'T': do_chan_mode(MODE_NOAMSG); break; case 'O': do_chan_mode(MODE_OPERSONLY); break; + case 'a': do_chan_mode(MODE_ADMINSONLY); break; case 'Z': do_chan_mode(MODE_SSLONLY); break; case 'L': do_chan_mode(MODE_HIDEMODE); break; case 'z': if (!(flags & MCP_REGISTERED)) { - do_chan_mode(MODE_REGISTERED); + do_chan_mode(MODE_REGISTERED); } else { - mod_chanmode_free(change); - return NULL; + mod_chanmode_free(change); + return NULL; } break; #undef do_chan_mode @@ -2571,10 +3400,10 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un break; case 'k': if (add) { - if (in_arg >= argc) + if ((in_arg >= argc) + || keyncpy(change->new_key, modes[in_arg++], sizeof(change->new_key))) goto error; change->modes_set |= MODE_KEY; - safestrncpy(change->new_key, modes[in_arg++], sizeof(change->new_key)); } else { change->modes_clear |= MODE_KEY; if (!(flags & MCP_KEY_FREE)) { @@ -2587,10 +3416,10 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un case 'U': if (add) { - if (in_arg >= argc) - goto error; - change->modes_set |= MODE_UPASS; - safestrncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass)); + if ((in_arg >= argc) + || keyncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass))) + goto error; + change->modes_set |= MODE_UPASS; } else { change->modes_clear |= MODE_UPASS; if (!(flags & MCP_UPASS_FREE)) { @@ -2602,10 +3431,9 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un break; case 'A': if (add) { - if (in_arg >= argc) - goto error; + if ((in_arg >= argc) + || keyncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass))) change->modes_set |= MODE_APASS; - safestrncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass)); } else { change->modes_clear |= MODE_APASS; if (!(flags & MCP_APASS_FREE)) { @@ -2789,7 +3617,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod mod_chanmode_append(&chbuf, 'k', channel->key); if (change->modes_clear & channel->modes & MODE_UPASS) mod_chanmode_append(&chbuf, 'U', channel->upass); - if (change->modes_clear * channel->modes & MODE_APASS) + if (change->modes_clear & channel->modes & MODE_APASS) mod_chanmode_append(&chbuf, 'A', channel->apass); } for (arg = 0; arg < change->argc; ++arg) { @@ -3000,61 +3828,62 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) static int clear_chanmode(struct chanNode *channel, const char *modes) { - unsigned int remove; + unsigned int cleared; - for (remove = 0; *modes; modes++) { + for (cleared = 0; *modes; modes++) { switch (*modes) { - case 'o': remove |= MODE_CHANOP; break; - case 'h': remove |= MODE_HALFOP; break; - case 'v': remove |= MODE_VOICE; break; - case 'p': remove |= MODE_PRIVATE; break; - case 's': remove |= MODE_SECRET; break; - case 'm': remove |= MODE_MODERATED; break; - case 't': remove |= MODE_TOPICLIMIT; break; - case 'i': remove |= MODE_INVITEONLY; break; - case 'n': remove |= MODE_NOPRIVMSGS; break; + case 'o': cleared |= MODE_CHANOP; break; + case 'h': cleared |= MODE_HALFOP; break; + case 'v': cleared |= MODE_VOICE; break; + case 'p': cleared |= MODE_PRIVATE; break; + case 's': cleared |= MODE_SECRET; break; + case 'm': cleared |= MODE_MODERATED; break; + case 't': cleared |= MODE_TOPICLIMIT; break; + case 'i': cleared |= MODE_INVITEONLY; break; + case 'n': cleared |= MODE_NOPRIVMSGS; break; case 'k': - remove |= MODE_KEY; + cleared |= MODE_KEY; channel->key[0] = '\0'; break; case 'A': - remove |= MODE_APASS; + cleared |= MODE_APASS; channel->apass[0] = '\0'; break; case 'U': - remove |= MODE_UPASS; + cleared |= MODE_UPASS; channel->upass[0] = '\0'; break; case 'l': - remove |= MODE_LIMIT; + cleared |= MODE_LIMIT; channel->limit = 0; break; - case 'b': remove |= MODE_BAN; break; - case 'e': remove |= MODE_EXEMPT; break; - case 'D': remove |= MODE_DELAYJOINS; break; - case 'r': remove |= MODE_REGONLY; break; - case 'c': remove |= MODE_NOCOLORS; break; - case 'C': remove |= MODE_NOCTCPS; break; - case 'S': remove |= MODE_STRIPCOLOR; break; - case 'M': remove |= MODE_MODUNREG; break; - case 'N': remove |= MODE_NONOTICE; break; - case 'Q': remove |= MODE_NOQUITMSGS; break; - case 'T': remove |= MODE_NOAMSG; break; - case 'O': remove |= MODE_OPERSONLY; break; - case 'z': remove |= MODE_REGISTERED; break; - case 'Z': remove |= MODE_SSLONLY; break; - case 'L': remove |= MODE_HIDEMODE; break; + case 'b': cleared |= MODE_BAN; break; + case 'e': cleared |= MODE_EXEMPT; break; + case 'D': cleared |= MODE_DELAYJOINS; break; + case 'r': cleared |= MODE_REGONLY; break; + case 'c': cleared |= MODE_NOCOLORS; break; + case 'C': cleared |= MODE_NOCTCPS; break; + case 'S': cleared |= MODE_STRIPCOLOR; break; + case 'M': cleared |= MODE_MODUNREG; break; + case 'N': cleared |= MODE_NONOTICE; break; + case 'Q': cleared |= MODE_NOQUITMSGS; break; + case 'T': cleared |= MODE_NOAMSG; break; + case 'O': cleared |= MODE_OPERSONLY; break; + case 'a': cleared |= MODE_ADMINSONLY; break; + case 'z': cleared |= MODE_REGISTERED; break; + case 'Z': cleared |= MODE_SSLONLY; break; + case 'L': cleared |= MODE_HIDEMODE; break; } } - if (!remove) + if (!cleared) return 1; /* Remove simple modes. */ - channel->modes &= ~remove; + channel->modes &= ~cleared; /* If removing bans, kill 'em all. */ - if ((remove & MODE_BAN) && channel->banlist.used) { + if ((cleared & MODE_BAN) && channel->banlist.used) { unsigned int i; for (i=0; ibanlist.used; i++) free(channel->banlist.list[i]); @@ -3062,16 +3891,16 @@ clear_chanmode(struct chanNode *channel, const char *modes) } /* If removing exempts, kill 'em all. */ - if ((remove & MODE_EXEMPT) && channel->exemptlist.used) { + if ((cleared & MODE_EXEMPT) && channel->exemptlist.used) { unsigned int i; for (i=0; iexemptlist.used; i++) free(channel->exemptlist.list[i]); channel->exemptlist.used = 0; } - /* Remove member modes. */ - if ((remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) && channel->members.used) { - int mask = ~(remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)); + /* Removed member modes. */ + if ((cleared & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) && channel->members.used) { + int mask = ~(cleared & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)); unsigned int i; for (i = 0; i < channel->members.used; i++) @@ -3086,9 +3915,10 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler) { unsigned int numeric = user->num_local; if (numeric >= num_privmsg_funcs) { - int newnum = numeric + 8; + int newnum = numeric + 8, ii; privmsg_funcs = realloc(privmsg_funcs, newnum*sizeof(privmsg_func_t)); - memset(privmsg_funcs+num_privmsg_funcs, 0, (newnum-num_privmsg_funcs)*sizeof(privmsg_func_t)); + for (ii = num_privmsg_funcs; ii < newnum; ++ii) + privmsg_funcs[ii] = NULL; num_privmsg_funcs = newnum; } if (privmsg_funcs[numeric]) @@ -3097,20 +3927,12 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler) } void -unreg_privmsg_func(struct userNode *user, privmsg_func_t handler) +unreg_privmsg_func(struct userNode *user) { - unsigned int x; - - if (!user || handler) - return; /* this really only works with users */ - - memset(privmsg_funcs+user->num_local, 0, sizeof(privmsg_func_t)); + if (!IsLocal(user) || user->num_local >= num_privmsg_funcs) + return; /* this really only works with users */ - for (x = user->num_local+1; x < num_privmsg_funcs; x++) - memmove(privmsg_funcs+x-1, privmsg_funcs+x, sizeof(privmsg_func_t)); - - privmsg_funcs = realloc(privmsg_funcs, num_privmsg_funcs*sizeof(privmsg_func_t)); - num_privmsg_funcs--; + privmsg_funcs[user->num_local] = NULL; } @@ -3119,9 +3941,10 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler) { unsigned int numeric = user->num_local; if (numeric >= num_notice_funcs) { - int newnum = numeric + 8; + int newnum = numeric + 8, ii; notice_funcs = realloc(notice_funcs, newnum*sizeof(privmsg_func_t)); - memset(notice_funcs+num_notice_funcs, 0, (newnum-num_notice_funcs)*sizeof(privmsg_func_t)); + for (ii = num_privmsg_funcs; ii < newnum; ++ii) + privmsg_funcs[ii] = NULL; num_notice_funcs = newnum; } if (notice_funcs[numeric]) @@ -3130,46 +3953,12 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler) } void -unreg_notice_func(struct userNode *user, privmsg_func_t handler) +unreg_notice_func(struct userNode *user) { - unsigned int x; - - if (!user || handler) - return; /* this really only works with users */ - - memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t)); + if (!IsLocal(user) || user->num_local >= num_privmsg_funcs) + return; /* this really only works with users */ - for (x = user->num_local+1; x < num_notice_funcs; x++) - memmove(notice_funcs+x-1, notice_funcs+x, sizeof(privmsg_func_t)); - - memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t)); - notice_funcs = realloc(notice_funcs, num_notice_funcs*sizeof(privmsg_func_t)); - num_notice_funcs--; -} - -void -reg_oper_func(oper_func_t handler) -{ - if (of_used == of_size) { - if (of_size) { - of_size <<= 1; - of_list = realloc(of_list, of_size*sizeof(oper_func_t)); - } else { - of_size = 8; - of_list = malloc(of_size*sizeof(oper_func_t)); - } - } - of_list[of_used++] = handler; -} - -static void -call_oper_funcs(struct userNode *user) -{ - unsigned int n; - if (IsLocal(user)) - return; - for (n=0; nnum_local] = NULL; } static void