This patch implements a (maybe) compliant WHOWAS command.

It is hard to test this in the test suite because we 1) shouldn't rely on
previous tests populating WHOWAS and 2) don't connect a user for more than 30
seconds.

Also makes WHOWAS return ERR_NONICKNAMEGIVEN_MSG as implied by RFC.
This commit is contained in:
Scott Perry 2008-05-12 12:59:55 +02:00 committed by Florian Westphal
parent b1d38de4d2
commit 70254a5553
2 changed files with 82 additions and 70 deletions

View File

@ -994,6 +994,22 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req )
} /* IRC_WHOIS */ } /* IRC_WHOIS */
static bool
WHOWAS_EntryWrite(CLIENT *prefix, WHOWAS *entry)
{
char t_str[60];
(void)strftime(t_str, sizeof(t_str), "%a %b %d %H:%M:%S %Y",
localtime(&entry->time));
if (!IRC_WriteStrClient(prefix, RPL_WHOWASUSER_MSG, Client_ID(prefix),
entry->id, entry->user, entry->host, entry->info))
return DISCONNECTED;
return IRC_WriteStrClient(prefix, RPL_WHOISSERVER_MSG, Client_ID(prefix),
entry->id, entry->server, t_str);
}
/** /**
* IRC "WHOWAS" function. * IRC "WHOWAS" function.
* This function implements the IRC command "WHOWHAS". It handles local * This function implements the IRC command "WHOWHAS". It handles local
@ -1004,40 +1020,41 @@ IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
{ {
CLIENT *target, *prefix; CLIENT *target, *prefix;
WHOWAS *whowas; WHOWAS *whowas;
int max, last, count, i; char tok_buf[COMMAND_LEN];
char t_str[60]; int max, last, count, i, nc;
const char *nick;
assert( Client != NULL ); assert( Client != NULL );
assert( Req != NULL ); assert( Req != NULL );
/* Wrong number of parameters? */ /* Wrong number of parameters? */
if(( Req->argc < 1 ) || ( Req->argc > 3 )) if (Req->argc > 3)
return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
Client_ID( Client ), Req->command ); Client_ID(Client), Req->command);
if (Req->argc < 1)
return IRC_WriteStrClient(Client, ERR_NONICKNAMEGIVEN_MSG, Client_ID(Client));
/* Search taget */ /* Search target */
if( Req->argc == 3 ) if (Req->argc == 3)
target = Client_Search( Req->argv[2] ); target = Client_Search(Req->argv[2]);
else else
target = Client_ThisServer( ); target = Client_ThisServer();
/* Get prefix */ /* Get prefix */
if( Client_Type( Client ) == CLIENT_SERVER ) if (Client_Type(Client) == CLIENT_SERVER)
prefix = Client_Search( Req->prefix ); prefix = Client_Search(Req->prefix);
else else
prefix = Client; prefix = Client;
if( ! prefix ) if (!prefix)
return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
Client_ID( Client ), Req->prefix ); Client_ID(Client), Req->prefix);
/* Forward to other server? */ /* Forward to other server? */
if( target != Client_ThisServer( )) if (target != Client_ThisServer()) {
{ if (!target || (Client_Type(target) != CLIENT_SERVER))
if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient(prefix, ERR_NOSUCHSERVER_MSG,
return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID(prefix), Req->argv[2]);
Client_ID( prefix ),
Req->argv[2] );
/* Forward */ /* Forward */
IRC_WriteStrClientPrefix( target, prefix, "WHOWAS %s %s %s", IRC_WriteStrClientPrefix( target, prefix, "WHOWAS %s %s %s",
@ -1048,55 +1065,49 @@ IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
whowas = Client_GetWhowas( ); whowas = Client_GetWhowas( );
last = Client_GetLastWhowasIndex( ); last = Client_GetLastWhowasIndex( );
if( last < 0 ) last = 0; if (last < 0)
last = 0;
if( Req->argc > 1 ) max = DEFAULT_WHOWAS;
{ if (Req->argc > 1) {
max = atoi( Req->argv[1] ); max = atoi(Req->argv[1]);
if( max < 1 ) max = MAX_WHOWAS; if (max < 1)
max = MAX_WHOWAS;
} }
else
max = DEFAULT_WHOWAS;
i = last; /*
count = 0; * Break up the nick argument into a list of nicks, if applicable
do * Can't modify Req->argv[0] because we need it for RPL_ENDOFWHOWAS_MSG.
{ */
/* Used entry? */ strlcpy(tok_buf, Req->argv[0], sizeof(tok_buf));
if( whowas[i].time > 0 && nick = strtok(tok_buf, ",");
strcasecmp( Req->argv[0], whowas[i].id ) == 0 )
{
(void)strftime( t_str, sizeof(t_str),
"%a %b %d %H:%M:%S %Y",
localtime( &whowas[i].time ));
if( ! IRC_WriteStrClient( prefix, RPL_WHOWASUSER_MSG, for (i=last, count=0; nick != NULL ; nick = strtok(NULL, ",")) {
Client_ID( prefix ), nc = 0;
whowas[i].id, do {
whowas[i].user, /* Used entry? */
whowas[i].host, if (whowas[i].time > 0 && strcasecmp(nick, whowas[i].id) == 0) {
whowas[i].info )) if (!WHOWAS_EntryWrite(prefix, &whowas[i]))
return DISCONNECTED; return DISCONNECTED;
nc++;
count++;
}
/* previous entry */
i--;
if( ! IRC_WriteStrClient( prefix, RPL_WHOISSERVER_MSG, /* "underflow", wrap around */
Client_ID( prefix ), if (i < 0)
whowas[i].id, i = MAX_WHOWAS - 1;
whowas[i].server, t_str ))
return DISCONNECTED;
count++; if (nc && count >= max)
if( count >= max ) break; break;
} } while (i != last);
/* previos entry */ if (nc == 0 && !IRC_WriteStrClient(prefix, ERR_WASNOSUCHNICK_MSG,
i--; Client_ID(prefix), nick))
return DISCONNECTED;
/* "underflow", wrap around */ }
if( i < 0 ) i = MAX_WHOWAS - 1; return IRC_WriteStrClient(prefix, RPL_ENDOFWHOWAS_MSG, Client_ID(prefix), Req->argv[0]);
} while( i != last );
return IRC_WriteStrClient( prefix, RPL_ENDOFWHOWAS_MSG,
Client_ID( prefix ), Req->argv[0] );
} /* IRC_WHOWAS */ } /* IRC_WHOWAS */

View File

@ -99,6 +99,7 @@
#define ERR_NOTEXTTOSEND_MSG "412 %s :No text to send" #define ERR_NOTEXTTOSEND_MSG "412 %s :No text to send"
#define ERR_UNKNOWNCOMMAND_MSG "421 %s %s :Unknown command" #define ERR_UNKNOWNCOMMAND_MSG "421 %s %s :Unknown command"
#define ERR_NOMOTD_MSG "422 %s :MOTD file is missing" #define ERR_NOMOTD_MSG "422 %s :MOTD file is missing"
#define ERR_NONICKNAMEGIVEN_MSG "431 %s :No nickname given"
#define ERR_ERRONEUSNICKNAME_MSG "432 %s %s :Erroneous nickname" #define ERR_ERRONEUSNICKNAME_MSG "432 %s %s :Erroneous nickname"
#define ERR_NICKNAMEINUSE_MSG "433 %s %s :Nickname already in use" #define ERR_NICKNAMEINUSE_MSG "433 %s %s :Nickname already in use"
#define ERR_USERNOTINCHANNEL_MSG "441 %s %s %s :They aren't on that channel" #define ERR_USERNOTINCHANNEL_MSG "441 %s %s %s :They aren't on that channel"