3 #include "../core/hooks.h"
4 #include "../control/control.h"
5 #include "../irc/irc.h"
6 #include "../lib/irc_string.h"
7 #include "../lib/version.h"
8 #include "../core/config.h"
11 #define XStringify(x) Stringify(x)
12 #define Stringify(x) #x
20 whowas
*whowas_fromnick(nick
*np
, int standalone
) {
23 struct irc_in_addr ipaddress_canonical
;
26 /* Create a new record. */
28 ww
= malloc(sizeof(whowas
));
30 ww
= &whowasrecs
[whowasoffset
];
32 whowasoffset
= (whowasoffset
+ 1) % whowasmax
;
35 memset(ww
, 0, sizeof(whowas
));
38 memset(wnp
, 0, sizeof(nick
));
39 strncpy(wnp
->nick
, np
->nick
, NICKLEN
+ 1);
40 wnp
->numeric
= np
->numeric
;
41 strncpy(wnp
->ident
, np
->ident
, USERLEN
+ 1);
43 wnp
->host
= newhost();
44 memset(wnp
->host
, 0, sizeof(host
));
45 wnp
->host
->name
= getsstring(np
->host
->name
->content
, HOSTLEN
);
47 wnp
->realname
= newrealname();
48 memset(wnp
->realname
, 0, sizeof(realname
));
49 wnp
->realname
->name
= getsstring(np
->realname
->name
->content
, REALLEN
);
50 wnp
->shident
= np
->shident
? getsstring(np
->shident
->content
, 512) : NULL
;
51 wnp
->sethost
= np
->sethost
? getsstring(np
->sethost
->content
, 512) : NULL
;
52 wnp
->opername
= np
->opername
? getsstring(np
->opername
->content
, 512) : NULL
;
53 wnp
->umodes
= np
->umodes
;
55 wnp
->auth
= newauthname();
56 memset(wnp
->auth
, 0, sizeof(authname
));
57 wnp
->auth
->userid
= np
->auth
->userid
;
58 strncpy(wnp
->auth
->name
, np
->auth
->name
, ACCOUNTLEN
+ 1);
59 wnp
->authname
= wnp
->auth
->name
;
61 wnp
->timestamp
= np
->timestamp
;
62 wnp
->accountts
= np
->accountts
;
63 wnp
->away
= np
->away
? getsstring(np
->away
->content
, 512) : NULL
;
65 memcpy(&wnp
->ipaddress
, &np
->ipaddress
, sizeof(struct irc_in_addr
));
67 ip_canonicalize_tunnel(&ipaddress_canonical
, &np
->ipaddress
);
68 wnp
->ipnode
= refnode(iptree
, &ipaddress_canonical
, PATRICIA_MAXBITS
);
70 wnp
->next
= (nick
*)ww
; /* Yuck. */
72 ww
->timestamp
= getnettime();
73 ww
->type
= WHOWAS_USED
;
77 triggerhook(HOOK_WHOWAS_NEWRECORD
, args
);
82 void whowas_clean(whowas
*ww
) {
85 if (!ww
|| ww
->type
== WHOWAS_UNUSED
)
88 triggerhook(HOOK_WHOWAS_LOSTRECORD
, ww
);
91 freesstring(np
->host
->name
);
93 freesstring(np
->realname
->name
);
94 freerealname(np
->realname
);
95 freesstring(np
->shident
);
96 freesstring(np
->sethost
);
97 freesstring(np
->opername
);
98 freeauthname(np
->auth
);
99 freesstring(np
->away
);
100 derefnode(iptree
, np
->ipnode
);
101 freesstring(ww
->reason
);
102 freesstring(ww
->newnick
);
103 ww
->type
= WHOWAS_UNUSED
;
106 void whowas_free(whowas
*ww
) {
111 static void whowas_handlequitorkill(int hooknum
, void *arg
) {
114 char *reason
= args
[1];
119 /* Create a new record. */
120 ww
= whowas_fromnick(np
, 0);
122 if (hooknum
== HOOK_NICK_KILL
) {
123 if ((rreason
= strchr(reason
, ' '))) {
124 sprintf(resbuf
, "Killed%s", rreason
);
128 ww
->type
= WHOWAS_KILL
;
130 if (strncmp(reason
, "G-lined", 7) == 0)
131 ww
->type
= WHOWAS_KILL
;
133 ww
->type
= WHOWAS_QUIT
;
136 ww
->reason
= getsstring(reason
, WW_REASONLEN
);
139 static void whowas_handlerename(int hooknum
, void *arg
) {
142 char *oldnick
= args
[1];
146 ww
= whowas_fromnick(np
, 0);
147 ww
->type
= WHOWAS_RENAME
;
149 ww
->newnick
= getsstring(wnp
->nick
, NICKLEN
);
150 strncpy(wnp
->nick
, oldnick
, NICKLEN
+ 1);
153 whowas
*whowas_chase(const char *target
, int maxage
) {
161 for (i
= whowasoffset
+ whowasmax
- 1; i
>= whowasoffset
; i
--) {
162 ww
= &whowasrecs
[i
% whowasmax
];
164 if (ww
->type
== WHOWAS_UNUSED
)
169 if (ww
->timestamp
< now
- maxage
)
170 break; /* records are in timestamp order, we're done */
172 if (ircd_strcmp(wnp
->nick
, target
) == 0)
179 const char *whowas_format(whowas
*ww
) {
180 nick
*np
= &ww
->nick
;
181 static char buf
[512];
185 snprintf(hostmask
, sizeof(hostmask
), "%s!%s@%s%s%s [%s] (%s)",
186 np
->nick
, np
->ident
, np
->host
->name
->content
,
187 np
->auth
? "/" : "", np
->auth
? np
->authname
: "",
188 IPtostr(np
->ipaddress
),
189 printflags(np
->umodes
, umodeflags
));
190 strftime(timebuf
, sizeof(timebuf
), "%d/%m/%y %H:%M:%S", localtime(&(ww
->timestamp
)));
192 if (ww
->type
== WHOWAS_RENAME
)
193 snprintf(buf
, sizeof(buf
), "[%s] NICK %s r(%s) -> %s", timebuf
, hostmask
, np
->realname
->name
->content
, ww
->newnick
->content
);
195 snprintf(buf
, sizeof(buf
), "[%s] %s %s r(%s): %s", timebuf
, (ww
->type
== WHOWAS_QUIT
) ? "QUIT" : "KILL", hostmask
, np
->realname
->name
->content
, ww
->reason
->content
);
200 const char *whowas_formatchannels(whowas
*ww
) {
201 static char buf
[512];
204 strcpy(buf
, "Channels: ");
206 for (i
= 0; i
< WW_MAXCHANNELS
; i
++) {
207 if (!ww
->channels
[i
])
211 strncat(buf
, ", ", sizeof(buf
));
215 strncat(buf
, ww
->channels
[i
]->name
->content
, sizeof(buf
));
218 if (!ww
->channels
[0])
219 strncat(buf
, "(No channels.)", sizeof(buf
));
221 buf
[sizeof(buf
) - 1] = '\0';
226 unsigned int nextwhowasmarker() {
229 static unsigned int whowasmarker
=0;
234 /* If we wrapped to zero, zap the marker on all records */
235 for (i
= 0; i
< whowasmax
; i
++) {
236 ww
= &whowasrecs
[i
% whowasmax
];
248 sstring
*temp
= getcopyconfigitem("whowas", "maxentries", XStringify(WW_DEFAULT_MAXENTRIES
), 10);
249 whowasmax
= atoi(temp
->content
);
252 whowasrecs
= calloc(whowasmax
, sizeof(whowas
));
254 registerhook(HOOK_NICK_QUIT
, whowas_handlequitorkill
);
255 registerhook(HOOK_NICK_KILL
, whowas_handlequitorkill
);
256 registerhook(HOOK_NICK_RENAME
, whowas_handlerename
);
263 deregisterhook(HOOK_NICK_QUIT
, whowas_handlequitorkill
);
264 deregisterhook(HOOK_NICK_KILL
, whowas_handlequitorkill
);
265 deregisterhook(HOOK_NICK_RENAME
, whowas_handlerename
);
267 for (i
= 0; i
< whowasmax
; i
++) {