unsigned int orig_limit;
chan_mode_t orig_modes;
char orig_key[KEYLEN+1];
+ char orig_apass[KEYLEN+1];
+ char orig_upass[KEYLEN+1];
unsigned int nn, argc;
/* nuke old topic */
orig_modes = cNode->modes;
orig_limit = cNode->limit;
strcpy(orig_key, cNode->key);
+ strcpy(orig_upass, cNode->upass);
+ strcpy(orig_apass, cNode->apass);
cNode->modes = 0;
mod_chanmode(NULL, cNode, modes, modec, 0);
cNode->timestamp = new_time;
change->modes_set = orig_modes;
change->new_limit = orig_limit;
strcpy(change->new_key, orig_key);
+ strcpy(change->new_upass, orig_upass);
+ strcpy(change->new_apass, orig_apass);
for (nn = argc = 0; nn < cNode->members.used; ++nn) {
struct modeNode *mn = cNode->members.list[nn];
if ((mn->modes & MODE_CHANOP) && IsService(mn->user) && IsLocal(mn->user)) {
modeList_append(&user->channels, mNode);
if (channel->members.used == 1
- && !(channel->modes & MODE_REGISTERED))
+ && !(channel->modes & MODE_REGISTERED)
+ && !(channel->modes & MODE_APASS))
mNode->modes |= MODE_CHANOP;
for (n=0; n<jf_used; n++) {
/* free memory */
free(mNode);
- if (!deleting && !channel->members.used && !channel->locks && !(channel->modes & MODE_REGISTERED))
+ /* A single check for APASS only should be enough here */
+ if (!deleting && !channel->members.used && !channel->locks
+ && !(channel->modes & MODE_REGISTERED) && !(channel->modes & MODE_APASS))
DelChannel(channel);
}
extern int off_channel;
+static int parse_oplevel(char *str);
+
/* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
* server and Y's indentifying the client on that server. */
struct server*
struct create_desc {
struct userNode *user;
+ int oplevel;
time_t when;
};
join_helper(struct chanNode *chan, void *data)
{
struct create_desc *cd = data;
- AddChannelUser(cd->user, chan);
+ struct modeNode *mNode;
+
+ mNode = AddChannelUser(cd->user, chan);
+ mNode->oplevel = cd->oplevel;
+ if (mNode->oplevel >= 0)
+ mNode->modes |= MODE_CHANOP;
}
static void
struct userNode *un;
struct modeNode *mNode;
long mode;
+ int oplevel = -1;
char *user, *end, sep;
time_t in_timestamp;
const char *pos;
int n_modes;
for (pos=argv[next], n_modes = 1; *pos; pos++)
- if ((*pos == 'k') || (*pos == 'l'))
+ if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A')
+ || (*pos == 'U'))
n_modes++;
unsplit_string(argv+next, n_modes, modes);
next += n_modes;
if (sep == ':') {
mode = 0;
while ((sep = *end++)) {
- if (sep == 'o')
+ if (sep == 'o') {
mode |= MODE_CHANOP;
- else if (sep == 'v')
+ oplevel = -1;
+ } else if (sep == 'v') {
mode |= MODE_VOICE;
- else if (isdigit(sep)) {
+ oplevel = -1;
+ } else if (isdigit(sep)) {
mode |= MODE_CHANOP;
+ if (oplevel >= 0)
+ oplevel += parse_oplevel(end);
+ else
+ oplevel = parse_oplevel(end);
while (isdigit(*end)) end++;
} else
break;
res = 0;
continue;
}
- if ((mNode = AddChannelUser(un, cNode)))
+ if ((mNode = AddChannelUser(un, cNode))) {
mNode->modes = mode;
+ mNode->oplevel = oplevel;
+ }
}
return res;
parse_foreach(char *target_list, foreach_chanfunc cf, foreach_nonchan nc, foreach_userfunc uf, foreach_nonuser nu, void *data)
{
char *j, old;
+ char *cPos, *hPos;
+ int oplevel;
+
do {
j = target_list;
while (*j != 0 && *j != ',')
j++;
old = *j;
*j = 0;
+
+ hPos = strchr(target_list,'#');
+ cPos = strchr(target_list,':');
+
+ /*
+ * Check if both a '#' and a ':' is in the target's name
+ * and if cPos < hPos.
+ * If that's the case, voila, we've found a join with an oplevel
+ */
+ if (hPos && cPos && (cPos < hPos))
+ {
+ oplevel = parse_oplevel(target_list);
+ target_list = hPos + 1;
+ }
+ else
+ oplevel = -1;
+
if (IsChannelName(target_list)
|| (target_list[0] == '0' && target_list[1] == '\0')) {
struct chanNode *chan = GetChannel(target_list);
+ struct create_desc *cd = (struct create_desc*) data;
+
+ cd->oplevel = oplevel;
if (chan) {
if (cf)
cf(chan, data);
}
}
break;
+ case 'U':
+ if (add)
+ {
+ if (in_arg >= argc)
+ goto error;
+ change->modes_set |= MODE_UPASS;
+ safestrncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass));
+ } else {
+ change->modes_clear |= MODE_UPASS;
+ if (!(flags & MCP_UPASS_FREE)) {
+ if (in_arg >= argc)
+ goto error;
+ in_arg++;
+ }
+ }
+ break;
+ case 'A':
+ if (add) {
+ if (in_arg >= argc)
+ goto error;
+ change->modes_set |= MODE_APASS;
+ safestrncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass));
+ } else {
+ change->modes_clear |= MODE_APASS;
+ if (!(flags & MCP_APASS_FREE)) {
+ if (in_arg >= argc)
+ goto error;
+ in_arg++;
+ }
+ }
+ break;
case 'b':
if (!(flags & MCP_ALLOW_OVB))
goto error;
case 'o': case 'v':
{
struct userNode *victim;
+ char *oplevel_str;
+ int oplevel;
+
+ oplevel_str = strchr(modes[in_arg], ':');
+
+ /* XXYYY M #channel +o XXYYY:<oplevel> */
+ if (oplevel_str)
+ {
+ oplevel = parse_oplevel(oplevel_str+1);
+ *oplevel_str = 0;
+ }
+ else if (channel->modes & MODE_UPASS)
+ {
+ /* TODO: need to set oplevel based on issuer's oplevel */
+ oplevel = -1;
+ }
+ else
+ oplevel = -1;
+
if (!(flags & MCP_ALLOW_OVB))
goto error;
if (in_arg >= argc)
if (!victim)
continue;
if ((change->args[ch_arg].u.member = GetUserMode(channel, victim)))
+ {
+ /* Apply the oplevel change */
+ change->args[ch_arg].u.member->oplevel = oplevel;
ch_arg++;
+ }
break;
}
default:
#undef DO_MODE_CHAR
if (change->modes_clear & channel->modes & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', channel->key);
+ if (change->modes_clear & channel->modes & MODE_UPASS)
+ mod_chanmode_append(&chbuf, 'U', channel->upass);
+ if (change->modes_clear * channel->modes & MODE_APASS)
+ mod_chanmode_append(&chbuf, 'A', channel->apass);
}
for (arg = 0; arg < change->argc; ++arg) {
if (!(change->args[arg].mode & MODE_REMOVE))
#undef DO_MODE_CHAR
if(change->modes_set & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', change->new_key);
+ if (change->modes_set & MODE_UPASS)
+ mod_chanmode_append(&chbuf, 'U', change->new_upass);
+ if (change->modes_set & MODE_APASS)
+ mod_chanmode_append(&chbuf, 'A', change->new_apass);
if(change->modes_set & MODE_LIMIT) {
sprintf(int_buff, "%d", change->new_limit);
mod_chanmode_append(&chbuf, 'l', int_buff);
DO_MODE_CHAR(NOPRIVMSGS, 'n');
DO_MODE_CHAR(LIMIT, 'l');
DO_MODE_CHAR(KEY, 'k');
+ DO_MODE_CHAR(UPASS, 'U');
+ DO_MODE_CHAR(APASS, 'A');
DO_MODE_CHAR(DELAYJOINS, 'D');
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
DO_MODE_CHAR(REGISTERED, 'z');
#undef DO_MODE_CHAR
- switch (change->modes_set & (MODE_KEY|MODE_LIMIT)) {
+ switch (change->modes_set & (MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS)) {
+ /* Doing this implementation has been a pain in the arse, I hope I didn't forget a possible combination */
+ case MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS:
+ used += sprintf(outbuff+used, "lkAU %d %s %s %s", change->new_limit, change->new_key, change->new_apass, change->new_upass);
+ break;
+
+ case MODE_KEY|MODE_LIMIT|MODE_APASS:
+ used += sprintf(outbuff+used, "lkA %d %s %s", change->new_limit, change->new_key, change->new_apass);
+ break;
+ case MODE_KEY|MODE_LIMIT|MODE_UPASS:
+ used += sprintf(outbuff+used, "lkU %d %s %s", change->new_limit, change->new_key, change->new_upass);
+ break;
+ case MODE_KEY|MODE_APASS|MODE_UPASS:
+ used += sprintf(outbuff+used, "kAU %s %s %s", change->new_key, change->new_apass, change->new_upass);
+ break;
+
+ case MODE_KEY|MODE_APASS:
+ used += sprintf(outbuff+used, "kA %s %s", change->new_key, change->new_apass);
+ break;
+ case MODE_KEY|MODE_UPASS:
+ used += sprintf(outbuff+used, "kU %s %s", change->new_key, change->new_upass);
+ break;
case MODE_KEY|MODE_LIMIT:
used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key);
break;
+ case MODE_LIMIT|MODE_UPASS:
+ used += sprintf(outbuff+used, "lU %d %s", change->new_limit, change->new_upass);
+ break;
+ case MODE_LIMIT|MODE_APASS:
+ used += sprintf(outbuff+used, "lA %d %s", change->new_limit, change->new_apass);
+ break;
+ case MODE_APASS|MODE_UPASS:
+ used += sprintf(outbuff+used, "AU %s %s", change->new_apass, change->new_upass);
+ break;
+
+ case MODE_LIMIT|MODE_APASS|MODE_UPASS:
+ used += sprintf(outbuff+used, "lAU %d %s %s", change->new_limit, change->new_apass, change->new_upass);
+ break;
+
+ case MODE_APASS:
+ used += sprintf(outbuff+used, "A %s", change->new_apass);
+ break;
+ case MODE_UPASS:
+ used += sprintf(outbuff+used, "U %s", change->new_upass);
+ break;
case MODE_KEY:
used += sprintf(outbuff+used, "k %s", change->new_key);
break;
remove |= MODE_KEY;
channel->key[0] = '\0';
break;
+ case 'A':
+ remove |= MODE_APASS;
+ channel->apass[0] = '\0';
+ break;
+ case 'U':
+ remove |= MODE_UPASS;
+ channel->upass[0] = '\0';
+ break;
case 'l':
remove |= MODE_LIMIT;
channel->limit = 0;
for (it = dict_first(channels); it; it = iter_next(it))
dict_insert(unbursted_channels, iter_key(it), iter_data(it));
}
+
+/*
+ * Oplevel parsing
+ */
+static int
+parse_oplevel(char *str)
+{
+ int oplevel = 0;
+ while (isdigit(*str))
+ oplevel = oplevel * 10 + *str++ - '0';
+ return oplevel;
+}