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