/* proto-p10.c - IRC protocol output
- * Copyright 2000-2004 srvx Development Team
+ * Copyright 2000-2006 srvx Development Team
*
* This file is part of srvx.
*
irc_user(struct userNode *user)
{
char b64ip[25];
- if (!user)
+ if (!user || IsDummy(user))
return;
irc_p10_ntop(b64ip, &user->ip);
if (user->modes) {
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. */
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
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 */
if ((n+1)<chan->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; n<chan->banlist.used; n++) {
+ for (n=0; n<chan->banlist.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);
{
struct userNode *from;
struct userNode *who;
+ char buf[MAXLEN];
+ unsigned int i, mlen, len;
if (argc < 3)
return 0;
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));
+
irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick);
return 1;
}
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; nn<dead_users.used; nn++)
}
struct userNode *
-AddService(const char *nick, const char *modes, const char *desc, const char *hostname)
+AddLocalUser(const char *nick, const char *ident, const char *hostname, const char *desc, const char *modes)
{
char numeric[COMBO_NUMERIC_LEN+1];
int local_num = get_local_numeric();
time_t timestamp = now;
struct userNode *old_user = GetUserH(nick);
+ if (!modes)
+ modes = "+oik";
if (old_user) {
if (IsLocal(old_user))
return old_user;
if (!hostname)
hostname = self->name;
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 *
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);
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;
}
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;
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
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++;
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) {
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) {
memset(privmsg_funcs+user->num_local, 0, sizeof(privmsg_func_t));
- for (x = user->num_local+1; x < num_privmsg_funcs; x++)
+ 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));
+
+ privmsg_funcs = realloc(privmsg_funcs, num_privmsg_funcs*sizeof(privmsg_func_t));
num_privmsg_funcs--;
}