X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/d76ed9a966ee3d955c8ef00ecc02e643c2005e2e..0f3e9cfc4b5d0f13085c975e10c0e6c4c8e5fbc3:/src/proto-p10.c diff --git a/src/proto-p10.c b/src/proto-p10.c index b2aa696..580cbc5 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -1,7 +1,7 @@ /* 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 * it under the terms of the GNU General Public License as published by @@ -18,6 +18,8 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include "nickserv.h" +#include "chanserv.h" #include "proto-common.c" /* Full commands. */ @@ -55,6 +57,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,6 +84,7 @@ #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" @@ -96,8 +100,10 @@ #define CMD_VERSION "VERSION" #define CMD_WALLCHOPS "WALLCHOPS" #define CMD_WALLOPS "WALLOPS" +#define CMD_WALLHOPS "WALLHOPS" #define CMD_WALLUSERS "WALLUSERS" #define CMD_WALLVOICES "WALLVOICES" +#define CMD_WALLHOPS "WALLHOPS" #define CMD_WHO "WHO" #define CMD_WHOIS "WHOIS" #define CMD_WHOWAS "WHOWAS" @@ -121,6 +127,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" @@ -137,6 +144,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" @@ -163,6 +171,7 @@ #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" @@ -178,8 +187,10 @@ #define TOK_VERSION "V" #define TOK_WALLCHOPS "WC" #define TOK_WALLOPS "WA" +#define TOK_WALLHOPS "WH" #define TOK_WALLUSERS "WU" #define TOK_WALLVOICES "WV" +#define TOK_WALLHOPS "WH" #define TOK_WHO "H" #define TOK_WHOIS "W" #define TOK_WHOWAS "X" @@ -230,6 +241,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) @@ -256,6 +268,7 @@ #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) @@ -271,11 +284,13 @@ #define P10_VERSION TYPE(VERSION) #define P10_WALLCHOPS TYPE(WALLCHOPS) #define P10_WALLOPS TYPE(WALLOPS) +#define P10_WALLHOPS TYPE(WALLHOPS) #define P10_WALLUSERS TYPE(WALLUSERS) #define P10_WALLVOICES TYPE(WALLVOICES) #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 @@ -291,6 +306,7 @@ 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); @@ -400,8 +416,12 @@ irc_user(struct userNode *user) modes[modelen++] = 'd'; if (IsGlobal(user)) modes[modelen++] = 'g'; - if (IsHelperIrcu(user)) + // sethost - reed/apples + // if (IsHelperIrcu(user)) + if (IsSetHost(user)) modes[modelen++] = 'h'; + if (IsFakeHost(user)) + modes[modelen++] = 'f'; if (IsHiddenHost(user)) modes[modelen++] = 'x'; modes[modelen] = 0; @@ -416,9 +436,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 @@ -542,10 +579,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> %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_GLINE " %s +%s %ld :%s", - self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, 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 @@ -563,6 +607,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) { @@ -570,6 +620,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; @@ -596,6 +647,8 @@ irc_burst(struct chanNode *chan) burst_line[pos++] = ':'; if (last_mode & MODE_CHANOP) burst_line[pos++] = 'o'; + if (last_mode & MODE_HALFOP) + burst_line[pos++] = 'h'; if (last_mode & MODE_VOICE) burst_line[pos++] = 'v'; } @@ -628,6 +681,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); @@ -669,6 +749,16 @@ irc_mode(struct userNode *from, struct chanNode *target, const char *modes) 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) { @@ -719,8 +809,14 @@ 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) { +/* UNCOMMENT FOR NEFARIOUS 0.5.0 TOPIC SUPPORT + * putsock("%s " P10_TOPIC " %s %s " FMT_TIME_T " " FMT_TIME_T " :%s", service->numeric, what->name, who->nick, what->timestamp, now, topic); + * UNCOMMENT FOR NEFARIOUS 0.5.0 TOPIC SUPPORT */ + + who = service; /* REMOVE LINE FOR NEFARIOUS 0.5.0 */ + putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic); } @@ -782,13 +878,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; } @@ -800,7 +894,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) @@ -933,7 +1027,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) @@ -1005,13 +1099,39 @@ 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]))) + { + /* 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; } @@ -1030,18 +1150,25 @@ static CMD_FUNC(cmd_fakehost) static CMD_FUNC(cmd_burst) { extern int rel_age; - char modes[MAXLEN], *members = "", *banlist = NULL; + char modes[MAXLEN], *members = ""; + static char exemptlist[MAXLEN], banlist[MAXLEN]; unsigned int next = 3, res = 1; + int ctype = 0, echeck = 0, bcheck = 0; struct chanNode *cNode; struct userNode *un; struct modeNode *mNode; long mode; char *user, *end, sep; time_t in_timestamp; + char* parm = NULL; if (argc < 3) return 0; modes[0] = 0; + + exemptlist[0] = 0; + banlist[0] = 0; + while (next < argc) { switch (argv[next][0]) { case '+': { @@ -1054,9 +1181,51 @@ static CMD_FUNC(cmd_burst) next += n_modes; break; } - case '%': banlist = argv[next++]+1; break; - default: members = argv[next++]; break; + case '%': { + for(parm = mysep(&argv[next], " "); /* parm = first param */ + parm; /* While param is not null */ + parm = mysep(&argv[next], " ") /* parm = next param */ + ) + { + switch (parm[0]) { + case '%': { + ctype = 1; + break; + } + case '~': { + ctype = 2; + break; + } + default: { + break; + } + } + if (ctype == 1) { + if (bcheck == 0) { + /* strip % char off start of very first ban */ + 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)); + 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]); @@ -1065,7 +1234,7 @@ static CMD_FUNC(cmd_burst) 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); /* Burst channel members in now. */ for (user = members, sep = *members, mode = 0; sep; user = end) { @@ -1076,9 +1245,14 @@ static CMD_FUNC(cmd_burst) while ((sep = *end++)) { if (sep == 'o') mode |= MODE_CHANOP; + else if (sep == 'h') + mode |= MODE_HALFOP; else if (sep == 'v') mode |= MODE_VOICE; - else + else if (isdigit(sep)) { + mode |= MODE_CHANOP; + while (isdigit(*end)) end++; + } else break; } if (rel_age < 0) @@ -1099,6 +1273,8 @@ static CMD_FUNC(cmd_mode) { struct chanNode *cn; struct userNode *un; + char *sethost; // sethost - reed/apples + int i; // sethost - reed/apples if (argc < 3) return 0; @@ -1108,7 +1284,19 @@ static CMD_FUNC(cmd_mode) log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose mode is changing.", argv[1]); return 0; } + // sethost - reed/apples + if (argc == 3) mod_usermode(un, argv[2]); + else { + sethost = malloc(strlen(argv[2]) + 1 + strlen(argv[3]) + 1); + i = 0; + while((sethost[i++] = *argv[2]++)); + i--; + sethost[i++] = ' '; + while((sethost[i++] = *argv[3]++)); + mod_usermode(un, sethost); // sethost - reed/apples + } + return 1; } @@ -1183,6 +1371,7 @@ static CMD_FUNC(cmd_topic) { struct chanNode *cn; time_t chan_ts, topic_ts; + struct userNode *user; if (argc < 3) return 0; @@ -1190,15 +1379,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; } @@ -1243,7 +1440,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; } @@ -1376,7 +1581,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); @@ -1385,6 +1590,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; @@ -1440,6 +1661,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); @@ -1532,6 +1755,8 @@ init_parse(void) 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); @@ -1558,9 +1783,21 @@ init_parse(void) dict_insert(irc_func_dict, TOK_WALLCHOPS, cmd_dummy); dict_insert(irc_func_dict, CMD_WALLVOICES, cmd_dummy); dict_insert(irc_func_dict, TOK_WALLVOICES, cmd_dummy); + dict_insert(irc_func_dict, CMD_WALLHOPS, cmd_dummy); + dict_insert(irc_func_dict, TOK_WALLHOPS, cmd_dummy); /* Ignore opers being silly. */ dict_insert(irc_func_dict, CMD_WALLOPS, cmd_dummy); 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); @@ -1573,11 +1810,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?) */ @@ -1801,7 +2040,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(); @@ -1820,7 +2059,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 * @@ -1846,12 +2086,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; @@ -1932,6 +2173,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; } @@ -1941,9 +2186,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); @@ -1982,15 +2232,16 @@ 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++; \ + 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++) { @@ -1998,13 +2249,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); @@ -2018,7 +2271,22 @@ 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 'h': do_user_mode(FLAGS_HELPER); 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, + // then everything after the space becomes their new host. + case 'h': do_user_mode(FLAGS_SETHOST); + if (*word) { + char sethost[MAXLEN]; + unsigned int ii; + for (ii=0; (*word != ' ') && (*word != '\0'); ) + sethost[ii++] = *word++; + sethost[ii] = 0; + while (*word == ' ') + word++; + safestrncpy(user->sethost, sethost, sizeof(user->sethost)); + } + break; case 'x': do_user_mode(FLAGS_HIDDEN_HOST); break; case 'r': if (*word) { @@ -2081,6 +2349,22 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un case 'r': do_chan_mode(MODE_REGONLY); break; case 's': do_chan_mode(MODE_SECRET); break; case 't': do_chan_mode(MODE_TOPICLIMIT); break; + case 'S': do_chan_mode(MODE_STRIPCOLOR); break; + case 'M': do_chan_mode(MODE_MODUNREG); break; + case 'N': do_chan_mode(MODE_NONOTICE); break; + 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); + } else { + mod_chanmode_free(change); + return NULL; + } + break; #undef do_chan_mode case 'l': if (add) { @@ -2116,16 +2400,33 @@ 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 'v': + case 'o': case 'h': case 'v': { struct userNode *victim; if (!(flags & MCP_ALLOW_OVB)) goto error; if (in_arg >= argc) goto error; - change->args[ch_arg].mode = (modes[0][ii] == 'o') ? MODE_CHANOP : MODE_VOICE; + + if (modes[0][ii] == 'o') + change->args[ch_arg].mode = MODE_CHANOP; + else if (modes[0][ii] == 'h') + change->args[ch_arg].mode = MODE_HALFOP; + else if (modes[0][ii] == 'v') + change->args[ch_arg].mode = MODE_VOICE; + if (!add) change->args[ch_arg].mode |= MODE_REMOVE; if (flags & MCP_FROM_SERVER) @@ -2134,7 +2435,7 @@ 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))) ch_arg++; break; } @@ -2224,6 +2525,15 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(REGONLY, 'r'); DO_MODE_CHAR(NOCOLORS, 'c'); DO_MODE_CHAR(NOCTCPS, 'C'); + DO_MODE_CHAR(STRIPCOLOR, 'S'); + DO_MODE_CHAR(MODUNREG, 'M'); + DO_MODE_CHAR(NONOTICE, 'N'); + DO_MODE_CHAR(NOQUITMSGS, 'Q'); + DO_MODE_CHAR(NOAMSG, 'T'); + DO_MODE_CHAR(OPERSONLY, 'O'); + 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); @@ -2235,13 +2545,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].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; } } @@ -2262,6 +2577,15 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(REGONLY, 'r'); DO_MODE_CHAR(NOCOLORS, 'c'); DO_MODE_CHAR(NOCTCPS, 'C'); + DO_MODE_CHAR(STRIPCOLOR, 'S'); + DO_MODE_CHAR(MODUNREG, 'M'); + DO_MODE_CHAR(NONOTICE, 'N'); + DO_MODE_CHAR(NOQUITMSGS, 'Q'); + DO_MODE_CHAR(NOAMSG, 'T'); + DO_MODE_CHAR(OPERSONLY, 'O'); + 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); @@ -2277,13 +2601,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].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; } } @@ -2317,6 +2646,15 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(REGONLY, 'r'); DO_MODE_CHAR(NOCOLORS, 'c'); DO_MODE_CHAR(NOCTCPS, 'C'); + DO_MODE_CHAR(STRIPCOLOR, 'S'); + DO_MODE_CHAR(MODUNREG, 'M'); + DO_MODE_CHAR(NONOTICE, 'N'); + DO_MODE_CHAR(NOQUITMSGS, 'Q'); + DO_MODE_CHAR(NOAMSG, 'T'); + DO_MODE_CHAR(OPERSONLY, 'O'); + DO_MODE_CHAR(REGISTERED, 'z'); + DO_MODE_CHAR(SSLONLY, 'Z'); + DO_MODE_CHAR(HIDEMODE, 'L'); #undef DO_MODE_CHAR } if (change->modes_set) { @@ -2332,6 +2670,15 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(REGONLY, 'r'); DO_MODE_CHAR(NOCOLORS, 'c'); DO_MODE_CHAR(NOCTCPS, 'C'); + DO_MODE_CHAR(STRIPCOLOR, 'S'); + DO_MODE_CHAR(MODUNREG, 'M'); + DO_MODE_CHAR(NONOTICE, 'N'); + DO_MODE_CHAR(NOQUITMSGS, 'Q'); + DO_MODE_CHAR(NOAMSG, 'T'); + DO_MODE_CHAR(OPERSONLY, 'O'); + 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)) { case MODE_KEY|MODE_LIMIT: @@ -2357,6 +2704,7 @@ clear_chanmode(struct chanNode *channel, const char *modes) for (remove = 0; *modes; modes++) { switch (*modes) { case 'o': remove |= MODE_CHANOP; break; + case 'h': remove |= MODE_HALFOP; break; case 'v': remove |= MODE_VOICE; break; case 'p': remove |= MODE_PRIVATE; break; case 's': remove |= MODE_SECRET; break; @@ -2373,10 +2721,20 @@ clear_chanmode(struct chanNode *channel, const char *modes) 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; + case 'N': remove |= MODE_NONOTICE; break; + case 'Q': remove |= MODE_NOQUITMSGS; break; + case 'T': remove |= MODE_NOAMSG; break; + case 'O': remove |= MODE_OPERSONLY; break; + case 'z': remove |= MODE_REGISTERED; break; + case 'Z': remove |= MODE_SSLONLY; break; + case 'L': remove |= MODE_HIDEMODE; break; } } @@ -2394,9 +2752,17 @@ 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_VOICE)) && channel->members.used) { - int mask = ~(remove & (MODE_CHANOP | MODE_VOICE)); + if ((remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) && channel->members.used) { + int mask = ~(remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)); unsigned int i; for (i = 0; i < channel->members.used; i++)