static void cs_cmd_unban(struct sourceinfo *si, int parc, char *parv[]) { const char *channel = parv[0]; const char *target = parv[1]; struct channel *c = channel_find(channel); struct mychan *mc = mychan_find(channel); struct user *tu; struct chanban *cb; if (si->su == NULL) { command_fail(si, fault_noprivs, STR_IRC_COMMAND_ONLY, "UNBAN"); return; } if (!channel) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "UNBAN"); command_fail(si, fault_needmoreparams, _("Syntax: UNBAN <#channel>")); return; } if (target && irccasecmp(target, si->su->nick)) { command_fail(si, fault_noprivs, _("You may only unban yourself via %s."), si->service->nick); if (validhostmask(target)) command_fail(si, fault_noprivs, _("Try \2/mode %s -b %s\2"), channel, target); return; } target = si->su->nick; if (!mc) { command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, channel); return; } if (!c) { command_fail(si, fault_nosuch_target, STR_CHANNEL_IS_EMPTY, channel); return; } if (!si->smu) { command_fail(si, fault_noprivs, STR_NOT_LOGGED_IN); return; } if (!chanacs_source_has_flag(mc, si, CA_REMOVE) && !chanacs_source_has_flag(mc, si, CA_EXEMPT)) { command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED); return; } tu = si->su; { mowgli_node_t *n, *tn; char hostbuf2[BUFSIZE]; unsigned int count = 0; snprintf(hostbuf2, BUFSIZE, "%s!%s@%s", tu->nick, tu->user, tu->vhost); for (n = next_matching_ban(c, tu, 'b', c->bans.head); n != NULL; n = next_matching_ban(c, tu, 'b', tn)) { tn = n->next; cb = n->data; logcommand(si, CMDLOG_DO, "UNBAN: \2%s\2 \2%s\2 (for user \2%s\2)", mc->name, cb->mask, hostbuf2); modestack_mode_param(chansvs.nick, c, MTYPE_DEL, cb->type, cb->mask); chanban_delete(cb); count++; } if (count > 0) command_success_nodata(si, ngettext(N_("Unbanned \2%s\2 on \2%s\2 (%u ban removed)."), N_("Unbanned \2%s\2 on \2%s\2 (%u bans removed)."), count), target, channel, count); else command_success_nodata(si, _("No bans found matching \2%s\2 on \2%s\2."), target, channel); return; } }
static void cs_cmd_up(sourceinfo_t *si, int parc, char *parv[]) { chanuser_t *cu; mychan_t *mc; char *name = parv[0]; char *chan = parv[0]; int fl; if (!name) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "UP"); command_fail(si, fault_needmoreparams, "Syntax: UP <#channel>"); return; } if (!(mc = mychan_find(name))) { command_fail(si, fault_nosuch_target, "\2%s\2 is not registered.", name); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, "\2%s\2 is closed.", name); return; } if (metadata_find(mc, "private:frozen:freezer")) { command_fail(si, fault_noprivs, _("\2%s\2 is frozen."), chan); return; } if (!mc->chan) { command_fail(si, fault_nosuch_target, "\2%s\2 does not exist.", name); return; } if (!si->su) return; // needs to be done over IRC if (chanacs_source_has_flag(mc, si, CA_SUSPENDED)) { command_fail(si, fault_noprivs, _("Your access in %s is \2suspended\2."), chan); return; } cu = chanuser_find(mc->chan, si->su); if (!cu) { command_fail(si, fault_nosuch_target, "You are not on \2%s\2.", mc->name); return; } fl = chanacs_user_flags(mc, cu->user); // Don't check NOOP, because they are explicitly requesting status if (ircd->uses_owner) { if (fl & CA_USEOWNER) { if (fl & CA_AUTOOP && !(ircd->owner_mode & cu->modes)) { modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, ircd->owner_mchar[1], CLIENT_NAME(cu->user)); cu->modes |= ircd->owner_mode; } } } if (ircd->uses_protect) { if (fl & CA_USEPROTECT) { if (fl & CA_AUTOOP && !(ircd->protect_mode & cu->modes) && !(ircd->uses_owner && cu->modes & ircd->owner_mode)) { modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, ircd->protect_mchar[1], CLIENT_NAME(cu->user)); cu->modes |= ircd->protect_mode; } } } if (fl & (CA_AUTOOP | CA_OP)) { if (fl & CA_AUTOOP && !(CSTATUS_OP & cu->modes)) { modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, 'o', CLIENT_NAME(cu->user)); cu->modes |= CSTATUS_OP; } } if (ircd->uses_halfops) { if (fl & (CA_AUTOHALFOP | CA_HALFOP)) { if (fl & CA_AUTOHALFOP && !(ircd->halfops_mode & cu->modes)) { modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, ircd->halfops_mchar[1], CLIENT_NAME(cu->user)); cu->modes |= ircd->halfops_mode; } } } if (fl & (CA_AUTOVOICE | CA_VOICE)) { if (fl & CA_AUTOVOICE && !(CSTATUS_VOICE & cu->modes)) { modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, 'v', CLIENT_NAME(cu->user)); cu->modes |= CSTATUS_VOICE; } } command_success_nodata(si, "Upped successfully on \2%s\2.", mc->name); }
static void cs_cmd_deop(sourceinfo_t *si, int parc, char *parv[]) { char *chan = parv[0]; char *nick = parv[1]; mychan_t *mc; user_t *tu; chanuser_t *cu; if (!chan) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DEOP"); command_fail(si, fault_needmoreparams, _("Syntax: DEOP <#channel> [nickname]")); return; } mc = mychan_find(chan); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), chan); return; } if (!chanacs_source_has_flag(mc, si, CA_OP)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), chan); return; } /* figure out who we're going to deop */ if (!nick) tu = si->su; else { if (!(tu = user_find_named(nick))) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not online."), nick); return; } } if (is_internal_client(tu)) return; cu = chanuser_find(mc->chan, tu); if (!cu) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not on \2%s\2."), tu->nick, mc->name); return; } modestack_mode_param(chansvs.nick, mc->chan, MTYPE_DEL, 'o', CLIENT_NAME(tu)); cu->modes &= ~CSTATUS_OP; if (si->c == NULL && tu != si->su) change_notify(chansvs.nick, tu, "You have been deopped on %s by %s", mc->name, get_source_name(si)); logcommand(si, CMDLOG_DO, "DEOP: \2%s!%s@%s\2 on \2%s\2", tu->nick, tu->user, tu->vhost, mc->name); if (!chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("\2%s\2 has been deopped on \2%s\2."), tu->nick, mc->name); }
static void cs_cmd_set_fantasy(struct sourceinfo *si, int parc, char *parv[]) { struct mychan *mc; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, parv[0]); return; } if (!parv[1]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET FANTASY"); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED); return; } if (!strcasecmp("ON", parv[1])) { struct metadata *md = metadata_find(mc, "disable_fantasy"); if (!md) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel \2%s\2."), "FANTASY", mc->name); return; } metadata_delete(mc, "disable_fantasy"); logcommand(si, CMDLOG_SET, "SET:FANTASY:ON: \2%s\2", mc->name); verbose(mc, "\2%s\2 enabled the FANTASY flag", get_source_name(si)); command_success_nodata(si, _("The \2%s\2 flag has been set for channel \2%s\2."), "FANTASY", mc->name); return; } else if (!strcasecmp("OFF", parv[1])) { struct metadata *md = metadata_find(mc, "disable_fantasy"); if (md) { command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for channel \2%s\2."), "FANTASY", mc->name); return; } metadata_add(mc, "disable_fantasy", "on"); logcommand(si, CMDLOG_SET, "SET:FANTASY:OFF: \2%s\2", mc->name); verbose(mc, "\2%s\2 disabled the FANTASY flag", get_source_name(si)); command_success_nodata(si, _("The \2%s\2 flag has been removed for channel \2%s\2."), "FANTASY", mc->name); return; } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "SET FANTASY"); return; } }
static void cs_cmd_set_pubacl(sourceinfo_t *si, int parc, char *parv[]) { mychan_t *mc; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), parv[0]); return; } if (!parv[1]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET PUBACL"); return; } if (!(chanacs_source_has_flag(mc, si, CA_SET) || chanacs_source_has_flag(mc, si, CA_FOUNDER))) { command_fail(si, fault_noprivs, _("You are not authorized to perform this command.")); return; } if (!strcasecmp("ON", parv[1]) || !strcasecmp("1", parv[1]) || !strcasecmp("TRUE", parv[1])) { if (MC_PUBACL & mc->flags) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel: \2%s\2"), "PUBACL", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:PUBACL:ON: \2%s\2", mc->name); verbose(mc, _("\2%s\2 enabled the PUBACL flag."), get_source_name(si)); mc->flags |= MC_PUBACL; command_success_nodata(si, _("The \2%s\2 flag has been set for channel: \2%s\2"), "PUBACL", mc->name); notify_channel_set_change(si, si->smu, mc, "PUBACL", "ON"); return; } else if (!strcasecmp("OFF", parv[1]) || !strcasecmp("0", parv[1]) || !strcasecmp("FALSE", parv[1])) { if (!(MC_PUBACL & mc->flags)) { command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for channel: \2%s\2"), "PUBACL", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:PUBACL:OFF: \2%s\2", mc->name); verbose(mc, _("\2%s\2 disabled the PUBACL flag."), get_source_name(si)); mc->flags &= ~MC_PUBACL; command_success_nodata(si, _("The \2%s\2 flag has been removed for channel: \2%s\2"), "PUBACL", mc->name); notify_channel_set_change(si, si->smu, mc, "PUBACL", "OFF"); return; } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "PUBACL"); return; } }
static void cs_cmd_ban(sourceinfo_t *si, int parc, char *parv[]) { char *channel = parv[0]; char *target = parv[1]; channel_t *c = channel_find(channel); mychan_t *mc = mychan_find(channel); user_t *tu; if (!channel || !target) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "BAN"); command_fail(si, fault_needmoreparams, _("Syntax: BAN <#channel> <nickname|hostmask>")); return; } if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), channel); return; } if (!c) { command_fail(si, fault_nosuch_target, _("\2%s\2 is currently empty."), channel); return; } if (!si->smu) { command_fail(si, fault_noprivs, _("You are not logged in.")); return; } if (!chanacs_source_has_flag(mc, si, CA_REMOVE)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), channel); return; } if (validhostmask(target)) { modestack_mode_param(chansvs.nick, c, MTYPE_ADD, 'b', target); chanban_add(c, target, 'b'); logcommand(si, CMDLOG_DO, "BAN: \2%s\2 on \2%s\2", target, mc->name); if (!chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("Banned \2%s\2 on \2%s\2."), target, channel); return; } else if ((tu = user_find_named(target))) { char hostbuf[BUFSIZE]; hostbuf[0] = '\0'; strlcat(hostbuf, "*!*@", BUFSIZE); strlcat(hostbuf, tu->vhost, BUFSIZE); modestack_mode_param(chansvs.nick, c, MTYPE_ADD, 'b', hostbuf); chanban_add(c, hostbuf, 'b'); logcommand(si, CMDLOG_DO, "BAN: \2%s\2 on \2%s\2 (for user \2%s!%s@%s\2)", hostbuf, mc->name, tu->nick, tu->user, tu->vhost); if (!chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("Banned \2%s\2 on \2%s\2."), target, channel); return; } else { command_fail(si, fault_badparams, _("Invalid nickname/hostmask provided: \2%s\2"), target); command_fail(si, fault_badparams, _("Syntax: BAN <#channel> <nickname|hostmask>")); return; } }
static void cs_cmd_topicswap(sourceinfo_t *si, int parc, char *parv[]) { char *chan = parv[0]; char *topic = parv[1]; mychan_t *mc; channel_t *c; const char *topicsetter; time_t prevtopicts; char topicbuf[BUFSIZE]; char commbuf[BUFSIZE]; char *pos = NULL; char *search = NULL; char *replace = NULL; size_t search_size = 0; size_t replace_size = 0; size_t copylen = 0; if (parc < 2) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "TOPICSWAP"); command_fail(si, fault_needmoreparams, _("Syntax: TOPICSWAP <#channel> <search>:[<replace>]")); return; } mowgli_strlcpy(commbuf, parv[1], BUFSIZE); search = commbuf; pos = strrchr(commbuf, ':'); if (!pos || pos == commbuf) { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "TOPICSWAP"); command_fail(si, fault_badparams, _("Syntax: TOPICSWAP <#channel> <search>:[<replace>]")); return; } mc = mychan_find(chan); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), chan); return; } c = channel_find(chan); if (!c) { command_fail(si, fault_nosuch_target, _("\2%s\2 is currently empty."), chan); return; } if (!chanacs_source_has_flag(mc, si, CA_TOPIC)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), chan); return; } if (metadata_find(mc, "private:frozen:freezer")) { command_fail(si, fault_noprivs, _("\2%s\2 is frozen."), chan); return; } if (!c->topic) topicbuf[0] = '\0'; else mowgli_strlcpy(topicbuf, c->topic, BUFSIZE); *pos = '\0'; replace = pos + 1; search_size = strlen(search); replace_size = strlen(replace); pos = strstr(topicbuf, search); if (!pos) { command_fail(si, fault_badparams, _("Channel \2%s\2 does not have \2%s\2 in its topic."), chan, search); return; } copylen = strlen(pos + search_size) + 1; if (pos - topicbuf + replace_size + copylen > BUFSIZE) goto invalid_error; memmove(pos + search_size + (replace_size - search_size), pos + search_size, copylen); memcpy(pos, replace, replace_size); if (!validtopic(topicbuf)) { invalid_error: command_fail(si, fault_badparams, _("The new topic is invalid or too long.")); return; } if (si->su != NULL) topicsetter = si->su->nick; else if (si->smu != NULL) topicsetter = entity(si->smu)->name; else topicsetter = "unknown"; prevtopicts = c->topicts; handle_topic(c, topicsetter, CURRTIME, topicbuf); topic_sts(c, si->service->me, topicsetter, CURRTIME, prevtopicts, topicbuf); logcommand(si, CMDLOG_DO, "TOPICSWAP: \2%s\2", mc->name); if (si->su == NULL || !chanuser_find(c, si->su)) command_success_nodata(si, _("Topic set to \2%s\2 on \2%s\2."), c->topic, chan); }
static void cs_cmd_set_private(sourceinfo_t *si, int parc, char *parv[]) { mychan_t *mc; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), parv[0]); return; } if (!parv[1]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET PRIVATE"); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this command.")); return; } if (!strcasecmp("ON", parv[1])) { if (MC_PRIVATE & mc->flags) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for \2%s\2."), "PRIVATE", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:PRIVATE:ON: \2%s\2", mc->name); mc->flags |= MC_PRIVATE; command_success_nodata(si, _("The \2%s\2 flag has been set for \2%s\2."), "PRIVATE", mc->name); return; } else if (!strcasecmp("OFF", parv[1])) { if (!(MC_PRIVATE & mc->flags)) { command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for \2%s\2."), "PRIVATE", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:PRIVATE:OFF: \2%s\2", mc->name); mc->flags &= ~MC_PRIVATE; command_success_nodata(si, _("The \2%s\2 flag has been removed for \2%s\2."), "PRIVATE", mc->name); return; } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "PRIVATE"); return; } }
static void cs_cmd_invite(sourceinfo_t *si, int parc, char *parv[]) { char *chan = parv[0]; mychan_t *mc; if (si->su == NULL) { command_fail(si, fault_noprivs, _("\2%s\2 can only be executed via IRC."), "INVITE"); return; } /* This command is not useful if the user is already in the channel, * ignore it if it is a fantasy command so users can program bots to * react on it without interference from ChanServ. */ if (si->c != NULL) return; if (!chan) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "INVITE"); command_fail(si, fault_needmoreparams, _("Syntax: INVITE <#channel>")); return; } mc = mychan_find(chan); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), chan); return; } if (metadata_find(mc, "private:frozen:freezer")) { command_fail(si, fault_noprivs, _("\2%s\2 is frozen."), chan); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), chan); return; } if (!chanacs_source_has_flag(mc, si, CA_INVITE)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (!mc->chan) { command_fail(si, fault_nosuch_target, _("\2%s\2 is currently empty."), mc->name); return; } if (chanuser_find(mc->chan, si->su)) { command_fail(si, fault_noprivs, _("You're already on \2%s\2."), mc->name); return; } invite_sts(si->service->me, si->su, mc->chan); logcommand(si, CMDLOG_DO, "INVITE: \2%s\2", mc->name); command_success_nodata(si, _("You have been invited to \2%s\2."), mc->name); }
static void cs_cmd_set_mlock(struct sourceinfo *si, int parc, char *parv[]) { struct mychan *mc; char modebuf[32], *end, c; int dir = MTYPE_NUL; int newlock_on = 0, newlock_off = 0, newlock_limit = 0, flag = 0; unsigned int mask, changed; bool mask_ext; char newlock_key[KEYLEN + 1]; char newlock_ext[ignore_mode_list_size][512]; bool newlock_ext_off[ignore_mode_list_size]; char newext[512]; char ext_plus[ignore_mode_list_size + 1]; char ext_minus[ignore_mode_list_size + 1]; size_t i; char *letters = strtok(parv[1], " "); char *arg; struct metadata *md; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, parv[0]); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { if (ircd->oper_only_modes == 0 || !has_priv(si, PRIV_CHAN_CMODES) || !has_priv(si, PRIV_CHAN_ADMIN)) { command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED); return; } mask = ~ircd->oper_only_modes; mask_ext = true; } else { mask = has_priv(si, PRIV_CHAN_CMODES) ? 0 : ircd->oper_only_modes; mask_ext = false; } for (i = 0; i < ignore_mode_list_size; i++) { newlock_ext[i][0] = '\0'; newlock_ext_off[i] = false; } newlock_key[0] = '\0'; while (letters && *letters) { if (*letters != '+' && *letters != '-' && dir == MTYPE_NUL) { letters++; continue; } switch ((c = *letters++)) { case '+': dir = MTYPE_ADD; break; case '-': dir = MTYPE_DEL; break; case 'k': if (dir == MTYPE_ADD) { arg = strtok(NULL, " "); if (!arg) { command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), 'k'); return; } else if (strlen(arg) > KEYLEN) { command_fail(si, fault_badparams, _("MLOCK key is too long (%zu > %u)."), strlen(arg), KEYLEN); return; } else if (strchr(arg, ',') || arg[0] == ':') { command_fail(si, fault_badparams, _("MLOCK key contains invalid characters.")); return; } mowgli_strlcpy(newlock_key, arg, sizeof newlock_key); newlock_off &= ~CMODE_KEY; } else { newlock_key[0] = '\0'; newlock_off |= CMODE_KEY; } break; case 'l': if (dir == MTYPE_ADD) { arg = strtok(NULL, " "); if(!arg) { command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), 'l'); return; } if (atol(arg) <= 0) { command_fail(si, fault_badparams, _("You must specify a positive integer for limit.")); return; } newlock_limit = atol(arg); newlock_off &= ~CMODE_LIMIT; } else { newlock_limit = 0; newlock_off |= CMODE_LIMIT; } break; default: flag = mode_to_flag(c); if (flag) { if (dir == MTYPE_ADD) { newlock_on |= flag; newlock_off &= ~flag; } else { newlock_off |= flag; newlock_on &= ~flag; } break; } for (i = 0; ignore_mode_list[i].mode != '\0'; i++) { if (c == ignore_mode_list[i].mode) { if (dir == MTYPE_ADD) { arg = strtok(NULL, " "); if(!arg) { command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), c); return; } if (strlen(arg) > 350) { command_fail(si, fault_badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c); return; } if ((mc->chan == NULL || mc->chan->extmodes[i] == NULL || strcmp(mc->chan->extmodes[i], arg)) && !ignore_mode_list[i].check(arg, mc->chan, mc, si->su, si->smu)) { command_fail(si, fault_badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c); return; } mowgli_strlcpy(newlock_ext[i], arg, sizeof newlock_ext[i]); newlock_ext_off[i] = false; } else { newlock_ext[i][0] = '\0'; newlock_ext_off[i] = true; } } } } } // note: the following does not treat +lk and extmodes correctly changed = ((newlock_on ^ mc->mlock_on) | (newlock_off ^ mc->mlock_off)); changed &= ~mask; /* if they're only allowed to alter oper only modes, require * them to actually change such modes -- jilles */ if (!changed && mask_ext) { command_fail(si, fault_noprivs, _("You may only alter \2+%s\2 modes."), flags_to_string(~mask)); return; } // save it to mychan, leave the modes in mask unchanged -- jilles mc->mlock_on = (newlock_on & ~mask) | (mc->mlock_on & mask); mc->mlock_off = (newlock_off & ~mask) | (mc->mlock_off & mask); if (!(mask & CMODE_LIMIT)) mc->mlock_limit = newlock_limit; if (!(mask & CMODE_KEY)) { sfree(mc->mlock_key); mc->mlock_key = *newlock_key != '\0' ? sstrdup(newlock_key) : NULL; } ext_plus[0] = '\0'; ext_minus[0] = '\0'; if (mask_ext) { md = metadata_find(mc, "private:mlockext"); if (md != NULL) { arg = md->value; while (*arg != '\0') { modebuf[0] = *arg; modebuf[1] = '\0'; mowgli_strlcat(arg[1] == ' ' || arg[1] == '\0' ? ext_minus : ext_plus, modebuf, ignore_mode_list_size + 1); arg++; while (*arg != ' ' && *arg != '\0') arg++; while (*arg == ' ') arg++; } } } else { newext[0] = '\0'; for (i = 0; i < ignore_mode_list_size; i++) { if (newlock_ext[i][0] != '\0' || newlock_ext_off[i]) { if (*newext != '\0') { modebuf[0] = ' '; modebuf[1] = '\0'; mowgli_strlcat(newext, modebuf, sizeof newext); } modebuf[0] = ignore_mode_list[i].mode; modebuf[1] = '\0'; mowgli_strlcat(newext, modebuf, sizeof newext); mowgli_strlcat(newlock_ext_off[i] ? ext_minus : ext_plus, modebuf, ignore_mode_list_size + 1); if (!newlock_ext_off[i]) mowgli_strlcat(newext, newlock_ext[i], sizeof newext); } } if (newext[0] != '\0') metadata_add(mc, "private:mlockext", newext); else metadata_delete(mc, "private:mlockext"); } end = modebuf; *end = 0; if (mc->mlock_on || mc->mlock_key || mc->mlock_limit || *ext_plus) end += snprintf(end, sizeof(modebuf) - (end - modebuf), "+%s%s%s%s", flags_to_string(mc->mlock_on), mc->mlock_key ? "k" : "", mc->mlock_limit ? "l" : "", ext_plus); if (mc->mlock_off || *ext_minus) end += snprintf(end, sizeof(modebuf) - (end - modebuf), "-%s%s%s%s", flags_to_string(mc->mlock_off), mc->mlock_off & CMODE_KEY ? "k" : "", mc->mlock_off & CMODE_LIMIT ? "l" : "", ext_minus); if (*modebuf) { command_success_nodata(si, _("The MLOCK for \2%s\2 has been set to \2%s\2."), mc->name, modebuf); logcommand(si, CMDLOG_SET, "SET:MLOCK: \2%s\2 to \2%s\2", mc->name, modebuf); verbose(mc, "\2%s\2 set the mode lock to \2%s\2", get_source_name(si), modebuf); } else { command_success_nodata(si, _("The MLOCK for \2%s\2 has been removed."), mc->name); logcommand(si, CMDLOG_SET, "SET:MLOCK:NONE: \2%s\2", mc->name); } if (changed & ircd->oper_only_modes) logcommand(si, CMDLOG_SET, "SET:MLOCK: \2%s\2 to \2%s\2 by \2%s\2", mc->name, *modebuf != '\0' ? modebuf : "+", get_oper_name(si)); check_modes(mc, true); if (mc->chan != NULL) mlock_sts(mc->chan); return; }
static void cs_cmd_set_verbose(sourceinfo_t *si, int parc, char *parv[]) { mychan_t *mc; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), parv[0]); return; } if (!parv[1]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET VERBOSE"); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this command.")); return; } if (!strcasecmp("ON", parv[1]) || !strcasecmp("ALL", parv[1])) { if (MC_VERBOSE & mc->flags) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel \2%s\2."), "VERBOSE", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:VERBOSE:ON: \2%s\2", mc->name); mc->flags &= ~MC_VERBOSE_OPS; mc->flags |= MC_VERBOSE; verbose(mc, _("\2%s\2 enabled the VERBOSE flag"), get_source_name(si)); command_success_nodata(si, _("The \2%s\2 flag has been set for channel \2%s\2."), "VERBOSE", mc->name); return; } else if (!strcasecmp("OPS", parv[1])) { if (MC_VERBOSE_OPS & mc->flags) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel \2%s\2."), "VERBOSE_OPS", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:VERBOSE:OPS: \2%s\2", mc->name); if (mc->flags & MC_VERBOSE) { verbose(mc, _("\2%s\2 restricted VERBOSE to chanops"), get_source_name(si)); mc->flags &= ~MC_VERBOSE; mc->flags |= MC_VERBOSE_OPS; } else { mc->flags |= MC_VERBOSE_OPS; verbose(mc, _("\2%s\2 enabled the VERBOSE_OPS flag"), get_source_name(si)); } command_success_nodata(si, _("The \2%s\2 flag has been set for channel \2%s\2."), "VERBOSE_OPS", mc->name); return; } else if (!strcasecmp("OFF", parv[1])) { if (!((MC_VERBOSE | MC_VERBOSE_OPS) & mc->flags)) { command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for channel \2%s\2."), "VERBOSE", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:VERBOSE:OFF: \2%s\2", mc->name); if (mc->flags & MC_VERBOSE) verbose(mc, _("\2%s\2 disabled the VERBOSE flag"), get_source_name(si)); else verbose(mc, _("\2%s\2 disabled the VERBOSE_OPS flag"), get_source_name(si)); mc->flags &= ~(MC_VERBOSE | MC_VERBOSE_OPS); command_success_nodata(si, _("The \2%s\2 flag has been removed for channel \2%s\2."), "VERBOSE", mc->name); return; } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "VERBOSE"); return; } }
static void cs_cmd_voice(sourceinfo_t *si, int parc, char *parv[]) { char *chan = parv[0]; char *nick = parv[1]; mychan_t *mc; user_t *tu; chanuser_t *cu; char *nicklist; char *strtokctx; if (!chan) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "VOICE"); command_fail(si, fault_needmoreparams, _("Syntax: VOICE <#channel> [nickname] [...]")); return; } mc = mychan_find(chan); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), chan); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), chan); return; } nicklist = (!nick ? strdup(si->su->nick) : strdup(nick)); nick = strtok_r(nicklist, " ", &strtokctx); do { if (invert_purpose(si, parc, chan, &nick, '-', &cs_cmd_devoice)) continue; /* figure out who we're going to voice */ if (!(tu = user_find_named(nick))) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not online."), nick); continue; } if (!chanacs_source_has_flag(mc, si, CA_VOICE) && (tu != si->su || !chanacs_source_has_flag(mc, si, CA_AUTOVOICE))) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); continue; } if (is_internal_client(tu)) continue; cu = chanuser_find(mc->chan, tu); if (!cu) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not on \2%s\2."), tu->nick, mc->name); continue; } modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, 'v', CLIENT_NAME(tu)); cu->modes |= CSTATUS_VOICE; if (si->c == NULL && tu != si->su) change_notify(chansvs.nick, tu, "You have been voiced on %s by %s", mc->name, get_source_name(si)); logcommand(si, CMDLOG_DO, "VOICE: \2%s!%s@%s\2 on \2%s\2", tu->nick, tu->user, tu->vhost, mc->name); if (si->su == NULL || !chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("\2%s\2 has been voiced on \2%s\2."), tu->nick, mc->name); } while ((nick = strtok_r(NULL, " ", &strtokctx)) != NULL); free(nicklist); }
static void cs_cmd_set_secure(sourceinfo_t *si, int parc, char *parv[]) { mychan_t *mc; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), parv[0]); return; } if (metadata_find(mc, "private:frozen:freezer")) { command_fail(si, fault_noprivs, _("\2%s\2 is frozen."), parv[0]); return; } if (!parv[1]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET SECURE"); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this command.")); return; } if (chanacs_source_has_flag(mc, si, CA_SUSPENDED)) { command_fail(si, fault_noprivs, _("Your access in %s is \2suspended\2."), parv[0]); return; } if (!strcasecmp("ON", parv[1])) { if (MC_SECURE & mc->flags) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel \2%s\2."), "SECURE", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:SECURE:ON: \2%s\2", mc->name); verbose(mc, _("\2%s\2 enabled the SECURE flag"), get_source_name(si)); mc->flags |= MC_SECURE; command_success_nodata(si, _("The \2%s\2 flag has been set for channel \2%s\2."), "SECURE", mc->name); return; } else if (!strcasecmp("OFF", parv[1])) { if (!(MC_SECURE & mc->flags)) { command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for channel \2%s\2."), "SECURE", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:SECURE:OFF: \2%s\2", mc->name); verbose(mc, _("\2%s\2 disabled the SECURE flag"), get_source_name(si)); mc->flags &= ~MC_SECURE; command_success_nodata(si, _("The \2%s\2 flag has been removed for channel \2%s\2."), "SECURE", mc->name); return; } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "SECURE"); return; } }
static void cs_cmd_owner(sourceinfo_t *si, int parc, char *parv[]) { char *chan = parv[0]; char *nick = parv[1]; mychan_t *mc; user_t *tu; chanuser_t *cu; if (ircd->uses_owner == false) { command_fail(si, fault_noprivs, _("The IRCd software you are running does not support this feature.")); return; } if (!chan) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "OWNER"); command_fail(si, fault_needmoreparams, _("Syntax: OWNER <#channel> [nickname]")); return; } mc = mychan_find(chan); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), chan); return; } if (!chanacs_source_has_flag(mc, si, CA_USEOWNER)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), chan); return; } /* figure out who we're going to op */ if (!nick) tu = si->su; else { if (!(tu = user_find_named(nick))) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not online."), nick); return; } } if (is_internal_client(tu)) return; /* SECURE check; we can skip this if sender == target, because we already verified */ if ((si->su != tu) && (mc->flags & MC_SECURE) && !chanacs_user_has_flag(mc, tu, CA_OP) && !chanacs_user_has_flag(mc, tu, CA_AUTOOP)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); command_fail(si, fault_noprivs, _("\2%s\2 has the SECURE option enabled, and \2%s\2 does not have appropriate access."), mc->name, tu->nick); return; } cu = chanuser_find(mc->chan, tu); if (!cu) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not on \2%s\2."), tu->nick, mc->name); return; } modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, ircd->owner_mchar[1], CLIENT_NAME(tu)); cu->modes |= CSTATUS_OWNER; if (si->c == NULL && tu != si->su) change_notify(chansvs.nick, tu, "You have been set as owner on %s by %s", mc->name, get_source_name(si)); logcommand(si, CMDLOG_DO, "OWNER: \2%s!%s@%s\2 on \2%s\2", tu->nick, tu->user, tu->vhost, mc->name); if (si->su == NULL || !chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("\2%s\2 has been set as owner on \2%s\2."), tu->nick, mc->name); }
static void cs_cmd_topic(sourceinfo_t *si, int parc, char *parv[]) { char *chan = parv[0]; char *topic = parv[1]; mychan_t *mc; channel_t *c; const char *topicsetter; time_t prevtopicts; if (!chan || !topic) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "TOPIC"); command_fail(si, fault_needmoreparams, _("Syntax: TOPIC <#channel> <topic>")); return; } mc = mychan_find(chan); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), chan); return; } c = channel_find(chan); if (!c) { command_fail(si, fault_nosuch_target, _("\2%s\2 is currently empty."), chan); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), chan); return; } if (metadata_find(mc, "private:frozen:freezer")) { command_fail(si, fault_noprivs, _("\2%s\2 is frozen."), chan); return; } if (!chanacs_source_has_flag(mc, si, CA_TOPIC)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (!validtopic(topic)) { command_fail(si, fault_badparams, _("The new topic is invalid or too long.")); return; } if (si->su != NULL) topicsetter = si->su->nick; else if (si->smu != NULL) topicsetter = entity(si->smu)->name; else topicsetter = "unknown"; prevtopicts = c->topicts; handle_topic(c, topicsetter, CURRTIME, topic); topic_sts(c, si->service->me, topicsetter, CURRTIME, prevtopicts, topic); logcommand(si, CMDLOG_DO, "TOPIC: \2%s\2", mc->name); if (si->su == NULL || !chanuser_find(c, si->su)) command_success_nodata(si, _("Topic set to \2%s\2 on \2%s\2."), topic, chan); }
static void cs_cmd_set_guard(sourceinfo_t *si, int parc, char *parv[]) { mychan_t *mc; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), parv[0]); return; } if (!parv[1]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET GUARD"); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this command.")); return; } if (!strcasecmp("ON", parv[1])) { if (MC_GUARD & mc->flags) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel \2%s\2."), "GUARD", mc->name); return; } if (metadata_find(mc, "private:botserv:bot-assigned") && module_find_published("botserv/main")) { command_fail(si, fault_noprivs, _("Channel \2%s\2 already has a BotServ bot assigned to it. You need to unassign it first."), mc->name); return; } logcommand(si, CMDLOG_SET, "SET:GUARD:ON: \2%s\2", mc->name); verbose(mc, _("\2%s\2 enabled the GUARD flag"), get_source_name(si)); mc->flags |= MC_GUARD; if (!(mc->flags & MC_INHABIT)) join(mc->name, chansvs.nick); command_success_nodata(si, _("The \2%s\2 flag has been set for channel \2%s\2."), "GUARD", mc->name); return; } else if (!strcasecmp("OFF", parv[1])) { if (!(MC_GUARD & mc->flags)) { command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for channel \2%s\2."), "GUARD", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:GUARD:OFF: \2%s\2", mc->name); verbose(mc, _("\2%s\2 disabled the GUARD flag"), get_source_name(si)); mc->flags &= ~MC_GUARD; if (mc->chan != NULL && !(mc->flags & MC_INHABIT) && !(mc->chan->flags & CHAN_LOG)) part(mc->name, chansvs.nick); command_success_nodata(si, _("The \2%s\2 flag has been removed for channel \2%s\2."), "GUARD", mc->name); return; } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "GUARD"); return; } }
static void cs_cmd_unban(sourceinfo_t *si, int parc, char *parv[]) { char *channel = parv[0]; char *target = parv[1]; channel_t *c = channel_find(channel); mychan_t *mc = mychan_find(channel); user_t *tu; chanban_t *cb; if (!channel) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "UNBAN"); command_fail(si, fault_needmoreparams, _("Syntax: UNBAN <#channel> <nickname|hostmask>")); return; } if (!target) { if (si->su == NULL) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "UNBAN"); command_fail(si, fault_needmoreparams, _("Syntax: UNBAN <#channel> <nickname|hostmask>")); return; } target = si->su->nick; } if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), channel); return; } if (!c) { command_fail(si, fault_nosuch_target, _("\2%s\2 is currently empty."), channel); return; } if (!si->smu) { command_fail(si, fault_noprivs, _("You are not logged in.")); return; } if (!chanacs_source_has_flag(mc, si, CA_REMOVE)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if ((tu = user_find_named(target))) { mowgli_node_t *n, *tn; char hostbuf2[BUFSIZE]; int count = 0; snprintf(hostbuf2, BUFSIZE, "%s!%s@%s", tu->nick, tu->user, tu->vhost); for (n = next_matching_ban(c, tu, 'b', c->bans.head); n != NULL; n = next_matching_ban(c, tu, 'b', tn)) { tn = n->next; cb = n->data; logcommand(si, CMDLOG_DO, "UNBAN: \2%s\2 on \2%s\2 (for user \2%s\2)", cb->mask, mc->name, hostbuf2); modestack_mode_param(chansvs.nick, c, MTYPE_DEL, cb->type, cb->mask); chanban_delete(cb); count++; } if (count > 0) command_success_nodata(si, _("Unbanned \2%s\2 on \2%s\2 (%d ban%s removed)."), target, channel, count, (count != 1 ? "s" : "")); else command_success_nodata(si, _("No bans found matching \2%s\2 on \2%s\2."), target, channel); return; } else if ((cb = chanban_find(c, target, 'b')) != NULL || validhostmask(target)) { if (cb) { modestack_mode_param(chansvs.nick, c, MTYPE_DEL, 'b', target); chanban_delete(cb); logcommand(si, CMDLOG_DO, "UNBAN: \2%s\2 on \2%s\2", target, mc->name); if (!chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("Unbanned \2%s\2 on \2%s\2."), target, channel); } else command_fail(si, fault_nosuch_key, _("No such ban \2%s\2 on \2%s\2."), target, channel); return; } else { command_fail(si, fault_badparams, _("Invalid nickname/hostmask provided: \2%s\2"), target); command_fail(si, fault_badparams, _("Syntax: UNBAN <#channel> [nickname|hostmask]")); return; } }
static void cs_cmd_set_topiclock(struct sourceinfo *si, int parc, char *parv[]) { struct mychan *mc; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), parv[0]); return; } if (!parv[1]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET TOPICLOCK"); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this command.")); return; } if (!strcasecmp("ON", parv[1])) { if (MC_TOPICLOCK & mc->flags) { command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel \2%s\2."), "TOPICLOCK", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:TOPICLOCK:ON: \2%s\2", mc->name); verbose(mc, _("\2%s\2 enabled the TOPICLOCK flag"), get_source_name(si)); mc->flags |= MC_KEEPTOPIC | MC_TOPICLOCK; topiclock_sts(mc->chan); command_success_nodata(si, _("The \2%s\2 flag has been set for channel \2%s\2."), "TOPICLOCK", mc->name); return; } else if (!strcasecmp("OFF", parv[1])) { if (!(MC_TOPICLOCK & mc->flags)) { command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for channel \2%s\2."), "TOPICLOCK", mc->name); return; } logcommand(si, CMDLOG_SET, "SET:TOPICLOCK:OFF: \2%s\2", mc->name); verbose(mc, _("\2%s\2 disabled the TOPICLOCK flag"), get_source_name(si)); mc->flags &= ~MC_TOPICLOCK; topiclock_sts(mc->chan); command_success_nodata(si, _("The \2%s\2 flag has been removed for channel \2%s\2."), "TOPICLOCK", mc->name); return; } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "TOPICLOCK"); return; } }
static void cs_cmd_topicprepend(sourceinfo_t *si, int parc, char *parv[]) { char *chan = parv[0]; char *topic = parv[1]; mychan_t *mc; char topicbuf[BUFSIZE]; channel_t *c; const char *topicsetter; time_t prevtopicts; if (!chan || !topic) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "TOPICPREPEND"); command_fail(si, fault_needmoreparams, _("Syntax: TOPICPREPEND <#channel> <topic>")); return; } mc = mychan_find(chan); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), chan); return; } c = channel_find(chan); if (!c) { command_fail(si, fault_nosuch_target, _("\2%s\2 is currently empty."), chan); return; } if (!chanacs_source_has_flag(mc, si, CA_TOPIC)) { command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED); return; } if (metadata_find(mc, "private:close:closer")) { command_fail(si, fault_noprivs, _("\2%s\2 is closed."), chan); return; } topicbuf[0] = '\0'; if (c->topic) { mowgli_strlcpy(topicbuf, topic, BUFSIZE); mowgli_strlcat(topicbuf, " | ", BUFSIZE); mowgli_strlcat(topicbuf, c->topic, BUFSIZE); } else mowgli_strlcpy(topicbuf, topic, BUFSIZE); if (!validtopic(topicbuf)) { command_fail(si, fault_badparams, _("The new topic is invalid or too long.")); return; } if (si->su != NULL) topicsetter = si->su->nick; else if (si->smu != NULL) topicsetter = entity(si->smu)->name; else topicsetter = "unknown"; prevtopicts = c->topicts; handle_topic(c, topicsetter, CURRTIME, topicbuf); topic_sts(c, si->service->me, topicsetter, CURRTIME, prevtopicts, topicbuf); logcommand(si, CMDLOG_DO, "TOPICPREPEND: \2%s\2", mc->name); if (si->su == NULL || !chanuser_find(c, si->su)) command_success_nodata(si, _("Topic set to \2%s\2 on \2%s\2."), c->topic, chan); }