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