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