Files
bitchx/source/who.c
Kevin Easton 0a16ab16ac Introduce strbegins() macro and replace all open-coded instances
This test is done quite a bit across the tree, and the open-coded variants make it easy to have an
accidental mismatch between the length of the prefix being tested and the length actually passed to
strncmp().

This fixes an issue of that type comparing the server version against the prefix "u2.10", where the old
code used an incorrect length of 4.
2017-06-06 23:47:10 +10:00

1064 lines
23 KiB
C

/*
* who.c -- The WHO queue. The ISON queue. The USERHOST queue.
*
* Written by Jeremy Nelson
* Copyright 1996, 1997 EPIC Software Labs
*/
#include "irc.h"
static char cvsrevision[] = "$Id$";
CVS_REVISION(who_c)
#include "struct.h"
#include "commands.h"
#include "ircaux.h"
#include "who.h"
#include "server.h"
#include "window.h"
#include "vars.h"
#include "hook.h"
#include "output.h"
#include "numbers.h"
#include "parse.h"
#include "if.h"
#include "names.h"
#include "misc.h"
#define MAIN_SOURCE
#include "modval.h"
/*
*
*
*
* WHO QUEUE
*
*
*
*/
/* flags used by who queue */
#define WHO_OPS 0x0001
#define WHO_NAME 0x0002
#define WHO_ZERO 0x0004
#define WHO_CHOPS 0x0008
#define WHO_FILE 0x0010
#define WHO_HOST 0x0020
#define WHO_SERVER 0x0040
#define WHO_HERE 0x0080
#define WHO_AWAY 0x0100
#define WHO_NICK 0x0200
#define WHO_LUSERS 0x0400
#define WHO_REAL 0x0800
#define WHO_NOCHOPS 0x1000
#define WHO_INVISIBLE 0x2000
/*
* This is tricky -- this doesnt get the LAST one, it gets the
* next to the last one. Why? Because the LAST one is the one
* asking, and they want to know who is LAST (before them)
* So it sucks. Sue me.
*/
static WhoEntry *who_previous_query (WhoEntry *me)
{
WhoEntry *what = who_queue_top(from_server);
while (what && what->next != me)
what = what->next;
return what;
}
static void who_queue_add (WhoEntry *item)
{
WhoEntry *bottom = who_queue_top(from_server);
while (bottom && bottom->next)
bottom = bottom->next;
if (!bottom)
set_who_queue_top(from_server, item);
else
bottom->next = item;
return;
}
static void delete_who_item (WhoEntry *save)
{
new_free(&save->who_target);
new_free(&save->who_name);
new_free(&save->who_host);
new_free(&save->who_server);
new_free(&save->who_nick);
new_free(&save->who_real);
new_free(&save->who_stuff);
new_free(&save->who_end);
new_free(&save->who_buff);
new_free(&save->who_args);
new_free((char **)&save);
}
static void who_queue_pop (void)
{
WhoEntry *save;
int piggyback;
do
{
if (!(save = who_queue_top(from_server)))
break;
piggyback = save->piggyback;
set_who_queue_top(from_server, save->next);
delete_who_item(save);
}
while (piggyback);
return;
}
static WhoEntry *get_new_who_entry (void)
{
WhoEntry *new_w = (WhoEntry *)new_malloc(sizeof(WhoEntry));
#if 0
no need to do this
new_w->dirty = 0;
new_w->piggyback = 0;
new_w->who_mask = 0;
new_w->who_target = NULL;
new_w->who_host = NULL;
new_w->who_name = NULL;
new_w->who_server = NULL;
new_w->who_nick = NULL;
new_w->who_real = NULL;
new_w->who_stuff = NULL;
new_w->who_end = NULL;
new_w->next = NULL;
#endif
return new_w;
}
static void who_queue_list (void)
{
WhoEntry *item = who_queue_top(from_server);
int count = 0;
while (item)
{
yell("[%d] [%d] [%s] [%s] [%s]", count,
item->who_mask,
item->who_nick ? item->who_nick : empty_string,
item->who_stuff ? item->who_stuff : empty_string,
item->who_end ? item->who_end : empty_string);
count++;
item = item->next;
}
}
static void who_queue_flush (void)
{
WhoEntry *item;
while ((item = who_queue_top(from_server)))
who_queue_pop();
yell("Who queue for server [%d] purged", from_server);
}
/*
* who: the /WHO command. Parses the who switches and sets the who_mask and
* whoo_stuff accordingly. Who_mask and who_stuff are used in whoreply() in
* parse.c
*/
BUILT_IN_COMMAND(whocmd)
{
whobase(args, NULL, NULL, NULL);
}
/*
* whobase: What does all the work.
*/
void BX_whobase(char *args, void (*line) (WhoEntry *, char *, char **), void (*end) (WhoEntry *, char *, char **), char *format, ...)
{
char *arg,
*channel = NULL;
int len;
WhoEntry *new_w, *old;
int done = 0;
/* Maybe should output a warning? */
if (from_server <= -1 || !is_server_connected(from_server))
return;
new_w = get_new_who_entry();
new_w->line = line;
new_w->end = end;
while ((arg = next_arg(args, &args)) != NULL && !done)
{
lower(arg);
if (*arg == '-' || *arg == '/')
{
arg++;
if ((len = strlen(arg)) == 0)
{
say("Unknown or missing flag");
return;
}
if (strbegins(arg, "line")) /* LINE */
{
char *line;
if ((line = next_expr(&args, '{')))
malloc_strcpy(&new_w->who_stuff, line);
else
say("Need {...} argument for -LINE argument.");
}
else if (strbegins(arg, "end")) /* END */
{
char *line;
if ((line = next_expr(&args, '{')))
malloc_strcpy(&new_w->who_end, line);
else
say("Need {...} argument for -END argument.");
}
else if (strbegins(arg, "raw")) /* RAW */
{
m_s3cat(&new_w->who_args, " ", args);
done = 1;
}
else if (strbegins(arg, "o")) /* OPS */
new_w->who_mask |= WHO_OPS;
else if (strbegins(arg, "lu")) /* LUSERS */
new_w->who_mask |= WHO_LUSERS;
else if (strbegins(arg, "ch")) /* CHOPS */
new_w->who_mask |= WHO_CHOPS;
else if (strbegins(arg, "no")) /* NOCHOPS */
new_w->who_mask |= WHO_NOCHOPS;
else if (strbegins(arg, "u-i")) /* INVISIBLE */
new_w->who_mask |= WHO_INVISIBLE;
else if (strbegins(arg, "ho")) /* HOSTS */
{
if ((arg = next_arg(args, &args)) == NULL)
{
say("WHO -HOST: missing argument");
return;
}
new_w->who_mask |= WHO_HOST;
malloc_strcpy(&new_w->who_host, arg);
channel = new_w->who_host;
}
else if (strbegins(arg, "he")) /* here */
new_w->who_mask |= WHO_HERE;
else if (strbegins(arg, "a")) /* away */
new_w->who_mask |= WHO_AWAY;
else if (strbegins(arg, "s")) /* servers */
{
if ((arg = next_arg(args, &args)) == NULL)
{
say("WHO -SERVER: missing arguement");
return;
}
new_w->who_mask |= WHO_SERVER;
malloc_strcpy(&new_w->who_server, arg);
channel = new_w->who_server;
}
else if (strbegins(arg, "na"))
{
if ((arg = next_arg(args, &args)) == NULL)
{
say("WHO -NAME: missing arguement");
return;
}
new_w->who_mask |= WHO_NAME;
malloc_strcpy(&new_w->who_name, arg);
channel = new_w->who_name;
}
else if (strbegins(arg, "re"))
{
if ((arg = next_arg(args, &args)) == NULL)
{
say("WHO -REALNAME: missing arguement");
return;
}
new_w->who_mask |= WHO_REAL;
malloc_strcpy(&new_w->who_real, arg);
channel = new_w->who_real;
}
else if (strbegins(arg, "ni"))
{
if ((arg = next_arg(args, &args)) == NULL)
{
say("WHO -NICK: missing arguement");
return;
}
new_w->who_mask |= WHO_NICK;
malloc_strcpy(&new_w->who_nick, arg);
channel = new_w->who_nick;
}
else if (strbegins(arg, "d"))
{
who_queue_list();
delete_who_item(new_w);
return;
}
else if (strbegins(arg, "f"))
{
who_queue_flush();
delete_who_item(new_w);
return;
}
else
m_s3cat(&new_w->who_args, " ", arg);
}
else if (strcmp(arg, "*") == 0)
{
channel = get_current_channel_by_refnum(0);
if (!channel || !*channel)
{
say("You are not on a channel. Use /WHO ** to see everybody.");
delete_who_item(new_w);
return;
}
}
else
channel = arg;
}
if (!channel && (new_w->who_mask & WHO_OPS))
channel = "*.*";
if (!channel || !*channel)
{
channel = get_current_channel_by_refnum(0);
if (!channel || !*channel)
{
say("You are not on a channel. Use /WHO ** to see everybody.");
delete_who_item(new_w);
return;
}
}
who_queue_add(new_w);
new_w->who_target = m_strdup(channel);
if (format)
{
va_list arg;
char buffer[BIG_BUFFER_SIZE+1];
*buffer = 0;
va_start(arg, format);
vsnprintf(buffer, sizeof buffer, format, arg);
va_end(arg);
new_w->who_buff = m_strdup(buffer);
}
/*
* Check to see if we can piggyback
*/
old = who_previous_query(new_w);
if (old && !old->dirty && old->who_target && channel &&
!strcmp(old->who_target, channel))
{
old->piggyback = 1;
if (x_debug & DEBUG_OUTBOUND)
yell("Piggybacking this WHO onto last one.");
}
else
send_to_server("WHO %s %s%s%s", new_w->who_target,
(new_w->who_mask & WHO_OPS) ? "o" : empty_string,
(new_w->who_mask & WHO_INVISIBLE) ? "x": empty_string,
new_w->who_args ? new_w->who_args : empty_string);
}
void quote_whine(char *type)
{
yell("### Please dont do /QUOTE %s. Use /%s instead", type, type);
return;
}
static int who_whine = 0;
void whoreply (char *from, char **ArgList)
{
int ok = 1;
int voice = 0, opped = 0;
char *channel,
*user,
*host,
*server,
*nick,
*stat,
*name;
char buf_data[BIG_BUFFER_SIZE+1];
WhoEntry *new_w = who_queue_top(from_server);
if (!ArgList[5])
return; /* Fake! */
if (!new_w && !who_whine)
{
who_whine = 1;
channel = ArgList[0];
user = ArgList[1];
host = ArgList[2];
server = ArgList[3];
nick = ArgList[4];
stat = ArgList[5];
PasteArgs(ArgList, 6);
name = ArgList[6];
voice = (strchr(stat, '+') != NULL);
opped = (strchr(stat, '@') != NULL);
set_display_target(channel, LOG_CRAP);
if (do_hook(WHO_LIST, "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name))
put_it("%s",convert_output_format(fget_string_var(FORMAT_WHO_FSET), "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name));
reset_display_target();
return;
}
do
{
/*
* this can happen in a very likely situation. The timing is critical.
* a user joins a channel. We send a userhost, but before the server
* responds, we are kicked and rejoin the channel. A reply is still
* coming from the server but the channel sync hasn't finished,
* which means we are in limbo. This should also fix the core when
* /quote who is done.
*/
if (!new_w)
break;
/*
* We have received a reply to this query -- its too late to
* piggyback it now!
*/
new_w->dirty = 1;
/*
* We dont always want to use this function.
* If another function is supposed to do the work for us,
* we yield to them.
*/
if (new_w->line)
{
new_w->line(new_w, from, ArgList);
continue;
}
channel = ArgList[0];
user = ArgList[1];
host = ArgList[2];
server = ArgList[3];
nick = ArgList[4];
stat = ArgList[5];
PasteArgs(ArgList, 6);
name = ArgList[6];
voice = (strchr(stat, '+') != NULL);
opped = (strchr(stat, '@') != NULL);
*buf_data = 0;
strmopencat(buf_data, BIG_BUFFER_SIZE, user, "@", host, NULL);
if (*stat == 'S') /* this only true for the header WHOREPLY */
{
char buffer[1024];
channel = "Channel";
snprintf(buffer, sizeof buffer, "%s %s %s %s %s %s %s", channel,
nick, stat, user, host, server, name);
set_display_target(channel, LOG_CRAP);
if (new_w->who_stuff)
; /* munch it */
else if (do_hook(WHO_LIST, "%s", buffer))
put_it("%s",convert_output_format(fget_string_var(FORMAT_WHO_FSET), "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name));
reset_display_target();
return;
}
if (new_w && new_w->who_mask)
{
if (new_w->who_mask & WHO_HERE)
ok = ok && (*stat == 'H');
if (new_w->who_mask & WHO_AWAY)
ok = ok && (*stat == 'G');
if (new_w->who_mask & WHO_OPS)
ok = ok && (*(stat + 1) == '*');
if (new_w->who_mask & WHO_LUSERS)
ok = ok && (*(stat + 1) != '*');
if (new_w->who_mask & WHO_CHOPS)
ok = ok && ((*(stat + 1) == '@') ||
(*(stat + 2) == '@'));
if (new_w->who_mask & WHO_NOCHOPS)
ok = ok && ((*(stat + 1) != '@') &&
(*(stat + 2) != '@') &&
(*(stat + 3) != '@'));
if (new_w->who_mask & WHO_NAME)
ok = ok && wild_match(new_w->who_name, user);
if (new_w->who_mask & WHO_NICK)
ok = ok && wild_match(new_w->who_nick, nick);
if (new_w->who_mask & WHO_HOST)
ok = ok && wild_match(new_w->who_host, host);
if (new_w->who_mask & WHO_REAL)
ok = ok && wild_match(new_w->who_real, name);
if (new_w->who_mask & WHO_SERVER)
ok = ok && wild_match(new_w->who_server, server);
}
if (ok)
{
char buffer[1024];
snprintf(buffer, sizeof buffer, "%s %s %s %s %s %s %s", channel,
nick, stat, user, host, server, name);
set_display_target(channel, LOG_CRAP);
add_to_channel(channel, nick, from_server, opped, voice, buf_data, server, stat, 0, my_atol(name));
if (new_w->who_stuff)
parse_line(NULL, new_w->who_stuff, buffer, 0, 0, 1);
else if (!in_join_list(channel, from_server) && do_hook(WHO_LIST, "%s", buffer))
{
if (do_hook(current_numeric, "%s", buffer))
{
if (!get_int_var(SHOW_WHO_HOPCOUNT_VAR))
next_arg(name, &name);
put_it("%s",convert_output_format(fget_string_var(FORMAT_WHO_FSET), "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name));
}
}
#if WANT_NSLOOKUP
if (get_int_var(AUTO_NSLOOKUP_VAR))
do_nslookup(host, nick, user, channel, from_server, auto_nslookup, NULL);
#endif
reset_display_target();
}
}
while (new_w->piggyback && (new_w = new_w->next));
}
void who_end (char *from, char **ArgList)
{
WhoEntry *new_w = who_queue_top(from_server);
char buffer[1024];
who_whine = 0;
if (!new_w)
return;
do
{
/*
* Defer to another function, if neccesary.
*/
if (new_w->end)
{
new_w->end(new_w, from, ArgList);
}
else
{
snprintf(buffer, sizeof buffer, "%s %s %s", from, ArgList[0], ArgList[1]);
if (new_w->who_end)
parse_line(NULL, new_w->who_end, buffer, 0, 0, 1);
else if (get_int_var(SHOW_END_OF_MSGS_VAR) && do_hook(current_numeric, "%s", buffer))
put_it("%s %s", numeric_banner(), buffer);
}
} while (new_w->piggyback && (new_w = new_w->next));
who_queue_pop();
}
/*
*
*
*
* ISON QUEUE
*
*
*
*/
static void ison_queue_add (IsonEntry *item)
{
IsonEntry *bottom = ison_queue_top(from_server);
while (bottom && bottom->next)
bottom = bottom->next;
if (!bottom)
set_ison_queue_top(from_server, item);
else
bottom->next = item;
return;
}
static void ison_queue_pop (void)
{
IsonEntry *save = ison_queue_top(from_server);
if (save)
{
set_ison_queue_top(from_server, save->next);
new_free(&save->ison_asked);
new_free(&save->ison_got);
new_free((char **)&save);
}
return;
}
static IsonEntry *get_new_ison_entry (void)
{
IsonEntry *new_w = (IsonEntry *)new_malloc(sizeof(IsonEntry));
#if 0
new_w->ison_asked = NULL;
new_w->ison_got = NULL;
new_w->next = NULL;
new_w->line = NULL;
#endif
ison_queue_add(new_w);
return new_w;
}
#if 0
static void ison_queue_list (void)
{
IsonEntry *item = ison_queue_top(from_server);
int count = 0;
while (item)
{
yell("[%d] [%s] [%#x]", count, ison_asked, line);
count++;
item = item->next;
}
}
#endif
BUILT_IN_COMMAND(isoncmd)
{
if (!args || !*args)
args = LOCAL_COPY(get_server_nickname(from_server));
isonbase(args, NULL);
}
void BX_isonbase (char *args, void (*line) (char *, char *))
{
IsonEntry *new_i;
char *next = args;
/* Maybe should output a warning? */
if (from_server <= -1 || !is_server_connected(from_server))
return;
while ((args = next))
{
new_i = get_new_ison_entry();
new_i->line = line;
if (strlen(args) > 500)
{
next = args + 500;
while (!isspace((unsigned char)*next))
next--;
*next++ = 0;
}
else
next = NULL;
malloc_strcpy(&new_i->ison_asked, args);
send_to_server("ISON %s", new_i->ison_asked);
}
}
/*
* ison_returned: this is called when numeric 303 is received in
* numbers.c. ISON must always be the property of the WHOIS queue.
* Although we will check first that the top element expected is
* actually an ISON.
*/
void ison_returned (char *from, char **ArgList)
{
IsonEntry *new_i = ison_queue_top(from_server);
if (!new_i)
{
quote_whine("ISON");
return;
}
PasteArgs(ArgList, 0);
if (new_i->line)
new_i->line(new_i->ison_asked, ArgList[0]);
else
{
if (do_hook(current_numeric, "%s", ArgList[0]))
put_it("%s Currently online: %s", numeric_banner(), ArgList[0]);
}
ison_queue_pop();
return;
}
/*
*
*
*
*
* USERHOST QUEUE
*
*
*
*
*/
static void userhost_queue_add (UserhostEntry *item)
{
UserhostEntry *bottom = userhost_queue_top(from_server);
while (bottom && bottom->next)
bottom = bottom->next;
if (!bottom)
set_userhost_queue_top(from_server, item);
else
bottom->next = item;
return;
}
static void userhost_queue_pop (void)
{
UserhostEntry *save = userhost_queue_top(from_server);
set_userhost_queue_top(from_server, save->next);
new_free(&save->userhost_asked);
new_free(&save->text);
new_free((char **)&save);
return;
}
static UserhostEntry *get_new_userhost_entry (void)
{
UserhostEntry *new_u = (UserhostEntry *)new_malloc(sizeof(UserhostEntry));
userhost_queue_add(new_u);
return new_u;
}
/*
* userhost: Does the USERHOST command. Need to split up the queries,
* since the server will only reply to 5 at a time.
*/
BUILT_IN_COMMAND(userhostcmd)
{
userhostbase(args, NULL, 1, NULL);
}
BUILT_IN_COMMAND(useripcmd)
{
userhostbase(args, NULL, 0, NULL);
}
BUILT_IN_COMMAND(usripcmd)
{
userhostbase(args, NULL, 2, NULL);
}
void BX_userhostbase(char *args, void (*line) (UserhostItem *, char *, char *), int userhost, char *format, ...)
{
int total = 0, userhost_cmd = 0, server_query_reqd = 0;
char *nick, *ptr, *next_ptr, *body = NULL;
va_list ap;
char buffer[BIG_BUFFER_SIZE], text[BIG_BUFFER_SIZE];
if (from_server < 0 || !is_server_connected(from_server))
return;
if (format)
{
va_start(ap, format);
vsnprintf(text, sizeof text, format, ap);
va_end(ap);
}
else
*text = 0;
*buffer = 0;
while ((nick = next_arg(args, &args)) != NULL)
{
if (check_nickname(nick))
{
total++;
if (!fetch_userhost(from_server, nick))
server_query_reqd++;
if (*buffer)
strlcat(buffer, space, sizeof buffer);
strlcat(buffer, nick, sizeof buffer);
}
else if (!my_strnicmp(nick, "-cmd", 2))
{
if (!total)
{
say("%s -cmd with no nicks specified", userhost == 1 ? "USERHOST" : userhost == 0 ? "USERIP" : "USRIP");
return;
}
while (my_isspace(*args))
args++;
if (!(body = next_expr_failok(&args, '{')))
body = args;
userhost_cmd = 1;
break;
}
else if (!my_strnicmp(nick, "-direct", 2))
server_query_reqd++;
}
if (!userhost_cmd && !total)
{
server_query_reqd++;
strlcpy(buffer, get_server_nickname(from_server), sizeof buffer);
}
ptr = buffer;
if (server_query_reqd || (!line && !userhost_cmd))
{
while (ptr && *ptr)
{
UserhostEntry *new_uh = get_new_userhost_entry();
move_to_abs_word(ptr, &next_ptr, 5);
if (next_ptr && *next_ptr && next_ptr > ptr)
next_ptr[-1] = 0;
new_uh->userhost_asked = m_strdup(ptr);
send_to_server("%s %s", userhost == 1 ? "USERHOST" : !userhost ? "USERIP" : "USRIP", new_uh->userhost_asked);
if (userhost_cmd)
new_uh->text = m_strdup(body);
else if (*text)
new_uh->text = m_strdup(text);
if (line)
new_uh->func = line;
else if (userhost_cmd)
new_uh->func = userhost_cmd_returned;
else
new_uh->func = NULL;
ptr = next_ptr;
}
}
else
{
while (ptr && *ptr)
{
char *uh, *nick = next_arg(ptr, &ptr);
const char *old_uh = fetch_userhost(from_server, nick);
UserhostItem item = { 0 };
uh = LOCAL_COPY(old_uh);
item.nick = nick;
item.oper = 0;
item.connected = 1;
item.away = 0;
item.user = uh;
item.host = strchr(uh, '@');
if (item.host)
*item.host++ = 0;
else
item.host = "<UNKNOWN>";
if (line)
line(&item, nick, body ? body : *text ? text : NULL);
else if (userhost_cmd)
userhost_cmd_returned(&item, nick, body);
else
yell("Yowza! I don't know what to do here!");
}
}
}
/*
* userhost_returned: this is called when numeric 302 is received in
* numbers.c. USERHOST must always remain the property of the userhost
* queue. Sending out USERHOST requests to the server without going
* through this queue will cause it to be corrupted and the client will
* go higgledy-piggledy.
*/
void userhost_returned (char *from, char **ArgList)
{
UserhostEntry *top = userhost_queue_top(from_server);
char *ptr;
if (!top)
{
quote_whine("USERHOST");
return;
}
ptr = top->userhost_asked;
/*
* Go through the nicknames that were requested...
*/
while (ptr && *ptr)
{
/*
* Grab the next nickname
*/
char *cnick = next_arg(ptr, &ptr);
int len = strlen(cnick);
/*
* Now either it is present at the next argument
* or its not. If it is, it will match the first
* part of ArgList, and the following char will
* either be a * or an = (eg, nick*= or nick=)
*/
if (ArgList)
{
while (*(*ArgList) == ' ')
(*ArgList)++;
}
if (ArgList && *ArgList && (!my_strnicmp(cnick, *ArgList, len)
&& ((*ArgList)[len] == '*' || (*ArgList)[len] == '=')))
{
UserhostItem item;
/* Extract all the interesting info */
item.connected = 1;
item.nick = next_arg(*ArgList, ArgList);
item.user = strchr(item.nick, '=');
if (item.user[-1] == '*')
{
item.user[-1] = 0;
item.oper = 1;
}
else
item.oper = 0;
if (item.user[1] == '+')
item.away = 0;
else
item.away = 1;
*item.user++ = 0;
item.user++;
item.host = strchr(item.user, '@');
*item.host++ = 0;
/*
* If the user wanted a callback, then
* feed the callback with the info.
*/
if (top->func)
top->func(&item, cnick, top->text);
/*
* Otherwise, the user just did /userhost,
* so we offer the numeric, and if the user
* doesnt bite, we output to the screen.
*/
else if (do_hook(current_numeric, "%s %s %s %s %s",
item.nick,
item.oper ? "+" : "-",
item.away ? "-" : "+",
item.user, item.host))
put_it("%s %s is %s@%s%s%s", numeric_banner(),
item.nick, item.user, item.host,
item.oper ? " (Is an IRC operator)" : empty_string,
item.away ? " (away)" : empty_string);
}
/*
* If ArgList isnt the current nick, then the current nick
* must not be on irc. So we whip up a dummy UserhostItem
* and send it on its way. We DO NOT HOOK the 302 numeric
* with this bogus entry, because thats the historical
* behavior. This can cause a problem if you do a USERHOST
* and wait on the 302 numeric. I think waiting on the 302
* numeric is stupid, anyhow.
*/
else
{
/*
* Of course, only if the user asked for a callback
* via /userhost -cmd or a direct call to userhostbase.
* If the user just did /userhost, and the nicks arent
* on, then we just dont display anything.
*/
if (top->func)
{
UserhostItem item;
item.nick = cnick;
item.user = item.host = "<UNKNOWN>";
item.oper = item.away = 0;
item.connected = 1;
top->func(&item, cnick, top->text);
}
}
}
userhost_queue_pop();
}
void userhost_cmd_returned (UserhostItem *stuff, char *nick, char *text)
{
char args[BIG_BUFFER_SIZE + 1];
strcpy(args, stuff->nick ? stuff->nick : empty_string);
strcat(args, stuff->oper ? " + " : " - ");
strcat(args, stuff->away ? "+ " : "- ");
strcat(args, stuff->user ? stuff->user : empty_string);
strcat(args, space);
strcat(args, stuff->host ? stuff->host : empty_string);
parse_line(NULL, text, args, 0, 0, 1);
}
void clean_server_queues (int i)
{
int old_from_server = from_server;
if (i == -1 || !get_server_list() || !is_server_connected(i))
return; /* Whatever */
from_server = i;
while (who_queue_top(i))
who_queue_pop();
while (ison_queue_top(i))
ison_queue_pop();
while (userhost_queue_top(i))
userhost_queue_pop();
from_server = old_from_server;
}