X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fproto-p10.c;h=f544f9f019a2ddc3799bb19de4e0dc013e0a982a;hb=0a7f0a288c131806db7b8538554b918a99c1a21d;hp=e29db35e6d42aab48d0c51c2daadea4fa3c01efe;hpb=c2c7d0f8759646e6bc3a7f9f9a308cb106863790;p=srvx.git diff --git a/src/proto-p10.c b/src/proto-p10.c index e29db35..f544f9f 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -40,6 +40,7 @@ #define CMD_EOB_ACK "EOB_ACK" #define CMD_ERROR "ERROR" #define CMD_FAKEHOST "FAKE" +#define CMD_FAKEHOST2 "FAKE2" #define CMD_GET "GET" #define CMD_GLINE "GLINE" #define CMD_HASH "HASH" @@ -72,6 +73,7 @@ #define CMD_PROTO "PROTO" #define CMD_QUIT "QUIT" #define CMD_REHASH "REHASH" +#define CMD_RELAY "RELAY" #define CMD_RESET "RESET" #define CMD_RESTART "RESTART" #define CMD_RPING "RPING" @@ -86,6 +88,8 @@ #define CMD_SQUIT "SQUIT" #define CMD_STATS "STATS" #define CMD_SVSNICK "SVSNICK" +#define CMD_SVSMODE "SVSMODE" +#define CMD_SVSJOIN "SVSJOIN" #define CMD_TIME "TIME" #define CMD_TOPIC "TOPIC" #define CMD_TRACE "TRACE" @@ -101,6 +105,8 @@ #define CMD_WHO "WHO" #define CMD_WHOIS "WHOIS" #define CMD_WHOWAS "WHOWAS" +#define CMD_XQUERY "XQUERY" +#define CMD_XRESPONSE "XRESPONSE" /* Tokenized commands. */ #define TOK_ACCOUNT "AC" @@ -122,6 +128,7 @@ #define TOK_EOB_ACK "EA" #define TOK_ERROR "Y" #define TOK_FAKEHOST "FA" +#define TOK_FAKEHOST2 "NFH" #define TOK_GET "GET" #define TOK_GLINE "GL" #define TOK_HASH "HASH" @@ -154,6 +161,7 @@ #define TOK_PROTO "PROTO" #define TOK_QUIT "Q" #define TOK_REHASH "REHASH" +#define TOK_RELAY "RL" #define TOK_RESET "RESET" #define TOK_RESTART "RESTART" #define TOK_RPING "RI" @@ -168,6 +176,8 @@ #define TOK_SQUIT "SQ" #define TOK_STATS "R" #define TOK_SVSNICK "SN" +#define TOK_SVSMODE "SM" +#define TOK_SVSJOIN "SJ" #define TOK_TIME "TI" #define TOK_TOPIC "T" #define TOK_TRACE "TR" @@ -183,6 +193,8 @@ #define TOK_WHO "H" #define TOK_WHOIS "W" #define TOK_WHOWAS "X" +#define TOK_XQUERY "XQ" +#define TOK_XRESPONSE "XR" /* Protocol messages; aliased to full commands or tokens depending on compile-time configuration. ircu prefers tokens WITH THE @@ -215,6 +227,7 @@ #define P10_EOB_ACK TYPE(EOB_ACK) #define P10_ERROR TYPE(ERROR) #define P10_FAKEHOST TYPE(FAKEHOST) +#define P10_FAKEHOST2 TYPE(FAKEHOST2) #define P10_GET TYPE(GET) #define P10_GLINE TYPE(GLINE) #define P10_HASH TYPE(HASH) @@ -247,6 +260,7 @@ #define P10_PROTO TYPE(PROTO) #define P10_QUIT TYPE(QUIT) #define P10_REHASH TYPE(REHASH) +#define P10_RELAY TYPE(RELAY) #define P10_RESET TYPE(RESET) #define P10_RESTART TYPE(RESTART) #define P10_RPING TYPE(RPING) @@ -261,6 +275,8 @@ #define P10_SQUIT TYPE(SQUIT) #define P10_STATS TYPE(STATS) #define P10_SVSNICK TYPE(SVSNICK) +#define P10_SVSMODE TYPE(SVSMODE) +#define P10_SVSJOIN TYPE(SVSJOIN) #define P10_TIME TYPE(TIME) #define P10_TOPIC TYPE(TOPIC) #define P10_TRACE TYPE(TRACE) @@ -276,6 +292,8 @@ #define P10_WHO TYPE(WHO) #define P10_WHOIS TYPE(WHOIS) #define P10_WHOWAS TYPE(WHOWAS) +#define P10_XQUERY TYPE(XQUERY) +#define P10_XRESPONSE TYPE(XRESPONSE) /* Servers claiming to have a boot or link time before PREHISTORY * trigger errors to the log. We hope no server has been running @@ -493,7 +511,31 @@ irc_account(struct userNode *user, const char *stamp, unsigned long timestamp, u void irc_fakehost(struct userNode *user, const char *host, const char *ident, int force) { - putsock("%s " P10_FAKEHOST " %s %s %s%s", self->numeric, user->numeric, ident, host, force ? " FORCE" : ""); + /* SRVX added the possibility for FAKE IDENTS + * but this is currently *NOT* supported by our IRCu + * + * edit 24.11.11: + * NFH (P10_FAKEHOST2) is now supported by our IRCu (git-65-21592a4) + */ + putsock("%s " P10_FAKEHOST2 " %s %s %s%s", self->numeric, user->numeric, ident, host, force ? " FORCE" : ""); +} + +void +irc_relay(char *message) +{ + putsock("%s " P10_RELAY " %s", self->numeric, message); +} + +void +irc_simul(struct userNode *target, char *command) +{ + putsock("%s " P10_RELAY " %s SI %s :%s", self->numeric, target->numeric, target->numeric, command); +} + +void +irc_keepconn(struct userNode *target, unsigned int timeout) +{ + putsock("%s " P10_RELAY " %s KC %s %u", self->numeric, target->numeric, target->numeric, timeout); } void @@ -594,6 +636,24 @@ irc_privmsg(struct userNode *from, const char *to, const char *message) putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message); } +void +irc_svsmode(struct userNode *from, struct userNode *user, const char *modes) +{ +putsock("%s " P10_SVSMODE " %s %s", from->numeric, user->numeric, modes); +} + +void +irc_svsjoin(struct userNode *from, struct userNode *user, struct chanNode *chan) +{ +putsock("%s " P10_SVSJOIN " %s %s", from->numeric, user->numeric, chan->name); +} + +void +irc_svsjoinchan(struct userNode *from, struct userNode *user, const char *chan) +{ +putsock("%s " P10_SVSJOIN " %s %s", from->numeric, user->numeric, chan); +} + void irc_eob(void) { @@ -654,12 +714,16 @@ irc_introduce(const char *passwd) void irc_gline(struct server *srv, struct gline *gline) { + // GL [!][+|-|>|<] [] [] [] [:] + //expiration = relative time (seconds) + //lastmod = timestamp + //livetime = timestamp if (gline->lastmod) - putsock("%s " P10_GLINE " %s +%s %lu %lu %lu :%s", - self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires, gline->lastmod, gline->lifetime, gline->reason); + putsock("%s " P10_GLINE " %s +%s %lu %lu %lu :%s", self->numeric, (srv ? srv->numeric : "*"), + gline->target, gline->expires-now, gline->lastmod, gline->lifetime, gline->reason); else - putsock("%s " P10_GLINE " %s +%s %lu :%s", - self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires, gline->reason); + putsock("%s " P10_GLINE " %s +%s %lu :%s", self->numeric, (srv ? srv->numeric : "*"), + gline->target, gline->expires-now, gline->reason); } void @@ -675,6 +739,7 @@ void irc_ungline(const char *mask) { putsock("%s " P10_GLINE " * -%s %lu", self->numeric, mask, now); + //putsock("%s " P10_GLINE " * %s * %lu", self->numeric, mask, now); } /* Return negative if *(struct modeNode**)pa is "less than" pb, @@ -908,6 +973,12 @@ irc_numeric(struct userNode *user, unsigned int num, const char *format, ...) putsock(":%s %03d %s %s", self->name, num, user->nick, buffer); } +void +irc_xresponse(struct server *target, const char *routing, const char *response) +{ + putsock("%s " P10_XRESPONSE " %s %s :%s", self->numeric, target->numeric, routing, response); +} + static void send_burst(void); static void @@ -1156,6 +1227,8 @@ create_helper(char *name, void *data) return; } + handle_new_channel_created(name, cd->user); + AddChannelUser(cd->user, AddChannel(name, cd->when, NULL, NULL)); } @@ -1434,7 +1507,7 @@ static CMD_FUNC(cmd_clearmode) static CMD_FUNC(cmd_topic) { struct chanNode *cn; - unsigned long chan_ts, topic_ts; + unsigned long topic_ts; if (argc < 3) return 0; @@ -1444,10 +1517,8 @@ static CMD_FUNC(cmd_topic) } if (argc >= 5) { /* Looks like an Asuka style topic burst. */ - chan_ts = atoi(argv[2]); topic_ts = atoi(argv[3]); } else { - chan_ts = cn->timestamp; topic_ts = now; } SetChannelTopic(cn, GetUserH(origin), argv[argc-1], 0); @@ -1546,6 +1617,8 @@ static CMD_FUNC(cmd_kick) { if (argc < 3) return 0; + if (GetUserN(argv[2]) && IsOper(GetUserN(argv[2]))) + operpart(GetChannel(argv[1]), GetUserN(argv[2])); ChannelUserKicked(GetUserH(origin), GetUserN(argv[2]), GetChannel(argv[1])); return 1; } @@ -1668,6 +1741,115 @@ static CMD_FUNC(cmd_time) return 1; } +static CMD_FUNC(cmd_relay) +{ + struct server *sNode; + unsigned int len; + char buf[3]; + // RELAY + len = strlen(argv[1]); + buf[2] = 0; + switch(len) { + case 2: + sNode = GetServerN(argv[1]); + break; + case 5: + buf[0] = argv[1][0]; + buf[1] = argv[1][1]; + sNode = GetServerN(buf); + break; + case 6: + buf[0] = argv[1][1]; + buf[1] = argv[1][2]; + sNode = GetServerN(buf); + break; + default: + /* Invalid destination. Ignore. */ + return 0; + } + if(sNode->numeric == self->numeric) { + //ok someone relayed something to us! + if(strcmp("LQ", argv[2]) == 0) { + //oooh thats exciting - we've got a LOC Query! :D + //LQ !ABADE pk910 80.153.5.212 server.zoelle1.de ~watchcat :test + //ok let's check the login datas + struct handle_info *hi; + char tmp[MAXLEN], tmp2[MAXLEN]; + sprintf(tmp, "%s@%s",argv[7],argv[6]); + sprintf(tmp2, "%s@%s",argv[7],argv[5]); + if((hi = checklogin(argv[4],argv[argc-1],&argv[3][1],tmp,tmp2))) { + //login ok + struct devnull_class *th; + char devnull[512]; + if(hi->devnull && (th = devnull_get(hi->devnull))) { + const char *devnull_modes = DEVNULL_MODES; + int ii, flen; + char flags[50]; + for (ii=flen=0; devnull_modes[ii]; ++ii) + if (th->modes & (1 << ii)) + flags[flen++] = devnull_modes[ii]; + flags[flen] = 0; + sprintf(devnull, "+%s %s %lu %lu",flags,th->name,th->maxchan,th->maxsendq); + } else { + devnull[0] = 0; + } + if(!HANDLE_FLAGGED(hi, AUTOHIDE)) { + sprintf(tmp,"%s LA %s 0 %s\n",argv[3],hi->handle,devnull); + } else if(getfakehost(argv[4])) { + sprintf(tmp,"%s LA %s %s %s\n",argv[3],hi->handle,getfakehost(argv[4]),devnull); + } else { + extern const char *hidden_host_suffix; + sprintf(tmp,"%s LA %s %s.%s %s\n",argv[3],hi->handle,hi->handle,hidden_host_suffix,devnull); + } + irc_relay(tmp); + } else { + //login rejected + sprintf(tmp,"%s LR\n",argv[3]); + irc_relay(tmp); + } + } else if(strcmp("UC", argv[2]) == 0) { + char tmp[MAXLEN]; + sprintf(tmp,"%s UC %s %s",argv[3],argv[3],argv[4]); + irc_relay(tmp); + } else if(strcmp("JA", argv[2]) == 0) { + struct userData *uData; + struct chanNode *cn; + struct userNode *user; + char tmp[MAXLEN]; + cn = GetChannel(argv[4]); + if (!cn) return 0; + if (!(user = GetUserN(argv[3]))) return 0; + if(!cn->channel_info) { + //channel not registered + sprintf(tmp,"%s JAA %s %s\n",argv[3],cn->name,argv[6]); + } else if((uData = GetChannelUser(cn->channel_info, user->handle_info))) { + if(uData->access >= atoi(argv[5])) { + //we can join + sprintf(tmp,"%s JAA %s %s\n",argv[3],cn->name,argv[6]); + } else { + //access too low + sprintf(tmp,"%s JAR %s %i %i\n",argv[3],cn->name,uData->access,uData->access); + } + } else { + //0 access + sprintf(tmp,"%s JAR %s %s %s\n",argv[3],cn->name,"0","0"); + } + irc_relay(tmp); + } + } + return 1; +} + +static CMD_FUNC(cmd_xquery) +{ + struct server *source; + if ((argc < 4) + || !(source = GetServerH(origin))) + return 0; + call_xquery_funcs(source, argv[2], argv[3]); + return 1; +} + void free_user(struct userNode *user) { @@ -1795,6 +1977,8 @@ 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_RELAY, cmd_relay); + dict_insert(irc_func_dict, TOK_RELAY, cmd_relay); 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); @@ -1809,6 +1993,8 @@ init_parse(void) dict_insert(irc_func_dict, TOK_ADMIN, cmd_admin); dict_insert(irc_func_dict, CMD_TIME, cmd_time); dict_insert(irc_func_dict, TOK_TIME, cmd_time); + /* We don't handle XR or the (not really defined) XQUERY. */ + dict_insert(irc_func_dict, TOK_XQUERY, cmd_xquery); /* In P10, DESTRUCT doesn't do anything except be broadcast to servers. * Apparently to obliterate channels from any servers that think they @@ -2082,7 +2268,6 @@ AddLocalUser(const char *nick, const char *ident, const char *hostname, const ch { char numeric[COMBO_NUMERIC_LEN+1]; int local_num = get_local_numeric(); - unsigned long timestamp = now; struct userNode *old_user = GetUserH(nick); if (!modes) @@ -2090,7 +2275,6 @@ AddLocalUser(const char *nick, const char *ident, const char *hostname, const ch if (old_user) { if (IsLocal(old_user)) return old_user; - timestamp = old_user->timestamp - 1; } if (local_num == -1) { log_module(MAIN_LOG, LOG_ERROR, "Unable to allocate numnick for service %s", nick); @@ -2302,8 +2486,10 @@ void mod_usermode(struct userNode *user, const char *mode_change) { case 'o': do_user_mode(FLAGS_OPER); if (!add) { + operdel(user); userList_remove(&curr_opers, user); } else if (!userList_contains(&curr_opers, user)) { + operadd(user); userList_append(&curr_opers, user); call_oper_funcs(user); } @@ -2401,7 +2587,7 @@ keyncpy(char output[], char input[], size_t output_size) } struct mod_chanmode * -mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags, short base_oplevel) +mod_chanmode_parse(struct chanNode *channel, struct userNode *user, char **modes, unsigned int argc, unsigned int flags, short base_oplevel) { struct mod_chanmode *change; unsigned int ii, in_arg, ch_arg, add; @@ -2427,6 +2613,8 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un case 'c': do_chan_mode(MODE_NOCOLORS); break; case 'M': do_chan_mode(MODE_NOAMSGS); break; case 'N': do_chan_mode(MODE_NONOTICES); break; + case 'u': do_chan_mode(MODE_AUDITORIUM); break; + case 'S': do_chan_mode(MODE_SSLCHAN); break; case 'i': do_chan_mode(MODE_INVITEONLY); break; case 'm': do_chan_mode(MODE_MODERATED); break; case 'n': do_chan_mode(MODE_NOPRIVMSGS); break; @@ -2437,12 +2625,12 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un case 'z': if (!(flags & MCP_REGISTERED) && (!(flags & MCP_IGN_REGISTERED) || add)) { do_chan_mode(MODE_REGISTERED); -+ } else if (flags & MCP_IGN_REGISTERED) { -+ /* ignore the modechange but continue parsing */ - } else { + } else if (flags & MCP_IGN_REGISTERED) { + /* ignore the modechange but continue parsing */ + } else { mod_chanmode_free(change); return NULL; - } + } break; #undef do_chan_mode case 'l': @@ -2482,12 +2670,66 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un } } break; + case 'f': + if (add) { + if (in_arg >= argc) + goto error; + char *mode = modes[in_arg++]; + if(mode[0] == '!' && !(flags & MCP_OPERMODE)) //noflood flag also for overriders + goto error;//only allow opers + else if(mode[0] == '!') + mode++; + + if(mode[0] == '+' || mode[0] == '@') { + mode++; + } + char *p; + int count = 0, time = 0; + for(p = mode; p[0]; p++) { + if(p[0] == ':') { + char tmpchar = p[0]; + p[0] = '\0'; + count = strtoul(mode,0,10); + p[0] = tmpchar; + p++; + time = strtoul(p,0,10); + break; + } + } + if(count <= 0 || time <= 0 || count > 100 || time > 600) + goto error; + change->modes_set |= MODE_NOFLOOD; + safestrncpy(change->new_noflood, modes[in_arg - 1], sizeof(change->new_noflood)); + } else { + change->modes_clear |= MODE_NOFLOOD; + } + break; case 'F': if (add) { if (in_arg >= argc) goto error; + char *altchan = modes[in_arg++]; + struct chanNode *target; + if(!IsChannelName(altchan) || !(target = GetChannel(altchan))) + goto error; + if(!(flags & MCP_OPERMODE)) { + //check if the user has the permissions to use this channel as target + struct modeNode *mn; + struct userData *uData; + struct chanData *cData; + if(user && (mn = GetUserMode(target, user)) && (mn->modes & MODE_CHANOP)) { + //allow - user is opped on target channel + } else if(user && user->handle_info && + (uData = GetChannelUser(channel->channel_info, user->handle_info)) && + (cData = uData->channel) && + uData->access >= cData->lvlOpts[lvlGiveOps] + ) { + //allow - user has access to get op on the channel + } else + goto error; + } change->modes_set |= MODE_ALTCHAN; - safestrncpy(change->new_altchan, modes[in_arg++], sizeof(change->new_altchan)); + safestrncpy(change->new_altchan, altchan, sizeof(change->new_altchan)); } else { change->modes_clear |= MODE_ALTCHAN; } @@ -2674,12 +2916,15 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(LIMIT, 'l'); DO_MODE_CHAR(ACCESS, 'a'); DO_MODE_CHAR(ALTCHAN, 'F'); + DO_MODE_CHAR(NOFLOOD, 'f'); DO_MODE_CHAR(DELAYJOINS, 'D'); DO_MODE_CHAR(REGONLY, 'r'); DO_MODE_CHAR(NOCOLORS, 'c'); DO_MODE_CHAR(NOCTCPS, 'C'); DO_MODE_CHAR(NONOTICES, 'N'); DO_MODE_CHAR(NOAMSGS, 'M'); + DO_MODE_CHAR(AUDITORIUM, 'u'); + DO_MODE_CHAR(SSLCHAN, 'S'); DO_MODE_CHAR(REGISTERED, 'z'); #undef DO_MODE_CHAR if (change->modes_clear & channel->modes & MODE_KEY) @@ -2725,6 +2970,8 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod DO_MODE_CHAR(NOCTCPS, 'C'); DO_MODE_CHAR(NONOTICES, 'N'); DO_MODE_CHAR(NOAMSGS, 'M'); + DO_MODE_CHAR(AUDITORIUM, 'u'); + DO_MODE_CHAR(SSLCHAN, 'S'); DO_MODE_CHAR(REGISTERED, 'z'); #undef DO_MODE_CHAR if(change->modes_set & MODE_KEY) @@ -2743,6 +2990,8 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod } if (change->modes_set & MODE_ALTCHAN) mod_chanmode_append(&chbuf, 'F', change->new_altchan); + if (change->modes_set & MODE_NOFLOOD) + mod_chanmode_append(&chbuf, 'f', change->new_noflood); } for (arg = 0; arg < change->argc; ++arg) { if (change->args[arg].mode & MODE_REMOVE) @@ -2791,6 +3040,7 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(LIMIT, 'l'); DO_MODE_CHAR(ACCESS, 'a'); DO_MODE_CHAR(ALTCHAN, 'F'); + DO_MODE_CHAR(NOFLOOD, 'f'); DO_MODE_CHAR(KEY, 'k'); DO_MODE_CHAR(UPASS, 'U'); DO_MODE_CHAR(APASS, 'A'); @@ -2800,6 +3050,8 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(NOCTCPS, 'C'); DO_MODE_CHAR(NONOTICES, 'N'); DO_MODE_CHAR(NOAMSGS, 'M'); + DO_MODE_CHAR(AUDITORIUM, 'u'); + DO_MODE_CHAR(SSLCHAN, 'S'); DO_MODE_CHAR(REGISTERED, 'z'); #undef DO_MODE_CHAR } @@ -2818,11 +3070,14 @@ mod_chanmode_format(struct mod_chanmode *change, char *outbuff) DO_MODE_CHAR(NOCTCPS, 'C'); DO_MODE_CHAR(NONOTICES, 'N'); DO_MODE_CHAR(NOAMSGS, 'M'); + DO_MODE_CHAR(AUDITORIUM, 'u'); + DO_MODE_CHAR(SSLCHAN, 'S'); DO_MODE_CHAR(REGISTERED, 'z'); DO_MODE_CHAR(LIMIT, 'l'), args_used += sprintf(args + args_used, " %d", change->new_limit); DO_MODE_CHAR(KEY, 'k'), args_used += sprintf(args + args_used, " %s", change->new_key); - DO_MODE_CHAR(KEY, 'a'), args_used += sprintf(args + args_used, " %s", change->new_access); - DO_MODE_CHAR(KEY, 'F'), args_used += sprintf(args + args_used, " %s", change->new_altchan); + DO_MODE_CHAR(ACCESS, 'a'), args_used += sprintf(args + args_used, " %d", change->new_access); + DO_MODE_CHAR(ALTCHAN, 'F'), args_used += sprintf(args + args_used, " %s", change->new_altchan); + DO_MODE_CHAR(NOFLOOD, 'f'), args_used += sprintf(args + args_used, " %s", change->new_noflood); DO_MODE_CHAR(UPASS, 'U'), args_used += sprintf(args + args_used, " %s", change->new_upass); DO_MODE_CHAR(APASS, 'A'), args_used += sprintf(args + args_used, " %s", change->new_apass); #undef DO_MODE_CHAR @@ -2851,6 +3106,10 @@ clear_chanmode(struct chanNode *channel, const char *modes) cleared |= MODE_ALTCHAN; channel->altchan[0] = '\0'; break; + case 'f': + cleared |= MODE_NOFLOOD; + channel->noflood[0] = '\0'; + break; case 'k': cleared |= MODE_KEY; channel->key[0] = '\0'; @@ -2877,6 +3136,8 @@ clear_chanmode(struct chanNode *channel, const char *modes) case 'c': cleared |= MODE_NOCOLORS; break; case 'C': cleared |= MODE_NOCTCPS; break; case 'M': cleared |= MODE_NOAMSGS; break; + case 'u': cleared |= MODE_AUDITORIUM; break; + case 'S': cleared |= MODE_SSLCHAN; break; case 'N': cleared |= MODE_NONOTICES; break; case 'z': cleared |= MODE_REGISTERED; break; }