X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/55342ce8a8e0e89892433948d7bb660682d13804..0e859bd9eaa372c09645cbf04193d784d1b629d7:/src/proto-p10.c diff --git a/src/proto-p10.c b/src/proto-p10.c index 7e2246d..d9944d7 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -1,11 +1,11 @@ /* proto-p10.c - IRC protocol output * Copyright 2000-2004 srvx Development Team * - * This file is part of srvx. + * This file is part of x3. * - * srvx is free software; you can redistribute it and/or modify + * 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, @@ -18,11 +18,18 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#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" @@ -55,6 +62,7 @@ #define CMD_LIST "LIST" #define CMD_LUSERS "LUSERS" #define CMD_MAP "MAP" +#define CMD_MARK "MARK" #define CMD_MODE "MODE" #define CMD_MOTD "MOTD" #define CMD_NAMES "NAMES" @@ -81,11 +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_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" #define CMD_TRACE "TRACE" @@ -107,6 +124,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" @@ -123,6 +141,7 @@ #define TOK_EOB "EB" #define TOK_EOB_ACK "EA" #define TOK_ERROR "Y" +#define TOK_EXEMPT "EX" #define TOK_FAKEHOST "FA" #define TOK_GET "GET" #define TOK_GLINE "GL" @@ -139,6 +158,7 @@ #define TOK_LIST "LIST" #define TOK_LUSERS "LU" #define TOK_MAP "MAP" +#define TOK_MARK "MK" #define TOK_MODE "M" #define TOK_MOTD "MO" #define TOK_NAMES "E" @@ -165,11 +185,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_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" #define TOK_TRACE "TR" @@ -234,6 +263,7 @@ #define P10_LIST TYPE(LIST) #define P10_LUSERS TYPE(LUSERS) #define P10_MAP TYPE(MAP) +#define P10_MARK TYPE(MARK) #define P10_MODE TYPE(MODE) #define P10_MOTD TYPE(MOTD) #define P10_NAMES TYPE(NAMES) @@ -260,11 +290,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_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) #define P10_TRACE TYPE(TRACE) @@ -281,6 +320,7 @@ #define P10_WHO TYPE(WHO) #define P10_WHOIS TYPE(WHOIS) #define P10_WHOWAS TYPE(WHOWAS) +#define P10_EXEMPT TYPE(EXEMPT) /* Servers claiming to have a boot or link time before PREHISTORY * trigger errors to the log. We hope no server has been running @@ -288,6 +328,8 @@ */ #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; @@ -296,10 +338,18 @@ static unsigned int num_notice_funcs; static struct dict *unbursted_channels; static char *his_servername; static char *his_servercomment; +static int extended_accounts; 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. */ @@ -347,6 +397,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) { @@ -358,11 +434,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) { @@ -370,22 +484,96 @@ irc_server(struct server *srv) inttobase64(extranum, srv->num_mask, (srv->numeric[1] || (srv->num_mask >= 64*64)) ? 3 : 2); if (srv == self) { - /* The +s, ignored by Run's ircu, means "service" to Undernet's ircu */ - putsock(P10_SERVER " %s %d %li %li J10 %s%s +s :%s", + 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); } else { - putsock("%s " P10_SERVER " %s %d %li %li %c10 %s%s +s :%s", + 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); } } +void +irc_p10_pton(irc_in_addr_t *ip, const char *input) +{ + if (strlen(input) == 6) { + unsigned int value; + memset(ip, 0, 6 * sizeof(ip->in6[0])); + value = base64toint(input, 6); + if (value) + ip->in6[5] = htons(65535); + ip->in6[6] = htons(value >> 16); + ip->in6[7] = htons(value & 65535); + } else { + unsigned int pos = 0; + do { + if (*input == '_') { + unsigned int left; + for (left = (25 - strlen(input)) / 3; left; left--) + ip->in6[pos++] = 0; + input++; + } else { + ip->in6[pos++] = ntohs(base64toint(input, 3)); + input += 3; + } + } while (pos < 8); + } +} + +void +irc_p10_ntop(char *output, const irc_in_addr_t *ip) +{ + if (!irc_in_addr_is_valid(*ip)) { + strcpy(output, "AAAAAA"); + } else if (irc_in_addr_is_ipv4(*ip)) { + unsigned int in4; + in4 = (ntohs(ip->in6[6]) << 16) | ntohs(ip->in6[7]); + inttobase64(output, in4, 6); + output[6] = '\0'; + } else if (irc_in_addr_is_ipv6(*ip)) { + unsigned int max_start, max_zeros, curr_zeros, zero, ii; + /* Can start by printing out the leading non-zero parts. */ + for (ii = 0; (ip->in6[ii]) && (ii < 8); ++ii) { + inttobase64(output, ntohs(ip->in6[ii]), 3); + output += 3; + } + /* Find the longest run of zeros. */ + for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) { + if (!ip->in6[ii]) + curr_zeros++; + else if (curr_zeros > max_zeros) { + max_start = ii - curr_zeros; + max_zeros = curr_zeros; + curr_zeros = 0; + } + } + if (curr_zeros > max_zeros) { + max_start = ii - curr_zeros; + max_zeros = curr_zeros; + curr_zeros = 0; + } + /* Print the rest of the address */ + for (ii = zero; ii < 8; ) { + if ((ii == max_start) && max_zeros) { + *output++ = '_'; + ii += max_zeros; + } else { + inttobase64(output, ntohs(ip->in6[ii]), 3); + output += 3; + } + } + *output = '\0'; + } else { + strcpy(output, "???"); + } +} + void irc_user(struct userNode *user) { - char b64ip[7]; + char b64ip[25]; if (!user) return; - inttobase64(b64ip, ntohl(user->ip.s_addr), 6); + irc_p10_ntop(b64ip, &user->ip); if (user->modes) { int modelen; char modes[32]; @@ -413,6 +601,15 @@ irc_user(struct userNode *user) modes[modelen++] = 'f'; if (IsHiddenHost(user)) modes[modelen++] = 'x'; + if (IsBotM(user)) + modes[modelen++] = 'B'; + if (IsHideChans(user)) + modes[modelen++] = 'n'; + if (IsHideIdle(user)) + modes[modelen++] = 'I'; + if (IsXtraOp(user)) + modes[modelen++] = 'X'; + modes[modelen] = 0; /* we don't need to put the + in modes because it's in the format string. */ @@ -425,9 +622,26 @@ irc_user(struct userNode *user) } void -irc_account(struct userNode *user, const char *stamp) +irc_rename(struct userNode *user, const char *new_handle) { - putsock("%s " P10_ACCOUNT " %s %s", self->numeric, user->numeric, stamp); + if(extended_accounts) + putsock("%s " P10_ACCOUNT " %s M %s", self->numeric, user->numeric, new_handle); +} + +void +irc_delete(struct userNode *user) +{ + if(extended_accounts) + putsock("%s " P10_ACCOUNT " %s U", self->numeric, user->numeric); +} + +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); + else + putsock("%s " P10_ACCOUNT " %s %s %lu", self->numeric, user->numeric, stamp, timestamp); } void @@ -490,6 +704,18 @@ 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); +} + + void irc_notice(struct userNode *from, const char *to, const char *message) { @@ -508,6 +734,18 @@ irc_privmsg(struct userNode *from, const char *to, const char *message) 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 irc_eob(void) { @@ -518,6 +756,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 @@ -532,6 +788,21 @@ irc_pong(const char *who, const char *data) putsock("%s " P10_PONG " %s :%s", self->numeric, who, data); } +void +irc_pong_asll(const char *who, const char *orig_ts) +{ + char *delim; + struct timeval orig; + struct timeval 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); +} + void irc_pass(const char *passwd) { @@ -551,10 +822,17 @@ irc_introduce(const char *passwd) } void -irc_gline(struct server *srv, struct gline *gline) +irc_gline(struct server *srv, struct gline *gline, int silent) +{ + putsock("%s " P10_GLINE " %s +%s %ld %ld :%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_GLINE " %s +%s %ld :<%s> %s", - self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->issuer, gline->reason); + putsock("%s " P10_SHUN " %s +%s %ld :<%s> %s", + self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, shun->issuer, shun->reason); } void @@ -572,6 +850,12 @@ irc_ungline(const char *mask) putsock("%s " P10_GLINE " * -%s", self->numeric, mask); } +void +irc_unshun(const char *mask) +{ + putsock("%s " P10_SHUN " * -%s", self->numeric, mask); +} + static void irc_burst(struct chanNode *chan) { @@ -579,6 +863,7 @@ irc_burst(struct chanNode *chan) int pos, base_len, len; struct modeNode *mn; struct banNode *bn; + struct exemptNode *en; long last_mode=-1; unsigned int n; @@ -589,6 +874,8 @@ irc_burst(struct chanNode *chan) if (len) 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]; @@ -598,6 +885,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)) { @@ -639,6 +927,33 @@ irc_burst(struct chanNode *chan) 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++) { + 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 */ + putsock("%s", burst_line); + pos = base_len; + } + memcpy(burst_line+pos, en->exempt, len); + pos += len; + burst_line[pos++] = ' '; + } + } /* print the last line */ burst_line[pos] = 0; putsock("%s", burst_line); @@ -675,17 +990,34 @@ irc_kill(struct userNode *from, struct userNode *target, const char *message) void irc_mode(struct userNode *from, struct chanNode *target, const char *modes) { + call_channel_mode_funcs(from, target, (char **)&modes, 0); putsock("%s " P10_MODE " %s %s "FMT_TIME_T, (from ? from->numeric : self->numeric), target->name, modes, target->timestamp); } +/* Added to allow services to mode users + 2005 - 8 - 10 by Life4Christ +*/ +void +irc_umode(struct userNode *target, const char *modes) +{ + putsock("%s " P10_MODE " %s %s ",self->numeric,target->nick, modes); +} + + void irc_invite(struct userNode *from, struct userNode *who, struct chanNode *to) { putsock("%s " P10_INVITE " %s %s", from->numeric, who->nick, to->name); } +void +irc_silence(struct userNode *who, const char *mask, int add) +{ + putsock("%s " P10_SILENCE " %s %s%s", self->numeric, who->numeric, add ? "+" : "-", mask); +} + void irc_join(struct userNode *who, struct chanNode *what) { @@ -697,6 +1029,24 @@ irc_join(struct userNode *who, struct chanNode *what) } } +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 *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) { @@ -719,6 +1069,14 @@ irc_svsnick(struct userNode *from, struct userNode *target, const char *newnick) putsock("%s " P10_SVSNICK " %s %s "FMT_TIME_T, from->uplink->numeric, target->numeric, newnick, now); } +void +irc_swhois(struct userNode *from, struct userNode *target, const char *message) +{ + putsock("%s " P10_SWHOIS " %s %s%s", from->uplink->numeric, target->numeric, message ? ":" : "", + message ? message : ""); + +} + void irc_part(struct userNode *who, struct chanNode *what, const char *reason) { @@ -730,9 +1088,49 @@ irc_part(struct userNode *who, struct chanNode *what, const char *reason) } void -irc_topic(struct userNode *who, struct chanNode *what, const char *topic) -{ - putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic); +irc_topic(struct userNode *service, struct userNode *who, struct chanNode *what, const char *topic) +{ + + int type = 4; + int host_in_topic = 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 (hstr) { + if (IsFakeHost(who)) + safestrncpy(shost, who->fakehost, sizeof(shost)); + else if (IsSetHost(who)) { + hostmask = strdup(who->sethost); + if ((host = (strrchr(hostmask, '@')))) + *host++ = '\0'; + else + host = hostmask; + + safestrncpy(sident, hostmask, 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); + } } void @@ -752,6 +1150,48 @@ 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); + } + } +} + static void send_burst(void); static void @@ -793,13 +1233,11 @@ static CMD_FUNC(cmd_whois) } irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info); if (his_servername && his_servercomment) - irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment); + 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 (IsOper(who)) { + irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description); + if (IsOper(who)) irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick); - } irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick); return 1; } @@ -811,7 +1249,7 @@ static CMD_FUNC(cmd_server) if (argc < 8) return 0; - if (origin) { + if (self->uplink) { /* another server introduced us */ srv = AddServer(GetServerH(origin), argv[1], atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), argv[6], argv[argc-1]); if (!srv) @@ -856,6 +1294,7 @@ static CMD_FUNC(cmd_server) return 1; } + static CMD_FUNC(cmd_eob) { struct server *sender; @@ -872,11 +1311,22 @@ 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; } @@ -892,13 +1342,26 @@ 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; struct userNode *un; - if(argc > 3) - irc_pong(argv[2], argv[1]); + if (argc > 3) + irc_pong_asll(argv[2], argv[3]); else if ((srv = GetServerH(origin))) irc_pong(self->name, srv->numeric); else if ((un = GetUserH(origin))) @@ -944,7 +1407,7 @@ create_helper(char *name, void *data) return; } - AddChannelUser(cd->user, AddChannel(name, cd->when, NULL, NULL)); + AddChannelUser(cd->user, AddChannel(name, cd->when, NULL, NULL, NULL)); } static CMD_FUNC(cmd_create) @@ -976,6 +1439,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) @@ -999,6 +1478,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) @@ -1008,7 +1488,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; } @@ -1016,13 +1496,54 @@ static CMD_FUNC(cmd_nick) static CMD_FUNC(cmd_account) { struct userNode *user; + struct server *server; + struct handle_info *hi; - if ((argc < 3) || !origin || !GetServerH(origin)) + if ((argc < 3) || !origin || !(server = GetServerH(origin))) return 0; /* Origin must be server. */ + + /* This next line appears to tremple origin.. why? */ user = GetUserN(argv[1]); if (!user) return 1; /* A QUIT probably passed the ACCOUNT. */ - call_account_func(user, argv[2]); + + if(!extended_accounts) /* any need for this function without? */ + return 1; + + if(!strcmp(argv[2],"C")) + { + if((hi = loc_auth(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); + + } + 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(argv[5], argv[6], argv[4] ))) + { + /* Return a AC A */ + putsock("%s " P10_ACCOUNT " %s A %s %lu", 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],"R")) + call_account_func(user, argv[3]); + else + call_account_func(user, argv[2]); /* For backward compatability */ return 1; } @@ -1038,47 +1559,220 @@ 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), +#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 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); +} + +static CMD_FUNC(cmd_privs) +{ + char *tstr = NULL; + int type = 0; + + tstr = conf_get_data("server/type", RECDB_QSTRING); + if(tstr) + type = atoi(tstr); + + if (type < 6) + return 1; /* silently ignore */ + + struct userNode *user = argc > 1 ? GetUserN(argv[1]) : NULL; + char buf[512] = ""; + int what = PRIV_ADD; + char *p = 0; + char *tmp; + unsigned int i; + + if (argc < 3) + return 0; + + if (!user) + return 0; + + for (i=1; i 1) { + strncat(banlist, strtok(parm, "%"), sizeof(banlist) - 1 - strlen(banlist)); + strncat(banlist, " ", sizeof(banlist) - 1 - strlen(banlist)); + } + bcheck = 1; + } else { + strncat(banlist, parm, sizeof(banlist) - 1 - strlen(banlist)); + strncat(banlist, " ", sizeof(banlist) - 1 - strlen(banlist)); + } + } else if (ctype == 2) { + if (echeck == 0) { + echeck = 1; + } else { + strncat(exemptlist, parm, sizeof(exemptlist) - 1 - strlen(exemptlist)); + strncat(exemptlist, " ", sizeof(exemptlist) - 1 - strlen(exemptlist)); + } + } + } + next++; + break; } + default: members = argv[next++]; break; + } } - in_timestamp = atoi(argv[2]); if ((cNode = dict_find(unbursted_channels, argv[1], NULL))) { cNode->timestamp = in_timestamp; dict_remove(unbursted_channels, cNode->name); irc_burst(cNode); } - cNode = AddChannel(argv[1], in_timestamp, modes, banlist); + 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) { @@ -1087,13 +1781,23 @@ static CMD_FUNC(cmd_burst) if (sep == ':') { mode = 0; while ((sep = *end++)) { - if (sep == 'o') + if (sep == 'o') { mode |= MODE_CHANOP; - else if (sep == 'h') + oplevel = -1; + } else if (sep == 'h') { mode |= MODE_HALFOP; - else if (sep == 'v') + oplevel = -1; + } else if (sep == 'v') { mode |= MODE_VOICE; - else + oplevel = -1; + } else if (isdigit(sep)) { + mode |= MODE_CHANOP; + if (oplevel >= 0) + oplevel += parse_oplevel(end); + else + oplevel = parse_oplevel(end); + while (isdigit(*end)) end++; + } else break; } if (rel_age < 0) @@ -1103,13 +1807,66 @@ static CMD_FUNC(cmd_burst) res = 0; continue; } - if ((mNode = AddChannelUser(un, cNode))) + if ((mNode = AddChannelUser(un, cNode))) { mNode->modes = mode; + mNode->oplevel = oplevel; + } } 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")) { + /* DNSBL_DATA name */ + 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; + } + /* unknown type of mark */ + return 1; +} + static CMD_FUNC(cmd_mode) { struct chanNode *cn; @@ -1155,6 +1912,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)); } @@ -1212,6 +1985,7 @@ static CMD_FUNC(cmd_topic) { struct chanNode *cn; time_t chan_ts, topic_ts; + struct userNode *user; if (argc < 3) return 0; @@ -1219,15 +1993,23 @@ static CMD_FUNC(cmd_topic) log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose topic is being set", argv[1]); return 0; } - if (argc >= 5) { - /* Looks like an Asuka style topic burst. */ + + + if (argc == 5) { /* Asuka / Topic Bursting IRCu's */ + user = GetUserH(origin); chan_ts = atoi(argv[2]); topic_ts = atoi(argv[3]); - } else { + } else if (argc >= 6) { /* Nefarious 0.5.0 */ + user = GetUserH(strtok(argv[2], "!")); + chan_ts = atoi(argv[3]); + topic_ts = atoi(argv[4]); + } else { /* Regular IRCu (No Topic Bursting)*/ + user = GetUserH(origin); chan_ts = cn->timestamp; topic_ts = now; } - SetChannelTopic(cn, GetUserH(origin), argv[argc-1], 0); + + SetChannelTopic(cn, user, user, argv[argc-1], 0); cn->topic_time = topic_ts; return 1; } @@ -1270,9 +2052,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); + 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 (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 < 7) { + if (argc < 6) + return 0; + else + shun_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0); + } else { + if (argv[5] == "+") + shun_add(origin, argv[3], atoi(argv[4])-now, argv[6], now, 0); + } return 1; } @@ -1327,6 +2129,62 @@ static CMD_FUNC(cmd_part) return 1; } +static CMD_FUNC(cmd_svspart) +{ + struct userNode *user; + + if (argc < 3) + return 0; + user = GetUserN(argv[1]); + if (!user) + return 0; + parse_foreach(argv[2], part_helper, NULL, NULL, NULL, user); + return 1; +} + +static CMD_FUNC(cmd_silence) +{ + struct userNode *user; + char *mask; + char *new_mask; + unsigned int i; + + if (argc < 2) + return 0; + + user = GetUserN(argv[1]); + + /* Sanity, go nuts if this happens */ + if (!user) + return 0; + + /* We can safely ignore this if a user adding a silence is not + * ignored. However this brings up a TODO. If a user logs in and + * they have silences on the IRCd then we need to set them here + * somehow + */ + if (!user->handle_info) + return 1; + + mask = argv[2]; + + if (*mask == '-') { + for (i=0; ihandle_info->ignores->used; i++) { + if (!irccasecmp(mask+1, user->handle_info->ignores->list[i])) + user->handle_info->ignores->list[i] = user->handle_info->ignores->list[--user->handle_info->ignores->used]; + } + } else { + for (i=0; ihandle_info->ignores->used; i++) { + if (!strcmp(mask+1, user->handle_info->ignores->list[i])) + return 1; /* Already on the users NickServ ignore list, safely ignore */ + } + + new_mask = strdup(mask+1); + string_list_append(user->handle_info->ignores, new_mask); + } + return 1; +} + static CMD_FUNC(cmd_kick) { if (argc < 3) @@ -1338,6 +2196,7 @@ static CMD_FUNC(cmd_kick) static CMD_FUNC(cmd_squit) { struct server *server; + char *uplink; if (argc < 4) return 0; @@ -1352,7 +2211,13 @@ 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; } @@ -1364,23 +2229,68 @@ static CMD_FUNC(cmd_privmsg) 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]; 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; } @@ -1405,7 +2315,7 @@ static CMD_FUNC(cmd_gline) if (argv[2][0] == '+') { if (argc < 5) return 0; - gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0); + gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0, 0); return 1; } else if (argv[2][0] == '-') { gline_remove(argv[2]+1, 0); @@ -1414,6 +2324,50 @@ 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) + return 0; + if (argv[2][0] == '+') { + if (argc < 5) + return 0; + shun_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0); + return 1; + } else if (argv[2][0] == '-') { + shun_remove(argv[2]+1, 0); + return 1; + } else + return 0; +} + static CMD_FUNC(cmd_svsnick) { struct userNode *target, *dest; @@ -1469,6 +2423,8 @@ init_parse(void) char numer[COMBO_NUMERIC_LEN+1]; /* read config items */ + str = conf_get_data("server/extended_accounts", RECDB_QSTRING); + extended_accounts = str ? enabled_string(str) : 1; str = conf_get_data("server/ping_freq", RECDB_QSTRING); ping_freq = str ? ParseInterval(str) : 120; str = conf_get_data("server/ping_timeout", RECDB_QSTRING); @@ -1515,6 +2471,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); @@ -1543,8 +2501,8 @@ init_parse(void) dict_insert(irc_func_dict, TOK_TOPIC, cmd_topic); dict_insert(irc_func_dict, CMD_AWAY, cmd_away); dict_insert(irc_func_dict, TOK_AWAY, cmd_away); - dict_insert(irc_func_dict, CMD_SILENCE, cmd_dummy); - dict_insert(irc_func_dict, TOK_SILENCE, cmd_dummy); + dict_insert(irc_func_dict, CMD_SILENCE, cmd_silence); + dict_insert(irc_func_dict, TOK_SILENCE, cmd_silence); dict_insert(irc_func_dict, CMD_KICK, cmd_kick); dict_insert(irc_func_dict, TOK_KICK, cmd_kick); dict_insert(irc_func_dict, CMD_SQUIT, cmd_squit); @@ -1555,12 +2513,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); @@ -1569,6 +2539,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 @@ -1594,9 +2573,25 @@ init_parse(void) dict_insert(irc_func_dict, TOK_WALLOPS, cmd_dummy); dict_insert(irc_func_dict, CMD_WALLHOPS, cmd_dummy); dict_insert(irc_func_dict, TOK_WALLHOPS, cmd_dummy); + 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, 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 remote luser */ + dict_insert(irc_func_dict, TOK_LUSERS, cmd_dummy); /* We have reliable clock! Always! Wraaa! */ dict_insert(irc_func_dict, CMD_SETTIME, cmd_dummy); dict_insert(irc_func_dict, TOK_SETTIME, cmd_dummy); + + /* 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); dict_insert(irc_func_dict, "332", cmd_num_topic); @@ -1606,11 +2601,13 @@ init_parse(void) /* ban list resetting */ /* "stats g" responses */ 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" */ /* other numeric responses we might get */ dict_insert(irc_func_dict, "401", cmd_dummy); /* target left network */ dict_insert(irc_func_dict, "403", cmd_dummy); /* no such channel */ dict_insert(irc_func_dict, "404", cmd_dummy); /* cannot send to channel */ + dict_insert(irc_func_dict, "439", cmd_dummy); /* target change too fast */ dict_insert(irc_func_dict, "441", cmd_dummy); /* target isn't on that channel */ dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */ dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */ @@ -1628,6 +2625,7 @@ init_parse(void) userList_init(&dead_users); reg_del_channel_func(remove_unbursted_channel); reg_exit_func(parse_cleanup); + // reg_notice_func(opserv, check_ctcp); } int @@ -1670,15 +2668,18 @@ static void parse_foreach(char *target_list, foreach_chanfunc cf, foreach_nonchan nc, foreach_userfunc uf, foreach_nonuser nu, void *data) { char *j, old; + do { j = target_list; while (*j != 0 && *j != ',') j++; old = *j; *j = 0; + if (IsChannelName(target_list) || (target_list[0] == '0' && target_list[1] == '\0')) { struct chanNode *chan = GetChannel(target_list); + if (chan) { if (cf) cf(chan, data); @@ -1834,7 +2835,7 @@ void DelServer(struct server* serv, int announce, const char *message) } struct userNode * -AddService(const char *nick, const char *desc, const char *hostname) +AddService(const char *nick, const char *modes, const char *desc, const char *hostname) { char numeric[COMBO_NUMERIC_LEN+1]; int local_num = get_local_numeric(); @@ -1853,7 +2854,8 @@ AddService(const char *nick, const char *desc, const char *hostname) if (!hostname) hostname = self->name; make_numeric(self, local_num, numeric); - return AddUser(self, nick, nick, hostname, "+oik", numeric, desc, now, "AAAAAA"); + /* TODO: Make these modes part of the conf file */ + return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA"); } struct userNode * @@ -1879,12 +2881,13 @@ AddClone(const char *nick, const char *ident, const char *hostname, const char * int is_valid_nick(const char *nick) { + unsigned int ii; /* IRC has some of The Most Fucked-Up ideas about character sets * in the world.. */ if (!isalpha(*nick) && !strchr("{|}~[\\]^_`", *nick)) return 0; - for (++nick; *nick; ++nick) - if (!isalnum(*nick) && !strchr("{|}~[\\]^-_`", *nick)) + for (ii = 0; nick[ii]; ++ii) + if (!isalnum(nick[ii]) && !strchr("{|}~[\\]^-_`", nick[ii])) return 0; if (strlen(nick) > nicklen) return 0; @@ -1896,6 +2899,8 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * { struct userNode *oldUser, *uNode; unsigned int n, ignore_user; + 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); @@ -1942,7 +2947,22 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * safestrncpy(uNode->info, userinfo, sizeof(uNode->info)); safestrncpy(uNode->hostname, hostname, sizeof(uNode->hostname)); safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric)); - uNode->ip.s_addr = htonl(base64toint(realip, 6)); + irc_p10_pton(&uNode->ip, realip); + + tstr = conf_get_data("server/type", RECDB_QSTRING); + type = atoi(tstr); + if (type > 6) { + 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->timestamp = timestamp; modeList_init(&uNode->channels); uNode->uplink = uplink; @@ -1952,6 +2972,9 @@ 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); + + set_geoip_info(uNode); + if (ignore_user) return uNode; @@ -1965,6 +2988,10 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * for (n=0; nloc == 1) && (uNode->handle_info)) + send_func_list(uNode); + return uNode; } @@ -1974,9 +3001,14 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char { unsigned int n; + verify(user); + /* mark them as dead, in case anybody cares */ user->dead = 1; + /* remove pending adduser commands */ + wipe_adduser_pending(NULL, user); + /* remove user from all channels */ while (user->channels.used > 0) DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, false, 0); @@ -2005,6 +3037,25 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char } modeList_clean(&user->channels); + + /* Clean up version data */ + if(user->version_reply) { + free(user->version_reply); + user->version_reply = 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. @@ -2015,15 +3066,19 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char free_user(user); } +static void call_oper_funcs(struct userNode *user); + void mod_usermode(struct userNode *user, const char *mode_change) { - static void call_oper_funcs(struct userNode *user); int add = 1; const char *word = mode_change; if (!user || !mode_change) return; - while (*word != ' ' && *word) word++;\ - while (*word == ' ') word++; \ + + call_user_mode_funcs(user, mode_change); + + while (*word != ' ' && *word) word++; + while (*word == ' ') word++; while (1) { #define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0) switch (*mode_change++) { @@ -2031,13 +3086,15 @@ void mod_usermode(struct userNode *user, const char *mode_change) { case '+': add = 1; break; case '-': add = 0; break; case 'o': - do_user_mode(FLAGS_OPER); if (add) { - userList_append(&curr_opers, user); - call_oper_funcs(user); + 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); break; case 'O': do_user_mode(FLAGS_LOCOP); break; case 'i': do_user_mode(FLAGS_INVISIBLE); @@ -2051,6 +3108,34 @@ void mod_usermode(struct userNode *user, const char *mode_change) { 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, @@ -2098,7 +3183,7 @@ void mod_usermode(struct userNode *user, const char *mode_change) { } struct mod_chanmode * -mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags) +mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags, short base_oplevel) { struct mod_chanmode *change; unsigned int ii, in_arg, ch_arg, add; @@ -2135,8 +3220,16 @@ 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; -// uncomment this when ssl is enabled on the network. -// case 'z': do_chan_mode(MODE_SSLONLY); 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); + } else { + mod_chanmode_free(change); + return NULL; + } + break; #undef do_chan_mode case 'l': if (add) { @@ -2164,6 +3257,37 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un } } break; + 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)); + } else { + change->modes_clear |= MODE_UPASS; + if (!(flags & MCP_UPASS_FREE)) { + if (in_arg >= argc) + goto error; + in_arg++; + } + } + break; + case 'A': + if (add) { + if (in_arg >= argc) + goto error; + 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)) { + if (in_arg >= argc) + goto error; + in_arg++; + } + } + break; case 'b': if (!(flags & MCP_ALLOW_OVB)) goto error; @@ -2172,11 +3296,44 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un change->args[ch_arg].mode = MODE_BAN; if (!add) change->args[ch_arg].mode |= MODE_REMOVE; - change->args[ch_arg++].hostmask = modes[in_arg++]; + change->args[ch_arg++].u.hostmask = modes[in_arg++]; + break; + case 'e': + if (!(flags & MCP_ALLOW_OVB)) + goto error; + if (in_arg >= argc) + goto error; + change->args[ch_arg].mode = MODE_EXEMPT; + if (!add) + change->args[ch_arg].mode |= MODE_REMOVE; + change->args[ch_arg++].u.hostmask = modes[in_arg++]; break; case 'o': case 'h': case 'v': { struct userNode *victim; + char *oplevel_str; + int oplevel; + + if (in_arg >= argc) + goto error; + oplevel_str = strchr(modes[in_arg], ':'); + if (oplevel_str) + { + /* XXYYY M #channel +o XXYYY: */ + *oplevel_str++ = '\0'; + oplevel = parse_oplevel(oplevel_str); + if (oplevel <= base_oplevel && !(flags & MCP_FROM_SERVER)) + oplevel = base_oplevel + 1; + } + else if (channel->modes & MODE_UPASS) + oplevel = base_oplevel + 1; + else + oplevel = -1; + + /* Check that oplevel is within bounds. */ + if (oplevel > MAXOPLEVEL) + oplevel = MAXOPLEVEL; + if (!(flags & MCP_ALLOW_OVB)) goto error; if (in_arg >= argc) @@ -2197,8 +3354,12 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un victim = GetUserH(modes[in_arg++]); if (!victim) continue; - if ((change->args[ch_arg].member = GetUserMode(channel, victim))) + if ((change->args[ch_arg].u.member = GetUserMode(channel, victim))) + { + /* Apply the oplevel change */ + change->args[ch_arg].u.member->oplevel = oplevel; ch_arg++; + } break; } default: @@ -2293,11 +3454,16 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(NOQUITMSGS, 'Q'); DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, 'z'); + DO_MODE_CHAR(REGISTERED, 'z'); + DO_MODE_CHAR(SSLONLY, 'Z'); + DO_MODE_CHAR(HIDEMODE, 'L'); #undef DO_MODE_CHAR if (change->modes_clear & channel->modes & MODE_KEY) 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) + mod_chanmode_append(&chbuf, 'A', channel->apass); } for (arg = 0; arg < change->argc; ++arg) { if (!(change->args[arg].mode & MODE_REMOVE)) @@ -2306,15 +3472,18 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod chbuf.modes[chbuf.modes_used++] = mode = '-'; switch (change->args[arg].mode & ~MODE_REMOVE) { case MODE_BAN: - mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask); + mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask); + break; + case MODE_EXEMPT: + mod_chanmode_append(&chbuf, 'e', change->args[arg].u.hostmask); break; default: if (change->args[arg].mode & MODE_CHANOP) - mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric); + mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric); if (change->args[arg].mode & MODE_HALFOP) - mod_chanmode_append(&chbuf, 'h', change->args[arg].member->user->numeric); + mod_chanmode_append(&chbuf, 'h', change->args[arg].u.member->user->numeric); if (change->args[arg].mode & MODE_VOICE) - mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric); + mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric); break; } } @@ -2341,11 +3510,16 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(NOQUITMSGS, 'Q'); DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, 'z'); + DO_MODE_CHAR(REGISTERED, 'z'); + DO_MODE_CHAR(SSLONLY, 'Z'); + DO_MODE_CHAR(HIDEMODE, 'L'); #undef DO_MODE_CHAR if(change->modes_set & MODE_KEY) mod_chanmode_append(&chbuf, 'k', change->new_key); + if (change->modes_set & MODE_UPASS) + mod_chanmode_append(&chbuf, 'U', change->new_upass); + if (change->modes_set & MODE_APASS) + mod_chanmode_append(&chbuf, 'A', change->new_apass); if(change->modes_set & MODE_LIMIT) { sprintf(int_buff, "%d", change->new_limit); mod_chanmode_append(&chbuf, 'l', int_buff); @@ -2358,15 +3532,18 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod chbuf.modes[chbuf.modes_used++] = mode = '+'; switch (change->args[arg].mode) { case MODE_BAN: - mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask); + mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask); + break; + case MODE_EXEMPT: + mod_chanmode_append(&chbuf, 'e', change->args[arg].u.hostmask); break; default: if (change->args[arg].mode & MODE_CHANOP) - mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric); + mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric); if (change->args[arg].mode & MODE_HALFOP) - mod_chanmode_append(&chbuf, 'h', change->args[arg].member->user->numeric); + mod_chanmode_append(&chbuf, 'h', change->args[arg].u.member->user->numeric); if (change->args[arg].mode & MODE_VOICE) - mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric); + mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric); break; } } @@ -2396,6 +3573,8 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(NOPRIVMSGS, 'n'); DO_MODE_CHAR(LIMIT, 'l'); DO_MODE_CHAR(KEY, 'k'); + DO_MODE_CHAR(UPASS, 'U'); + DO_MODE_CHAR(APASS, 'A'); DO_MODE_CHAR(DELAYJOINS, 'D'); DO_MODE_CHAR(REGONLY, 'r'); DO_MODE_CHAR(NOCOLORS, 'c'); @@ -2406,8 +3585,9 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(NOQUITMSGS, 'Q'); DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, 'z'); + DO_MODE_CHAR(REGISTERED, 'z'); + DO_MODE_CHAR(SSLONLY, 'Z'); + DO_MODE_CHAR(HIDEMODE, 'L'); #undef DO_MODE_CHAR } if (change->modes_set) { @@ -2429,13 +3609,55 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(NOQUITMSGS, 'Q'); DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, 'z'); + DO_MODE_CHAR(REGISTERED, 'z'); + DO_MODE_CHAR(SSLONLY, 'Z'); + DO_MODE_CHAR(HIDEMODE, 'L'); #undef DO_MODE_CHAR - switch (change->modes_set & (MODE_KEY|MODE_LIMIT)) { + switch (change->modes_set & (MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS)) { + /* Doing this implementation has been a pain in the arse, I hope I didn't forget a possible combination */ + case MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS: + used += sprintf(outbuff+used, "lkAU %d %s %s %s", change->new_limit, change->new_key,change->new_apass, change->new_upass); + break; + + case MODE_KEY|MODE_LIMIT|MODE_APASS: + used += sprintf(outbuff+used, "lkA %d %s %s", change->new_limit, change->new_key, change->new_apass); + break; + case MODE_KEY|MODE_LIMIT|MODE_UPASS: + used += sprintf(outbuff+used, "lkU %d %s %s", change->new_limit, change->new_key, change->new_upass); + break; + case MODE_KEY|MODE_APASS|MODE_UPASS: + used += sprintf(outbuff+used, "kAU %s %s %s", change->new_key, change->new_apass, change->new_upass); + break; + + case MODE_KEY|MODE_APASS: + used += sprintf(outbuff+used, "kA %s %s", change->new_key, change->new_apass); + break; + case MODE_KEY|MODE_UPASS: + used += sprintf(outbuff+used, "kU %s %s", change->new_key, change->new_upass); + break; case MODE_KEY|MODE_LIMIT: used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key); break; + + case MODE_LIMIT|MODE_UPASS: + used += sprintf(outbuff+used, "lU %d %s", change->new_limit, change->new_upass); + break; + case MODE_LIMIT|MODE_APASS: + used += sprintf(outbuff+used, "lA %d %s", change->new_limit, change->new_apass); + break; + case MODE_APASS|MODE_UPASS: + used += sprintf(outbuff+used, "AU %s %s", change->new_apass, change->new_upass); + + case MODE_LIMIT|MODE_APASS|MODE_UPASS: + used += sprintf(outbuff+used, "lAU %d %s %s", change->new_limit, change->new_apass, change->new_upass); + break; + + case MODE_APASS: + used += sprintf(outbuff+used, "A %s", change->new_apass); + break; + case MODE_UPASS: + used += sprintf(outbuff+used, "U %s", change->new_upass); + break; case MODE_KEY: used += sprintf(outbuff+used, "k %s", change->new_key); break; @@ -2468,14 +3690,23 @@ clear_chanmode(struct chanNode *channel, const char *modes) remove |= MODE_KEY; channel->key[0] = '\0'; break; + case 'A': + remove |= MODE_APASS; + channel->apass[0] = '\0'; + break; + case 'U': + remove |= MODE_UPASS; + channel->upass[0] = '\0'; + break; case 'l': remove |= 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; + case 'c': remove |= MODE_NOCOLORS; break; case 'C': remove |= MODE_NOCTCPS; break; case 'S': remove |= MODE_STRIPCOLOR; break; case 'M': remove |= MODE_MODUNREG; break; @@ -2483,6 +3714,9 @@ clear_chanmode(struct chanNode *channel, const char *modes) 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; } } @@ -2500,6 +3734,14 @@ clear_chanmode(struct chanNode *channel, const char *modes) channel->banlist.used = 0; } + /* If removing exempts, kill 'em all. */ + if ((remove & 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)); @@ -2632,3 +3874,16 @@ send_burst(void) for (it = dict_first(channels); it; it = iter_next(it)) dict_insert(unbursted_channels, iter_key(it), iter_data(it)); } + +/* + * Oplevel parsing + */ +static int +parse_oplevel(char *str) +{ + int oplevel = 0; + while (isdigit(*str)) + oplevel = oplevel * 10 + *str++ - '0'; + return oplevel; +} +