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"
|
|
|
|
|
|
2018-04-14 02:52:08 +02:00
|
|
|
#ifdef STATS
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-03-08 19:56:21 -05:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
2025-11-20 14:55:08 +01:00
|
|
|
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",
|
2018-03-14 03:02:30 +01:00
|
|
|
"SPY_BOTNET",
|
|
|
|
|
"SPY_URL",
|
2018-04-15 03:57:44 +02:00
|
|
|
"SPY_SYSMON",
|
2021-06-20 20:57:36 +02:00
|
|
|
"SPY_RANDSRC",
|
2014-03-08 19:56:21 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
2025-09-21 16:26:51 +02:00
|
|
|
#if defined(SHACRYPT) || defined(MD5CRYPT)
|
2025-11-20 14:55:08 +01:00
|
|
|
|
2025-09-21 16:26:51 +02:00
|
|
|
char *CRYPT_FUNC(const char *, const char *);
|
2025-11-20 14:55:08 +01:00
|
|
|
|
2025-09-21 16:26:51 +02:00
|
|
|
#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;
|
2025-11-20 14:55:08 +01:00
|
|
|
char tempdata[MAXLEN];
|
2025-11-10 22:28:21 +01:00
|
|
|
int fd;
|
2014-03-08 19:56:21 -05:00
|
|
|
|
2025-11-20 14:55:08 +01:00
|
|
|
printmsg = (src == SPYSTR_RAWIRC) ? format : NULL;
|
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,
|
2025-10-27 15:13:49 +01:00
|
|
|
(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)
|
|
|
|
|
{
|
2025-11-20 14:55:08 +01:00
|
|
|
/*
|
|
|
|
|
* Dont support RANDSRC unless there is a good hashing function to
|
|
|
|
|
* create high quality randomness.
|
|
|
|
|
*/
|
|
|
|
|
#if defined(SHACRYPT) || defined(MD5CRYPT)
|
2021-06-20 20:57:36 +02:00
|
|
|
if (spy->t_src == SPY_RANDSRC)
|
|
|
|
|
{
|
2025-11-20 14:55:08 +01:00
|
|
|
char mysalt[16],mydata[128];
|
|
|
|
|
char *rnd,*dst,*end;
|
|
|
|
|
|
2021-06-20 20:57:36 +02:00
|
|
|
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 */
|
2025-11-20 14:55:08 +01:00
|
|
|
spy->data.delay = now + 20 + RANDOM(0,29); /* make it unpredictable which messages will be sourced */
|
2021-06-20 20:57:36 +02:00
|
|
|
|
2025-11-20 14:55:08 +01:00
|
|
|
sprintf(mysalt,
|
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
|
|
|
(uint32_t)(now & 0xFFFF));
|
2025-11-20 14:55:08 +01:00
|
|
|
|
|
|
|
|
/* SHA512 internal returns NULL if strlen(format) > 256 */
|
|
|
|
|
stringcpy_n(mydata,format,120);
|
|
|
|
|
|
|
|
|
|
rnd = CRYPT_FUNC(mydata,mysalt);
|
2021-06-20 20:57:36 +02:00
|
|
|
|
|
|
|
|
dst = tempdata;
|
|
|
|
|
end = STREND(rnd);
|
|
|
|
|
rnd += 8; /* skip salt */
|
2025-11-10 22:28:21 +01:00
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
2025-11-20 14:55:08 +01:00
|
|
|
/*
|
|
|
|
|
|..aaaaaa|..bbbbbb|..cccccc|..dddddd|
|
|
|
|
|
| |aaaaaa..|bbbbbb..|cccccc..|
|
|
|
|
|
| | ddddDD|
|
|
|
|
|
| ddDD|dd
|
|
|
|
|
DD|dddd |
|
|
|
|
|
*/
|
2025-11-10 22:28:21 +01:00
|
|
|
/* 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)
|
|
|
|
|
{
|
2025-11-20 14:55:08 +01:00
|
|
|
int n __notused__;
|
2025-09-21 16:26:51 +02:00
|
|
|
n = write(fd,tempdata,dst - tempdata);
|
2021-06-20 20:57:36 +02:00
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-11-20 14:55:08 +01:00
|
|
|
#endif /* defined(SHACRYPT) || defined(MD5CRYPT) */
|
2025-11-10 22:28:21 +01:00
|
|
|
|
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;
|
|
|
|
|
|
2025-11-20 14:55:08 +01:00
|
|
|
if (spy->t_src == SPY_STATUS)
|
|
|
|
|
{
|
|
|
|
|
spysrc = maketimestr(now,TFMT_CLOCK);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
spysrc = spy->src;
|
|
|
|
|
|
|
|
|
|
if (printmsg == NULL)
|
2014-03-08 19:56:21 -05:00
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2025-11-20 14:55:08 +01:00
|
|
|
to_file(fd,"[%s] %s\n",maketimestr(now,TFMT_LOG),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
|
|
|
|
|
{
|
2018-03-14 03:02:30 +01:00
|
|
|
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 },
|
2018-03-14 03:02:30 +01:00
|
|
|
#ifdef URLCAPTURE
|
|
|
|
|
{ SPYSTR_URL, SPY_URL },
|
|
|
|
|
#endif /* URLCAPTURE */
|
2018-04-15 03:57:44 +02:00
|
|
|
#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 },
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-14 03:02:30 +01:00
|
|
|
int spy_source(char *from, int *t_src, const char **src)
|
2014-03-08 19:56:21 -05:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2018-03-14 03:02:30 +01:00
|
|
|
#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));
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-14 02:52:08 +02:00
|
|
|
#ifdef REDIRECT
|
|
|
|
|
|
|
|
|
|
int begin_redirect(char *from, char *args)
|
|
|
|
|
{
|
|
|
|
|
char *pt,*nick;
|
|
|
|
|
|
|
|
|
|
if (!args)
|
|
|
|
|
return(0);
|
2025-11-20 14:55:08 +01:00
|
|
|
pt = stringchr(args,'>');
|
2018-04-14 02:52:08 +02:00
|
|
|
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);
|
2018-04-14 02:52:08 +02:00
|
|
|
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 */
|
2018-04-14 02:52:08 +02:00
|
|
|
{
|
|
|
|
|
to_user(from,"Bad filename.");
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
2021-06-20 20:57:36 +02:00
|
|
|
set_mallocdoer(begin_redirect);
|
2018-04-14 02:52:08 +02:00
|
|
|
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);
|
2018-04-14 02:52:08 +02:00
|
|
|
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");
|
2018-04-14 10:24:41 -04:00
|
|
|
if (write(fd,message,(fmt-message)) == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
2018-04-14 02:52:08 +02:00
|
|
|
close(fd);
|
|
|
|
|
return;
|
|
|
|
|
#ifdef BOTNET
|
|
|
|
|
case R_BOTNET:
|
|
|
|
|
{
|
|
|
|
|
char tempdata[MAXLEN];
|
|
|
|
|
Mech *backup;
|
|
|
|
|
|
|
|
|
|
/* PM<targetguid> <targetuserhost> <source> <message> */
|
2025-10-27 15:13:49 +01:00
|
|
|
sprintf(tempdata,"%i %s %s %s",redirect.guid,redirect.to,getbotnick(current),message);
|
2018-04-14 02:52:08 +02:00
|
|
|
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 = ¤t->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
|
|
|
|
|
|
2025-11-20 14:55:08 +01:00
|
|
|
void urlhost(const char *url)
|
2018-04-14 02:52:08 +02:00
|
|
|
{
|
|
|
|
|
char copy[strlen(url)];
|
2025-11-20 14:55:08 +01:00
|
|
|
const char *end,*beg;
|
2018-04-14 02:52:08 +02:00
|
|
|
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)
|
|
|
|
|
{
|
2025-11-20 14:55:08 +01:00
|
|
|
Strp *sp;
|
2018-04-14 02:52:08 +02:00
|
|
|
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)
|
|
|
|
|
{
|
2018-04-22 02:34:04 +02:00
|
|
|
purge_linklist((void**)&sp->next);
|
2018-04-14 02:52:08 +02:00
|
|
|
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]
|
2018-03-14 03:02:30 +01:00
|
|
|
|
|
|
|
|
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.
|
2018-03-14 03:02:30 +01:00
|
|
|
|
|
|
|
|
(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.
|
2018-03-14 03:02:30 +01:00
|
|
|
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;
|
2018-03-14 03:02:30 +01:00
|
|
|
const char *src;
|
|
|
|
|
char *dest;
|
2014-03-08 19:56:21 -05:00
|
|
|
int t_src,t_dest;
|
2018-03-14 03:02:30 +01:00
|
|
|
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.
|
|
|
|
|
*/
|
2018-03-14 03:02:30 +01:00
|
|
|
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;
|
2018-03-14 03:02:30 +01:00
|
|
|
}
|
|
|
|
|
#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)
|
2025-10-27 15:13:49 +01:00
|
|
|
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;
|
2018-03-14 03:02:30 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
/*
|
2018-03-14 03:02:30 +01:00
|
|
|
* 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 = ¤t->spylist;
|
|
|
|
|
while(*pspy)
|
|
|
|
|
{
|
|
|
|
|
if (*pspy == spy)
|
|
|
|
|
{
|
|
|
|
|
*pspy = spy->next;
|
|
|
|
|
Free((char**)&spy);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pspy = &(*pspy)->next;
|
|
|
|
|
}
|
|
|
|
|
spy_typecount(current);
|
|
|
|
|
}
|
2018-04-14 02:52:08 +02:00
|
|
|
|
|
|
|
|
#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;
|
2025-11-08 14:56:19 +01:00
|
|
|
char modes[128];
|
2018-04-14 02:52:08 +02:00
|
|
|
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");
|
|
|
|
|
|
2018-04-14 02:52:08 +02:00
|
|
|
for(chan=current->chanlist;chan;chan=chan->next)
|
|
|
|
|
{
|
2025-11-08 14:56:19 +01:00
|
|
|
stats = chan->stats;
|
|
|
|
|
if (stats == NULL)
|
2018-04-14 02:52:08 +02:00
|
|
|
{
|
2025-11-08 14:56:19 +01:00
|
|
|
table_buffer("%s (no current data)",chan->name);
|
|
|
|
|
continue;
|
2018-04-14 02:52:08 +02:00
|
|
|
}
|
2025-11-08 14:56:19 +01:00
|
|
|
|
|
|
|
|
if (stats->LHuserseconds > 0)
|
|
|
|
|
avg = stats->LHuserseconds / (60*60);
|
2018-04-14 02:52:08 +02:00
|
|
|
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);
|
2018-04-14 02:52:08 +02:00
|
|
|
}
|
2025-11-08 14:56:19 +01:00
|
|
|
table_send(from,2);
|
2018-04-14 02:52:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* STATS */
|
|
|
|
|
|