mirror of
https://github.com/EnergyMech/energymech.git
synced 2025-12-29 16:14:43 +00:00
1037 lines
18 KiB
C
1037 lines
18 KiB
C
/*
|
|
|
|
EnergyMech, IRC bot software
|
|
Parts Copyright (c) 1997-2004 proton
|
|
|
|
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 SEEN_C
|
|
#include "config.h"
|
|
|
|
#include "defines.h"
|
|
#include "structs.h"
|
|
#include "global.h"
|
|
#include "h.h"
|
|
#include "text.h"
|
|
#include "mcmd.h"
|
|
|
|
#ifdef NOTIFY
|
|
|
|
#define CHOOSE_NUMBER 25
|
|
#define CHOOSE_MOVETO (CHOOSE_NUMBER - 2)
|
|
|
|
#define LOGFILENAMEFMT "notify-guid%i.log"
|
|
#define LOGFILENAMEBUF 32 /* need to recalculate this if LOGFILENAMEFMT is changed */
|
|
|
|
#define NFF_ALL 1
|
|
#define NFF_NOMATCH 2
|
|
#define NFF_RELOAD 4
|
|
#define NFF_FULL 8
|
|
#define NFF_SEEN 16
|
|
|
|
#define NF_OPTIONS 7
|
|
|
|
LS const char notify_opt[NF_OPTIONS][10] =
|
|
{
|
|
"-ALL",
|
|
"-NOMATCH",
|
|
"-RELOAD",
|
|
"-FULL",
|
|
"-SEEN",
|
|
};
|
|
|
|
LS Notify **endoflist;
|
|
LS int lock_ison = FALSE;
|
|
LS int nf_header;
|
|
|
|
void purge_notify(void)
|
|
{
|
|
Notify *nf;
|
|
nfLog *nlog;
|
|
|
|
/*
|
|
* empty the notifylist
|
|
*/
|
|
while(current->notifylist)
|
|
{
|
|
nf = current->notifylist;
|
|
current->notifylist = nf->next;
|
|
while(nf->log)
|
|
{
|
|
nlog = nf->log;
|
|
nf->log = nlog->next;
|
|
Free((char**)&nlog);
|
|
}
|
|
Free((char**)&nf);
|
|
}
|
|
}
|
|
|
|
int mask_check(Notify *nf, char *userhost)
|
|
{
|
|
char *mask,*rest;
|
|
int ret;
|
|
|
|
/*
|
|
* no mask (NULL)
|
|
*/
|
|
if (!nf->mask)
|
|
return(NF_MASKONLINE);
|
|
|
|
ret = NF_NOMATCH;
|
|
if (nf->endofmask)
|
|
{
|
|
/*
|
|
* multiple masks separated by spaces
|
|
*/
|
|
mask = rest = nf->mask;
|
|
chop(&rest);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* single mask
|
|
*/
|
|
if (!matches(nf->mask,userhost))
|
|
ret = NF_MASKONLINE;
|
|
return(ret);
|
|
}
|
|
while(mask)
|
|
{
|
|
if (!matches(mask,userhost))
|
|
{
|
|
ret = NF_MASKONLINE;
|
|
break;
|
|
}
|
|
mask = chop(&rest);
|
|
}
|
|
if (nf->endofmask)
|
|
{
|
|
/*
|
|
* undo the chop()'s
|
|
*/
|
|
for(mask=nf->mask;mask<nf->endofmask;mask++)
|
|
{
|
|
if (*mask == 0)
|
|
*mask = ' ';
|
|
}
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
void send_ison(void)
|
|
{
|
|
Notify *nf,*chosen[CHOOSE_NUMBER];
|
|
char isonmsg[MSGLEN];
|
|
char *p,*src;
|
|
int i,x,period;
|
|
|
|
/*
|
|
* dont send nicks to ISON too often
|
|
*/
|
|
period = current->setting[INT_ISONDELAY].int_var;
|
|
x = now - current->lastnotify;
|
|
if ((x < period) || (lock_ison && (x < 600)))
|
|
return;
|
|
|
|
current->lastnotify = now;
|
|
|
|
/*
|
|
* the nature of the code makes it so that the first NULL is
|
|
* pushed further down the list as more entries are added,
|
|
* so no need to blank the whole list
|
|
*/
|
|
chosen[0] = NULL;
|
|
|
|
/*
|
|
* select the oldest (CHOOSE_NUMBER) nicks for an update
|
|
*/
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
for(i=0;i<CHOOSE_NUMBER;i++)
|
|
{
|
|
if (!chosen[i] || (chosen[i]->checked > nf->checked))
|
|
{
|
|
for(x=CHOOSE_MOVETO;x>=i;x--)
|
|
chosen[x+1] = chosen[x];
|
|
chosen[i] = nf;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (chosen[0])
|
|
{
|
|
p = isonmsg;
|
|
for(i=0;i<CHOOSE_NUMBER;i++)
|
|
{
|
|
/*
|
|
* drop out once the end-of-chosen-list NULL is found
|
|
*/
|
|
if (!chosen[i])
|
|
break;
|
|
chosen[i]->checked = 1;
|
|
src = chosen[i]->nick;
|
|
if (i) *(p++) = ' ';
|
|
while((*p = *(src++))) p++;
|
|
}
|
|
to_server("ISON :%s\n",isonmsg);
|
|
lock_ison = TRUE;
|
|
}
|
|
}
|
|
|
|
void catch_ison(char *rest)
|
|
{
|
|
Notify *nf;
|
|
char whoismsg[MSGLEN];
|
|
char *nick,*dst;
|
|
|
|
lock_ison = FALSE;
|
|
*whoismsg = 0;
|
|
dst = whoismsg;
|
|
while((nick = chop(&rest)))
|
|
{
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
if (!nickcmp(nf->nick,nick))
|
|
{
|
|
nf->checked = now;
|
|
/*
|
|
* /whois user to get user@host + realname
|
|
*/
|
|
if (nf->status == NF_OFFLINE)
|
|
{
|
|
if (*whoismsg) *(dst++) = ',';
|
|
*dst = 0;
|
|
dst = stringcat(dst,nf->nick);
|
|
nf->status = NF_WHOIS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*whoismsg)
|
|
to_server("WHOIS %s\n",whoismsg);
|
|
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
if (nf->checked == 1)
|
|
{
|
|
nf->checked = now;
|
|
if (nf->status >= NF_WHOIS)
|
|
{
|
|
/*
|
|
* close the log entry for this online period
|
|
*/
|
|
if (nf->log && nf->log->signon && !nf->log->signoff)
|
|
nf->log->signoff = now;
|
|
/*
|
|
* announce that the user is offline if its a mask match
|
|
*/
|
|
if (nf->status == NF_MASKONLINE)
|
|
send_spy(SPYSTR_STATUS,"Notify: %s is offline",nf->nick);
|
|
nf->status = NF_OFFLINE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void catch_whois(char *nick, char *userhost, char *realname)
|
|
{
|
|
Notify *nf;
|
|
nfLog *nlog;
|
|
|
|
if (!realname || !*realname)
|
|
realname = "unknown";
|
|
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
if ((nf->status == NF_WHOIS) && !nickcmp(nf->nick,nick))
|
|
{
|
|
/*
|
|
* put in a new log entry
|
|
*/
|
|
set_mallocdoer(catch_whois);
|
|
nlog = (nfLog*)Calloc(sizeof(nfLog) + Strlen2(userhost,realname)); // realname is never NULL
|
|
nlog->signon = now;
|
|
nlog->next = nf->log;
|
|
nf->log = nlog;
|
|
nlog->realname = stringcat(nlog->userhost,userhost) + 1;
|
|
stringcpy(nlog->realname,realname);
|
|
/*
|
|
* if there is a mask, we need a match to announce the online status
|
|
*/
|
|
nf->status = mask_check(nf,userhost);
|
|
if (nf->status == NF_MASKONLINE)
|
|
send_spy(SPYSTR_STATUS,"Notify: %s (%s) is online",nf->nick,userhost);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
* saving and loading notify information
|
|
*
|
|
*/
|
|
|
|
int notifylog_callback(char *rest)
|
|
{
|
|
Notify *nf;
|
|
nfLog *nlog,**pp;
|
|
time_t on,off;
|
|
char *nick,*userhost;
|
|
|
|
if (*rest == COMMENT_CHAR)
|
|
return(FALSE);
|
|
|
|
nick = chop(&rest);
|
|
|
|
on = asc2int(chop(&rest));
|
|
if (errno)
|
|
return(FALSE);
|
|
|
|
off = asc2int(chop(&rest));
|
|
if (errno)
|
|
return(FALSE);
|
|
|
|
userhost = chop(&rest);
|
|
|
|
if (rest && *rest == ':')
|
|
rest++;
|
|
if (!*rest)
|
|
return(FALSE);
|
|
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
if (!nickcmp(nick,nf->nick))
|
|
{
|
|
pp = &nf->log;
|
|
while(*pp)
|
|
{
|
|
if ((*pp)->signon < on)
|
|
break;
|
|
pp = &(*pp)->next;
|
|
}
|
|
set_mallocdoer(notifylog_callback);
|
|
nlog = (nfLog*)Calloc(sizeof(nfLog) + Strlen2(userhost,rest)); // rest is never NULL
|
|
nlog->signon = on;
|
|
nlog->signoff = off;
|
|
nlog->next = *pp;
|
|
*pp = nlog;
|
|
nlog->realname = stringcat(nlog->userhost,userhost) + 1;
|
|
stringcpy(nlog->realname,rest);
|
|
break;
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
void read_notifylog(void)
|
|
{
|
|
char fname[LOGFILENAMEBUF];
|
|
int fd;
|
|
#ifdef DEBUG
|
|
int dd;
|
|
#endif /* DEBUG */
|
|
|
|
sprintf(fname,LOGFILENAMEFMT,current->guid);
|
|
if ((fd = open(fname,O_RDONLY)) < 0)
|
|
return;
|
|
#ifdef DEBUG
|
|
dd = dodebug;
|
|
dodebug = FALSE;
|
|
#endif /* DEBUG */
|
|
|
|
readline(fd,¬ifylog_callback); /* readline closes fd */
|
|
|
|
#ifdef DEBUG
|
|
dodebug = dd;
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
void write_notifylog(void)
|
|
{
|
|
Notify *nf;
|
|
nfLog *nlog;
|
|
char fname[LOGFILENAMEBUF];
|
|
int fd;
|
|
#ifdef DEBUG
|
|
int dd;
|
|
#endif /* DEBUG */
|
|
|
|
sprintf(fname,LOGFILENAMEFMT,current->guid);
|
|
if ((fd = open(fname,O_WRONLY|O_CREAT|O_TRUNC,NEWFILEMODE)) < 0)
|
|
return;
|
|
|
|
#ifdef DEBUG
|
|
dd = dodebug;
|
|
dodebug = FALSE;
|
|
#endif /* DEBUG */
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
to_file(fd,COMMENT_STRCHR "\n" COMMENT_STRCHR " Nick: %s\n",nf->nick);
|
|
if (nf->info)
|
|
to_file(fd,COMMENT_STRCHR " Note: %s\n",nf->info);
|
|
if (nf->mask)
|
|
to_file(fd,COMMENT_STRCHR " Mask: %s\n",nf->mask);
|
|
to_file(fd,COMMENT_STRCHR "\n");
|
|
for(nlog=nf->log;nlog;nlog=nlog->next)
|
|
{
|
|
to_file(fd,"%s %lu %lu %s :%s\n",nf->nick,nlog->signon,
|
|
(nlog->signoff) ? nlog->signoff : now,
|
|
nlog->userhost,nlog->realname);
|
|
}
|
|
}
|
|
close(fd);
|
|
#ifdef DEBUG
|
|
dodebug = dd;
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
int notify_callback(char *rest)
|
|
{
|
|
Notify *nf;
|
|
char *nick;
|
|
char *src,*dst;
|
|
char *lspace;
|
|
|
|
errno = EINVAL;
|
|
|
|
if (!rest || *rest == COMMENT_CHAR)
|
|
return(FALSE);
|
|
fix_config_line(rest);
|
|
if ((nick = chop(&rest)) == NULL)
|
|
return(FALSE);
|
|
|
|
#ifdef DEBUG
|
|
debug("(notify_callback) parsing %s `%s'\n",nick,nullstr(rest));
|
|
#endif /* DEBUG */
|
|
|
|
lspace = rest - 1;
|
|
src = dst = rest;
|
|
while(*src)
|
|
{
|
|
if (*src == ' ')
|
|
{
|
|
if (!lspace)
|
|
{
|
|
lspace = dst;
|
|
*(dst++) = *src;
|
|
}
|
|
src++;
|
|
}
|
|
else
|
|
if (*src == ':' && lspace)
|
|
{
|
|
*lspace = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
lspace = NULL;
|
|
*(dst++) = *(src++);
|
|
}
|
|
}
|
|
|
|
if (*src == ':')
|
|
*(src++) = 0;
|
|
if (!*src)
|
|
src = NULL;
|
|
|
|
#ifdef DEBUG
|
|
debug("(notify_callback) creating struct\n");
|
|
#endif /* DEBUG */
|
|
|
|
/*
|
|
* nick = nick
|
|
* rest = mask(s) or *rest == 0
|
|
* src = description or NULL
|
|
*/
|
|
set_mallocdoer(notify_callback);
|
|
nf = (Notify*)Calloc(sizeof(Notify) + StrlenX(nick,rest,src,NULL));
|
|
dst = stringcat(nf->nick,nick);
|
|
if (*rest)
|
|
{
|
|
nf->mask = dst + 1;
|
|
dst = stringcat(nf->mask,rest);
|
|
if (STRCHR(nf->mask,' '))
|
|
nf->endofmask = dst;
|
|
}
|
|
if (src)
|
|
{
|
|
nf->info = dst + 1;
|
|
stringcpy(nf->info,src);
|
|
}
|
|
/* put it at the end of notifylist */
|
|
*endoflist = nf;
|
|
endoflist = &nf->next;
|
|
|
|
errno = 0;
|
|
return(FALSE);
|
|
}
|
|
|
|
int read_notify(char *filename)
|
|
{
|
|
int fd;
|
|
|
|
if (!filename)
|
|
return(FALSE);
|
|
|
|
if ((fd = open(filename,O_RDONLY)) < 0)
|
|
return(FALSE);
|
|
|
|
/*
|
|
* save online logs
|
|
*/
|
|
if (current->notifylist)
|
|
write_notifylog();
|
|
|
|
/*
|
|
* delete the whole list
|
|
*/
|
|
purge_notify();
|
|
|
|
endoflist = ¤t->notifylist;
|
|
readline(fd,¬ify_callback); /* readline closes fd */
|
|
|
|
/*
|
|
* read back online logs
|
|
*/
|
|
read_notifylog();
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
void nfshow_brief(Notify *nf)
|
|
{
|
|
time_t when;
|
|
char mem[40];
|
|
char *s;
|
|
int d,h,m;
|
|
|
|
if (nf->status == NF_NOMATCH)
|
|
s = " nickname in use";
|
|
else
|
|
if (nf->status >= NF_WHOIS)
|
|
s = " online now";
|
|
else
|
|
if (nf->log && nf->log->signoff)
|
|
{
|
|
s = mem;
|
|
when = now - nf->log->signoff;
|
|
d = when / 86400;
|
|
h = (when -= d * 86400) / 3600;
|
|
m = (when -= h * 3600) / 60;
|
|
sprintf(mem,"%2i day%1s %02i:%02i ago",d,EXTRA_CHAR(d),h,m);
|
|
}
|
|
else
|
|
s = " never seen";
|
|
|
|
if (!nf_header)
|
|
to_user(global_from,"\037nick\037 \037last seen\037 \037note\037");
|
|
to_user(global_from,(nf->info) ? "%-9s %-22s %s" : "%-9s %s",
|
|
nf->nick,s,nf->info);
|
|
nf_header++;
|
|
}
|
|
|
|
void nfshow_full(Notify *nf)
|
|
{
|
|
char mem[MSGLEN];
|
|
nfLog *nlog;
|
|
char *s,*opt;
|
|
|
|
if (nf_header)
|
|
to_user(global_from," ");
|
|
to_user(global_from,(nf->status == NF_MASKONLINE) ? "Nick: \037%s\037" : "Nick: %s",nf->nick);
|
|
if (nf->info)
|
|
to_user(global_from,"Note: %s",nf->info);
|
|
if (nf->mask)
|
|
to_user(global_from,"Mask: %s",nf->mask);
|
|
if (nf->log)
|
|
{
|
|
to_user(global_from,"Online history:");
|
|
for(nlog=nf->log;nlog;nlog=nlog->next)
|
|
{
|
|
opt = mem;
|
|
s = time2away(nlog->signon);
|
|
if (s[1] == ':')
|
|
*(opt++) = ' ';
|
|
*opt = 0;
|
|
opt = stringcat(opt,s);
|
|
while(opt < (mem+18))
|
|
*(opt++) = ' ';
|
|
*opt = 0;
|
|
opt = stringcat(opt," -- ");
|
|
if (nlog->signoff)
|
|
{
|
|
s = time2away(nlog->signoff);
|
|
if (s[1] == ':')
|
|
*(opt++) = ' ';
|
|
*opt = 0;
|
|
}
|
|
else
|
|
{
|
|
s = " online now";
|
|
}
|
|
opt = stringcat(opt,s);
|
|
while(opt < (mem+41))
|
|
*(opt++) = ' ';
|
|
*opt = 0;
|
|
s = (nlog->realname) ? "%s: %s (%s)" : "%s: %s";
|
|
to_user(global_from,s,mem,nlog->userhost,nlog->realname);
|
|
}
|
|
}
|
|
nf_header++;
|
|
}
|
|
|
|
void sub_notifynick(char *from, char *rest)
|
|
{
|
|
Notify *nf,**pp;
|
|
char *nick;
|
|
int i;
|
|
|
|
nick = chop(&rest);
|
|
if (!nick)
|
|
{
|
|
usage(from);
|
|
return;
|
|
}
|
|
i = 0;
|
|
pp = ¤t->notifylist;
|
|
while(*pp)
|
|
{
|
|
nf = *pp;
|
|
if (!nickcmp(nick,nf->nick))
|
|
{
|
|
*pp = nf->next;
|
|
Free((char**)&nf);
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
pp = &nf->next;
|
|
}
|
|
}
|
|
if (!i)
|
|
to_user(from,"Nick not found: %s",nick);
|
|
else
|
|
to_user(from,"Nick removed from notify: %s",nick);
|
|
}
|
|
|
|
#endif /* ifdef NOTIFY */
|
|
|
|
#ifdef SEEN
|
|
|
|
int write_seenlist(void)
|
|
{
|
|
Seen *seen;
|
|
int f;
|
|
#ifdef DEBUG
|
|
int dodeb;
|
|
#endif /* DEBUG */
|
|
|
|
if (!seenfile)
|
|
return(FALSE);
|
|
if ((f = open(seenfile,O_WRONLY|O_CREAT|O_TRUNC,NEWFILEMODE)) < 0)
|
|
return(FALSE);
|
|
|
|
#ifdef DEBUG
|
|
dodeb = dodebug;
|
|
dodebug = FALSE;
|
|
#endif /* DEBUG */
|
|
|
|
for(seen=seenlist;seen;seen=seen->next)
|
|
{
|
|
if ((seen->when - now) > (86400 * SEEN_TIME))
|
|
continue;
|
|
else
|
|
{
|
|
if (seen->t != 0)
|
|
{
|
|
to_file(f,"%s %s %lu %i %s %s\n",
|
|
seen->nick,seen->userhost,
|
|
seen->when,seen->t,
|
|
(seen->pa) ? seen->pa : "",
|
|
(seen->pb) ? seen->pb : "");
|
|
}
|
|
}
|
|
}
|
|
close(f);
|
|
|
|
#ifdef DEBUG
|
|
dodebug = dodeb;
|
|
#endif /* DEBUG */
|
|
return(TRUE);
|
|
}
|
|
|
|
int read_seenlist_callback(char *rest)
|
|
{
|
|
char *nick,*uh,*pa,*pb;
|
|
time_t when;
|
|
int t;
|
|
|
|
nick = chop(&rest);
|
|
uh = chop(&rest);
|
|
|
|
when = asc2int(chop(&rest)); /* seen time, asc2int handles NULL */
|
|
if (errno)
|
|
return(FALSE);
|
|
|
|
t = asc2int(chop(&rest)); /* seen type, asc2int handles NULL */
|
|
if (errno)
|
|
return(FALSE);
|
|
|
|
pa = chop(&rest);
|
|
pb = rest;
|
|
|
|
if ((now - when) < (SEEN_TIME * 86400))
|
|
{
|
|
/* if (pa && !*pa)
|
|
pa = NULL; chop() doesnt return empty strings */
|
|
if (!*pb)
|
|
pb = NULL;
|
|
make_seen(nick,uh,pa,pb,when,t);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
int read_seenlist(void)
|
|
{
|
|
Seen *seen;
|
|
int in;
|
|
#ifdef DEBUG
|
|
int dodeb;
|
|
#endif /* DEBUG */
|
|
|
|
if (!seenfile || ((in = open(seenfile,O_RDONLY)) < 0))
|
|
return(FALSE);
|
|
|
|
#ifdef DEBUG
|
|
dodeb = dodebug;
|
|
dodebug = FALSE;
|
|
#endif /* DEBUG */
|
|
|
|
while((seen = seenlist))
|
|
{
|
|
seenlist = seen->next;
|
|
Free((char**)&seen);
|
|
}
|
|
|
|
readline(in,&read_seenlist_callback); /* readline closes in */
|
|
|
|
#ifdef DEBUG
|
|
dodebug = dodeb;
|
|
#endif /* DEBUG */
|
|
return(TRUE);
|
|
}
|
|
|
|
void make_seen(char *nick, char *userhost, char *pa, char *pb, time_t when, int t)
|
|
{
|
|
Seen *seen,**pp;
|
|
char *pt;
|
|
uchar c1;
|
|
int i;
|
|
|
|
for(pt=userhost;*pt;pt++)
|
|
{
|
|
if (*pt == '!')
|
|
{
|
|
userhost = pt + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
c1 = nickcmptab[(uchar)(*nick)];
|
|
pt = nick + 1;
|
|
pp = &seenlist;
|
|
|
|
step_one:
|
|
if (*pp)
|
|
{
|
|
if (c1 > nickcmptab[(uchar)(*(*pp)->nick)])
|
|
{
|
|
pp = &(*pp)->next;
|
|
goto step_one;
|
|
}
|
|
}
|
|
|
|
step_two:
|
|
if (*pp)
|
|
{
|
|
if (c1 == nickcmptab[(uchar)(*(*pp)->nick)])
|
|
{
|
|
i = nickcmp(pt,(*pp)->nick+1);
|
|
if (i > 0)
|
|
{
|
|
pp = &(*pp)->next;
|
|
goto step_two;
|
|
}
|
|
if (!i)
|
|
{
|
|
seen = *pp;
|
|
*pp = seen->next;
|
|
Free((char**)&seen);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* dont fuck with this code unless you really know what you're doing
|
|
* pa might be NULL, but then pb is NULL also; pb might be NULL
|
|
* any NULL terminates the StrlenX() check
|
|
*/
|
|
set_mallocdoer(make_seen);
|
|
seen = (Seen*)Calloc(sizeof(Seen) + StrlenX(nick,userhost,pa,pb,NULL));
|
|
|
|
seen->next = *pp;
|
|
*pp = seen;
|
|
seen->when = when;
|
|
seen->t = t;
|
|
/* Calloc sets to zero seen->pa = seen->pb = NULL; */
|
|
|
|
seen->userhost = stringcpy(seen->nick,nick) + 1;
|
|
pt = stringcpy(seen->userhost,userhost) + 1;
|
|
if (pa)
|
|
{
|
|
seen->pa = pt;
|
|
pt = stringcpy(seen->pa,pa) + 1;
|
|
if (pb)
|
|
{
|
|
seen->pb = pt;
|
|
stringcpy(seen->pb,pb);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
-+=====================================================================================================================+-
|
|
seen.c commands
|
|
-+=====================================================================================================================+-
|
|
*/
|
|
|
|
void do_seen(COMMAND_ARGS)
|
|
{
|
|
Seen *seen;
|
|
char ago[35]; /* enought for "36500 days, 23 hours and 59 minutes" (100 years) */
|
|
const char *chan;
|
|
char *fmt,*n,*u,*c1,*c2,*c3;
|
|
time_t when;
|
|
int d,h,m,mul;
|
|
|
|
chan = get_channel(to,&rest);
|
|
mul = get_maxaccess(from);
|
|
|
|
if (!*rest)
|
|
{
|
|
if (mul) to_user_q(from,"Who do you want me look for?");
|
|
return;
|
|
}
|
|
|
|
n = chop(&rest);
|
|
if (!is_nick(n))
|
|
{
|
|
if (mul) to_user_q(from,ERR_NICK,n);
|
|
return;
|
|
}
|
|
|
|
if (!nickcmp(n,getbotnick(current)))
|
|
{
|
|
fmt = "%s is me you dweeb!";
|
|
}
|
|
else
|
|
if (!nickcmp(n,from))
|
|
{
|
|
fmt = "Trying to find yourself %s?";
|
|
}
|
|
else
|
|
{
|
|
for(seen=seenlist;seen;seen=seen->next)
|
|
{
|
|
if (!stringcasecmp(n,seen->nick))
|
|
break;
|
|
}
|
|
|
|
if (!seen)
|
|
{
|
|
fmt = "I have no memory of %s";
|
|
}
|
|
else
|
|
{
|
|
when = now - seen->when;
|
|
d = when / 86400;
|
|
h = (when -= d * 86400) / 3600;
|
|
m = (when -= h * 3600) / 60;
|
|
|
|
*ago = 0;
|
|
c2 = ago;
|
|
|
|
if (d)
|
|
{
|
|
sprintf(c2,"%i day%s, ",d,EXTRA_CHAR(d));
|
|
}
|
|
if (h || d)
|
|
{
|
|
sprintf(ago+strlen(ago),"%i hour%s and ",h,EXTRA_CHAR(h));
|
|
}
|
|
sprintf(ago+strlen(ago),"%i minute%s",m,EXTRA_CHAR(m));
|
|
|
|
n = seen->nick;
|
|
u = seen->userhost;
|
|
c1 = seen->pa;
|
|
c2 = ago;
|
|
|
|
switch(seen->t)
|
|
{
|
|
case SEEN_PARTED:
|
|
fmt = "%s (%s) parted from %s, %s ago";
|
|
break;
|
|
case SEEN_QUIT:
|
|
fmt = "%s (%s) signed off with message \"%s\", %s ago";
|
|
break;
|
|
case SEEN_NEWNICK:
|
|
fmt = "%s (%s) changed nicks to %s, %s ago";
|
|
break;
|
|
case SEEN_KICKED:
|
|
c2 = seen->pb;
|
|
c3 = ago;
|
|
fmt = "%s (%s) was kicked by %s with message \"%s\", %s ago";
|
|
}
|
|
}
|
|
}
|
|
|
|
to_user_q(from,fmt,n,u,c1,c2,c3);
|
|
}
|
|
|
|
#endif /* SEEN */
|
|
|
|
#ifdef NOTIFY
|
|
|
|
void do_notify(COMMAND_ARGS)
|
|
{
|
|
char message[MSGLEN];
|
|
Notify *nf;
|
|
nfLog *nlog;
|
|
char *opt;
|
|
int n,flags;
|
|
|
|
global_from = from;
|
|
flags = nf_header = 0;
|
|
*message = 0;
|
|
|
|
if (*rest)
|
|
{
|
|
while((opt = chop(&rest)))
|
|
{
|
|
if (!stringcmp(opt,"+"))
|
|
{
|
|
endoflist = ¤t->notifylist;
|
|
while(*endoflist)
|
|
endoflist = &(*endoflist)->next;
|
|
notify_callback(rest);
|
|
return;
|
|
}
|
|
if (!stringcmp(opt,"-"))
|
|
{
|
|
sub_notifynick(from,rest);
|
|
return;
|
|
}
|
|
for(n=0;n<NF_OPTIONS;n++)
|
|
{
|
|
if (!stringcasecmp(notify_opt[n],opt))
|
|
{
|
|
flags |= (1 << n);
|
|
break;
|
|
}
|
|
}
|
|
if (n>=NF_OPTIONS)
|
|
{
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
if (!nickcmp(opt,nf->nick))
|
|
{
|
|
if (flags & NFF_FULL)
|
|
nfshow_full(nf);
|
|
else
|
|
nfshow_brief(nf);
|
|
break;
|
|
}
|
|
}
|
|
if (!nf)
|
|
{
|
|
if (*message)
|
|
stringcat(message,", ");
|
|
stringcat(message,opt);
|
|
}
|
|
nf_header++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*message)
|
|
{
|
|
#ifdef DEBUG
|
|
debug("(do_notify) dumping errnames\n");
|
|
#endif /* DEBUG */
|
|
to_user(from,"User%s not found: %s",(STRCHR(message,',')) ? "s" : "",message);
|
|
}
|
|
|
|
if (nf_header)
|
|
return;
|
|
|
|
if (flags & NFF_RELOAD)
|
|
{
|
|
opt = current->setting[STR_NOTIFYFILE].str_var;
|
|
if (opt && read_notify(opt))
|
|
{
|
|
flags = get_useraccess(from,"");
|
|
send_spy(SPYSTR_STATUS,"Notify: %s reloaded by %s[%i]",
|
|
opt,CurrentNick,flags);
|
|
to_user(from,"notify list read from file %s",opt);
|
|
}
|
|
else
|
|
{
|
|
to_user(from,"notify list could not be read from file %s",nullstr(opt));
|
|
}
|
|
return;
|
|
}
|
|
|
|
for(nf=current->notifylist;nf;nf=nf->next)
|
|
{
|
|
if ((nf->status == NF_MASKONLINE) || (flags & NFF_ALL) || ((flags & NFF_NOMATCH) && (nf->status == NF_NOMATCH)))
|
|
goto show_it;
|
|
if ((flags & NFF_SEEN) && nf->log)
|
|
{
|
|
for(nlog=nf->log;nlog;nlog=nlog->next)
|
|
{
|
|
if (mask_check(nf,nlog->userhost) == NF_MASKONLINE)
|
|
goto show_it;
|
|
}
|
|
}
|
|
continue;
|
|
show_it:
|
|
if (flags & NFF_FULL)
|
|
nfshow_full(nf);
|
|
else
|
|
nfshow_brief(nf);
|
|
}
|
|
if (!nf_header)
|
|
{
|
|
to_user(from,"no notify users are online");
|
|
}
|
|
}
|
|
|
|
#endif /* NOTIFY */
|