Exemple #1
0
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);
	}
}
Exemple #2
0
/*
 * 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;
}
Exemple #3
0
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);
}
Exemple #4
0
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);
}
Exemple #5
0
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);
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}
Exemple #8
0
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);
}
Exemple #9
0
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]);
}
Exemple #10
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;
	}
}
Exemple #11
0
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);
}
Exemple #12
0
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]);
	}
}
Exemple #15
0
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;
}