1 /*
2 * Copyright (C) 2000,2001 Florian Sander
3 *
4 * $Id: do_seen.c (1.1.0) for AversE-XP v1.0+ 2003/12/06 [Xp-AvR] Exp $
5 */
6
7 /* Checks if someone matches the mask, and returns the reply
8 * mask : first paramater (e.g. "G`Quann", "G`Quann", "*!*@*.isp.de", ...)
9 * nick : nick of the one, who triggered the command
10 * uhost: user@host of nick
11 * chan : chan, where the command was triggered
12 * bns :
13 * 1 : do a botnet-seen if no matches are found
14 * 0 : don't do a botnet-seen
15 * -1 : return NULL instead of text, if no matches were found
16 * (necessary for botnet seen) */
do_seen(char * mask,char * nick,char * uhost,char * chan,int bns)17 static char *do_seen(char *mask, char *nick, char *uhost, char *chan, int bns)
18 {
19 char hostbuf[UHOSTLEN + 1], *host, *newhost, *tmp, *dur;
20 seendat *l;
21 gseenres *r;
22 int wild, nr;
23 char bnquery[256];
24 struct userrec *u;
25 struct laston_info *li;
26 struct chanset_t *ch;
27
28 Context;
29 start_seentime_calc();
30 if (seen_reply) {
31 nfree(seen_reply);
32 seen_reply = NULL;
33 }
34 l = NULL;
35 host = hostbuf;
36 newhost = NULL;
37 mask = newsplit(&mask);
38 glob_query = mask;
39 while (mask[0] == ' ')
40 mask++;
41 if (!mask[0]) {
42 return SLNOPARAM;
43 }
44 if (strchr(mask, '?') || strchr(mask, '*')) {
45 if (!wildcard_search) {
46 if (bns == -1)
47 return NULL;
48 else
49 return SLNOWILDCARDS;
50 } else
51 wild = 1;
52 } else {
53 if (strlen(mask) > nick_len)
54 return SLTOOLONGNICK;
55 if (!strcasecmp(mask, nick)) {
56 return SLMIRROR;
57 }
58 if (onchan(mask, chan))
59 return SLONCHAN;
60 if ((glob_othernick = handonchan(mask, chan)))
61 return SLHANDONCHAN;
62 if ((ch = onanychan(mask))) {
63 if (!secretchan(ch->dname)) {
64 glob_otherchan = ch->dname;
65 return SLONOTHERCHAN;
66 }
67 }
68 if ((ch = handonanychan(mask))) {
69 if (!secretchan(ch->dname)) {
70 glob_otherchan = ch->dname;
71 return SLONOTHERCHAN;
72 }
73 }
74 add_seenreq(mask, nick, uhost, chan, now);
75 wild = 0;
76 l = findseen(mask);
77 if (l && !fuzzy_search) {
78 tmp = do_seennick(l);
79 end_seentime_calc();
80 return tmp;
81 }
82 if (!l) {
83 u = get_user_by_handle(userlist, mask);
84 if (u) {
85 li = get_user(&USERENTRY_LASTON, u);
86 }
87 if (!u || !li) {
88 if (bns == -1) {
89 end_seentime_calc();
90 return NULL;
91 }
92 tmp = SLNOTSEEN;
93 if (bns && ((strlen(mask) + strlen(nick) + strlen(uhost)
94 + strlen(chan) + 20) < 255)) {
95 debug0("trying botnet seen");
96 if (bnsnick)
97 nfree(bnsnick);
98 if (bnschan)
99 nfree(bnschan);
100 bnsnick = nmalloc(strlen(nick) + 1);
101 strcpy(bnsnick, nick);
102 bnschan = nmalloc(strlen(chan) + 1);
103 strcpy(bnschan, chan);
104 sprintf(bnquery, "gseen_req %s %s %s %s", mask, nick, uhost, chan);
105 botnet_send_zapf_broad(-1, botnetnick, NULL, bnquery);
106 }
107 } else {
108 dur = gseen_duration(now - li->laston);
109 glob_laston = dur;
110 tmp = SLPOORSEEN;
111 seen_reply = nmalloc(strlen(tmp) + 1);
112 strcpy(seen_reply, tmp);
113 end_seentime_calc();
114 return seen_reply;
115 }
116 end_seentime_calc();
117 return tmp;
118 }
119 if (strlen(l->host) < UHOSTLEN) {
120 maskstricthost(l->host, host);
121 host = strchr(host, '!') + 1;
122 } else {
123 end_seentime_calc();
124 return "error, too long host";
125 }
126 }
127 if (l && (l->type == SEEN_CHPT)) {
128 tmp = do_seennick(l);
129 end_seentime_calc();
130 return tmp;
131 }
132 numresults = 0;
133 temp_wildmatch_host = my_malloc(1);
134 wildmatch_seens(host, mask, wild);
135 my_free(temp_wildmatch_host);
136 temp_wildmatch_host = NULL;
137 if (!results) {
138 end_seentime_calc();
139 if (bns == -1)
140 return NULL;
141 return SLNOMATCH;
142 }
143 if (numresults >= max_matches) {
144 end_seentime_calc();
145 free_seenresults();
146 return SLTOOMANYMATCHES;
147 }
148 sortresults();
149 if (strcasecmp(results->seen->nick, mask)) {
150 if (numresults == 1)
151 tmp = SLONEMATCH;
152 else if (numresults <= 5)
153 tmp = SLLITTLEMATCHES;
154 else
155 tmp = SLMANYMATCHES;
156 seen_reply = nmalloc(strlen(tmp) + 1);
157 strcpy(seen_reply, tmp);
158 nr = 0;
159 for (r = results; (r && (nr < 5)); r = r->next) {
160 nr++;
161 if (nr > 1) {
162 seen_reply = nrealloc(seen_reply, 1 + strlen(seen_reply) + 1 + strlen(r->seen->nick) + 1);
163 strcat(seen_reply, ", ");
164 } else {
165 seen_reply = nrealloc(seen_reply, 1 + strlen(seen_reply) + strlen(r->seen->nick) + 1);
166 strcat(seen_reply, " ");
167 }
168 strcat(seen_reply, r->seen->nick);
169 }
170 tmp = do_seennick(results->seen);
171 seen_reply = nrealloc(seen_reply, 2 + strlen(seen_reply) + strlen(tmp) + 1);
172 sprintf(seen_reply, "%s. %s", seen_reply, tmp);
173 } else {
174 tmp = do_seennick(results->seen);
175 seen_reply = nmalloc(strlen(tmp) + 1);
176 strcpy(seen_reply, tmp);
177 }
178 free_seenresults();
179 end_seentime_calc();
180 return seen_reply;
181 }
182
183 /* takes a seen-dataset and produces the corresponding reply basically
184 * by referencing to the lang entry with the same number as the seen-type. */
do_seennick(seendat * l)185 static char *do_seennick(seendat *l)
186 {
187 int stype;
188
189 Context;
190 if (!l) {
191 debug0("ERROR! Tryed to do a seennick on a NULL pointer!");
192 return "ERROR! seendat == NULL!!!";
193 }
194 glob_seendat = l;
195 stype = l->type + 100;
196 switch (l->type) {
197 case SEEN_JOIN:
198 if (!onchan(l->nick, l->chan))
199 stype += 20;
200 break;
201 case SEEN_PART:
202 break;
203 case SEEN_SIGN:
204 break;
205 case SEEN_NICK:
206 if (!onchan(l->msg, l->chan))
207 stype += 20;
208 break;
209 case SEEN_NCKF:
210 if (!onchan(l->nick, l->chan))
211 stype += 20;
212 break;
213 case SEEN_KICK:
214 break;
215 case SEEN_SPLT:
216 break;
217 case SEEN_REJN:
218 if (!onchan(l->nick, l->chan))
219 stype += 20;
220 break;
221 case SEEN_CHJN:
222 case SEEN_CHPT:
223 if (!strcmp(l->chan, "0"))
224 stype += 20;
225 break;
226 default:
227 stype = 140;
228 }
229 return getslang(stype);
230 }
231
232 /* interface for webseen.mod
233 * find all results for a query and return a pointer to this list
234 * (basically the core of do_seen()) */
findseens(char * mask,int * ret,int fuzzy)235 static gseenres *findseens(char *mask, int *ret, int fuzzy)
236 {
237 char hostbuf[UHOSTLEN + 1], *host, *newhost;
238 seendat *l;
239 int wild;
240
241 Context;
242 start_seentime_calc();
243 *ret = WS_OK;
244 l = NULL;
245 host = hostbuf;
246 newhost = NULL;
247 mask = newsplit(&mask);
248 while (mask[0] == ' ')
249 mask++;
250 if (!mask[0]) {
251 *ret = WS_NOPARAM;
252 return NULL;
253 }
254 if (strchr(mask, '?') || strchr(mask, '*')) {
255 if (!wildcard_search) {
256 *ret = WS_NOWILDCARDS;
257 return NULL;
258 }
259 wild = 1;
260 } else {
261 if (strlen(mask) > nick_len) {
262 *ret = WS_TOOLONGNICK;
263 return NULL;
264 }
265 add_seenreq(mask, "www-user", "unknown_host", "webinterface", now);
266 wild = 0;
267 l = findseen(mask);
268 if (l && (!fuzzy_search || !fuzzy)) {
269 numresults = 1;
270 add_seenresult(l);
271 end_seentime_calc();
272 return results;
273 }
274 if (!l) {
275 *ret = WS_NORESULT;
276 end_seentime_calc();
277 return NULL;
278 }
279 if (strlen(l->host) < UHOSTLEN) {
280 maskstricthost(l->host, host);
281 host = strchr(host, '!') + 1;
282 } else {
283 *ret = WS_TOOLONGHOST;
284 end_seentime_calc();
285 return NULL;
286 }
287 }
288 if (l && (l->type == SEEN_CHPT)) {
289 numresults = 1;
290 add_seenresult(l);
291 end_seentime_calc();
292 return results;
293 }
294 numresults = 0;
295 temp_wildmatch_host = my_malloc(1);
296 wildmatch_seens(host, mask, wild);
297 my_free(temp_wildmatch_host);
298 temp_wildmatch_host = NULL;
299 if (!results) {
300 *ret = WS_NORESULT;
301 end_seentime_calc();
302 return NULL;
303 }
304 if (numresults >= max_matches) {
305 free_seenresults();
306 *ret = WS_TOOMANYMATCHES;
307 end_seentime_calc();
308 return NULL;
309 }
310 sortresults();
311 *ret = 0;
312 end_seentime_calc();
313 return results;
314 }
315
316 char seenstats_reply[512];
do_seenstats()317 static char *do_seenstats()
318 {
319 glob_totalnicks = count_seens();
320 glob_totalbytes = gseen_expmem();
321 sprintf(seenstats_reply, "%s", SLSEENSTATS);
322 return seenstats_reply;
323 }
324
325 /* add an seen result (to the top of the list) */
add_seenresult(seendat * seen)326 static void add_seenresult(seendat *seen)
327 {
328 gseenres *nl;
329
330 numresults++;
331 if (numresults > max_matches)
332 return;
333 nl = nmalloc(sizeof(gseenres));
334 nl->seen = seen;
335 nl->next = results;
336 results = nl;
337 }
338
expmem_seenresults()339 static int expmem_seenresults()
340 {
341 int bytes = 0;
342 gseenres *l;
343
344 for (l = results; l; l = l->next)
345 bytes += sizeof(gseenres);
346 return bytes;
347 }
348
free_seenresults()349 static void free_seenresults()
350 {
351 gseenres *l, *ll;
352
353 l = results;
354 while (l) {
355 ll = l->next;
356 nfree(l);
357 l = ll;
358 }
359 results = NULL;
360 }
361
sortresults()362 static void sortresults()
363 {
364 int again = 1;
365 gseenres *last, *p, *c, *n;
366 int a, b;
367
368 Context;
369 again = 1;
370 last = NULL;
371 while ((results != last) && (again)) {
372 p = NULL;
373 c = results;
374 n = c->next;
375 again = 0;
376 while (n != last) {
377 if (!c || !n)
378 a = b = 0;
379 else
380 a = c->seen->when;
381 b = n->seen->when;
382 if (a < b) {
383 again = 1;
384 c->next = n->next;
385 n->next = c;
386 if (p == NULL)
387 results = n;
388 else
389 p->next = n;
390 }
391 p = c;
392 c = n;
393 n = n->next;
394 }
395 last = c;
396 }
397 Context;
398 return;
399 }
400
sortrequests(seenreq * l)401 static void sortrequests(seenreq *l)
402 {
403 int again = 1;
404 seenreq_by *last, *p, *c, *n;
405 int a, b;
406
407 Context;
408 again = 1;
409 last = NULL;
410 while ((l->by != last) && (again)) {
411 p = NULL;
412 c = l->by;
413 n = c->next;
414 again = 0;
415 while (n != last) {
416 if (!c || !n)
417 a = b = 0;
418 else
419 a = c->when;
420 b = n->when;
421 if (a < b) {
422 again = 1;
423 c->next = n->next;
424 n->next = c;
425 if (p == NULL)
426 l->by = n;
427 else
428 p->next = n;
429 }
430 p = c;
431 c = n;
432 n = n->next;
433 }
434 last = c;
435 }
436 Context;
437 return;
438 }
439
440 /* stolen from tcl_duration in tclmisc.c */
441 char gs_duration_temp[256];
gseen_duration(int seconds)442 static char *gseen_duration(int seconds)
443 {
444 char s[256];
445 time_t sec;
446
447 sec = seconds;
448 s[0] = 0;
449 if (sec < 1) {
450 snprintf(gs_duration_temp, sizeof(gs_duration_temp), "%s", SLSOMETIME);
451 return gs_duration_temp;
452 }
453 if (sec < 60) {
454 sprintf(gs_duration_temp, "%d %s", (int) (sec / 1),
455 ((int) (sec / 1) > 1) ? SLSECONDS : SLSECOND);
456 return gs_duration_temp;
457 }
458 if (sec >= 31536000) {
459 sprintf(s, "%d %s ", (int) (sec / 31536000),
460 ((int) (sec / 31536000) > 1) ? SLYEARS : SLYEAR);
461 sec -= (((int) (sec / 31536000)) * 31536000);
462 }
463 if (sec >= 604800) {
464 sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 604800),
465 ((int) (sec / 604800) > 1) ? SLWEEKS : SLWEEK);
466 sec -= (((int) (sec / 604800)) * 604800);
467 }
468 if (sec >= 86400) {
469 sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 86400),
470 ((int) (sec / 86400) > 1) ? SLDAYS : SLDAY);
471 sec -= (((int) (sec / 86400)) * 86400);
472 }
473 if (sec >= 3600) {
474 sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 3600),
475 ((int) (sec / 3600) > 1) ? SLHOURS : SLHOUR);
476 sec -= (((int) (sec / 3600)) * 3600);
477 }
478 if (sec >= 60) {
479 sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 60),
480 ((int) (sec / 60) > 1) ? SLMINUTES : SLMINUTE);
481 sec -= (((int) (sec / 60)) * 60);
482 }
483 strcpy(gs_duration_temp, s);
484 if (gs_duration_temp[strlen(gs_duration_temp) - 1] == ' ')
485 gs_duration_temp[strlen(gs_duration_temp) - 1] = 0;
486 return gs_duration_temp;
487 }
488
onchan(char * nick,char * chan)489 static int onchan(char *nick, char *chan)
490 {
491 struct chanset_t *ch;
492 memberlist *m;
493
494 ch = findchan_by_dname(chan);
495 if (!ch)
496 return 0;
497 m = ismember(ch, nick);
498 if (!m)
499 return 0;
500 else if (chan_issplit(m))
501 return 0;
502 else
503 return 1;
504 }
505
506 /* checks if the given user is on the channel and returns its nick */
handonchan(char * hand,char * chan)507 static char *handonchan(char *hand, char *chan)
508 {
509 struct chanset_t *ch;
510 memberlist *m;
511
512 ch = findchan_by_dname(chan);
513 if (!ch)
514 return 0;
515 if (ch->channel.members > 0) {
516 for (m = ch->channel.member; m; m = m->next) {
517 if (m->user) {
518 if (m->user->handle && !rfc_casecmp(m->user->handle, hand))
519 return m->nick;
520 }
521 }
522 }
523 return NULL;
524 }
525
526 /* checks if the given nickname is on any of the bot's chans. */
onanychan(char * nick)527 static struct chanset_t *onanychan(char *nick)
528 {
529 struct chanset_t *ch;
530 memberlist *m;
531
532 for (ch = chanset; ch; ch = ch->next) {
533 m = ismember(ch, nick);
534 if (m && !chan_issplit(m))
535 return ch;
536 }
537 return NULL;
538 }
539
540 /* checks if the given user is on any channel (no matter under which nick) */
handonanychan(char * hand)541 static struct chanset_t *handonanychan(char *hand)
542 {
543 struct chanset_t *ch;
544 memberlist *m;
545
546 for (ch = chanset; ch; ch = ch->next) {
547 if (ch->channel.members > 0) {
548 for (m = ch->channel.member; m; m = m->next) {
549 if (m->user) {
550 if (m->user->handle && !rfc_casecmp(m->user->handle, hand))
551 return ch;
552 }
553 }
554 }
555 }
556 return NULL;
557 }
558
add_seenreq(char * nick,char * from,char * host,char * chan,time_t when)559 static void add_seenreq(char *nick, char *from, char *host, char *chan,
560 time_t when)
561 {
562 seenreq *l, *nl;
563 seenreq_by *b, *nb;
564 char buf[10] = "[secret]";
565
566 Context;
567 if (!tell_seens)
568 return;
569 if (strcmp(chan, "[partyline]") && secretchan(chan))
570 chan = buf;
571 for (l = requests; l; l = l->next) {
572 if (!strcasecmp(nick, l->nick)) {
573 for (b = l->by; b; b = b->next) {
574 if (!strcasecmp(from, b->who)) {
575 nfree(b->chan);
576 b->chan = nmalloc(strlen(chan) + 1);
577 strcpy(b->chan, chan);
578 b->when = when;
579 return;
580 }
581 }
582 b = l->by;
583 while (b && b->next)
584 b = b->next;
585 nb = nmalloc(sizeof(seenreq_by));
586 nb->who = nmalloc(strlen(from) + 1);
587 strcpy(nb->who, from);
588 nb->host = nmalloc(strlen(host) + 1);
589 strcpy(nb->host, host);
590 nb->chan = nmalloc(strlen(chan) + 1);
591 strcpy(nb->chan, chan);
592 nb->when = when;
593 nb->next = NULL;
594 if (l->by)
595 b->next = nb;
596 else
597 l->by = nb;
598 return;
599 }
600 }
601 nb = nmalloc(sizeof(seenreq_by));
602 nb->who = nmalloc(strlen(from) + 1);
603 strcpy(nb->who, from);
604 nb->host = nmalloc(strlen(host) + 1);
605 strcpy(nb->host, host);
606 nb->chan = nmalloc(strlen(chan) + 1);
607 strcpy(nb->chan, chan);
608 nb->when = when;
609 nb->next = NULL;
610 l = requests;
611 while (l && l->next)
612 l = l->next;
613 nl = nmalloc(sizeof(seenreq));
614 nl->nick = nmalloc(strlen(nick) + 1);
615 strcpy(nl->nick, nick);
616 nl->by = nb;
617 nl->next = NULL;
618 if (requests)
619 l->next = nl;
620 else
621 requests = nl;
622 }
623
expmem_seenreq()624 static int expmem_seenreq()
625 {
626 seenreq *l;
627 seenreq_by *b;
628 int size;
629
630 size = 0;
631 for (l = requests; l; l = l->next) {
632 size += sizeof(seenreq);
633 size += strlen(l->nick) + 1;
634 for (b = l->by; b; b = b->next) {
635 size += sizeof(seenreq_by);
636 size += strlen(b->who) + 1;
637 size += strlen(b->host) + 1;
638 size += strlen(b->chan) + 1;
639 }
640 }
641 return size;
642 }
643
count_seenreq(seenreq_by * b)644 static int count_seenreq(seenreq_by *b)
645 {
646 seenreq_by *l;
647 int nr;
648
649 nr = 0;
650 for (l = b; l; l = l->next)
651 nr++;
652 return nr;
653 }
654
free_seenreq()655 static void free_seenreq()
656 {
657 seenreq *l, *ll;
658 seenreq_by *b, *bb;
659
660 Context;
661 l = requests;
662 while (l) {
663 b = l->by;
664 while (b) {
665 bb = b->next;
666 nfree(b->who);
667 nfree(b->host);
668 nfree(b->chan);
669 nfree(b);
670 b = bb;
671 }
672 ll = l->next;
673 nfree(l->nick);
674 nfree(l);
675 l = ll;
676 }
677 requests = NULL;
678 }
679
report_seenreq(char * channel,char * nick)680 static void report_seenreq(char *channel, char *nick)
681 {
682 seenreq *l, *ll;
683 seenreq_by *b, *bb;
684 char *reply, *tmp;
685 int nr;
686
687 if (!tell_seens)
688 return;
689 ll = NULL;
690 l = requests;
691 reply = NULL;
692 while (l) {
693 if (!strcasecmp(l->nick, nick)) {
694 reset_global_vars();
695 glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, channel));
696 glob_nick = nick;
697 nr = count_seenreq(l->by);
698 if (nr == 1) {
699 glob_seenrequest = l;
700 dprintf(DP_HELP, "NOTICE %s :%s\n", l->nick, SLONELOOK);
701 } else {
702 sortrequests(l);
703 glob_seenrequest = l;
704 glob_seenrequests = nr;
705 tmp = SLMORELOOKS;
706 reply = nmalloc(strlen(tmp) + 1);
707 strcpy(reply, tmp);
708 nr = 0;
709 for (b = l->by; b; b = b->next) {
710 nr++;
711 reply = nrealloc(reply, strlen(reply) + ((nr == 1) ? 1 : 2) + strlen(b->who) + 1);
712 sprintf(reply, "%s%s%s", reply, (nr == 1) ? " " : ", ", b->who);
713 }
714 tmp = SLLASTLOOK;
715 reply = nrealloc(reply, strlen(reply) + 2 + strlen(tmp) + 1);
716 sprintf(reply, "%s. %s", reply, tmp);
717 dprintf(DP_HELP, "NOTICE %s :%s\n", l->nick, reply);
718 nfree(reply);
719 }
720 b = l->by;
721 while (b) {
722 bb = b->next;
723 nfree(b->who);
724 nfree(b->host);
725 nfree(b->chan);
726 nfree(b);
727 b = bb;
728 }
729 nfree(l->nick);
730 if (ll)
731 ll->next = l->next;
732 else
733 requests = l->next;
734 nfree(l);
735 if (ll)
736 l = ll->next;
737 else
738 l = requests;
739 } else {
740 ll = l;
741 l = l->next;
742 }
743 }
744 }
745
start_seentime_calc()746 static void start_seentime_calc()
747 {
748 struct timeval t;
749
750 gettimeofday(&t, NULL);
751 glob_presearch = (float) t.tv_sec + (((float) t.tv_usec) / 1000000);
752 }
753
end_seentime_calc()754 static void end_seentime_calc()
755 {
756 struct timeval t;
757
758 gettimeofday(&t, NULL);
759 glob_aftersearch = (float) t.tv_sec + (((float) t.tv_usec) / 1000000);
760 glob_total_searchtime += glob_aftersearch - glob_presearch;
761 glob_total_queries++;
762 }
763