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