]> jfr.im git - irc/quakenet/newserv.git/blame - whowas/whowas.c
whowas: Use a ring buffer for the whowas records.
[irc/quakenet/newserv.git] / whowas / whowas.c
CommitLineData
fa6819a7 1#include <string.h>
0eb4cbd3 2#include <stdio.h>
fa6819a7
GB
3#include "../core/hooks.h"
4#include "../control/control.h"
5#include "../irc/irc.h"
6#include "../lib/irc_string.h"
363e3ed0 7#include "../lib/version.h"
fa6819a7
GB
8#include "whowas.h"
9
363e3ed0 10MODULE_VERSION("");
fa6819a7 11
0495c1d1
GB
12whowas whowasrecs[WW_MAXENTRIES];
13int whowasoffset = 0;
d6385de2 14
0495c1d1 15whowas *whowas_fromnick(nick *np, int standalone) {
fa6819a7 16 whowas *ww;
0eb4cbd3
GB
17 nick *wnp;
18 struct irc_in_addr ipaddress_canonical;
fa6819a7
GB
19
20 /* Create a new record. */
0495c1d1
GB
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
4030a47e 29 memset(ww, 0, sizeof(whowas));
0eb4cbd3 30
0495c1d1 31 wnp = &ww->nick;
0eb4cbd3
GB
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);
81e02f8e
GB
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;
0eb4cbd3
GB
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);
b965fa47 53 wnp->authname = wnp->auth->name;
0eb4cbd3 54 }
0eb4cbd3
GB
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
0eb4cbd3 66 ww->timestamp = getnettime();
fa6819a7 67
4030a47e
GB
68 return ww;
69}
d6385de2 70
0495c1d1 71void whowas_clean(whowas *ww) {
0eb4cbd3
GB
72 nick *np;
73
0495c1d1 74 if (!ww || ww->type == WHOWAS_UNUSED)
accce086
GB
75 return;
76
0495c1d1 77 np = &ww->nick;
0eb4cbd3
GB
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);
0495c1d1 87
accce086 88 freesstring(ww->reason);
0495c1d1 89 ww->type = WHOWAS_UNUSED;
accce086
GB
90}
91
0495c1d1
GB
92void whowas_free(whowas *ww) {
93 whowas_clean(ww);
94 free(ww);
fa6819a7 95}
4030a47e
GB
96
97static 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
4030a47e 105 /* Create a new record. */
0495c1d1 106 ww = whowas_fromnick(np, 0);
4030a47e
GB
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;
98005421
GB
115 } else {
116 if (strncmp(reason, "G-lined", 7) == 0)
117 ww->type = WHOWAS_KILL;
118 else
119 ww->type = WHOWAS_QUIT;
120 }
4030a47e
GB
121
122 ww->reason = getsstring(reason, WW_REASONLEN);
4030a47e
GB
123}
124
125static void whowas_handlerename(int hooknum, void *arg) {
126 void **args = arg;
127 nick *np = args[0];
128 char *oldnick = args[1];
129 whowas *ww;
0eb4cbd3 130 nick *wnp;
4030a47e 131
0495c1d1 132 ww = whowas_fromnick(np, 0);
4030a47e 133 ww->type = WHOWAS_RENAME;
0495c1d1 134 wnp = &ww->nick;
0eb4cbd3
GB
135 ww->newnick = getsstring(wnp->nick, NICKLEN);
136 strncpy(wnp->nick, oldnick, NICKLEN + 1);
4030a47e
GB
137}
138
0495c1d1 139whowas *whowas_chase(const char *target, int maxage) {
56cab147 140 whowas *ww;
0495c1d1 141 nick *wnp;
56cab147 142 time_t now;
0495c1d1 143 int i;
56cab147
GB
144
145 now = getnettime();
146
0495c1d1
GB
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
0eb4cbd3 155 if (ww->timestamp < now - maxage)
56cab147
GB
156 break; /* records are in timestamp order, we're done */
157
0495c1d1 158 if (ircd_strcmp(wnp->nick, target) == 0)
56cab147
GB
159 return ww;
160 }
161
162 return NULL;
163}
164
0eb4cbd3 165const char *whowas_format(whowas *ww) {
0495c1d1 166 nick *np = &ww->nick;
0eb4cbd3 167 static char buf[512];
accce086 168 char timebuf[30];
0eb4cbd3 169 char hostmask[512];
accce086 170
432206be 171 snprintf(hostmask, sizeof(hostmask), "%s!%s@%s%s%s [%s] (%s)",
0eb4cbd3
GB
172 np->nick, np->ident, np->host->name->content,
173 np->auth ? "/" : "", np->auth ? np->authname : "",
432206be
GB
174 IPtostr(np->p_ipaddr),
175 printflags(np->umodes, umodeflags));
0eb4cbd3 176 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&(ww->timestamp)));
accce086
GB
177
178 if (ww->type == WHOWAS_RENAME)
0eb4cbd3 179 snprintf(buf, sizeof(buf), "[%s] NICK %s r(%s) -> %s", timebuf, hostmask, np->realname->name->content, ww->newnick->content);
accce086 180 else
0eb4cbd3
GB
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
186unsigned int nextwhowasmarker() {
187 whowas *ww;
0495c1d1 188 int i;
0eb4cbd3
GB
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 */
0495c1d1
GB
195 for (i = 0; i < WW_MAXENTRIES; i++) {
196 ww = &whowasrecs[i % WW_MAXENTRIES];
197 ww->marker=0;
198 }
199
0eb4cbd3
GB
200 whowasmarker++;
201 }
202
203 return whowasmarker;
accce086
GB
204}
205
4030a47e
GB
206void _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
212void _fini(void) {
0495c1d1
GB
213 int i;
214 whowas *ww;
215
4030a47e
GB
216 deregisterhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
217 deregisterhook(HOOK_NICK_KILL, whowas_handlequitorkill);
218 deregisterhook(HOOK_NICK_RENAME, whowas_handlerename);
219
0495c1d1
GB
220 for (i = 0; i < WW_MAXENTRIES; i++) {
221 ww = &whowasrecs[i % WW_MAXENTRIES];
222 whowas_clean(ww);
223 }
4030a47e 224}