624 lines
17 KiB
C
624 lines
17 KiB
C
/* SeenServ - Nickname Seen Service - NeoStats Addon Module
|
|
** Copyright (c) 2003-2006 Justin Hammond, Mark Hetherington, Jeff Lang
|
|
**
|
|
** This program 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.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** 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, write to the Free Software
|
|
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
** USA
|
|
**
|
|
** SeenServ CVS Identification
|
|
** $Id$
|
|
*/
|
|
|
|
#include "neostats.h" /* Required for bot support */
|
|
#include "seenserv.h"
|
|
|
|
#define MAX_NICK_HISTORY 5
|
|
#define SEEN_ENTRY_NICK_SIZE ( ( MAXNICK + 3 ) * MAX_NICK_HISTORY )
|
|
|
|
static list_t *seenlist;
|
|
|
|
static char combinedtimetext[SS_GENCHARLEN];
|
|
static char matchstr[USERHOSTLEN];
|
|
static char currentlyconnectedtext[SS_GENCHARLEN];
|
|
static char seenentrynick[SEEN_ENTRY_NICK_SIZE];
|
|
static char matchednickstr[SS_MESSAGESIZE];
|
|
static char nicklower[MAXNICK];
|
|
|
|
/** @brief findnick
|
|
*
|
|
* list sorting helper
|
|
*
|
|
* @param key1
|
|
* @param key2
|
|
*
|
|
* @return results of strcmp
|
|
*/
|
|
|
|
int findnick( const void *key1, const void *key2 )
|
|
{
|
|
SeenData *sd = ( SeenData * ) key1;
|
|
return ircstrcasecmp( sd->nick, key2 );
|
|
}
|
|
|
|
/*
|
|
* Removes SeenData for nickname if exists
|
|
*
|
|
* returns NS_SUCCESS if nick removed or NS_FAILURE if nick not in list
|
|
*/
|
|
int removepreviousnick(char *nick)
|
|
{
|
|
lnode_t *ln;
|
|
SeenData *sd;
|
|
|
|
ln = list_last( seenlist );
|
|
while ( ln )
|
|
{
|
|
sd = lnode_get( ln );
|
|
if (!ircstrcasecmp(nick, sd->nick))
|
|
{
|
|
ns_free( sd );
|
|
list_delete( seenlist, ln );
|
|
lnode_destroy( ln );
|
|
return NS_SUCCESS;
|
|
}
|
|
ln = list_prev( seenlist, ln );
|
|
}
|
|
return NS_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* add new seen entry to list
|
|
*/
|
|
void addseenentry(char *nick, char *host, char *vhost, char *message, int type)
|
|
{
|
|
SeenData *sd;
|
|
int nickremoved;
|
|
|
|
nickremoved = removepreviousnick(nick);
|
|
sd = ns_calloc(sizeof(SeenData));
|
|
strlcpy(sd->nick, nick, MAXNICK);
|
|
strlcpy(sd->userhost, host, USERHOSTLEN);
|
|
strlcpy(sd->uservhost, vhost, USERHOSTLEN);
|
|
strlcpy(sd->message, message ? message : "", SS_MESSAGESIZE);
|
|
sd->seentype = type;
|
|
sd->seentime = me.now;
|
|
sd->recordsaved = 0;
|
|
lnode_create_append( seenlist, sd );
|
|
/* only check list limit if the nick wasn't already in the list */
|
|
if( nickremoved == NS_FAILURE )
|
|
checkseenlistlimit(SS_LISTLIMIT_COUNT);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Save Data to DB on timer
|
|
*
|
|
* remove records from list if set to work from DB only
|
|
*/
|
|
int dbsavetimer(void *userptr)
|
|
{
|
|
lnode_t *ln, *ln2;
|
|
SeenData *sd;
|
|
|
|
SET_SEGV_LOCATION();
|
|
ln = list_last( seenlist );
|
|
while ( ln )
|
|
{
|
|
sd = lnode_get( ln );
|
|
ln2 = list_prev( seenlist, ln );
|
|
if (sd->recordsaved == 0)
|
|
{
|
|
sd->recordsaved = 1;
|
|
strlcpy( nicklower, sd->nick, MAXNICK );
|
|
DBAStore( "seendata", ns_strlwr(nicklower),( void * )sd, sizeof( SeenData ) );
|
|
if( !SeenServ.memorylist )
|
|
{
|
|
ns_free( sd );
|
|
list_delete( seenlist, ln );
|
|
lnode_destroy( ln );
|
|
}
|
|
} else {
|
|
if( !SeenServ.memorylist )
|
|
{
|
|
ns_free( sd );
|
|
list_delete( seenlist, ln );
|
|
lnode_destroy( ln );
|
|
} else {
|
|
return NS_SUCCESS;
|
|
}
|
|
}
|
|
ln = ln2;
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Removes SeenData if records past max entries setting
|
|
*/
|
|
void checkseenlistlimit(int checktype)
|
|
{
|
|
int currentlistcount;
|
|
int maxageallowed;
|
|
lnode_t *ln, *ln2;
|
|
SeenData *sd;
|
|
|
|
currentlistcount = list_count(seenlist);
|
|
maxageallowed = me.now - ( SeenServ.expiretime * TS_ONE_DAY );
|
|
ln = list_first( seenlist );
|
|
sd = lnode_get( ln );
|
|
while( ( checktype == SS_LISTLIMIT_COUNT && currentlistcount > SeenServ.maxentries ) || ( checktype == SS_LISTLIMIT_AGE && SeenServ.expiretime > 0 && maxageallowed > sd->seentime ) )
|
|
{
|
|
ln2 = list_next( seenlist, ln );
|
|
strlcpy( nicklower, sd->nick, MAXNICK );
|
|
DBADelete( "seendata", ns_strlwr( nicklower ) );
|
|
ns_free( sd );
|
|
list_delete( seenlist, ln );
|
|
lnode_destroy( ln );
|
|
ln = ln2;
|
|
sd = lnode_get( ln );
|
|
currentlistcount --;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Load Saved Seen Records
|
|
*/
|
|
int loadseenrecords(void *data, int size)
|
|
{
|
|
SeenData *sd;
|
|
|
|
sd = ns_calloc( sizeof( SeenData ) );
|
|
os_memcpy( sd, data, sizeof( SeenData ) );
|
|
sd->recordsaved = 1;
|
|
lnode_create_append( seenlist, sd );
|
|
return NS_FALSE;
|
|
}
|
|
|
|
void createseenlist(void)
|
|
{
|
|
seenlist = list_create( LISTCOUNT_T_MAX );
|
|
}
|
|
|
|
void loadseendata(void)
|
|
{
|
|
DBAFetchRows( "seendata", loadseenrecords );
|
|
list_sort( seenlist, sortlistbytime );
|
|
return;
|
|
}
|
|
|
|
int sortlistbytime( const void *key1, const void *key2 )
|
|
{
|
|
const SeenData *sd1 = key1;
|
|
const SeenData *sd2 = key2;
|
|
return (sd1->seentime - sd2->seentime);
|
|
}
|
|
|
|
/*
|
|
* Destroy Seen List
|
|
*/
|
|
void destroyseenlist(void)
|
|
{
|
|
lnode_t *ln, *ln2;
|
|
SeenData *sd;
|
|
|
|
ln = list_first(seenlist);
|
|
while( ln )
|
|
{
|
|
sd = lnode_get(ln);
|
|
ln2 = list_next( seenlist, ln );
|
|
ns_free(sd);
|
|
list_delete(seenlist, ln);
|
|
lnode_destroy(ln);
|
|
ln = ln2;
|
|
}
|
|
list_destroy_auto(seenlist);
|
|
}
|
|
|
|
#if 0
|
|
/** seen_report
|
|
*
|
|
* handles channel/user message selection
|
|
*/
|
|
/* we do this via a macro now, to avoid possible exploits,
|
|
* see seenserv.h. If the macro isn't portable, then we can use this function now
|
|
* without having the exploit present, but its spins more CPU cycles!
|
|
*/
|
|
static char seen_report_buf[BUFSIZE];
|
|
|
|
void seen_report( const CmdParams *cmdparams, const char *fmt, ... )
|
|
{
|
|
va_list ap;
|
|
|
|
va_start( ap, fmt );
|
|
ircvsnprintf( seen_report_buf, BUFSIZE, fmt, ap );
|
|
va_end( ap );
|
|
if( cmdparams->channel == NULL )
|
|
irc_prefmsg (sns_bot, cmdparams->source, "%s", seen_report_buf );
|
|
else
|
|
irc_chanprivmsg (sns_bot, cmdparams->channel->name, "%s" seen_report_buf );
|
|
}
|
|
#endif
|
|
/*
|
|
* Check whether we can run the seen command
|
|
*/
|
|
static int SeenAvailable( const CmdParams *cmdparams )
|
|
{
|
|
#if 0
|
|
if( strstr(cmdparams->av[0], "%") != NULL )
|
|
return NS_FALSE;
|
|
#endif
|
|
if( cmdparams->source->user->ulevel < NS_ULEVEL_LOCOPER )
|
|
{
|
|
if( !SeenServ.enable && cmdparams->channel == NULL )
|
|
return NS_FALSE;
|
|
if( !SeenServ.enableseenchan && cmdparams->channel != NULL )
|
|
return NS_FALSE;
|
|
}
|
|
return NS_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Seen for wildcarded Host
|
|
*/
|
|
int sns_cmd_seenhost(const CmdParams *cmdparams)
|
|
{
|
|
Client *u;
|
|
|
|
SET_SEGV_LOCATION();
|
|
/* do lookup on nick only if working from DB and not memory list */
|
|
if( !SeenServ.memorylist )
|
|
return sns_cmd_seennick(cmdparams);
|
|
if( SeenAvailable( cmdparams ) == NS_FALSE )
|
|
return NS_SUCCESS;
|
|
/* ensure DB is saved before doing lookup */
|
|
dbsavetimer( NULL );
|
|
if( ValidateNick( cmdparams->av[0] ) == NS_SUCCESS )
|
|
{
|
|
u = FindUser( cmdparams->av[0] );
|
|
if (u)
|
|
{
|
|
seen_report( cmdparams, "%s (%s@%s) is connected right now", u->name, u->user->username, u->user->vhost);
|
|
return NS_SUCCESS;
|
|
}
|
|
}
|
|
if( CheckSeenData( cmdparams, SS_CHECK_WILDCARD ) == NS_FAILURE )
|
|
seen_report( cmdparams, "Sorry %s, I can't remember seeing anyone matching that mask (%s)", cmdparams->source->name, matchstr );
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Seen for valid nickname
|
|
*/
|
|
int sns_cmd_seennick(const CmdParams *cmdparams)
|
|
{
|
|
Client *u;
|
|
|
|
SET_SEGV_LOCATION();
|
|
if( SeenAvailable( cmdparams ) == NS_FALSE )
|
|
return NS_SUCCESS;
|
|
/* ensure DB is saved before doing lookup */
|
|
dbsavetimer( NULL );
|
|
if( ValidateNick( cmdparams->av[0] ) == NS_FAILURE )
|
|
{
|
|
seen_report( cmdparams, "%s is not a valid nickname", cmdparams->av[0] );
|
|
return NS_SUCCESS;
|
|
}
|
|
u = FindUser( cmdparams->av[0] );
|
|
if (u)
|
|
{
|
|
seen_report( cmdparams, "%s (%s@%s) is connected right now", u->name, u->user->username, u->user->vhost);
|
|
return NS_SUCCESS;
|
|
}
|
|
if( CheckSeenData( cmdparams, SS_CHECK_NICK ) == NS_FAILURE )
|
|
seen_report( cmdparams, "Sorry %s, I can't remember seeing anyone called %s", cmdparams->source->name, cmdparams->av[0] );
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Build time string
|
|
*/
|
|
void BuildTimeString( int ts )
|
|
{
|
|
static char temptimetext[12];
|
|
int d, h, m, s;
|
|
|
|
combinedtimetext[0] = '\0';
|
|
if (ts > 0)
|
|
{
|
|
s = ( ts % 60 );
|
|
ts -= s;
|
|
ts = ( ts / 60 );
|
|
m = ( ts % 60 );
|
|
ts -= m;
|
|
ts = ( ts / 60 );
|
|
h = ( ts % 24 );
|
|
ts -= h;
|
|
d = ( ts / 24 );
|
|
if( d )
|
|
{
|
|
ircsnprintf( temptimetext, 12, "%d Days ", d );
|
|
strlcat( combinedtimetext, temptimetext, SS_GENCHARLEN );
|
|
}
|
|
if( h )
|
|
{
|
|
ircsnprintf( temptimetext, 12, "%d Hours ", h );
|
|
strlcat( combinedtimetext, temptimetext, SS_GENCHARLEN );
|
|
}
|
|
if( m )
|
|
{
|
|
ircsnprintf( temptimetext, 12, "%d Minutes ", m );
|
|
strlcat( combinedtimetext, temptimetext, SS_GENCHARLEN );
|
|
}
|
|
if( s )
|
|
{
|
|
ircsnprintf( temptimetext, 12, "%d Seconds", s );
|
|
strlcat( combinedtimetext, temptimetext, SS_GENCHARLEN );
|
|
}
|
|
} else {
|
|
ircsnprintf( combinedtimetext, SS_GENCHARLEN, "0 Seconds" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check For Seen Records
|
|
*/
|
|
int CheckSeenData(const CmdParams *cmdparams, SEEN_CHECK checktype)
|
|
{
|
|
lnode_t *ln, *oln[MAX_NICK_HISTORY];
|
|
SeenData *sd, *sdo = NULL;
|
|
Client *u;
|
|
Channel *c;
|
|
int matchfound = 0, seenentriesfound = 0, maxageallowed = 0;
|
|
int isopersource = 0, i;
|
|
|
|
if( cmdparams->source->user->ulevel >= NS_ULEVEL_LOCOPER )
|
|
isopersource = 1;
|
|
/* used for expiring records on age if shown in request */
|
|
for( i = 0 ; i < MAX_NICK_HISTORY ; i++ )
|
|
oln[i] = NULL;
|
|
seenentrynick[0] = '\0';
|
|
currentlyconnectedtext[0] = '\0';
|
|
if (checktype == SS_CHECK_WILDCARD)
|
|
{
|
|
if ( strchr( cmdparams->av[0], '*' ) )
|
|
ircsnprintf(matchstr, USERHOSTLEN, "%s", cmdparams->av[0]);
|
|
else
|
|
ircsnprintf(matchstr, USERHOSTLEN, "*%s*", cmdparams->av[0]);
|
|
}
|
|
if( !SeenServ.memorylist )
|
|
{
|
|
sdo = ns_calloc( sizeof( SeenData ) );
|
|
strlcpy( nicklower, cmdparams->av[0], MAXNICK );
|
|
if( DBAFetch( "seendata", ns_strlwr(nicklower), ( void * )sdo, sizeof( SeenData ) ) != NS_FAILURE )
|
|
seenentriesfound = 1;
|
|
} else {
|
|
ln = list_last(seenlist);
|
|
while( ln != NULL && seenentriesfound < MAX_NICK_HISTORY )
|
|
{
|
|
sd = lnode_get(ln);
|
|
if (checktype == SS_CHECK_NICK)
|
|
{
|
|
if( !ircstrcasecmp( cmdparams->av[0], sd->nick ) )
|
|
matchfound = 1;
|
|
}
|
|
else if (checktype == SS_CHECK_WILDCARD)
|
|
{
|
|
if( isopersource )
|
|
{
|
|
if ( match( matchstr, sd->userhost ) )
|
|
matchfound = 1;
|
|
}
|
|
if( match( matchstr, sd->uservhost ) )
|
|
matchfound = 1;
|
|
}
|
|
if (matchfound)
|
|
{
|
|
oln[seenentriesfound] = ln;
|
|
seenentriesfound++;
|
|
if( seenentriesfound == 1 )
|
|
{
|
|
sdo = sd;
|
|
if (checktype == SS_CHECK_NICK)
|
|
break;
|
|
else
|
|
strlcpy( seenentrynick, sd->nick, SEEN_ENTRY_NICK_SIZE );
|
|
} else {
|
|
strlcat( seenentrynick, ", ", SEEN_ENTRY_NICK_SIZE );
|
|
strlcat( seenentrynick, sd->nick, SEEN_ENTRY_NICK_SIZE );
|
|
}
|
|
matchfound = 0;
|
|
}
|
|
ln = list_prev(seenlist, ln);
|
|
}
|
|
}
|
|
if( seenentriesfound == 0 )
|
|
return NS_FAILURE;
|
|
BuildTimeString( ( int )( me.now - sdo->seentime ) );
|
|
matchednickstr[0] = '\0';
|
|
if( seenentriesfound > 1 )
|
|
ircsnprintf(matchednickstr, SS_MESSAGESIZE, "The %d most recent matches are - %s : ", seenentriesfound, seenentrynick);
|
|
switch( sdo->seentype )
|
|
{
|
|
case SS_CONNECTED:
|
|
u = FindUser(sdo->nick);
|
|
if (u)
|
|
{
|
|
if (!ircstrcasecmp(sdo->userhost, u->user->userhostmask))
|
|
ircsnprintf(currentlyconnectedtext, SS_GENCHARLEN, ", %s is currently connected", u->name);
|
|
}
|
|
if( isopersource && cmdparams->channel == NULL )
|
|
irc_prefmsg( sns_bot, cmdparams->source, "%s%s was last seen connecting %s ago%s", matchednickstr, sdo->userhost, combinedtimetext, currentlyconnectedtext );
|
|
else
|
|
seen_report( cmdparams, "%s%s was last seen connecting %s ago%s", matchednickstr, sdo->nick, combinedtimetext, currentlyconnectedtext );
|
|
break;
|
|
case SS_QUIT:
|
|
if( isopersource && cmdparams->channel == NULL )
|
|
irc_prefmsg( sns_bot, cmdparams->source, "%s%s was last seen quiting %s ago, stating %s", matchednickstr, sdo->userhost, combinedtimetext, sdo->message );
|
|
else
|
|
seen_report( cmdparams, "%s%s was last seen quiting %s ago, stating %s", matchednickstr, sdo->uservhost, combinedtimetext, sdo->message);
|
|
break;
|
|
case SS_KILLED:
|
|
if( isopersource && cmdparams->channel == NULL )
|
|
irc_prefmsg( sns_bot, cmdparams->source, "%s%s was last seen being killed %s ago %s", matchednickstr, sdo->userhost, combinedtimetext, sdo->message );
|
|
else
|
|
seen_report( cmdparams, "%s%s was last seen being killed %s ago %s", matchednickstr, sdo->uservhost, combinedtimetext, sdo->message );
|
|
break;
|
|
case SS_NICKCHANGE:
|
|
u = FindUser(sdo->message);
|
|
if (u)
|
|
{
|
|
if (!ircstrcasecmp(sdo->userhost, u->user->userhostmask))
|
|
ircsnprintf(currentlyconnectedtext, SS_GENCHARLEN, ", %s is currently connected", u->name);
|
|
}
|
|
if( isopersource && cmdparams->channel == NULL )
|
|
irc_prefmsg( sns_bot, cmdparams->source, "%s%s was last seen changing Nickname %s ago to %s%s", matchednickstr, sdo->userhost, combinedtimetext, sdo->message, currentlyconnectedtext );
|
|
else
|
|
seen_report( cmdparams, "%s%s was last seen changing Nickname %s ago to %s%s", matchednickstr, sdo->uservhost, combinedtimetext, sdo->message, currentlyconnectedtext );
|
|
break;
|
|
case SS_JOIN:
|
|
u = FindUser(sdo->nick);
|
|
if (u)
|
|
{
|
|
if (!ircstrcasecmp(sdo->userhost, u->user->userhostmask))
|
|
{
|
|
c = FindChannel(sdo->message);
|
|
if (c)
|
|
{
|
|
if (IsChannelMember(c, u) && !is_hidden_chan(c))
|
|
ircsnprintf(currentlyconnectedtext, SS_GENCHARLEN, ", %s is currently in %s", u->name, c->name);
|
|
}
|
|
}
|
|
}
|
|
if( isopersource && cmdparams->channel == NULL )
|
|
irc_prefmsg (sns_bot, cmdparams->source, "%s%s was last seen Joining %s %s ago%s", matchednickstr, sdo->userhost, sdo->message, combinedtimetext, currentlyconnectedtext);
|
|
else
|
|
seen_report( cmdparams, "%s%s was last seen Joining %s %s ago%s", matchednickstr, sdo->uservhost, sdo->message, combinedtimetext, currentlyconnectedtext );
|
|
break;
|
|
case SS_PART:
|
|
if( isopersource && cmdparams->channel == NULL )
|
|
irc_prefmsg( sns_bot, cmdparams->source, "%s%s was last seen Parting %s %s ago", matchednickstr, sdo->userhost, sdo->message, combinedtimetext );
|
|
else
|
|
seen_report( cmdparams, "%s%s was last seen Parting %s %s ago", matchednickstr, sdo->uservhost, sdo->message, combinedtimetext );
|
|
break;
|
|
case SS_KICKED:
|
|
if( isopersource && cmdparams->channel == NULL )
|
|
irc_prefmsg( sns_bot, cmdparams->source, "%s%s was last seen being Kicked From %s %s ago", matchednickstr, sdo->userhost, sdo->message, combinedtimetext );
|
|
else
|
|
seen_report( cmdparams, "%s%s was last seen Kicked From %s %s", matchednickstr, sdo->uservhost, sdo->message, combinedtimetext);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if( !SeenServ.memorylist )
|
|
{
|
|
/* delete record if DB Only and past expiration date */
|
|
if( SeenServ.expiretime > 0 && ( ( me.now - ( SeenServ.expiretime * TS_ONE_DAY ) ) > sdo->seentime ) )
|
|
{
|
|
strlcpy( nicklower, sdo->nick, MAXNICK );
|
|
DBADelete( "seendata", ns_strlwr(nicklower) );
|
|
}
|
|
ns_free( sdo );
|
|
} else {
|
|
/* expire displayed records on age if required */
|
|
if( SeenServ.expiretime > 0 )
|
|
{
|
|
maxageallowed = me.now - ( SeenServ.expiretime * TS_ONE_DAY );
|
|
i = 0;
|
|
while( i < MAX_NICK_HISTORY && oln[i] != NULL )
|
|
{
|
|
ln = oln[i];
|
|
sd = lnode_get( ln );
|
|
if( maxageallowed > sd->seentime )
|
|
{
|
|
strlcpy( nicklower, sd->nick, MAXNICK );
|
|
DBADelete( "seendata", ns_strlwr(nicklower) );
|
|
ns_free( sd );
|
|
list_delete( seenlist, ln );
|
|
lnode_destroy( ln );
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Delete all matching entries
|
|
*/
|
|
int sns_cmd_del(const CmdParams *cmdparams)
|
|
{
|
|
lnode_t *ln, *ln2;
|
|
SeenData *sd;
|
|
int i;
|
|
|
|
SET_SEGV_LOCATION();
|
|
i = 0;
|
|
ln = list_first(seenlist);
|
|
while (ln != NULL)
|
|
{
|
|
sd = lnode_get(ln);
|
|
if (match(cmdparams->av[0], sd->userhost) || match(cmdparams->av[0], sd->uservhost))
|
|
{
|
|
strlcpy( nicklower, sd->nick, MAXNICK );
|
|
DBADelete( "seendata", ns_strlwr( nicklower ) );
|
|
i++;
|
|
ns_free(sd);
|
|
ln2 = list_next(seenlist, ln);
|
|
list_delete(seenlist, ln);
|
|
lnode_destroy(ln);
|
|
ln = ln2;
|
|
} else {
|
|
ln = list_next(seenlist, ln);
|
|
}
|
|
}
|
|
seen_report( cmdparams, "%d matching entries deleted", i );
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Display Seen Statistics
|
|
*/
|
|
int sns_cmd_status(const CmdParams *cmdparams)
|
|
{
|
|
int seenstats[SEEN_TYPE_MAX];
|
|
lnode_t *ln;
|
|
SeenData *sd;
|
|
|
|
SET_SEGV_LOCATION();
|
|
if( !SeenServ.memorylist )
|
|
{
|
|
seen_report( cmdparams, "Seen Statistics Unavailable when using DB only" );
|
|
return NS_SUCCESS;
|
|
}
|
|
os_memset( seenstats, 0, sizeof( seenstats ) );
|
|
ln = list_first(seenlist);
|
|
while (ln)
|
|
{
|
|
sd = lnode_get(ln);
|
|
seenstats[ sd->seentype ]++;
|
|
ln = list_next(seenlist, ln);
|
|
}
|
|
seen_report( cmdparams, "Seen Statistics (Current Records Per Type)" );
|
|
seen_report( cmdparams, "%d Connections", seenstats[SS_CONNECTED] );
|
|
seen_report( cmdparams, "%d Quits", seenstats[SS_QUIT] );
|
|
seen_report( cmdparams, "%d Kills", seenstats[SS_KILLED] );
|
|
seen_report( cmdparams, "%d Nick Changes", seenstats[SS_NICKCHANGE] );
|
|
seen_report( cmdparams, "%d Channel Joins", seenstats[SS_JOIN] );
|
|
seen_report( cmdparams, "%d Channel Parts", seenstats[SS_PART] );
|
|
seen_report( cmdparams, "%d Channel Kicks", seenstats[SS_KICKED] );
|
|
seen_report( cmdparams, "End Of Statistics");
|
|
return NS_SUCCESS;
|
|
}
|