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