]> jfr.im git - irc/quakenet/newserv.git/blob - whowas/whowas.c
whowas: Fix invalid free().
[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 *whowas_head = NULL, *whowas_tail = NULL;
13 int whowas_count = 0;
14
15 whowas *whowas_fromnick(nick *np) {
16 whowas *ww;
17 nick *wnp;
18 struct irc_in_addr ipaddress_canonical;
19
20 /* Create a new record. */
21 ww = malloc(sizeof(whowas));
22 memset(ww, 0, sizeof(whowas));
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);
37 wnp->shident = np->away ? getsstring(np->shident->content, 512) : NULL;
38 wnp->sethost = np->away ? getsstring(np->sethost->content, 512) : NULL;
39 wnp->opername = np->away ? getsstring(np->opername->content, 512) : NULL;
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();
62
63 return ww;
64 }
65
66 void whowas_linkrecord(whowas *ww) {
67 if (whowas_head)
68 whowas_head->prev = ww;
69
70 ww->next = whowas_head;
71 whowas_head = ww;
72
73 ww->prev = NULL;
74
75 if (!whowas_tail)
76 whowas_tail = ww;
77
78 whowas_count++;
79 }
80
81 void 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--;
91 }
92
93 void whowas_free(whowas *ww) {
94 nick *np;
95
96 if (!ww)
97 return;
98
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);
110 freenick(np);
111 freesstring(ww->reason);
112 free(ww);
113 }
114
115 static void whowas_cleanup(void) {
116 time_t now;
117 whowas *ww;
118
119 time(&now);
120
121 /* Clean up old records. */
122 while (whowas_tail && (whowas_tail->timestamp < now - WW_MAXAGE || whowas_count >= WW_MAXENTRIES)) {
123 ww = whowas_tail;
124 whowas_unlinkrecord(ww);
125 whowas_free(ww);
126 }
127 }
128
129 static 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
157 static void whowas_handlerename(int hooknum, void *arg) {
158 void **args = arg;
159 nick *np = args[0];
160 char *oldnick = args[1];
161 whowas *ww;
162 nick *wnp;
163
164 whowas_cleanup();
165
166 ww = whowas_fromnick(np);
167 ww->type = WHOWAS_RENAME;
168 wnp = ww->nick;
169 ww->newnick = getsstring(wnp->nick, NICKLEN);
170 strncpy(wnp->nick, oldnick, NICKLEN + 1);
171
172 whowas_linkrecord(ww);
173 }
174
175 whowas *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) {
182 if (ww->timestamp < now - maxage)
183 break; /* records are in timestamp order, we're done */
184
185 if (ircd_strcmp(ww->nick->nick, nick) == 0)
186 return ww;
187 }
188
189 return NULL;
190 }
191
192 const char *whowas_format(whowas *ww) {
193 nick *np = ww->nick;
194 static char buf[512];
195 char timebuf[30];
196 char hostmask[512];
197
198 snprintf(hostmask, sizeof(hostmask), "%s!%s@%s%s%s [%s]",
199 np->nick, np->ident, np->host->name->content,
200 np->auth ? "/" : "", np->auth ? np->authname : "",
201 IPtostr(np->p_ipaddr));
202 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&(ww->timestamp)));
203
204 if (ww->type == WHOWAS_RENAME)
205 snprintf(buf, sizeof(buf), "[%s] NICK %s r(%s) -> %s", timebuf, hostmask, np->realname->name->content, ww->newnick->content);
206 else
207 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);
208
209 return buf;
210 }
211
212 unsigned int nextwhowasmarker() {
213 whowas *ww;
214 static unsigned int whowasmarker=0;
215
216 whowasmarker++;
217
218 if (!whowasmarker) {
219 /* If we wrapped to zero, zap the marker on all records */
220 for (ww = whowas_head; ww; ww = ww->next)
221 ww->marker=0;
222 whowasmarker++;
223 }
224
225 return whowasmarker;
226 }
227
228 void _init(void) {
229 registerhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
230 registerhook(HOOK_NICK_KILL, whowas_handlequitorkill);
231 registerhook(HOOK_NICK_RENAME, whowas_handlerename);
232 }
233
234 void _fini(void) {
235 deregisterhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
236 deregisterhook(HOOK_NICK_KILL, whowas_handlequitorkill);
237 deregisterhook(HOOK_NICK_RENAME, whowas_handlerename);
238
239 while (whowas_head)
240 whowas_unlinkrecord(whowas_head);
241 }