]> jfr.im git - irc/quakenet/newserv.git/blob - whowas/whowas.c
Merge pull request #1 from meeb/meeb
[irc/quakenet/newserv.git] / whowas / whowas.c
1 #include <string.h>
2 #include <stdio.h>
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"
9 #include "whowas.h"
10
11 MODULE_VERSION("");
12
13 whowas *whowasrecs;
14 int whowasoffset = 0;
15 int whowasmax;
16
17 whowas *whowas_fromnick(nick *np, int standalone) {
18 whowas *ww;
19 nick *wnp;
20 struct irc_in_addr ipaddress_canonical;
21 void *args[2];
22
23 /* Create a new record. */
24 if (standalone)
25 ww = malloc(sizeof(whowas));
26 else {
27 ww = &whowasrecs[whowasoffset];
28 whowas_clean(ww);
29 whowasoffset = (whowasoffset + 1) % whowasmax;
30 }
31
32 memset(ww, 0, sizeof(whowas));
33
34 wnp = &ww->nick;
35 memset(wnp, 0, sizeof(nick));
36 strncpy(wnp->nick, np->nick, NICKLEN + 1);
37 wnp->numeric = np->numeric;
38 strncpy(wnp->ident, np->ident, USERLEN + 1);
39
40 wnp->host = newhost();
41 memset(wnp->host, 0, sizeof(host));
42 wnp->host->name = getsstring(np->host->name->content, HOSTLEN);
43
44 wnp->realname = newrealname();
45 memset(wnp->realname, 0, sizeof(realname));
46 wnp->realname->name = getsstring(np->realname->name->content, REALLEN);
47 wnp->shident = np->shident ? getsstring(np->shident->content, 512) : NULL;
48 wnp->sethost = np->sethost ? getsstring(np->sethost->content, 512) : NULL;
49 wnp->opername = np->opername ? getsstring(np->opername->content, 512) : NULL;
50 wnp->umodes = np->umodes;
51 if (np->auth) {
52 wnp->auth = newauthname();
53 memset(wnp->auth, 0, sizeof(authname));
54 wnp->auth->userid = np->auth->userid;
55 strncpy(wnp->auth->name, np->auth->name, ACCOUNTLEN + 1);
56 wnp->authname = wnp->auth->name;
57 }
58 wnp->timestamp = np->timestamp;
59 wnp->accountts = np->accountts;
60 wnp->away = np->away ? getsstring(np->away->content, 512) : NULL;
61
62 memcpy(&wnp->ipaddress, &np->ipaddress, sizeof(struct irc_in_addr));
63
64 ip_canonicalize_tunnel(&ipaddress_canonical, &np->ipaddress);
65 wnp->ipnode = refnode(iptree, &ipaddress_canonical, PATRICIA_MAXBITS);
66
67 wnp->next = (nick *)ww; /* Yuck. */
68
69 ww->timestamp = getnettime();
70 ww->type = WHOWAS_USED;
71
72 args[0] = ww;
73 args[1] = np;
74 triggerhook(HOOK_WHOWAS_NEWRECORD, args);
75
76 return ww;
77 }
78
79 void whowas_clean(whowas *ww) {
80 nick *np;
81
82 if (!ww || ww->type == WHOWAS_UNUSED)
83 return;
84
85 triggerhook(HOOK_WHOWAS_LOSTRECORD, ww);
86
87 np = &ww->nick;
88 freesstring(np->host->name);
89 freehost(np->host);
90 freesstring(np->realname->name);
91 freerealname(np->realname);
92 freesstring(np->shident);
93 freesstring(np->sethost);
94 freesstring(np->opername);
95 freeauthname(np->auth);
96 freesstring(np->away);
97 derefnode(iptree, np->ipnode);
98 freesstring(ww->reason);
99 freesstring(ww->newnick);
100 ww->type = WHOWAS_UNUSED;
101 }
102
103 void whowas_free(whowas *ww) {
104 whowas_clean(ww);
105 free(ww);
106 }
107
108 static void whowas_handlequitorkill(int hooknum, void *arg) {
109 void **args = arg;
110 nick *np = args[0];
111 char *reason = args[1];
112 char *rreason;
113 char resbuf[512];
114 whowas *ww;
115
116 /* Create a new record. */
117 ww = whowas_fromnick(np, 0);
118
119 if (hooknum == HOOK_NICK_KILL) {
120 if ((rreason = strchr(reason, ' '))) {
121 sprintf(resbuf, "Killed%s", rreason);
122 reason = resbuf;
123 }
124
125 ww->type = WHOWAS_KILL;
126 } else {
127 if (strncmp(reason, "G-lined", 7) == 0)
128 ww->type = WHOWAS_KILL;
129 else
130 ww->type = WHOWAS_QUIT;
131 }
132
133 ww->reason = getsstring(reason, WW_REASONLEN);
134 }
135
136 static void whowas_handlerename(int hooknum, void *arg) {
137 void **args = arg;
138 nick *np = args[0];
139 char *oldnick = args[1];
140 whowas *ww;
141 nick *wnp;
142
143 ww = whowas_fromnick(np, 0);
144 ww->type = WHOWAS_RENAME;
145 wnp = &ww->nick;
146 ww->newnick = getsstring(wnp->nick, NICKLEN);
147 strncpy(wnp->nick, oldnick, NICKLEN + 1);
148 }
149
150 whowas *whowas_chase(const char *target, int maxage) {
151 whowas *ww;
152 nick *wnp;
153 time_t now;
154 int i;
155
156 now = getnettime();
157
158 for (i = whowasoffset + whowasmax - 1; i >= whowasoffset; i--) {
159 ww = &whowasrecs[i % whowasmax];
160
161 if (ww->type == WHOWAS_UNUSED)
162 continue;
163
164 wnp = &ww->nick;
165
166 if (ww->timestamp < now - maxage)
167 break; /* records are in timestamp order, we're done */
168
169 if (ircd_strcmp(wnp->nick, target) == 0)
170 return ww;
171 }
172
173 return NULL;
174 }
175
176 const char *whowas_format(whowas *ww) {
177 nick *np = &ww->nick;
178 static char buf[512];
179 char timebuf[30];
180 char hostmask[512];
181
182 snprintf(hostmask, sizeof(hostmask), "%s!%s@%s%s%s [%s] (%s)",
183 np->nick, np->ident, np->host->name->content,
184 np->auth ? "/" : "", np->auth ? np->authname : "",
185 IPtostr(np->ipaddress),
186 printflags(np->umodes, umodeflags));
187 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&(ww->timestamp)));
188
189 if (ww->type == WHOWAS_RENAME)
190 snprintf(buf, sizeof(buf), "[%s] NICK %s r(%s) -> %s", timebuf, hostmask, np->realname->name->content, ww->newnick->content);
191 else
192 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);
193
194 return buf;
195 }
196
197 const char *whowas_formatchannels(whowas *ww) {
198 static char buf[512];
199 int i, first = 1;
200
201 strcpy(buf, "Channels: ");
202
203 for (i = 0; i < WW_MAXCHANNELS; i++) {
204 if (!ww->channels[i])
205 break;
206
207 if (!first)
208 strncat(buf, ", ", sizeof(buf));
209 else
210 first = 0;
211
212 strncat(buf, ww->channels[i]->name->content, sizeof(buf));
213 }
214
215 if (!ww->channels[0])
216 strncat(buf, "(No channels.)", sizeof(buf));
217
218 buf[sizeof(buf) - 1] = '\0';
219
220 return buf;
221 }
222
223 unsigned int nextwhowasmarker() {
224 whowas *ww;
225 int i;
226 static unsigned int whowasmarker=0;
227
228 whowasmarker++;
229
230 if (!whowasmarker) {
231 /* If we wrapped to zero, zap the marker on all records */
232 for (i = 0; i < whowasmax; i++) {
233 ww = &whowasrecs[i % whowasmax];
234 ww->marker=0;
235 }
236
237 whowasmarker++;
238 }
239
240 return whowasmarker;
241 }
242
243 void _init(void) {
244 {
245 sstring *temp = getcopyconfigitem("whowas", "maxentries", XStringify(WW_DEFAULT_MAXENTRIES), 10);
246 whowasmax = atoi(temp->content);
247 freesstring(temp);
248 }
249 whowasrecs = calloc(whowasmax, sizeof(whowas));
250
251 registerhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
252 registerhook(HOOK_NICK_KILL, whowas_handlequitorkill);
253 registerhook(HOOK_NICK_RENAME, whowas_handlerename);
254 }
255
256 void _fini(void) {
257 int i;
258 whowas *ww;
259
260 deregisterhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
261 deregisterhook(HOOK_NICK_KILL, whowas_handlequitorkill);
262 deregisterhook(HOOK_NICK_RENAME, whowas_handlerename);
263
264 for (i = 0; i < whowasmax; i++) {
265 ww = &whowasrecs[i];
266 whowas_clean(ww);
267 }
268
269 free(whowasrecs);
270 }