X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fproto-p10.c;h=003bbe62999cf23eb3a7312a99dd9c1f145cba88;hb=bc8461e95aafc26b36ee41ca66ff5aabfb6d728f;hp=c7d69b06476c68a124cdf270ebeb215545f1a526;hpb=e89fe7dbb4b2b1d66ea4909b3be7ccea689bfeaa;p=srvx.git diff --git a/src/proto-p10.c b/src/proto-p10.c index c7d69b0..003bbe6 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -1,5 +1,5 @@ /* proto-p10.c - IRC protocol output - * Copyright 2000-2004 srvx Development Team + * Copyright 2000-2006 srvx Development Team * * This file is part of srvx. * @@ -383,6 +383,8 @@ irc_p10_pton(irc_in_addr_t *ip, const char *input) unsigned int value; memset(ip, 0, 6 * sizeof(ip->in6[0])); value = base64toint(input, 6); + if (value) + ip->in6[5] = htons(65535); ip->in6[6] = htons(value >> 16); ip->in6[7] = htons(value & 65535); } else { @@ -404,7 +406,9 @@ irc_p10_pton(irc_in_addr_t *ip, const char *input) static void irc_p10_ntop(char *output, const irc_in_addr_t *ip) { - if (irc_in_addr_is_ipv4(*ip)) { + if (!irc_in_addr_is_valid(*ip)) { + strcpy(output, "AAAAAA"); + } else if (irc_in_addr_is_ipv4(*ip)) { unsigned int in4; in4 = (ntohs(ip->in6[6]) << 16) | ntohs(ip->in6[7]); inttobase64(output, in4, 6); @@ -451,7 +455,7 @@ void irc_user(struct userNode *user) { char b64ip[25]; - if (!user) + if (!user || IsDummy(user)) return; irc_p10_ntop(b64ip, &user->ip); if (user->modes) { @@ -467,16 +471,16 @@ irc_user(struct userNode *user) modes[modelen++] = 'w'; if (IsService(user)) modes[modelen++] = 'k'; - if (IsServNotice(user)) - modes[modelen++] = 's'; if (IsDeaf(user)) modes[modelen++] = 'd'; if (IsGlobal(user)) modes[modelen++] = 'g'; - if (IsHelperIrcu(user)) - modes[modelen++] = 'h'; + if (IsNoChan(user)) + modes[modelen++] = 'n'; if (IsHiddenHost(user)) modes[modelen++] = 'x'; + if (IsNoIdle(user)) + modes[modelen++] = 'I'; modes[modelen] = 0; /* we don't need to put the + in modes because it's in the format string. */ @@ -554,22 +558,48 @@ irc_wallchops(struct userNode *from, const char *to, const char *message) putsock("%s " P10_WALLCHOPS " %s :%s", from->numeric, to, message); } +static int +deliver_to_dummy(struct userNode *source, struct userNode *dest, const char *message, int type) +{ + unsigned int num; + + if (!dest || !IsDummy(dest) || !IsLocal(dest)) + return 0; + num = dest->num_local; + switch (type) { + default: + if ((num < num_notice_funcs) && notice_funcs[num]) + notice_funcs[num](source, dest, message, 0); + break; + case 1: + if ((num < num_privmsg_funcs) && privmsg_funcs[num]) + privmsg_funcs[num](source, dest, message, 0); + break; + } + return 1; +} + void irc_notice(struct userNode *from, const char *to, const char *message) { - putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message); + if (to[0] == '#' || to[0] == '$' + || !deliver_to_dummy(from, GetUserN(to), message, 0)) + putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message); } void irc_notice_user(struct userNode *from, struct userNode *to, const char *message) { - putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message); + if (!deliver_to_dummy(from, to, message, 0)) + putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message); } void irc_privmsg(struct userNode *from, const char *to, const char *message) { - putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message); + if (to[0] == '#' || to[0] == '$' + || !deliver_to_dummy(from, GetUserN(to), message, 1)) + putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message); } void @@ -596,6 +626,21 @@ irc_pong(const char *who, const char *data) putsock("%s " P10_PONG " %s :%s", self->numeric, who, data); } +void +irc_pong_asll(const char *who, const char *orig_ts) +{ + char *delim; + struct timeval orig; + struct timeval now; + int diff; + + orig.tv_sec = strtoul(orig_ts, &delim, 10); + orig.tv_usec = (*delim == '.') ? strtoul(delim + 1, NULL, 10) : 0; + gettimeofday(&now, NULL); + diff = (now.tv_sec - orig.tv_sec) * 1000 + (now.tv_usec - orig.tv_usec) / 1000; + putsock("%s " P10_PONG " %s %s %d " FMT_TIME_T ".%06u", self->numeric, who, orig_ts, diff, now.tv_sec, (unsigned)now.tv_usec); +} + void irc_pass(const char *passwd) { @@ -617,8 +662,12 @@ irc_introduce(const char *passwd) void irc_gline(struct server *srv, struct gline *gline) { - putsock("%s " P10_GLINE " %s +%s %ld :%s", - self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->reason); + if (gline->lastmod) + putsock("%s " P10_GLINE " %s +%s %ld %ld :%s", + self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->lastmod, gline->reason); + else + putsock("%s " P10_GLINE " %s +%s %ld :%s", + self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->reason); } void @@ -644,13 +693,14 @@ irc_burst(struct chanNode *chan) struct modeNode *mn; struct banNode *bn; long last_mode=-1; + unsigned int first_ban; unsigned int n; base_len = sprintf(burst_line, "%s " P10_BURST " %s " FMT_TIME_T " ", self->numeric, chan->name, chan->timestamp); len = irc_make_chanmode(chan, burst_line+base_len); pos = base_len + len; - if (len) + if (len > 0 && chan->members.used > 0) burst_line[pos++] = ' '; /* dump the users */ @@ -675,32 +725,36 @@ irc_burst(struct chanNode *chan) if ((n+1)members.used) burst_line[pos++] = ','; } + + /* dump the bans */ if (chan->banlist.used) { - /* dump the bans */ - if (pos+2+strlen(chan->banlist.list[0]->ban) > 505) { - burst_line[pos-1] = 0; - putsock("%s", burst_line); - pos = base_len; - } else { + first_ban = 1; + + if (chan->members.used > 0) burst_line[pos++] = ' '; - } - burst_line[pos++] = ':'; - burst_line[pos++] = '%'; - base_len = pos; - for (n=0; nbanlist.used; n++) { + for (n=0; nbanlist.used; ) { + if (first_ban && (pos < 500)) { + burst_line[pos++] = ':'; + burst_line[pos++] = '%'; + } bn = chan->banlist.list[n]; len = strlen(bn->ban); - if (pos+len+1 > 510) { - burst_line[pos-1] = 0; /* -1 to back up over the space or comma */ + if (pos + 2 + len < 505) { + memcpy(burst_line + pos, bn->ban, len); + pos += len; + burst_line[pos++] = ' '; + first_ban = 0; + n++; + } else { + burst_line[pos-1] = 0; putsock("%s", burst_line); pos = base_len; + first_ban = 1; } - memcpy(burst_line+pos, bn->ban, len); - pos += len; - burst_line[pos++] = ' '; } } + /* print the last line */ burst_line[pos] = 0; putsock("%s", burst_line); @@ -838,6 +892,8 @@ static CMD_FUNC(cmd_whois) { struct userNode *from; struct userNode *who; + char buf[MAXLEN]; + unsigned int i, mlen, len; if (argc < 3) return 0; @@ -849,17 +905,69 @@ static CMD_FUNC(cmd_whois) irc_numeric(from, ERR_NOSUCHNICK, "%s@%s :No such nick", argv[2], self->name); return 1; } - if (IsHiddenHost(who) && !IsOper(from)) { - /* Just stay quiet. */ - return 1; + + if (IsFakeHost(who) && IsHiddenHost(who)) + irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->fakehost, who->info); + else if (IsHiddenHost(who) && who->handle_info && hidden_host_suffix) + irc_numeric(from, RPL_WHOISUSER, "%s %s %s.%s * :%s", who->nick, who->ident, who->handle_info->handle, hidden_host_suffix, who->info); + else + irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info); + + if ((!IsService(who) && !IsNoChan(who)) || (from == who)) { + struct modeNode *mn; + mlen = strlen(self->name) + strlen(from->nick) + 12 + strlen(who->nick); + len = 0; + *buf = '\0'; + for (i = 0; i < who->channels.used; i++) + { + mn = who->channels.list[i]; + + if (!IsOper(from) && (mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from)) + continue; + + if (len + strlen(mn->channel->name) + mlen > MAXLEN - 5) + { + irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf); + *buf = '\0'; + len = 0; + } + + if (IsDeaf(who)) + *(buf + len++) = '-'; + if ((mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from)) + *(buf + len++) = '*'; + if (mn->modes & MODE_CHANOP) + *(buf + len++) = '@'; + else if (mn->modes & MODE_VOICE) + *(buf + len++) = '+'; + + if (len) + *(buf + len) = '\0'; + strcpy(buf + len, mn->channel->name); + len += strlen(mn->channel->name); + strcat(buf + len, " "); + len++; + } + if (buf[0] != '\0') + irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf); } - irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info); - if (his_servername && his_servercomment) + + if (his_servername && his_servercomment && !IsOper(from) && from != who) 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 (IsAway(who)) + irc_numeric(from, RPL_AWAY, "%s :Away", who->nick); if (IsOper(who)) - irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick); + irc_numeric(from, RPL_WHOISOPERATOR, "%s :%s", who->nick, IsLocal(who) ? "is a megalomaniacal power hungry tyrant" : "is an IRC Operator"); + if (who->handle_info) + irc_numeric(from, RPL_WHOISACCOUNT, "%s %s :is logged in as", who->nick, who->handle_info->handle); + if (IsHiddenHost(who) && who->handle_info && (IsOper(from) || from == who)) + irc_numeric(from, RPL_WHOISACTUALLY, "%s %s@%s %s :Actual user@host, Actual IP", who->nick, who->ident, who->hostname, irc_ntoa(&who->ip)); + if (IsLocal(who) && !IsService(who) && (!IsNoIdle(who) || IsOper(from) || from == who)) + irc_numeric(from, RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time", who->nick, now - who->idle_since, who->timestamp); + irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick); return 1; } @@ -957,8 +1065,8 @@ static CMD_FUNC(cmd_ping) struct server *srv; struct userNode *un; - if(argc > 3) - irc_pong(argv[2], argv[1]); + if (argc > 3) + irc_pong_asll(argv[2], argv[3]); else if ((srv = GetServerH(origin))) irc_pong(self->name, srv->numeric); else if ((un = GetUserH(origin))) @@ -1123,6 +1231,8 @@ static CMD_FUNC(cmd_burst) if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A') || (*pos == 'U')) n_modes++; + if (next + n_modes > argc) + n_modes = argc - next; unsplit_string(argv+next, n_modes, modes); next += n_modes; break; @@ -1325,9 +1435,11 @@ static CMD_FUNC(cmd_num_topic) static CMD_FUNC(cmd_num_gline) { + time_t lastmod; if (argc < 6) return 0; - gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0); + lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0; + gline_add(origin, argv[3], atoi(argv[4])-now, argv[argc - 1], now, lastmod, 0); return 1; } @@ -1369,19 +1481,6 @@ static CMD_FUNC(cmd_kill) return 1; } -static CMD_FUNC(cmd_part) -{ - struct userNode *user; - - if (argc < 2) - return 0; - user = GetUserH(origin); - if (!user) - return 0; - parse_foreach(argv[1], part_helper, NULL, NULL, NULL, user); - return 1; -} - static CMD_FUNC(cmd_kick) { if (argc < 3) @@ -1414,13 +1513,13 @@ static CMD_FUNC(cmd_squit) static CMD_FUNC(cmd_privmsg) { struct privmsg_desc pd; - if (argc != 3) + if (argc < 3) return 0; pd.user = GetUserH(origin); if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user))) return 1; pd.is_notice = 0; - pd.text = argv[2]; + pd.text = argv[argc - 1]; parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd); return 1; } @@ -1428,13 +1527,13 @@ static CMD_FUNC(cmd_privmsg) static CMD_FUNC(cmd_notice) { struct privmsg_desc pd; - if (argc != 3) + if (argc < 3) return 0; pd.user = GetUserH(origin); if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user))) return 1; pd.is_notice = 1; - pd.text = argv[2]; + pd.text = argv[argc - 1]; parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd); return 1; } @@ -1455,12 +1554,15 @@ static CMD_FUNC(cmd_away) static CMD_FUNC(cmd_gline) { + time_t lastmod; + if (argc < 3) return 0; if (argv[2][0] == '+') { if (argc < 5) return 0; - gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0); + lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0; + gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, lastmod, 0); return 1; } else if (argv[2][0] == '-') { gline_remove(argv[2]+1, 0); @@ -1497,12 +1599,16 @@ parse_cleanup(void) unsigned int nn; free(of_list); free(privmsg_funcs); + num_privmsg_funcs = 0; free(notice_funcs); + num_notice_funcs = 0; free(mcf_list); dict_delete(irc_func_dict); for (nn=0; nnname; make_numeric(self, local_num, numeric); - return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA"); + return AddUser(self, nick, ident, hostname, modes, numeric, desc, now, "AAAAAA"); } struct userNode * @@ -1951,7 +2059,7 @@ static struct userNode* AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip) { struct userNode *oldUser, *uNode; - unsigned int n, ignore_user; + unsigned int n, ignore_user, dummy; if ((strlen(numeric) < 3) || (strlen(numeric) > 5)) { log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink, nick, numeric); @@ -1968,7 +2076,10 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * return NULL; } - if (!is_valid_nick(nick)) { + dummy = modes && modes[0] == '*'; + if (dummy) { + ++modes; + } else if (!is_valid_nick(nick)) { log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", uplink, nick); return NULL; } @@ -2000,6 +2111,7 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric)); irc_p10_pton(&uNode->ip, realip); uNode->timestamp = timestamp; + uNode->idle_since = timestamp; modeList_init(&uNode->channels); uNode->uplink = uplink; if (++uNode->uplink->clients > uNode->uplink->max_clients) { @@ -2008,6 +2120,8 @@ AddUser(struct server* uplink, const char *nick, const char *ident, const char * uNode->num_local = base64toint(numeric+strlen(uNode->uplink->numeric), 3) & uNode->uplink->num_mask; uNode->uplink->users[uNode->num_local] = uNode; mod_usermode(uNode, modes); + if (dummy) + uNode->modes |= FLAGS_DUMMY; if (ignore_user) return uNode; @@ -2037,7 +2151,7 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char /* remove user from all channels */ while (user->channels.used > 0) - DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, false, 0); + DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, NULL, false); /* Call these in reverse order so ChanServ can update presence information before NickServ nukes the handle_info. */ @@ -2062,6 +2176,14 @@ DelUser(struct userNode* user, struct userNode *killer, int announce, const char irc_kill(killer, user, why); } + if (IsLocal(user)) { + unsigned int num = user->num_local; + if (num < num_privmsg_funcs) + privmsg_funcs[num] = NULL; + if (num < num_notice_funcs) + notice_funcs[num] = NULL; + } + modeList_clean(&user->channels); /* We don't free them, in case we try to privmsg them or something * (like when a stupid oper kills themself). We just put them onto @@ -2098,7 +2220,6 @@ void mod_usermode(struct userNode *user, const char *mode_change) { userList_remove(&curr_opers, user); } break; - case 'O': do_user_mode(FLAGS_LOCOP); break; case 'i': do_user_mode(FLAGS_INVISIBLE); if (add) invis_clients++; @@ -2106,11 +2227,11 @@ void mod_usermode(struct userNode *user, const char *mode_change) { invis_clients--; break; case 'w': do_user_mode(FLAGS_WALLOP); break; - case 's': do_user_mode(FLAGS_SERVNOTICE); break; case 'd': do_user_mode(FLAGS_DEAF); break; case 'k': do_user_mode(FLAGS_SERVICE); break; case 'g': do_user_mode(FLAGS_GLOBAL); break; - case 'h': do_user_mode(FLAGS_HELPER); break; + case 'n': do_user_mode(FLAGS_NOCHAN); break; + case 'I': do_user_mode(FLAGS_NOIDLE); break; case 'x': do_user_mode(FLAGS_HIDDEN_HOST); break; case 'r': if (*word) { @@ -2255,6 +2376,8 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un char *oplevel_str; int oplevel; + if (in_arg >= argc) + goto error; oplevel_str = strchr(modes[in_arg], ':'); if (oplevel_str) { @@ -2386,7 +2509,7 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod 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) + if (change->modes_clear & channel->modes & MODE_APASS) mod_chanmode_append(&chbuf, 'A', channel->apass); } for (arg = 0; arg < change->argc; ++arg) { @@ -2631,9 +2754,10 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler) { unsigned int numeric = user->num_local; if (numeric >= num_privmsg_funcs) { - int newnum = numeric + 8; + int newnum = numeric + 8, ii; privmsg_funcs = realloc(privmsg_funcs, newnum*sizeof(privmsg_func_t)); - memset(privmsg_funcs+num_privmsg_funcs, 0, (newnum-num_privmsg_funcs)*sizeof(privmsg_func_t)); + for (ii = num_privmsg_funcs; ii < newnum; ++ii) + privmsg_funcs[ii] = NULL; num_privmsg_funcs = newnum; } if (privmsg_funcs[numeric]) @@ -2642,20 +2766,12 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler) } void -unreg_privmsg_func(struct userNode *user, privmsg_func_t handler) +unreg_privmsg_func(struct userNode *user) { - unsigned int x; - - if (!user || handler) - return; /* this really only works with users */ + if (!IsLocal(user) || user->num_local >= num_privmsg_funcs) + return; /* this really only works with users */ - memset(privmsg_funcs+user->num_local, 0, sizeof(privmsg_func_t)); - - for (x = user->num_local+1; x < num_privmsg_funcs; x++) - memmove(privmsg_funcs+x-1, privmsg_funcs+x, sizeof(privmsg_func_t)); - - privmsg_funcs = realloc(privmsg_funcs, num_privmsg_funcs*sizeof(privmsg_func_t)); - num_privmsg_funcs--; + privmsg_funcs[user->num_local] = NULL; } @@ -2664,9 +2780,10 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler) { unsigned int numeric = user->num_local; if (numeric >= num_notice_funcs) { - int newnum = numeric + 8; + int newnum = numeric + 8, ii; notice_funcs = realloc(notice_funcs, newnum*sizeof(privmsg_func_t)); - memset(notice_funcs+num_notice_funcs, 0, (newnum-num_notice_funcs)*sizeof(privmsg_func_t)); + for (ii = num_privmsg_funcs; ii < newnum; ++ii) + privmsg_funcs[ii] = NULL; num_notice_funcs = newnum; } if (notice_funcs[numeric]) @@ -2675,21 +2792,12 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler) } void -unreg_notice_func(struct userNode *user, privmsg_func_t handler) +unreg_notice_func(struct userNode *user) { - unsigned int x; - - if (!user || handler) - return; /* this really only works with users */ - - memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t)); - - for (x = user->num_local+1; x < num_notice_funcs; x++) - memmove(notice_funcs+x-1, notice_funcs+x, sizeof(privmsg_func_t)); + if (!IsLocal(user) || user->num_local >= num_privmsg_funcs) + return; /* this really only works with users */ - memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t)); - notice_funcs = realloc(notice_funcs, num_notice_funcs*sizeof(privmsg_func_t)); - num_notice_funcs--; + notice_funcs[user->num_local] = NULL; } void