}
}
+static void
+irc_p10_pton(irc_in_addr_t *ip, const char *input)
+{
+ if (strlen(input) == 6) {
+ unsigned int value;
+ memset(ip, 0, 6 * sizeof(ip->in6[0]));
+ value = base64toint(input, 6);
+ ip->in6[6] = htons(value >> 16);
+ ip->in6[7] = htons(value & 65535);
+ } else {
+ unsigned int pos = 0;
+ do {
+ if (*input == '_') {
+ unsigned int left;
+ for (left = (25 - strlen(input)) / 3; left; left--)
+ ip->in6[pos++] = 0;
+ input++;
+ } else {
+ ip->in6[pos++] = ntohs(base64toint(input, 3));
+ input += 3;
+ }
+ } while (pos < 8);
+ }
+}
+
+static void
+irc_p10_ntop(char *output, const irc_in_addr_t *ip)
+{
+ if (irc_in_addr_is_ipv4(*ip)) {
+ unsigned int in4;
+ in4 = (ntohs(ip->in6[6]) << 16) | ntohs(ip->in6[7]);
+ inttobase64(output, in4, 6);
+ output[6] = '\0';
+ } else if (irc_in_addr_is_ipv6(*ip)) {
+ unsigned int max_start, max_zeros, curr_zeros, zero, ii;
+ /* Can start by printing out the leading non-zero parts. */
+ for (ii = 0; (ip->in6[ii]) && (ii < 8); ++ii) {
+ inttobase64(output, ntohs(ip->in6[ii]), 3);
+ output += 3;
+ }
+ /* Find the longest run of zeros. */
+ for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
+ if (!ip->in6[ii])
+ curr_zeros++;
+ else if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ }
+ if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ /* Print the rest of the address */
+ for (ii = zero; ii < 8; ) {
+ if ((ii == max_start) && max_zeros) {
+ *output++ = '_';
+ ii += max_zeros;
+ } else {
+ inttobase64(output, ntohs(ip->in6[ii]), 3);
+ output += 3;
+ }
+ }
+ *output = '\0';
+ } else {
+ strcpy(output, "???");
+ }
+}
+
void
irc_user(struct userNode *user)
{
- char b64ip[7];
+ char b64ip[25];
if (!user)
return;
- inttobase64(b64ip, ntohl(user->ip.s_addr), 6);
+ irc_p10_ntop(b64ip, &user->ip);
if (user->modes) {
int modelen;
char modes[32];
}
irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
if (his_servername && his_servercomment)
- irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment);
+ irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment);
else
- irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description);
-
- if (IsOper(who)) {
+ irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description);
+ if (IsOper(who))
irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick);
- }
irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick);
return 1;
}
if (argc < 8)
return 0;
- if (origin) {
+ if (self->uplink) {
/* another server introduced us */
srv = AddServer(GetServerH(origin), argv[1], atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), argv[6], argv[argc-1]);
if (!srv)
mode |= MODE_CHANOP;
else if (sep == 'v')
mode |= MODE_VOICE;
- else
+ else if (isdigit(sep)) {
+ mode |= MODE_CHANOP;
+ while (isdigit(*end)) end++;
+ } else
break;
}
if (rel_age < 0)
dict_insert(irc_func_dict, "401", cmd_dummy); /* target left network */
dict_insert(irc_func_dict, "403", cmd_dummy); /* no such channel */
dict_insert(irc_func_dict, "404", cmd_dummy); /* cannot send to channel */
+ dict_insert(irc_func_dict, "439", cmd_dummy); /* target change too fast */
dict_insert(irc_func_dict, "441", cmd_dummy); /* target isn't on that channel */
dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */
dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */
int
is_valid_nick(const char *nick) {
+ unsigned int ii;
/* IRC has some of The Most Fucked-Up ideas about character sets
* in the world.. */
if (!isalpha(*nick) && !strchr("{|}~[\\]^_`", *nick))
return 0;
- for (++nick; *nick; ++nick)
- if (!isalnum(*nick) && !strchr("{|}~[\\]^-_`", *nick))
+ for (ii = 0; nick[ii]; ++ii)
+ if (!isalnum(nick[ii]) && !strchr("{|}~[\\]^-_`", nick[ii]))
return 0;
if (strlen(nick) > nicklen)
return 0;
safestrncpy(uNode->info, userinfo, sizeof(uNode->info));
safestrncpy(uNode->hostname, hostname, sizeof(uNode->hostname));
safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric));
- uNode->ip.s_addr = htonl(base64toint(realip, 6));
+ irc_p10_pton(&uNode->ip, realip);
uNode->timestamp = timestamp;
modeList_init(&uNode->channels);
uNode->uplink = uplink;
{
unsigned int n;
+ verify(user);
+
/* mark them as dead, in case anybody cares */
user->dead = 1;
free_user(user);
}
+static void call_oper_funcs(struct userNode *user);
+
void mod_usermode(struct userNode *user, const char *mode_change) {
- static void call_oper_funcs(struct userNode *user);
int add = 1;
const char *word = mode_change;
if (!user || !mode_change)
return;
- while (*word != ' ' && *word) word++;\
- while (*word == ' ') word++; \
+ while (*word != ' ' && *word) word++;
+ while (*word == ' ') word++;
while (1) {
#define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
switch (*mode_change++) {
case 'r': do_chan_mode(MODE_REGONLY); break;
case 's': do_chan_mode(MODE_SECRET); break;
case 't': do_chan_mode(MODE_TOPICLIMIT); break;
+ case 'z':
+ if (!(flags & MCP_REGISTERED)) {
+ do_chan_mode(MODE_REGISTERED);
+ } else {
+ mod_chanmode_free(change);
+ return NULL;
+ }
+ break;
#undef do_chan_mode
case 'l':
if (add) {
change->args[ch_arg].mode = MODE_BAN;
if (!add)
change->args[ch_arg].mode |= MODE_REMOVE;
- change->args[ch_arg++].hostmask = modes[in_arg++];
+ change->args[ch_arg++].u.hostmask = modes[in_arg++];
break;
case 'o': case 'v':
{
victim = GetUserH(modes[in_arg++]);
if (!victim)
continue;
- if ((change->args[ch_arg].member = GetUserMode(channel, victim)))
+ if ((change->args[ch_arg].u.member = GetUserMode(channel, victim)))
ch_arg++;
break;
}
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
+ DO_MODE_CHAR(REGISTERED, 'z');
#undef DO_MODE_CHAR
if (change->modes_clear & channel->modes & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', channel->key);
chbuf.modes[chbuf.modes_used++] = mode = '-';
switch (change->args[arg].mode & ~MODE_REMOVE) {
case MODE_BAN:
- mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask);
+ mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
break;
default:
if (change->args[arg].mode & MODE_CHANOP)
- mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
if (change->args[arg].mode & MODE_VOICE)
- mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
break;
}
}
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
+ DO_MODE_CHAR(REGISTERED, 'z');
#undef DO_MODE_CHAR
if(change->modes_set & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', change->new_key);
chbuf.modes[chbuf.modes_used++] = mode = '+';
switch (change->args[arg].mode) {
case MODE_BAN:
- mod_chanmode_append(&chbuf, 'b', change->args[arg].hostmask);
+ mod_chanmode_append(&chbuf, 'b', change->args[arg].u.hostmask);
break;
default:
if (change->args[arg].mode & MODE_CHANOP)
- mod_chanmode_append(&chbuf, 'o', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'o', change->args[arg].u.member->user->numeric);
if (change->args[arg].mode & MODE_VOICE)
- mod_chanmode_append(&chbuf, 'v', change->args[arg].member->user->numeric);
+ mod_chanmode_append(&chbuf, 'v', change->args[arg].u.member->user->numeric);
break;
}
}
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
+ DO_MODE_CHAR(REGISTERED, 'z');
#undef DO_MODE_CHAR
}
if (change->modes_set) {
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)) {
case MODE_KEY|MODE_LIMIT:
case 'b': remove |= MODE_BAN; break;
case 'D': remove |= MODE_DELAYJOINS; break;
case 'r': remove |= MODE_REGONLY; break;
- case 'c': remove |= MODE_NOCOLORS;
+ case 'c': remove |= MODE_NOCOLORS; break;
case 'C': remove |= MODE_NOCTCPS; break;
+ case 'z': remove |= MODE_REGISTERED; break;
}
}