X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fproto-p10.c;h=37eb33445040081cdd174fd3bed899005419d21a;hb=35ffb2ad774fac945c200d06a30174fe676d94bb;hp=2fc7fac7d964928ff56abdf8c30dfb885b3efca8;hpb=222e1b0003536cf7b47858961d4b56d45c6d6606;p=srvx.git diff --git a/src/proto-p10.c b/src/proto-p10.c index 2fc7fac..37eb334 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -1,11 +1,12 @@ /* proto-p10.c - IRC protocol output * Copyright 2000-2004 srvx Development Team * - * This program is free software; you can redistribute it and/or modify + * This file is part of srvx. + * + * srvx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. Important limitations are - * listed in the COPYING file that accompanies this software. + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +14,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, email srvx-maintainers@srvx.net. + * along with srvx; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "proto-common.c" @@ -37,6 +39,7 @@ #define CMD_EOB "END_OF_BURST" #define CMD_EOB_ACK "EOB_ACK" #define CMD_ERROR "ERROR" +#define CMD_FAKEHOST "FAKE" #define CMD_GET "GET" #define CMD_GLINE "GLINE" #define CMD_HASH "HASH" @@ -118,6 +121,7 @@ #define TOK_EOB "EB" #define TOK_EOB_ACK "EA" #define TOK_ERROR "Y" +#define TOK_FAKEHOST "FA" #define TOK_GET "GET" #define TOK_GLINE "GL" #define TOK_HASH "HASH" @@ -210,6 +214,7 @@ #define P10_EOB TYPE(EOB) #define P10_EOB_ACK TYPE(EOB_ACK) #define P10_ERROR TYPE(ERROR) +#define P10_FAKEHOST TYPE(FAKEHOST) #define P10_GET TYPE(GET) #define P10_GLINE TYPE(GLINE) #define P10_HASH TYPE(HASH) @@ -284,9 +289,13 @@ static unsigned int num_privmsg_funcs; static privmsg_func_t *notice_funcs; static unsigned int num_notice_funcs; static struct dict *unbursted_channels; +static char *his_servername; +static char *his_servercomment; 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); +extern int off_channel; + /* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the * server and Y's indentifying the client on that server. */ struct server* @@ -412,6 +421,12 @@ irc_account(struct userNode *user, const char *stamp) putsock("%s " P10_ACCOUNT " %s %s", self->numeric, user->numeric, stamp); } +void +irc_fakehost(struct userNode *user, const char *host) +{ + putsock("%s " P10_FAKEHOST " %s %s", self->numeric, user->numeric, host); +} + void irc_regnick(UNUSED_ARG(struct userNode *user)) { @@ -472,6 +487,12 @@ irc_notice(struct userNode *from, const char *to, const char *message) 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); +} + void irc_privmsg(struct userNode *from, const char *to, const char *message) { @@ -552,8 +573,6 @@ irc_burst(struct chanNode *chan) long last_mode=-1; unsigned int n; - if (!chan->members.used) - return; 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); @@ -672,7 +691,7 @@ irc_kick(struct userNode *who, struct userNode *target, struct chanNode *channel { const char *numeric; struct modeNode *mn = GetUserMode(channel, who); - numeric = (mn && (mn->modes & MODE_CHANOP)) ? who->numeric : self->numeric; + numeric = ((mn && (mn->modes & MODE_CHANOP)) || off_channel) ? who->numeric : self->numeric; putsock("%s " P10_KICK " %s %s :%s", numeric, channel->name, target->numeric, msg); } @@ -742,6 +761,36 @@ change_nicklen(int new_nicklen) } } +static CMD_FUNC(cmd_whois) +{ + struct userNode *from; + struct userNode *who; + + if (argc < 3) + return 0; + if (!(from = GetUserH(origin))) { + log_module(MAIN_LOG, LOG_ERROR, "Could not find WHOIS origin user %s", origin); + return 0; + } + if(!(who = GetUserH(argv[2]))) { + 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; + } + 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); + else + 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; +} + static CMD_FUNC(cmd_server) { struct server *srv; @@ -749,7 +798,7 @@ static CMD_FUNC(cmd_server) 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) @@ -832,14 +881,18 @@ static CMD_FUNC(cmd_eob_ack) static CMD_FUNC(cmd_ping) { + struct server *srv; + struct userNode *un; + if(argc > 3) - { irc_pong(argv[2], argv[1]); - } + else if ((srv = GetServerH(origin))) + irc_pong(self->name, srv->numeric); + else if ((un = GetUserH(origin))) + irc_pong(self->name, un->numeric); else - { irc_pong(self->name, origin); - } + timeq_del(0, timed_send_ping, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA); timeq_del(0, timed_ping_timeout, 0, TIMEQ_IGNORE_WHEN|TIMEQ_IGNORE_DATA); timeq_add(now + ping_freq, timed_send_ping, 0); @@ -871,20 +924,14 @@ static void create_helper(char *name, void *data) { struct create_desc *cd = data; - /* We can't assume the channel create was allowed because of the - * bad-word channel checking. - */ - struct chanNode *cn; - struct modeNode *mn; + if (!strcmp(name, "0")) { while (cd->user->channels.used > 0) DelChannelUser(cd->user, cd->user->channels.list[0]->channel, 0, 0); return; } - cn = AddChannel(name, cd->when, NULL, NULL); - mn = AddChannelUser(cd->user, cn); - if (mn && (cn->members.used == 1)) - mn->modes = MODE_CHANOP; + + AddChannelUser(cd->user, AddChannel(name, cd->when, NULL, NULL)); } static CMD_FUNC(cmd_create) @@ -966,6 +1013,18 @@ static CMD_FUNC(cmd_account) return 1; } +static CMD_FUNC(cmd_fakehost) +{ + struct userNode *user; + + if ((argc < 3) || !origin || !GetServerH(origin)) + return 0; + if (!(user = GetUserN(argv[1]))) + return 1; + assign_fakehost(user, argv[2], 0); + return 1; +} + static CMD_FUNC(cmd_burst) { extern int rel_age; @@ -1017,7 +1076,10 @@ static CMD_FUNC(cmd_burst) 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) @@ -1120,7 +1182,8 @@ static CMD_FUNC(cmd_clearmode) static CMD_FUNC(cmd_topic) { - static struct chanNode *cn; + struct chanNode *cn; + time_t chan_ts, topic_ts; if (argc < 3) return 0; @@ -1128,13 +1191,22 @@ static CMD_FUNC(cmd_topic) log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose topic is being set", argv[1]); return 0; } - SetChannelTopic(cn, GetUserH(origin), argv[2], 0); + if (argc >= 5) { + /* Looks like an Asuka style topic burst. */ + chan_ts = atoi(argv[2]); + topic_ts = atoi(argv[3]); + } else { + chan_ts = cn->timestamp; + topic_ts = now; + } + SetChannelTopic(cn, GetUserH(origin), argv[argc-1], 0); + cn->topic_time = topic_ts; return 1; } static CMD_FUNC(cmd_num_topic) { - static struct chanNode *cn; + struct chanNode *cn; if (!argv[0]) return 0; /* huh? */ @@ -1389,6 +1461,12 @@ init_parse(void) inttobase64(numer, (numnick << 12) + (usermask & 0x00fff), 3); else inttobase64(numer, (numnick << 18) + (usermask & 0x3ffff), 5); + + str = conf_get_data("server/his_servername", RECDB_QSTRING); + his_servername = str ? strdup(str) : NULL; + str = conf_get_data("server/his_servercomment", RECDB_QSTRING); + his_servercomment = str ? strdup(str) : NULL; + str = conf_get_data("server/hostname", RECDB_QSTRING); desc = conf_get_data("server/description", RECDB_QSTRING); if (!str || !desc) { @@ -1413,6 +1491,8 @@ init_parse(void) dict_insert(irc_func_dict, TOK_NICK, cmd_nick); dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account); dict_insert(irc_func_dict, TOK_ACCOUNT, cmd_account); + dict_insert(irc_func_dict, CMD_FAKEHOST, cmd_fakehost); + dict_insert(irc_func_dict, TOK_FAKEHOST, cmd_fakehost); dict_insert(irc_func_dict, CMD_PASS, cmd_pass); dict_insert(irc_func_dict, TOK_PASS, cmd_pass); dict_insert(irc_func_dict, CMD_PING, cmd_ping); @@ -1489,6 +1569,7 @@ init_parse(void) dict_insert(irc_func_dict, "331", cmd_num_topic); dict_insert(irc_func_dict, "332", cmd_num_topic); dict_insert(irc_func_dict, "333", cmd_num_topic); + dict_insert(irc_func_dict, "345", cmd_dummy); /* blah has been invited to blah */ dict_insert(irc_func_dict, "432", cmd_error_nick); /* Erroneus [sic] nickname */ /* ban list resetting */ /* "stats g" responses */ @@ -1502,6 +1583,7 @@ init_parse(void) 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?) */ dict_insert(irc_func_dict, "461", cmd_dummy); /* Not enough parameters (after TOPIC w/ 0 args) */ + dict_insert(irc_func_dict, "467", cmd_dummy); /* Channel key already set */ num_privmsg_funcs = 16; privmsg_funcs = malloc(sizeof(privmsg_func_t)*num_privmsg_funcs); @@ -1720,7 +1802,7 @@ void DelServer(struct server* serv, int announce, const char *message) } struct userNode * -AddService(const char *nick, const char *desc) +AddService(const char *nick, const char *modes, const char *desc, const char *hostname) { char numeric[COMBO_NUMERIC_LEN+1]; int local_num = get_local_numeric(); @@ -1736,8 +1818,10 @@ AddService(const char *nick, const char *desc) log_module(MAIN_LOG, LOG_ERROR, "Unable to allocate numnick for service %s", nick); return 0; } + if (!hostname) + hostname = self->name; make_numeric(self, local_num, numeric); - return AddUser(self, nick, nick, self->name, "+oik", numeric, desc, now, "AAAAAA"); + return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA"); } struct userNode * @@ -1906,8 +1990,8 @@ void mod_usermode(struct userNode *user, const char *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++) { @@ -1949,6 +2033,18 @@ void mod_usermode(struct userNode *user, const char *mode_change) { call_account_func(user, tag); } break; + case 'f': + if (*word) { + char host[MAXLEN]; + unsigned int ii; + for (ii=0; (*word != ' ') && (*word != '\0'); ) + host[ii++] = *word++; + host[ii] = 0; + while (*word == ' ') + word++; + assign_fakehost(user, host, 0); + } + break; } #undef do_user_mode } @@ -1975,7 +2071,7 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un case '-': add = 0; break; -#define do_chan_mode(FLAG) do { if (add) change->modes_set |= FLAG, change->modes_clear &= ~FLAG; else change->modes_clear |= FLAG, change->modes_set &= ~FLAG; } while(0) +#define do_chan_mode(FLAG) do { if (add) change->modes_set |= (FLAG), change->modes_clear &= ~(FLAG); else change->modes_clear |= (FLAG), change->modes_set &= ~(FLAG); } while(0) case 'C': do_chan_mode(MODE_NOCTCPS); break; case 'D': do_chan_mode(MODE_DELAYJOINS); break; case 'c': do_chan_mode(MODE_NOCOLORS); break; @@ -2021,7 +2117,7 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un 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': { @@ -2037,13 +2133,26 @@ mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, un victim = GetUserN(modes[in_arg++]); else victim = GetUserH(modes[in_arg++]); - if ((change->args[ch_arg].member = GetUserMode(channel, victim))) + if (!victim) + continue; + if ((change->args[ch_arg].u.member = GetUserMode(channel, victim))) ch_arg++; break; } + default: + if (!(flags & MCP_FROM_SERVER)) + goto error; + break; } } change->argc = ch_arg; /* in case any turned out to be ignored */ + if (change->modes_set & MODE_SECRET) { + change->modes_set &= ~(MODE_PRIVATE); + change->modes_clear |= MODE_PRIVATE; + } else if (change->modes_set & MODE_PRIVATE) { + change->modes_set &= ~(MODE_SECRET); + change->modes_clear |= MODE_SECRET; + } return change; error: mod_chanmode_free(change); @@ -2066,7 +2175,8 @@ static void mod_chanmode_append(struct chanmode_buffer *buf, char ch, const char *arg) { size_t arg_len = strlen(arg); - if (buf->modes_used + buf->args_used + buf->chname_len + arg_len > 450) { + if (buf->modes_used > (MAXMODEPARAMS) || + buf->modes_used + buf->args_used + buf->chname_len + arg_len > 450) { memcpy(buf->modes + buf->modes_used, buf->args, buf->args_used); buf->modes[buf->modes_used + buf->args_used] = '\0'; irc_mode((buf->is_chanop ? buf->actor : NULL), buf->channel, buf->modes); @@ -2088,11 +2198,14 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod struct modeNode *mn; char int_buff[32], mode = '\0'; + assert(change->argc <= change->alloc_argc); memset(&chbuf, 0, sizeof(chbuf)); chbuf.channel = channel; chbuf.actor = who; chbuf.chname_len = strlen(channel->name); - if ((mn = GetUserMode(channel, who)) && (mn->modes & MODE_CHANOP)) + + mn = GetUserMode(channel, who); + if ((mn && (mn->modes & MODE_CHANOP)) || off_channel) chbuf.is_chanop = 1; /* First remove modes */ @@ -2123,13 +2236,13 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod 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; } } @@ -2165,13 +2278,13 @@ mod_chanmode_announce(struct userNode *who, struct chanNode *channel, struct mod 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; } } @@ -2189,6 +2302,7 @@ char * mod_chanmode_format(struct mod_chanmode *change, char *outbuff) { unsigned int used = 0; + assert(change->argc <= change->alloc_argc); if (change->modes_clear) { outbuff[used++] = '-'; #define DO_MODE_CHAR(BIT, CHAR) if (change->modes_clear & MODE_##BIT) outbuff[used++] = CHAR @@ -2262,7 +2376,7 @@ clear_chanmode(struct chanNode *channel, const char *modes) 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; } } @@ -2308,6 +2422,24 @@ reg_privmsg_func(struct userNode *user, privmsg_func_t handler) privmsg_funcs[numeric] = handler; } +void +unreg_privmsg_func(struct userNode *user, privmsg_func_t handler) +{ + unsigned int x; + + if (!user || handler) + 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--; +} + + void reg_notice_func(struct userNode *user, privmsg_func_t handler) { @@ -2323,6 +2455,24 @@ reg_notice_func(struct userNode *user, privmsg_func_t handler) notice_funcs[numeric] = handler; } +void +unreg_notice_func(struct userNode *user, privmsg_func_t handler) +{ + 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)); + + 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--; +} + void reg_oper_func(oper_func_t handler) {