X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/180e0971962fa45f6fae9e072d585620ae386d7f..0779bbcf5d967eb285df6af23f7e7199caa6fc7b:/src/proto-p10.c diff --git a/src/proto-p10.c b/src/proto-p10.c index 0393b06..7d17423 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -3,7 +3,7 @@ * * 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 * (at your option) any later version. @@ -18,6 +18,9 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include "nickserv.h" +#include "chanserv.h" +#include "hosthiding.h" #include "proto-common.c" /* Full commands. */ @@ -55,6 +58,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 +85,13 @@ #define CMD_SERVSET "SERVSET" #define CMD_SET "SET" #define CMD_SETTIME "SETTIME" +#define CMD_SHUN "SHUN" #define CMD_SILENCE "SILENCE" #define CMD_SQUERY "SQUERY" #define CMD_SQUIT "SQUIT" #define CMD_STATS "STATS" #define CMD_SVSNICK "SVSNICK" +#define CMD_SWHOIS "SWHOIS" #define CMD_TIME "TIME" #define CMD_TOPIC "TOPIC" #define CMD_TRACE "TRACE" @@ -123,6 +129,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 +146,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 +173,13 @@ #define TOK_SERVSET "SERVSET" #define TOK_SET "SET" #define TOK_SETTIME "SE" +#define TOK_SHUN "SU" #define TOK_SILENCE "U" #define TOK_SQUERY "SQUERY" #define TOK_SQUIT "SQ" #define TOK_STATS "R" #define TOK_SVSNICK "SN" +#define TOK_SWHOIS "SW" #define TOK_TIME "TI" #define TOK_TOPIC "T" #define TOK_TRACE "TR" @@ -234,6 +244,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 +271,13 @@ #define P10_SERVSET TYPE(SERVSET) #define P10_SET TYPE(SET) #define P10_SETTIME TYPE(SETTIME) +#define P10_SHUN TYPE(SHUN) #define P10_SILENCE TYPE(SILENCE) #define P10_SQUERY TYPE(SQUERY) #define P10_SQUIT TYPE(SQUIT) #define P10_STATS TYPE(STATS) #define P10_SVSNICK TYPE(SVSNICK) +#define P10_SWHOIS TYPE(SWHOIS) #define P10_TIME TYPE(TIME) #define P10_TOPIC TYPE(TOPIC) #define P10_TRACE TYPE(TRACE) @@ -281,6 +294,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 @@ -296,11 +310,14 @@ 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; +static int parse_oplevel(char *str); + /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the * server and Y's indentifying the client on that server. */ struct server* @@ -370,22 +387,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); } } +static 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); + } +} + +static 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]; @@ -424,10 +515,27 @@ irc_user(struct userNode *user) } } +void +irc_rename(struct userNode *user, const char *new_handle) +{ + 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) { - putsock("%s " P10_ACCOUNT " %s R %s %lu", self->numeric, user->numeric, stamp, 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 @@ -532,6 +640,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 +674,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 :<%s> %s", - self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->issuer, gline->reason); + 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); +} + +void +irc_shun(struct server *srv, struct shun *shun) +{ + 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 +702,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) { @@ -703,17 +839,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) { @@ -747,6 +900,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) { @@ -758,9 +919,20 @@ irc_part(struct userNode *who, struct chanNode *what, const char *reason) } void -irc_topic(struct userNode *who, struct chanNode *what, const char *topic) +irc_topic(struct userNode *service, struct userNode *who, struct chanNode *what, const char *topic) { - putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic); + + int type = 4; + const char *str; + str = conf_get_data("server/type", RECDB_QSTRING); + type = atoi(str); + + 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); + } else { + who = service; /* REMOVE LINE FOR NEFARIOUS 0.5.0 */ + putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic); + } } void @@ -923,8 +1095,8 @@ 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))) @@ -1052,6 +1224,9 @@ static CMD_FUNC(cmd_account) user = GetUserN(argv[1]); if (!user) return 1; /* A QUIT probably passed the ACCOUNT. */ + + if(!extended_accounts) /* any need for this function without? */ + return 1; if(!strcmp(argv[2],"C")) { @@ -1098,6 +1273,7 @@ static CMD_FUNC(cmd_burst) struct userNode *un; struct modeNode *mNode; long mode; + int oplevel = -1; char *user, *end, sep; time_t in_timestamp; char* parm = NULL; @@ -1115,7 +1291,8 @@ static CMD_FUNC(cmd_burst) const char *pos; int n_modes; for (pos=argv[next], n_modes = 1; *pos; pos++) - if ((*pos == 'k') || (*pos == 'l')) + if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A') + || (*pos == 'U')) n_modes++; unsplit_string(argv+next, n_modes, modes); next += n_modes; @@ -1143,8 +1320,10 @@ static CMD_FUNC(cmd_burst) if (ctype == 1) { if (bcheck == 0) { /* strip % char off start of very first ban */ - strncat(banlist, strtok(parm, "%"), sizeof(banlist) - 1 - strlen(banlist)); - strncat(banlist, " ", sizeof(banlist) - 1 - strlen(banlist)); + if (strlen(parm) > 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)); @@ -1181,14 +1360,21 @@ 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 if (isdigit(sep)) { + 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; @@ -1200,8 +1386,10 @@ 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; @@ -1309,6 +1497,7 @@ static CMD_FUNC(cmd_topic) { struct chanNode *cn; time_t chan_ts, topic_ts; + struct userNode *user; if (argc < 3) return 0; @@ -1316,15 +1505,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; } @@ -1369,7 +1566,15 @@ static CMD_FUNC(cmd_num_gline) { if (argc < 6) return 0; - gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0); + gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], 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); return 1; } @@ -1502,7 +1707,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); @@ -1511,6 +1716,22 @@ static CMD_FUNC(cmd_gline) return 0; } +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; @@ -1566,6 +1787,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); @@ -1654,10 +1877,14 @@ init_parse(void) dict_insert(irc_func_dict, TOK_STATS, cmd_stats); dict_insert(irc_func_dict, CMD_SVSNICK, cmd_svsnick); dict_insert(irc_func_dict, TOK_SVSNICK, cmd_svsnick); + 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_SHUN, cmd_shun); + dict_insert(irc_func_dict, TOK_SHUN, cmd_shun); 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); @@ -1691,9 +1918,22 @@ 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, TOK_MARK, cmd_dummy); + /* Ignore privs */ + dict_insert(irc_func_dict, TOK_PRIVS, 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); + /* handle topics */ dict_insert(irc_func_dict, "331", cmd_num_topic); dict_insert(irc_func_dict, "332", cmd_num_topic); @@ -1703,6 +1943,7 @@ 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 */ @@ -1768,15 +2009,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); @@ -2042,7 +2286,15 @@ 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); + + 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); + } + uNode->timestamp = timestamp; modeList_init(&uNode->channels); uNode->uplink = uplink; @@ -2065,6 +2317,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; } @@ -2079,6 +2335,9 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char /* 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); @@ -2117,13 +2376,17 @@ 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; + + call_user_mode_funcs(user, mode_change); + while (*word != ' ' && *word) word++; while (*word == ' ') word++; while (1) { @@ -2133,13 +2396,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); @@ -2200,7 +2465,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; @@ -2237,6 +2502,8 @@ 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 '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); @@ -2245,8 +2512,6 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un return NULL; } break; -// uncomment this when ssl is enabled on the network. -// case 'Z': do_chan_mode(MODE_SSLONLY); break; #undef do_chan_mode case 'l': if (add) { @@ -2274,6 +2539,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; @@ -2297,6 +2593,29 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un 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) @@ -2318,7 +2637,11 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un if (!victim) continue; 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: @@ -2414,11 +2737,15 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); DO_MODE_CHAR(REGISTERED, 'z'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, '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)) @@ -2466,11 +2793,15 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); DO_MODE_CHAR(REGISTERED, 'z'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, '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); @@ -2524,6 +2855,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'); @@ -2535,8 +2868,8 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); DO_MODE_CHAR(REGISTERED, 'z'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, 'Z'); + DO_MODE_CHAR(SSLONLY, 'Z'); + DO_MODE_CHAR(HIDEMODE, 'L'); #undef DO_MODE_CHAR } if (change->modes_set) { @@ -2559,13 +2892,54 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(NOAMSG, 'T'); DO_MODE_CHAR(OPERSONLY, 'O'); DO_MODE_CHAR(REGISTERED, 'z'); - // uncomment this for ssl support - //DO_MODE_CHAR(SSLONLY, '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; @@ -2598,6 +2972,14 @@ 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; @@ -2606,7 +2988,7 @@ clear_chanmode(struct chanNode *channel, const char *modes) 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; @@ -2615,6 +2997,8 @@ clear_chanmode(struct chanNode *channel, const char *modes) 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; } } @@ -2772,3 +3156,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; +} +