energymech/src/spy.c

1068 lines
21 KiB
C
Raw Normal View History

2014-03-08 19:56:21 -05:00
/*
EnergyMech, IRC bot software
2025-10-24 16:12:30 +02:00
Parts Copyright (c) 1997-2025 proton
2014-03-08 19:56:21 -05:00
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define SPY_C
#include "config.h"
#include "defines.h"
#include "structs.h"
#include "global.h"
#include "h.h"
#include "text.h"
#include "mcmd.h"
#ifdef STATS
#include <math.h>
#endif
2014-03-08 19:56:21 -05:00
#ifdef DEBUG
LS const char SPY_DEFS[][12] =
2014-03-08 19:56:21 -05:00
{
"SPY_FILE",
"SPY_CHANNEL",
"SPY_DCC",
"SPY_STATUS",
"SPY_MESSAGE",
"SPY_RAWIRC",
"SPY_BOTNET",
"SPY_URL",
"SPY_SYSMON",
2021-06-20 20:57:36 +02:00
"SPY_RANDSRC",
2014-03-08 19:56:21 -05:00
};
#endif /* DEBUG */
#if defined(SHACRYPT) || defined(MD5CRYPT)
char *CRYPT_FUNC(const char *, const char *);
#endif
2021-06-20 20:57:36 +02:00
2014-03-08 19:56:21 -05:00
void send_spy(const char *src, const char *format, ...)
{
Chan *chan;
Mech *backup;
Spy *spy;
va_list msg;
2025-11-10 22:28:21 +01:00
const char *spysrc;
2021-06-20 20:57:36 +02:00
const char *printmsg;
char tempdata[MAXLEN],*rnd,*dst,*end;
2025-11-10 22:28:21 +01:00
int fd;
2014-03-08 19:56:21 -05:00
int printed = FALSE;
2021-06-20 20:57:36 +02:00
if (src == SPYSTR_RAWIRC)
{
2025-11-10 22:28:21 +01:00
printmsg = format;
2021-06-20 20:57:36 +02:00
printed = TRUE;
}
2014-03-08 19:56:21 -05:00
#ifdef DEBUG
2025-10-24 16:12:30 +02:00
if (src != SPYSTR_RAWIRC) /* too much debug spam */
2024-01-19 18:12:17 +01:00
debug("(send_spy) src <%s> format = '%s', current = '%s' (%i)\n",src,format,
(current == NULL) ? "<NULL>" : getbotnick(current),(current == NULL) ? -1 : current->guid);
2014-03-08 19:56:21 -05:00
#endif /* DEBUG */
for(spy=current->spylist;spy;spy=spy->next)
{
2021-06-20 20:57:36 +02:00
if (spy->t_src == SPY_RANDSRC)
{
if (src != SPYSTR_RAWIRC)
continue;
if (spy->data.delay > now)
continue;
2025-11-10 22:28:21 +01:00
/* dont use four-char server messages such as "PING :..." */
if (format[5] == ':')
continue;
/* create delay until next */
2021-06-20 20:57:36 +02:00
spy->data.delay = now + 10 + RANDOM(0,9); /* make it unpredictable which messages will be sourced */
/*
2025-11-10 22:28:21 +01:00
* MD5 | 22 characters, $1$
* SHA-512 | 86 characters, $6$
*/
#if defined(SHACRYPT) || defined(MD5CRYPT)
sprintf(tempdata,
2021-06-20 20:57:36 +02:00
#ifdef SHACRYPT
2025-11-10 22:28:21 +01:00
"$6$%04x",
#else
"$1$%04x",
2021-06-20 20:57:36 +02:00
#endif /* SHACRYPT */
2025-11-10 22:28:21 +01:00
#endif /* defined(SHACRYPT) || defined(MD5CRYPT) */
2021-06-20 20:57:36 +02:00
2025-11-10 22:28:21 +01:00
(uint32_t)(now & 0xFFFF));
rnd = CRYPT_FUNC(format,tempdata);
2021-06-20 20:57:36 +02:00
dst = tempdata;
end = STREND(rnd);
2025-11-10 22:28:21 +01:00
2021-06-20 20:57:36 +02:00
#if defined(SHACRYPT) || defined(MD5CRYPT)
rnd += 8; /* skip salt */
2025-11-10 22:28:21 +01:00
#endif /* defined(SHACRYPT) || defined(MD5CRYPT) */
while(rnd < (end - 4))
2021-06-20 20:57:36 +02:00
{
2025-11-10 22:28:21 +01:00
union WordtoBytes
{
uint32_t m;
uint8_t b[4];
} m32;
uint32_t n, o, p;
int a,b,c,d;
m32.m = *((uint32_t*)rnd);
/*
* branchless bit operations to do 4 bytes at a time
* if input is not base64, the output is undefined
*/
n = (((m32.m - 0x3a3a3a3a) & 0x80808080) >> 7) * 7;
o = (((m32.m - 0x5b5b5b5b) & 0x80808080) >> 7) * 6;
p = (((m32.m - 0x7b7b7b7b) & 0x80808080) >> 7) * 6;
m32.m = m32.m - 0x41414141 + n + o + p;
a = m32.b[0];
b = m32.b[1];
c = m32.b[2];
d = m32.b[3];
/* base64 to bin, 4 chars to 3 */
dst[0] = (a << 2) | (b >> 4); /* aaaaaabb */
dst[1] = (b << 4) | (c >> 2); /* bbbbcccc */
2021-06-20 20:57:36 +02:00
dst[2] = (c << 6) | (d); /* ccdddddd */
dst += 3;
rnd += 4;
}
if ((dst - tempdata) > 0)
{
#ifdef DEBUG
debug("(send_spy) randsrc got %i bytes\n",dst - tempdata);
#endif /* DEBUG */
if ((fd = open(spy->dest,O_WRONLY|O_CREAT|O_APPEND,NEWFILEMODE)) >= 0)
{
int n;
n = write(fd,tempdata,dst - tempdata);
2021-06-20 20:57:36 +02:00
close(fd);
}
}
continue;
}
2025-11-10 22:28:21 +01:00
if (spy->t_src == SPY_STATUS)
spysrc = time2medium(now);
else
spysrc = spy->src;
2014-03-08 19:56:21 -05:00
if ((*src == '#' || *src == '*') && spy->t_src == SPY_CHANNEL)
{
2018-04-04 06:04:58 +02:00
if ((*src != '*') && stringcasecmp(spy->src,src))
2014-03-08 19:56:21 -05:00
continue;
if ((chan = find_channel_ac(spy->src)) == NULL)
continue;
if (find_chanuser(chan,CurrentNick) == NULL)
continue;
}
else
/*
* by using string constants we can compare addresses
*/
if (spy->src != src)
continue;
if (!printed)
{
printed = TRUE;
va_start(msg,format);
vsprintf(tempdata,format,msg);
va_end(msg);
2021-06-20 20:57:36 +02:00
printmsg = tempdata;
2014-03-08 19:56:21 -05:00
}
2025-11-10 22:28:21 +01:00
2014-03-08 19:56:21 -05:00
switch(spy->t_dest)
{
case SPY_DCC:
2025-11-10 22:28:21 +01:00
to_file(spy->data.dcc->sock,"[%s] %s\n",spysrc,printmsg);
2014-03-08 19:56:21 -05:00
break;
case SPY_CHANNEL:
2021-06-20 20:57:36 +02:00
if (spy->data.destbot >= 0)
2014-03-08 19:56:21 -05:00
{
backup = current;
for(current=botlist;current;current=current->next)
{
2021-06-20 20:57:36 +02:00
if (current->guid == spy->data.destbot)
2014-03-08 19:56:21 -05:00
{
2025-11-10 22:28:21 +01:00
to_server("PRIVMSG %s :[%s] %s\n",spy->dest,spysrc,printmsg);
2014-03-08 19:56:21 -05:00
break;
}
}
current = backup;
}
else
{
2025-11-10 22:28:21 +01:00
to_user(spy->dest,"[%s] %s",spysrc,printmsg);
2014-03-08 19:56:21 -05:00
}
break;
case SPY_FILE:
if ((fd = open(spy->dest,O_WRONLY|O_CREAT|O_APPEND,NEWFILEMODE)) >= 0)
{
2021-06-20 20:57:36 +02:00
to_file(fd,"[%s] %s\n",logtime(now),printmsg);
2014-03-08 19:56:21 -05:00
close(fd);
}
}
}
}
void send_global(const char *src, const char *format, ...)
{
va_list msg;
Mech *backup;
char tempdata[MAXLEN];
int printed = FALSE;
backup = current;
for(current=botlist;current;current=current->next)
{
if (current->spy & SPYF_ANY)
{
if (!printed)
{
printed = TRUE;
va_start(msg,format);
vsprintf(tempdata,format,msg);
va_end(msg);
}
send_spy(src,FMT_PLAIN,tempdata);
}
}
current = backup;
}
void spy_typecount(Mech *bot)
{
Spy *spy;
bot->spy = 0;
for(spy=bot->spylist;spy;spy=spy->next)
{
bot->spy |= SPYF_ANY;
bot->spy |= (1 << spy->t_src);
}
}
struct
{
const char *idstring;
2018-04-04 08:56:14 +02:00
int typenum;
2018-03-10 02:55:07 +01:00
} spy_source_list[] =
2014-03-08 19:56:21 -05:00
{
{ SPYSTR_STATUS, SPY_STATUS },
{ SPYSTR_MESSAGE, SPY_MESSAGE },
{ SPYSTR_RAWIRC, SPY_RAWIRC },
{ SPYSTR_BOTNET, SPY_BOTNET },
#ifdef URLCAPTURE
{ SPYSTR_URL, SPY_URL },
#endif /* URLCAPTURE */
#ifdef HOSTINFO
{ SPYSTR_SYSMON, SPY_SYSMON },
#endif
2021-06-20 20:57:36 +02:00
{ SPYSTR_RANDSRC, SPY_RANDSRC },
2014-03-08 19:56:21 -05:00
{ NULL, 0 },
};
int spy_source(char *from, int *t_src, const char **src)
2014-03-08 19:56:21 -05:00
{
int i;
#ifdef DEBUG
debug("(spy_source) t_src %i, src %s\n",*t_src,*src);
#endif /* ifdef DEBUG */
2014-03-08 19:56:21 -05:00
for(i=0;spy_source_list[i].idstring;i++)
{
2018-04-04 06:04:58 +02:00
if (!stringcasecmp(*src,spy_source_list[i].idstring))
2014-03-08 19:56:21 -05:00
{
*src = spy_source_list[i].idstring;
*t_src = spy_source_list[i].typenum;
return(200);
}
}
*t_src = SPY_CHANNEL;
if (!ischannel(*src))
return(-1);
return(get_useraccess(from,*src));
}
#ifdef REDIRECT
int begin_redirect(char *from, char *args)
{
char *pt,*nick;
if (!args)
return(0);
pt = STRCHR(args,'>');
if (pt)
{
*pt = 0;
nick = pt+1;
pt--;
while((pt > args) && (*pt == ' '))
{
*pt = 0;
pt--;
}
while(*nick == ' ')
nick++;
if (*nick)
{
#ifdef DEBUG
debug("(begin_redirect) from %s --> %s\n",from,nick);
#endif /* DEBUG */
if (ischannel(nick))
{
if (find_channel_ac(nick))
{
2021-06-20 20:57:36 +02:00
set_mallocdoer(begin_redirect);
redirect.to = stringdup(nick);
redirect.method = R_PRIVMSG;
return(0);
}
else
{
to_user(from,ERR_CHAN,nick);
return(-1);
}
}
if (*nick == '>')
{
nick++;
while(*nick == ' ')
nick++;
if (!*nick)
{
to_user(from,"Missing name for redirect.");
return(-1);
}
2018-04-24 18:28:10 +02:00
if (is_safepath(nick,FILE_MAY_EXIST) != FILE_IS_SAFE) /* redirect output is appended */
{
to_user(from,"Bad filename.");
return(-1);
}
2021-06-20 20:57:36 +02:00
set_mallocdoer(begin_redirect);
redirect.to = stringdup(nick);
redirect.method = R_FILE;
return(0);
}
if ((pt = find_nuh(nick)))
{
2021-06-20 20:57:36 +02:00
set_mallocdoer(begin_redirect);
redirect.to = stringdup(nick);
redirect.method = R_NOTICE;
return(0);
}
else
{
to_user(from,TEXT_UNKNOWNUSER,nick);
return(-1);
}
}
else
{
to_user(from,"Bad redirect");
return(-1);
}
}
return(0);
}
void send_redirect(char *message)
{
Strp *new,**pp;
char *fmt;
int fd;
if (!redirect.to)
return;
switch(redirect.method)
{
case R_FILE:
if ((fd = open(redirect.to,O_WRONLY|O_CREAT|O_APPEND,NEWFILEMODE)) < 0)
return;
fmt = stringcat(message,"\n");
if (write(fd,message,(fmt-message)) == -1)
return;
close(fd);
return;
#ifdef BOTNET
case R_BOTNET:
{
char tempdata[MAXLEN];
Mech *backup;
/* PM<targetguid> <targetuserhost> <source> <message> */
sprintf(tempdata,"%i %s %s %s",redirect.guid,redirect.to,getbotnick(current),message);
backup = current;
partyMessage(NULL,tempdata);
current = backup;
}
return;
#endif /* BOTNET */
case R_NOTICE:
fmt = "NOTICE %s :%s";
break;
/* case R_PRIVMSG: */
default:
fmt = "PRIVMSG %s :%s";
break;
}
pp = &current->sendq;
while(*pp)
pp = &(*pp)->next;
*pp = new = (Strp*)Calloc(sizeof(Strp) + StrlenX(message,fmt,redirect.to,NULL));
/* Calloc sets to zero new->next = NULL; */
sprintf(new->p,fmt,redirect.to,message);
}
void end_redirect(void)
{
if (redirect.to)
Free((char**)&redirect.to);
}
#endif /* REDIRECT */
#ifdef URLCAPTURE
char *urlhost(const char *url)
{
char copy[strlen(url)];
const char *end,*beg,*dst;
int n = 0;
beg = end = url;
while(*end)
{
if (*end == '@')
beg = end+1;
else
if (*end == '/')
{
if (n == 1)
beg = end+1;
else
if (n == 2)
break;
n++;
}
end++;
}
stringcpy_n(copy,beg,(end-beg));
#ifdef DEBUG
debug("(urlhost) host = %s\n",copy);
#endif
}
void urlcapture(const char *rest)
{
Strp *sp,*nx;
char *dest,url[MSGLEN];
int n;
dest = url;
while(*rest && *rest != ' ' && dest < url+MSGLEN-1)
*(dest++) = *(rest++);
*dest = 0;
#ifdef DEBUG
debug("(urlcapture) URL = \"%s\"\n",url);
#endif /* ifdef DEBUG */
urlhost(url);
send_spy(SPYSTR_URL,"%s",url);
if ((n = urlhistmax) < 0)
return;
prepend_strp(&urlhistory,url);
for(sp=urlhistory;sp;sp=sp->next)
{
if (n <= 0)
{
purge_linklist((void**)&sp->next);
return;
}
n--;
}
}
#endif /* ifdef URLCAPTURE */
#ifdef STATS
void stats_loghour(Chan *chan, char *filename, int hour)
{
ChanStats *stats;
time_t when;
int fd;
if (!(stats = chan->stats))
return;
when = (now - (now % 3600));
if ((fd = open(filename,O_WRONLY|O_APPEND|O_CREAT,NEWFILEMODE)) >= 0)
{
stats->userseconds += stats->users * (when - stats->lastuser);
to_file(fd,"H %s %i %i %i %i\n",chan->name,hour,
(stats->flags & CSTAT_PARTIAL) ? -stats->userseconds : stats->userseconds,
stats->userpeak,stats->userlow);
close(fd);
}
stats->LHuserseconds = stats->userseconds;
stats->userseconds = 0;
stats->lastuser = when;
stats->flags = 0;
}
void stats_plusminususer(Chan *chan, int plusminus)
{
ChanStats *stats;
ChanUser *cu;
if (!(stats = chan->stats))
{
set_mallocdoer(stats_plusminususer);
chan->stats = stats = (ChanStats*)Calloc(sizeof(ChanStats)); /* Calloc sets memory to 0 */
for(cu=chan->users;cu;cu=cu->next)
stats->users++;
stats->userpeak = stats->users;
stats->userlow = stats->users;
stats->lastuser = now;
stats->flags = CSTAT_PARTIAL;
}
/*
* add (number of users until now * seconds since last user entered/left)
*/
stats->userseconds += stats->users * (now - stats->lastuser);
stats->lastuser = now;
stats->users += plusminus; /* can be both negative (-1), zero (0) and positive (+1) */
if (stats->userpeak < stats->users)
stats->userpeak = stats->users;
if (stats->userlow > stats->users)
stats->userlow = stats->users;
#ifdef DEBUG
debug("(stats_plusminususer) %s: %i users, %i userseconds, %i high, %i low; %s (%lu)\n",
chan->name,stats->users,stats->userseconds,stats->userpeak,stats->userlow,
atime(stats->lastuser),stats->lastuser);
#endif /* DEBUG */
}
#endif /* ifdef STATS */
2014-03-08 19:56:21 -05:00
/*
*
* commands related to spy-pipes
*
*/
2018-04-04 08:56:14 +02:00
/*
2024-01-19 18:12:17 +01:00
help:SPY:[STATUS|MESSAGE|RAWIRC|URL|RANDSRC|[guid: ]channel] [channel|> filename]
Spy on a certain source of messages. When you join DCC chat,
the STATUS source is added by default as a spy source for you.
If no arguments are given, the current list of active spy
2024-01-19 18:12:17 +01:00
channels is shown.
(sources)
STATUS Status messages.
MESSAGE Pivate messages that the bot receives.
RAWIRC Lines received from irc server before processing.
URL URLs seen by the bot.
2021-06-20 20:57:36 +02:00
RANDSRC Produce random data from <RAWIRC>, can only output to file.
guid: Messages from a bot specified by guid.
channel Activities on the specified channel.
(destinations)
(none) Send output to you (default).
channel Send output to the specified channel.
>file Send output to file. Lines are appended to the end of the file.
See also: rspy
*/
2014-03-08 19:56:21 -05:00
void do_spy(COMMAND_ARGS)
{
/*
* on_msg checks: CARGS
*/
Spy *spy;
Mech *backup,*destbot;
const char *src;
char *dest;
2014-03-08 19:56:21 -05:00
int t_src,t_dest;
int sz,r,guid;
2014-03-08 19:56:21 -05:00
if (!*rest)
{
if (!current->spylist)
{
to_user(from,"No active spy channels");
return;
}
2018-04-04 06:04:58 +02:00
if (partyline_only_command(from))
2014-03-08 19:56:21 -05:00
return;
2018-04-04 08:56:14 +02:00
table_buffer(str_underline("source") "\t" str_underline("target"));
2014-03-08 19:56:21 -05:00
for(spy=current->spylist;spy;spy=spy->next)
{
switch(spy->t_src)
{
case SPY_MESSAGE:
src = "messages";
break;
default:
src = spy->src;
}
dest = (spy->t_dest == SPY_FILE) ? " (file)" : "";
table_buffer("%s\t%s%s",src,spy->dest,dest);
}
table_send(from,2);
return;
}
src = chop(&rest);
dest = chop(&rest);
if (!src)
{
spy_usage:
usage(from); /* usage for CurrentCmd->name */
return;
}
t_dest = SPY_DCC;
guid = -1;
destbot = NULL;
if (*src >= '0' && *src <= '9')
{
guid = 0;
while(*src && *src != ':')
{
guid = *src - '0';
src++;
}
if (*src != ':' && !ischannel(src+1))
goto spy_usage;
src++;
2024-01-19 18:12:17 +01:00
t_dest = t_src = SPY_CHANNEL;
2014-03-08 19:56:21 -05:00
/*
* TODO: check access
*/
#ifdef DEBUG
debug("(do_spy) spy source guid = %i, channel = %s\n",guid,src);
#endif /* DEBUG */
/*
* is it a bot?
* TODO: check botnet bots also
*/
for(backup=botlist;backup;backup=backup->next)
{
if (backup->guid == guid)
{
destbot = backup;
}
}
2024-01-19 18:12:17 +01:00
if (destbot == NULL)
{
to_user(from,"Unknown bot guid: %i",guid);
return;
}
2014-03-08 19:56:21 -05:00
}
else
{
sz = spy_source(from,&t_src,&src);
2018-04-24 18:28:10 +02:00
if (sz < 0) /* user has insufficient access to source */
2014-03-08 19:56:21 -05:00
goto spy_usage;
2018-04-24 18:28:10 +02:00
if (sz < cmdaccess) /* user has less access relative to source than the command level of SPY */
2014-03-08 19:56:21 -05:00
return;
}
if (dest)
{
/*
* log to a file
*/
if (*dest == '>')
{
2018-04-24 18:28:10 +02:00
/* accept both ">file" and "> file" */
2014-03-08 19:56:21 -05:00
dest++;
if (!*dest)
{
dest = chop(&rest);
if (!dest || !*dest)
goto spy_usage;
}
/*
* Dont just open anything.
*/
r = is_safepath(dest,FILE_MAY_EXIST);
if (r != FILE_IS_SAFE)
#ifdef DEBUG
{
debug("(do_spy) Filename \"%s\" was deemed unsafe (%i)\n",dest,r);
2014-03-08 19:56:21 -05:00
goto spy_usage;
}
#else
goto spy_usage;
#endif /* DEBUG */
2014-03-08 19:56:21 -05:00
t_dest = SPY_FILE;
goto spy_dest_ok;
}
if (!ischannel(dest))
goto spy_usage;
if (get_useraccess(from,dest) < cmdaccess)
{
to_user(from,"You don't have enough access on %s",dest);
return;
}
t_dest = SPY_CHANNEL;
}
spy_dest_ok:
#ifdef DEBUG
2024-01-19 18:12:17 +01:00
debug("(do_spy) src = `%s'; t_src = %i (%s); dest = `%s'; t_dest = %i (%s), CurrentDCC "mx_pfmt"\n",
src,t_src,SPY_DEFS[t_src-1],nullstr(dest),t_dest,SPY_DEFS[t_dest-1],CurrentDCC);
2014-03-08 19:56:21 -05:00
if (guid >= 0)
debug("(do_spy) spying from remote bot guid %i (%s), channel %s\n",guid,(destbot) ? getbotnick(destbot) : "unknown",src);
2014-03-08 19:56:21 -05:00
#endif /* DEBUG */
if (t_dest == SPY_DCC)
{
if (!CurrentDCC)
{
to_user(from,"Spying is only allowed in DCC chat");
return;
}
dest = CurrentDCC->user->name;
}
for(spy=current->spylist;spy;spy=spy->next)
{
if ((spy->t_src == t_src) && (spy->t_dest == t_dest) &&
2018-04-04 06:04:58 +02:00
!stringcasecmp(spy->src,src) && !stringcasecmp(spy->dest,dest))
2014-03-08 19:56:21 -05:00
{
to_user(from,"Requested spy channel is already active");
return;
}
}
2021-06-20 20:57:36 +02:00
if (t_src == SPY_RANDSRC && t_dest != SPY_FILE)
{
to_user(from,"Randsrc data can only be written to a file.");
return;
}
2014-03-08 19:56:21 -05:00
sz = sizeof(Spy);
if (t_dest != SPY_DCC)
sz += strlen(dest);
if (t_src == SPY_CHANNEL)
sz += strlen(src);
2024-01-19 18:12:17 +01:00
set_mallocdoer(do_spy);
2014-03-08 19:56:21 -05:00
spy = Calloc(sz);
if (t_dest != SPY_DCC)
{
spy->dest = spy->p;
2018-04-04 06:04:58 +02:00
spy->src = stringcat(spy->p,dest) + 1;
2014-03-08 19:56:21 -05:00
}
else
{
spy->dest = CurrentDCC->user->name;
2021-06-20 20:57:36 +02:00
spy->data.dcc = CurrentDCC;
2014-03-08 19:56:21 -05:00
spy->src = spy->p;
}
if (t_src == SPY_CHANNEL)
{
2018-04-04 06:04:58 +02:00
stringcpy((char*)spy->src,src);
2014-03-08 19:56:21 -05:00
}
else
{
spy->src = src;
}
spy->t_src = t_src;
spy->t_dest = t_dest;
/*
* finally link the spy record into the chain
* TODO: botnet bots
*/
if (guid >= 0)
{
if (destbot)
{
2021-06-20 20:57:36 +02:00
spy->data.destbot = current->guid;
2014-03-08 19:56:21 -05:00
spy->next = destbot->spylist;
destbot->spylist = spy;
spy_typecount(destbot);
}
}
else
{
2024-01-19 18:12:17 +01:00
if (t_dest != SPY_DCC)
spy->data.destbot = -1;
2014-03-08 19:56:21 -05:00
spy->next = current->spylist;
current->spylist = spy;
spy_typecount(current);
}
2021-06-20 20:57:36 +02:00
if (t_src == SPY_RANDSRC)
spy->data.delay = 0;
2014-03-08 19:56:21 -05:00
switch(t_src)
{
case SPY_STATUS:
send_spy(SPYSTR_STATUS,"(%s) Added to mech core",nickcpy(NULL,from));
break;
case SPY_MESSAGE:
src = "messages";
default:
to_user(from,"Spy channel for %s has been activated",src);
}
}
void do_rspy(COMMAND_ARGS)
{
/*
* on_msg checks: CARGS
*/
Spy *spy,**pspy;
const char *src;
char *dest,*tmp;
2014-03-08 19:56:21 -05:00
int t_src,t_dest;
int n;
src = chop(&rest);
dest = chop(&rest);
t_dest = SPY_DCC;
if (!src)
{
rspy_usage:
usage(from); /* usage for CurrentCmd->name */
return;
}
n = spy_source(from,&t_src,&src);
if (n < 0)
goto rspy_usage;
if (n < cmdaccess)
return;
if (dest)
{
if (*dest == '>')
{
dest++;
if (!*dest)
{
dest = chop(&rest);
if (!dest || !*dest)
goto rspy_usage;
}
/*
* this is about removing an existing spy channel
* filename does not need to be checked because
* - if its a bogus filename, it wont match any open spy channels
* - if its a matching filename, its going to be removed right now
2014-03-08 19:56:21 -05:00
*/
t_dest = SPY_FILE;
goto rspy_dest_ok;
}
if (ischannel(dest))
t_dest = SPY_CHANNEL;
}
else
dest = from;
rspy_dest_ok:
#ifdef DEBUG
debug("(do_rspy) src = `%s'; t_src = %i (%s); dest = `%s'; t_dest = %i (%s)\n",
src,t_src,SPY_DEFS[t_src-1],dest,t_dest,SPY_DEFS[t_dest-1]);
#endif /* DEBUG */
/*
* check if the spy channel exists
*/
for(spy=current->spylist;spy;spy=spy->next)
{
2018-04-04 06:04:58 +02:00
if ((spy->t_src == t_src) && (spy->t_dest == t_dest) && (!stringcasecmp(spy->src,src)))
2014-03-08 19:56:21 -05:00
{
if ((t_dest == SPY_DCC) && (!nickcmp(spy->dest,dest)))
break;
else
2018-04-04 06:04:58 +02:00
if (!stringcasecmp(spy->dest,dest))
2014-03-08 19:56:21 -05:00
break;
}
}
if (!spy)
{
to_user(from,"No matching spy channel could be found");
return;
}
switch(t_src)
{
case SPY_STATUS:
tmp = (t_dest == SPY_DCC) ? nickcpy(NULL,spy->dest) : spy->dest;
send_spy(SPYSTR_STATUS,"(%s) Removed from mech core",tmp);
break;
case SPY_MESSAGE:
src = "messages";
default:
to_user(from,"Spy channel for %s has been removed",src);
break;
}
pspy = &current->spylist;
while(*pspy)
{
if (*pspy == spy)
{
*pspy = spy->next;
Free((char**)&spy);
return;
}
pspy = &(*pspy)->next;
}
spy_typecount(current);
}
#ifdef URLCAPTURE
/*
help:URLHIST:[max]
Display a list of URLs seen by the bot in order most recent to oldest.
[max] Maximum number of URLs to display.
*/
void do_urlhist(COMMAND_ARGS)
{
Strp *sp;
char *thenum;
int n,maxnum;
if (urlhistory == NULL)
{
to_user(from,"No URLs recorded.");
return;
}
if (!rest || !*rest)
maxnum = urlhistmax;
else
{
thenum = chop(&rest);
maxnum = asc2int(thenum);
}
if ((maxnum < 1) || (maxnum > urlhistmax))
usage(from); /* usage for CurrentCmd->name */
n = 1;
for(sp=urlhistory;sp;sp=sp->next)
{
if (n > maxnum)
break;
to_user(from,"[%i] %s",n,sp->p);
n++;
}
}
#endif /* URLCAPTURE */
#ifdef STATS
void do_info(COMMAND_ARGS)
{
ChanStats *stats;
Chan *chan;
char *p;
char text[MSGLEN];
2025-11-08 14:56:19 +01:00
char modes[128];
uint32_t avg;
if (current->chanlist == NULL)
{
to_user(from,ERR_NOCHANNELS);
return;
}
2025-11-08 14:56:19 +01:00
table_buffer(str_underline("Channel") "\t" str_underline("Statistics") "\t");
for(chan=current->chanlist;chan;chan=chan->next)
{
2025-11-08 14:56:19 +01:00
stats = chan->stats;
if (stats == NULL)
{
2025-11-08 14:56:19 +01:00
table_buffer("%s (no current data)",chan->name);
continue;
}
2025-11-08 14:56:19 +01:00
if (stats->LHuserseconds > 0)
avg = stats->LHuserseconds / (60*60);
else
2025-11-08 14:56:19 +01:00
avg = (stats->userpeak + stats->userlow) / 2;
chan_modestr(chan,modes);
table_buffer("%s%s%s\tUsers:\tAvg\t%u\tPeak\t%i\tLow\t%i",
chan->name,(chan == current->activechan) ? " (current)" : EMPTYSTR,
(stats->flags == CSTAT_PARTIAL) ? " (partial)" : EMPTYSTR,
avg,stats->userpeak,stats->userlow);
table_buffer("Modes: %s\tMessages:\t\t%i\tNotices:\t%i\tJoins:\t%i",modes,
stats->privmsg,stats->notice,stats->joins);
table_buffer("\tParts:\t\t%i\tKicks:\t%i\tQuits:\t%i",
stats->parts,stats->kicks,stats->quits);
}
2025-11-08 14:56:19 +01:00
table_send(from,2);
}
#endif /* STATS */