static void build_criteriastr(char *buf, int parc, char *parv[]) { int i; return_if_fail(buf != NULL); *buf = 0; for (i = 0; i < parc; i++) { mowgli_strlcat(buf, parv[i], BUFSIZE); mowgli_strlcat(buf, " ", BUFSIZE); } }
/* * linker_open_ext() * * Inputs: * path to file to open * * Outputs: * linker handle * * Side Effects: * the extension is appended if it's not already there. * a shared module is loaded into the application's memory space */ mowgli_module_t *linker_open_ext(const char *path, char *errbuf, int errlen) { size_t len = strlen(path) + 20; char *buf = smalloc(len); void *ret; mowgli_strlcpy(buf, path, len); if (!strstr(buf, PLATFORM_SUFFIX)) mowgli_strlcat(buf, PLATFORM_SUFFIX, len); /* Don't try to open a file that doesn't exist. */ struct stat s; if (0 != stat(buf, &s)) { mowgli_strlcpy(errbuf, strerror(errno), errlen); free(buf); return NULL; } ret = mowgli_module_open(buf); free(buf); if (!ret) mowgli_strlcpy(errbuf, "mowgli_module_open() failed", errlen); return ret; }
static void opensex_db_close(database_handle_t *db) { opensex_t *rs; int errno1; char oldpath[BUFSIZE], newpath[BUFSIZE]; return_if_fail(db != NULL); rs = db->priv; mowgli_strlcpy(oldpath, db->file, sizeof oldpath); mowgli_strlcat(oldpath, ".new", sizeof oldpath); mowgli_strlcpy(newpath, db->file, sizeof newpath); fclose(rs->f); if (db->txn == DB_WRITE) { /* now, replace the old database with the new one, using an atomic rename */ if (srename(oldpath, newpath) < 0) { errno1 = errno; slog(LG_ERROR, "db_save(): cannot rename services.db.new to services.db: %s", strerror(errno1)); wallops(_("\2DATABASE ERROR\2: db_save(): cannot rename services.db.new to services.db: %s"), strerror(errno1)); } hook_call_db_saved(); } free(rs->buf); free(rs); free(db->file); free(db); }
static void command_namegen(struct sourceinfo *si, int parc, char *parv[]) { unsigned int iter; unsigned int amt = 20; char buf[BUFSIZE]; struct mychan *mc; if (!gs_do_parameters(si, &parc, &parv, &mc)) return; if (parv[0]) amt = atoi(parv[0]); // limit to 20 if (amt > 20) amt = 20; *buf = '\0'; for (iter = 0; iter < amt; iter++) { char namebuf[BUFSIZE]; unsigned int medial_iter; // Here we generate the name. mowgli_strlcpy(namebuf, begin_sym[rand() % BEGIN_SYM_SZ], BUFSIZE); for (medial_iter = rand() % 3; medial_iter > 0; medial_iter--) mowgli_strlcat(namebuf, medial_sym[rand() % MEDIAL_SYM_SZ], BUFSIZE); mowgli_strlcat(namebuf, end_sym[rand() % END_SYM_SZ], BUFSIZE); if (iter == 0) mowgli_strlcpy(buf, namebuf, BUFSIZE); else mowgli_strlcat(buf, namebuf, BUFSIZE); mowgli_strlcat(buf, iter + 1 < amt ? ", " : ".", BUFSIZE); } gs_command_report(si, _("Some names to ponder: %s"), buf); }
static void list_one(sourceinfo_t *si, myuser_t *mu, mynick_t *mn) { char buf[BUFSIZE]; if (mn != NULL) mu = mn->owner; *buf = '\0'; if (metadata_find(mu, "private:freeze:freezer")) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "\2[frozen]\2", BUFSIZE); } if (metadata_find(mu, "private:mark:setter")) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "\2[marked]\2", BUFSIZE); } if (metadata_find(mu, "private:restrict:setter")) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "\2[restricted]\2", BUFSIZE); } if (mu->flags & MU_HOLD) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "\2[held]\2", BUFSIZE); } if (mu->flags & MU_WAITAUTH) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "\2[unverified]\2", BUFSIZE); } if (mn == NULL || !irccasecmp(mn->nick, entity(mu)->name)) command_success_nodata(si, "- %s (%s) %s", entity(mu)->name, mu->email, buf); else command_success_nodata(si, "- %s (%s) (%s) %s", mn->nick, mu->email, entity(mu)->name, buf); }
const char *xflag_tostr(unsigned int flags) { unsigned int i; static char buf[BUFSIZE]; *buf = '\0'; for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++) { if (chanacs_flags[i].name == NULL) continue; if (!(flags & chanacs_flags[i].value)) continue; if (*buf != '\0') mowgli_strlcat(buf, ", ", sizeof buf); mowgli_strlcat(buf, chanacs_flags[i].name, sizeof buf); } return buf; }
static database_handle_t *opensex_db_open_write(const char *filename) { database_handle_t *db; opensex_t *rs; int fd; FILE *f; int errno1; char bpath[BUFSIZE], path[BUFSIZE]; snprintf(bpath, BUFSIZE, "%s/%s", datadir, filename != NULL ? filename : "services.db"); mowgli_strlcpy(path, bpath, sizeof path); mowgli_strlcat(path, ".new", sizeof path); fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (fd < 0 || ! (f = fdopen(fd, "w"))) { errno1 = errno; slog(LG_ERROR, "db-open-write: cannot open '%s' for writing: %s", path, strerror(errno1)); wallops(_("\2DATABASE ERROR\2: db-open-write: cannot open '%s' for writing: %s"), path, strerror(errno1)); return NULL; } rs = scalloc(sizeof(opensex_t), 1); rs->f = f; rs->grver = 1; db = scalloc(sizeof(database_handle_t), 1); db->priv = rs; db->vt = &opensex_vt; db->txn = DB_WRITE; db->file = sstrdup(bpath); db->line = 0; db->token = 0; db_start_row(db, "GRVER"); db_write_int(db, rs->grver); db_commit_row(db); return db; }
static void command_df(sourceinfo_t *si, int parc, char *parv[]) { mychan_t *mc; char *arg_dice; char buf[BUFSIZE]; int i, dice; if (!gs_do_parameters(si, &parc, &parv, &mc)) return; if (parc < 1) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DF"); command_fail(si, fault_needmoreparams, _("Syntax: DF <dice>")); return; } arg_dice = parv[0]; dice = atoi(arg_dice); *buf = '\0'; if (dice > 30 || dice < 1) { command_fail(si, fault_badparams, _("Only 1-30 dice may be thrown at one time.")); return; } for (i = 0; i < dice; i++) { int roll = arc4random() % 3; if (*buf != '\0') mowgli_strlcat(buf, df_dice_table[roll], BUFSIZE); else mowgli_strlcpy(buf, df_dice_table[roll], BUFSIZE); } gs_command_report(si, _("Result: %s"), buf); }
static void gs_cmd_info(sourceinfo_t *si, int parc, char *parv[]) { mygroup_t *mg; struct tm tm; char buf[BUFSIZE], strfbuf[BUFSIZE]; metadata_t *md; if (!parv[0]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "INFO"); command_fail(si, fault_needmoreparams, _("Syntax: INFO <!groupname>")); return; } if (!(mg = mygroup_find(parv[0]))) { command_fail(si, fault_alreadyexists, _("Group \2%s\2 does not exist."), parv[0]); return; } tm = *localtime(&mg->regtime); strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm); command_success_nodata(si, _("Information for \2%s\2:"), parv[0]); command_success_nodata(si, _("Registered : %s (%s ago)"), strfbuf, time_ago(mg->regtime)); if (config_options.show_entity_id || has_priv(si, PRIV_GROUP_AUSPEX)) command_success_nodata(si, _("Entity ID : %s"), entity(mg)->id); if (mg->flags & MG_PUBLIC || (si->smu != NULL && groupacs_sourceinfo_has_flag(mg, si, 0) && !groupacs_sourceinfo_has_flag(mg, si, GA_BAN)) || has_priv(si, PRIV_GROUP_AUSPEX)) command_success_nodata(si, _("Founder : %s"), mygroup_founder_names(mg)); if ((md = metadata_find(mg, "description"))) command_success_nodata(si, _("Description : %s"), md->value); if ((md = metadata_find(mg, "channel"))) command_success_nodata(si, _("Channel : %s"), md->value); if ((md = metadata_find(mg, "url"))) command_success_nodata(si, _("URL : %s"), md->value); if ((md = metadata_find(mg, "email"))) command_success_nodata(si, _("Email : %s"), md->value); *buf = '\0'; if (mg->flags & MG_REGNOLIMIT) mowgli_strlcat(buf, "REGNOLIMIT", BUFSIZE); if (mg->flags & MG_ACSNOLIMIT) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "ACSNOLIMIT", BUFSIZE); } if (mg->flags & MG_OPEN) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "OPEN", BUFSIZE); } if (mg->flags & MG_PUBLIC) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "PUBLIC", BUFSIZE); } if (*buf) command_success_nodata(si, _("Flags : %s"), buf); command_success_nodata(si, _("\2*** End of Info ***\2")); logcommand(si, CMDLOG_GET, "INFO: \2%s\2", parv[0]); }
static void cs_cmd_ban(sourceinfo_t *si, int parc, char *parv[]) { char *channel = parv[0]; char *target = parv[1]; char *newtarget; 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 (!chanacs_source_has_flag(mc, si, CA_REMOVE)) { 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."), channel); return; } if ((tu = user_find_named(target))) { char hostbuf[BUFSIZE]; hostbuf[0] = '\0'; mowgli_strlcat(hostbuf, "*!*@", BUFSIZE); mowgli_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 (si->su == NULL || !chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("Banned \2%s\2 on \2%s\2."), target, channel); return; } else if ((is_extban(target) && (newtarget = target)) || ((newtarget = pretty_mask(target)) && validhostmask(newtarget))) { modestack_mode_param(chansvs.nick, c, MTYPE_ADD, 'b', newtarget); chanban_add(c, newtarget, 'b'); logcommand(si, CMDLOG_DO, "BAN: \2%s\2 on \2%s\2", newtarget, mc->name); if (si->su == NULL || !chanuser_find(mc->chan, si->su)) command_success_nodata(si, _("Banned \2%s\2 on \2%s\2."), newtarget, 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_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, _("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; } 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); }
static void eval_dice(sourceinfo_t *si, char *s_input) { static char buffer[1024], result[32]; char op = '\0', *c = s_input; unsigned int dice, roll, x, y, z = 0; double total; while (*c && isspace(*c)) ++c; if (!*c || !isdigit(*c)) { gs_command_report(si, _("Syntax: XdY [ {-|+|*|/} Z ]")); return; } x = strtoul(c, &c, 10); if (x == 0 || c == NULL || ToLower(*c++) != 'd' || !isdigit(*c)) { if (x < 1 || x > DICE_MAX_DICE) { gs_command_report(si, _("Only 1-100 dice may be thrown at once.")); return; } gs_command_report(si, _("Syntax: XdY [ {-|+|*|/} Z ]")); return; } y = strtoul(c, &c, 10); if (c != NULL) { while (*c && isspace(*c)) ++c; if (*c && strchr("-+*/", *c) == NULL) { gs_command_report(si, _("Syntax: XdY [ {-|+|*|/} Z ]")); return; } } if (x < 1 || x > 100) { gs_command_report(si, _("Syntax: XdY [ {-|+|*|/} Z ]")); return; } if (y < 1 || y > DICE_MAX_SIDES) { gs_command_report(si, _("Only 1-100 sides may be used on a dice.")); return; } if (*c) { op = *c++; z = strtoul(c, &c, 10); while (*c && isspace(*c)) ++c; if (*c) { gs_command_report(si, _("Syntax: XdY [ {-|+|*|/} Z ]")); return; } else if (op == '/' && z == 0) { gs_command_report(si, _("Can't divide by zero.")); return; } } total = 0.0; snprintf(buffer, 1024, "\2%s\2 rolled %ud%u: ", si->su->nick, x, y); for (roll = 0; roll < x; ++roll) { snprintf(result, 32, "%d ", dice = (1 + (arc4random() % y))); mowgli_strlcat(buffer, result, sizeof(buffer)); total += dice; } if (op == '\0') snprintf(result, 32, " <Total: %g>", total); else { snprintf(result, 32, " <Total: %g(%c%u) = ", total, op, z); mowgli_strlcat(buffer, result, sizeof(buffer)); switch (op) { case '+': total += z; break; case '-': total -= z; break; case '/': total /= z; break; case '*': total *= z; break; default: break; } snprintf(result, 32, "%g>", total); } mowgli_strlcat(buffer, result, sizeof(buffer)); gs_command_report(si, "%s", buffer); }
static void ms_cmd_fsend(sourceinfo_t *si, int parc, char *parv[]) { /* misc structs etc */ user_t *tu; myuser_t *tmu; mowgli_node_t *n; mymemo_t *memo; service_t *memoserv; /* Grab args */ char *target = parv[0]; char *m = parv[1]; /* Arg validation */ if (!target || !m) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FSEND"); command_fail(si, fault_needmoreparams, "Syntax: FSEND <user> <memo>"); return; } if (!si->smu) { command_fail(si, fault_noprivs, _("You are not logged in.")); return; } /* rate limit it -- jilles */ if (CURRTIME - si->smu->memo_ratelimit_time > MEMO_MAX_TIME) si->smu->memo_ratelimit_num = 0; if (si->smu->memo_ratelimit_num > MEMO_MAX_NUM && !has_priv(si, PRIV_FLOOD)) { command_fail(si, fault_toomany, _("You have used this command too many times; please wait a while and try again.")); return; } /* Check for memo text length -- includes/common.h */ if (strlen(m) >= MEMOLEN) { command_fail(si, fault_badparams, "Please make sure your memo is less than %d characters", MEMOLEN); return; } /* Check to make sure the memo doesn't contain hostile CTCP responses. * realistically, we'll probably want to check the _entire_ message for this... --nenolod */ if (*m == '\001') { command_fail(si, fault_badparams, _("Your memo contains invalid characters.")); return; } memoserv = service_find("memoserv"); if (memoserv == NULL) memoserv = si->service; if (*target != '#' && *target != '!') { /* See if target is valid */ if (!(tmu = myuser_find_ext(target))) { command_fail(si, fault_nosuch_target, "\2%s\2 is not registered.", target); return; } si->smu->memo_ratelimit_num++; si->smu->memo_ratelimit_time = CURRTIME; /* Check to make sure target inbox not full */ if (tmu->memos.count >= me.mdlimit) { command_fail(si, fault_toomany, _("%s's inbox is full"), target); logcommand(si, CMDLOG_SET, "failed SEND to \2%s\2 (target inbox full)", entity(tmu)->name); return; } logcommand(si, CMDLOG_ADMIN, "FSEND: to \2%s\2", entity(tmu)->name); /* Malloc and populate struct */ memo = smalloc(sizeof(mymemo_t)); memo->sent = CURRTIME; memo->status = 0; mowgli_strlcpy(memo->sender,entity(si->smu)->name,NICKLEN); mowgli_strlcpy(memo->text, "[FORCE] ", FMEMOLEN); mowgli_strlcat(memo->text, m, FMEMOLEN); /* Create a linked list node and add to memos */ n = mowgli_node_create(); mowgli_node_add(memo, n, &tmu->memos); tmu->memoct_new++; /* Should we email this? */ if (tmu->flags & MU_EMAILMEMOS) { compat_sendemail(si->su, tmu, EMAIL_MEMO, tmu->email, memo->text); } /* Note: do not disclose other nicks they're logged in with * -- jilles * * Actually, I don't see the point in this at all. If they want this information, * they should use WHOIS. --nenolod */ tu = user_find_named(target); if (tu != NULL && tu->myuser == tmu) command_success_nodata(si, _("%s is currently online, and you may talk directly, by sending a private message."), target); /* Is the user online? If so, tell them about the new memo. */ if (si->su == NULL || !irccasecmp(si->su->nick, entity(si->smu)->name)) myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (%zu).", entity(si->smu)->name, MOWGLI_LIST_LENGTH(&tmu->memos)); else myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (nick: %s) (%zu).", entity(si->smu)->name, si->su->nick, MOWGLI_LIST_LENGTH(&tmu->memos)); myuser_notice(memoserv->nick, tmu, _("To read it, type /%s%s READ %zu"), ircd->uses_rcommand ? "" : "msg ", memoserv->disp, MOWGLI_LIST_LENGTH(&tmu->memos)); /* Tell user memo sent */ command_success_nodata(si, _("The memo has been successfully sent to \2%s\2."), target); } else if (*target == '#') { command_fail(si, fault_nosuch_target, _("Channel memos may not be forced.")); } else { command_fail(si, fault_nosuch_target, _("Group memos may not be forced.")); } return; }
static void ns_cmd_ajoin(sourceinfo_t *si, int parc, char *parv[]) { char buf[512]; char *chan; metadata_t *md; if (!parv[0]) { command_fail(si, fault_badparams, STR_INSUFFICIENT_PARAMS, "AJOIN"); command_fail(si, fault_badparams, "Syntax: AJOIN <list|add|del> [#channel]"); return; } if (!strcasecmp(parv[0], "LIST")) { command_success_nodata(si, "\2AJOIN LIST\2:"); if ((md = metadata_find(si->smu, "private:autojoin"))) { mowgli_strlcpy(buf, md->value, sizeof buf); chan = strtok(buf, ","); while (chan != NULL) { command_success_nodata(si, "%s", chan); chan = strtok(NULL, ","); } } command_success_nodata(si, "End of \2AJOIN LIST\2"); } else if (!strcasecmp(parv[0], "ADD")) { if (!parv[1]) { command_fail(si, fault_badparams, STR_INSUFFICIENT_PARAMS, "AJOIN"); command_fail(si, fault_badparams, "Syntax: AJOIN <list|add|del|clear> [#channel]"); return; } if ((md = metadata_find(si->smu, "private:autojoin"))) { mowgli_strlcpy(buf, md->value, sizeof buf); chan = strtok(buf, ","); while (chan != NULL) { if (!strcasecmp(chan, parv[1])) { command_fail(si, fault_badparams, "%s is already on your AJOIN list.", parv[1]); return; } chan = strtok(NULL, ","); } // Little arbitrary, but stop both overflow and RAM consumption going out of control if (strlen(md->value) + strlen(parv[1]) > 400) { command_fail(si, fault_badparams, "Sorry, you have too many AJOIN entries set."); return; } mowgli_strlcpy(buf, md->value, sizeof buf); mowgli_strlcat(buf, ",", sizeof buf); mowgli_strlcat(buf, parv[1], sizeof buf); metadata_delete(si->smu, "private:autojoin"); metadata_add(si->smu, "private:autojoin", buf); } else { metadata_add(si->smu, "private:autojoin", parv[1]); } command_success_nodata(si, "%s added to AJOIN successfully.", parv[1]); } else if (!strcasecmp(parv[0], "CLEAR")) { metadata_delete(si->smu, "private:autojoin"); command_success_nodata(si, "AJOIN list cleared successfully."); } else if (!strcasecmp(parv[0], "DEL")) { if (!parv[1]) { command_fail(si, fault_badparams, STR_INSUFFICIENT_PARAMS, "AJOIN"); command_fail(si, fault_badparams, "Syntax: AJOIN <list|add|del|clear> [#channel]"); return; } if (!(md = metadata_find(si->smu, "private:autojoin"))) { command_fail(si, fault_badparams, "%s is not on your AJOIN list.", parv[1]); return; } // Thanks to John Brooks for his help with this. char *list = md->value; char *remove1 = parv[1]; int listlen = 0; int rmlen = 0; int itempos = 0; int i = 0, j = 0; // This loop will find the item (if present), find the length of the item, and find the length of the entire string. for (; list[i]; i++) { if (!rmlen) { // We have not found the string yet if (tolower(list[i]) == tolower(remove1[j])) { if (j == 0) { // First character of a potential match; remember it's location itempos = i; } j++; if (!remove1[j]) { // Found the entire string rmlen = j; } } else j = 0; } } if (remove1[j]) { command_fail(si, fault_badparams, "%s is not on your AJOIN list.", parv[1]); return; } listlen = i; // listlen is the length of the list, rmlen is the length of the item to remove, itempos is the beginning of that item. if (!list[itempos + rmlen]) { // This item is the last item in the list, so we can simply truncate if (itempos > 0) { itempos--; list[itempos] = '\0'; } else metadata_delete(si->smu, "private:autojoin"); } else { // There are items after this one, so we must copy memory // Account for the comma following this item (if there is a space, account for that too, depends on how you format your list) rmlen += 1; memmove(list + itempos, list + itempos + rmlen, listlen - rmlen - itempos); list[listlen - rmlen] = '\0'; } command_success_nodata(si, "%s removed from AJOIN successfully.", parv[1]); } }
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; }