summaryrefslogtreecommitdiffstats
path: root/extra/eggdrop/gseen.mod.patch
diff options
context:
space:
mode:
Diffstat (limited to 'extra/eggdrop/gseen.mod.patch')
-rw-r--r--extra/eggdrop/gseen.mod.patch5123
1 files changed, 0 insertions, 5123 deletions
diff --git a/extra/eggdrop/gseen.mod.patch b/extra/eggdrop/gseen.mod.patch
deleted file mode 100644
index e70aef887..000000000
--- a/extra/eggdrop/gseen.mod.patch
+++ /dev/null
@@ -1,5123 +0,0 @@
-diff -Nur src/mod/gseen.mod/Makefile src/mod/gseen.mod/Makefile
---- src/mod/gseen.mod/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/Makefile 2002-10-26 13:17:44.000000000 +0200
-@@ -0,0 +1,28 @@
-+# Makefile for src/mod/gseen.mod/
-+
-+doofus:
-+ @echo ""
-+ @echo "Let's try this from the right directory..."
-+ @echo ""
-+ @cd ../../../; make
-+
-+clean:
-+ @rm -f *.o *.$(MOD_EXT) *~
-+
-+static: ../gseen.o
-+
-+modules: ../../../gseen.$(MOD_EXT)
-+
-+../gseen.o: ../module.h ../modvals.h ../../eggdrop.h datahandling.c \
-+ gseen.c sensors.c gseencmds.c gseencmds.c do_seen.c ai.c tclcmds.c \
-+ misc.c seentree.c generic_binary_tree.c slang_gseen_commands.c \
-+ slang.c slang_text.c slang_ids.c slang_chanlang.c seenlang.h \
-+ slang_multitext.c gseen.h
-+ $(CC) $(CFLAGS) $(CPPFLAGS) -DMAKING_MODS -c gseen.c
-+ rm -f ../gseen.o
-+ mv gseen.o ../
-+
-+../../../gseen.$(MOD_EXT): ../gseen.o
-+ $(LD) -o ../../../gseen.$(MOD_EXT) ../gseen.o $(XLIBS)
-+
-+#safety hash
-diff -Nur src/mod/gseen.mod/README src/mod/gseen.mod/README
---- src/mod/gseen.mod/README 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/README 2002-10-26 13:17:45.000000000 +0200
-@@ -0,0 +1,140 @@
-+Description:
-+------------
-+
-+gseen.mod is a seen module for eggdrop that tracks not only the users in the
-+bot's userfile, but everyone who enters one of the bots channels.
-+It does pretty much the same as the popular script bseen and has a few
-+additional features like AI-seen and seen-notification.
-+It's also way faster than any corresponding script because scripts are always
-+much slower than modules. Especially scripts that deal with large amount of
-+data often become incredible slow.
-+
-+Installation:
-+-------------
-+
-+gseen.mod is written for eggdrop1.6, but it should also work with eggdrop 1.4.
-+
-+You need the eggdrop source to compile the module.
-+
-+The following instructions assume, ~/eggdrop1.6.2/ is the directory
-+where you installed your eggdrop from. (of course, other source dirs
-+will work as well)
-+
-+Put gseen.mod.1.1.0.tar.gz in ~/eggdrop1.6.2/src/mod/,
-+and unpack it (tar xfz gseen.mod.1.1.0.tar.gz). Change directory
-+back to ~/eggdrop1.6.2/.
-+
-+Now just do what you've done when you compiled your bot:
-+"./configure"
-+"make config" (you can skip this command on eggdrop 1.4)
-+"make"
-+"make install"
-+
-+Don't forget to copy the langfiles from eggdrop1.6.2/src/mod/gseen.mod/ to
-+eggdrop/language.
-+
-+All settings can be found in ~/eggdrop1.6.2/src/mod/gseen.mod/gseen.conf
-+Copy it to your eggdrop directory, edit it to fit your needs and put
-+"source gseen.conf" at the end of your eggdrop config file. The last thing
-+to do is to .rehash your bot.
-+
-+
-+Public commands:
-+----------------
-+
-+!seen <nick>
-+ I think this command doesn't need an explanation. ^_^
-+!seen <mask>
-+ Searches the database for entries that match <mask>
-+ for example "!seen *!user@dialin-*.isp.com"
-+!seennick <nick>
-+ !seen also checks if a user was online later with a
-+ different nick. !seennick only seens for <nick>
-+!seenstats
-+ just a little report on how many nicks are tracked
-+
-+All commands are also accessible via /msg.
-+("/msg <bot> seen <nick>", for example)
-+
-+
-+AI seen:
-+--------
-+
-+This module has a simple built in AI routine.
-+A short example:
-+
-+<G`Quann> Argo: have you seen Fabian recently?
-+<|Argo|> G`Quann, fabian (~fabian@dns.gifs.de) was last seen quitting
-+from #eggdev 1 week 4 days 9 hours 40 minutes 56 seconds ago
-+(20.02. 01:39) stating ".....zzzzZZZzzZZZzZZZZZZZZZZzzz..".
-+
-+Well, it's not a very intelligent AI, it's rather brute-force. So don't
-+forget to use the ai-seen-ignore setting.
-+I know that's not coded very elegant, but if you configure it correctly,
-+the failure-rate is way lower than with other AI scripts...
-+
-+DCC commands:
-+-------------
-+
-+.seen
-+.seennick
-+.seenstats
-+ just the same as the public versions
-+.purgeseens
-+ deletes expired data (this also happens automatically once a day)
-+ (m)
-+
-+Channel Settings:
-+-----------------
-+
-+ +noseendata
-+ don't log any seen data in this channel
-+ +quietseens
-+ send answers directly via notice to the person who asked and
-+ don't bother the rest of the channel with the reply
-+ +quietaiseens
-+ same as +quietseens, but for AI seens
-+ +nopubseens
-+ ignore every seen-command in this channel
-+
-+TCL commands:
-+-------------
-+
-+There are no special tcl commands, only the usual bind procs.
-+
-+The only one that should be mentioned is:
-+
-+*pubm:seen <nick> <uhost> <hand> <chan> <text>
-+ triggers the AI seen
-+ returns: 1 if a reply was sent, 0 otherwise
-+
-+So if you're using another AI script on your bot, you can modify it to
-+use this proc and avoid doubled replies this way.
-+
-+Other:
-+------
-+
-+There is absolutely NO WARRANTY on this module. I do my best to make it
-+work properly, but if anything gets screwed up, I'm not responsible. Use
-+this module at your own risk.
-+
-+Feedback:
-+---------
-+
-+Feel free to send feedback and bugreports (I hope there won't be any<g>) to
-+gseen.mod@visions-of-fantasy.de
-+
-+The newest gseen version can always be found at:
-+http://www.visions-of-fantasy.de/gseen.mod/
-+
-+Thanks to:
-+----------
-+
-+- Fabian for teaching me plenty of things
-+- everyone who tested the many buggy development versions :)
-+- the eggdev team for developing eggdrop
-+
-+Most of all, I would like to thank Bass for writing bseen.tcl because alot
-+of the ideas for this module came from using that tcl script. It's still the
-+most powerful seen script, so if you want something that's easier to use than
-+a module, get a copy of bseen.tcl.
-diff -Nur src/mod/gseen.mod/UPDATES src/mod/gseen.mod/UPDATES
---- src/mod/gseen.mod/UPDATES 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/UPDATES 2002-10-26 13:17:46.000000000 +0200
-@@ -0,0 +1,55 @@
-+Changes in gseen.mod: (since v1.0.0)
-+--------------------
-+
-+1.1.1
-+- fixed "no newline" compilation warnings that appeared on some systems.
-+- fixed uninitialized "li" variable in do_seen()
-+- fixed lacking compatibility to eggdrop1.4 (confirmation anyone?)
-+- new option: hide-secret-chans
-+
-+1.1.0 (15.6.2001)
-+- added multilang support
-+- removed static buffers
-+- organized data in a binary search tree (much faster)
-+- optimized a few other things
-+- added settings:
-+ - fuzzy-search
-+ - max-matches
-+ - wildcard-search
-+
-+1.0.8
-+- quiet-seens wasn't working for !seennick
-+- added quiet-ai-seens
-+- renamed nopub to nopubseens and nolog to noseendata and
-+ quietseen to quietseens
-+
-+1.0.7
-+- added compatibility to !channels
-+- fixed a bug relating strict-host 0 had some strange effects on
-+ !seen requests for users with ~ in their ident
-+
-+1.0.6
-+- fixed a very evil bug that allowed anyone to crash the bot, sorry
-+
-+1.0.5
-+- quietseens wasn't working correctly
-+- added support for egg1.5's udef chansets
-+
-+1.0.4
-+- added GPL stuff
-+- changed error msg that appears if no gseen file exists
-+
-+1.0.3
-+- readme updates
-+- fixed a grammatical error in do_seen
-+
-+1.0.2
-+- bot wanted to free a NULL pointer sometimes
-+
-+1.0.1
-+- !seen without parameter returned stupid results :)
-+- fixed little typo in .purgeseens
-+- "I found 1 matches..." -> "I found 1 match..."
-+
-+1.0.0
-+- release :)
-diff -Nur src/mod/gseen.mod/addons/gseen.selectlang.1.0.0.tcl src/mod/gseen.mod/addons/gseen.selectlang.1.0.0.tcl
---- src/mod/gseen.mod/addons/gseen.selectlang.1.0.0.tcl 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/addons/gseen.selectlang.1.0.0.tcl 2002-10-26 13:18:14.000000000 +0200
-@@ -0,0 +1,80 @@
-+#####################################################################
-+#
-+# gseen.selectlang v1.0.0
-+#
-+# This is a simple script which selects a language based on the
-+# user's host.
-+#
-+# It only works for /msg commands.
-+#
-+# If the user is in a channel which has a language defined, gseen's
-+# internal functions will override this selection and use the language
-+# of the channel instead.
-+#
-+#####################################################################
-+
-+
-+# Here you can define which language to use for which host.
-+# The first part is the mask for the host, and the second part
-+# is the language which should be used for this host.
-+
-+set tld-langs {
-+ {"*.de" "de"}
-+ {"*.at" "de"}
-+ {"*.ch" "de"}
-+ {"*.t-dialin.net" "de"}
-+ {"*.t-ipconnect.net" "de"}
-+ {"*.pl" "pl"}
-+ {"*.jp" "ja"}
-+}
-+
-+#################################################
-+
-+
-+proc selectlang:getlang {uhost} {
-+ global tld-langs
-+
-+ foreach tld ${tld-langs} {
-+ if {[string match [lindex $tld 0] $uhost]} {
-+ return [lindex $tld 1]
-+ }
-+ }
-+ return ""
-+}
-+
-+proc sl:rebind {oldtarget newtarget} {
-+ foreach binding [binds msg] {
-+ if {[lindex $binding 4] == $oldtarget} {
-+ unbind [lindex $binding 0] [lindex $binding 1] [lindex $binding 2] [lindex $binding 4]
-+ bind [lindex $binding 0] [lindex $binding 1] [lindex $binding 2] $newtarget
-+ }
-+ }
-+}
-+
-+proc sl:msg:trigger {nick uhost hand rest target} {
-+ global default-slang
-+
-+ set lang [selectlang:getlang $uhost]
-+ set old-slang ${default-slang}
-+ if {$lang != ""} {
-+ set default-slang $lang
-+ putlog "using '$lang'..."
-+ }
-+ $target $nick $uhost $hand $rest
-+ set default-slang ${old-slang}
-+}
-+
-+sl:rebind *msg:seen sl:msg:seen
-+proc sl:msg:seen {nick uhost hand rest} {
-+ sl:msg:trigger $nick $uhost $hand $rest *msg:seen
-+}
-+
-+sl:rebind *msg:seenstats sl:msg:seenstats
-+proc sl:msg:seenstats {nick uhost hand rest} {
-+ sl:msg:trigger $nick $uhost $hand $rest *msg:seenstats
-+}
-+
-+sl:rebind *msg:seennick sl:msg:seennick
-+proc sl:msg:seennick {nick uhost hand rest} {
-+ sl:msg:trigger $nick $uhost $hand $rest *msg:seennick
-+}
-\ No newline at end of file
-diff -Nur src/mod/gseen.mod/ai.c src/mod/gseen.mod/ai.c
---- src/mod/gseen.mod/ai.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/ai.c 2002-10-26 13:17:47.000000000 +0200
-@@ -0,0 +1,151 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+static int quietaiseens(char *chan)
-+{
-+ char buf[121], *b;
-+
-+ Context;
-+ strncpy(buf, quiet_ai_seen, 120);
-+ buf[120] = 0;
-+ b = buf;
-+ while (b[0])
-+ if (!strcasecmp(chan, newsplit(&b)))
-+ return 1;
-+#if EGG_IS_MIN_VER(10503)
-+ if (ngetudef("quietaiseens", chan))
-+ return 1;
-+#endif
-+ return 0;
-+}
-+
-+static int tcl_pubmseen STDVAR
-+{
-+ char *nick, *uhost, *hand, *chan, *text;
-+ char buf[1024];
-+ char *words, *word;
-+ seendat *l;
-+ int i;
-+
-+ Context;
-+ BADARGS(6, 6, " nick uhost hand chan text");
-+ nick = argv[1];
-+ uhost = argv[2];
-+ hand = argv[3];
-+ chan = argv[4];
-+ text = argv[5];
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, chan));
-+ glob_nick = nick;
-+ for (i = 0; i < strlen(text); i++)
-+ if (strchr("!?.,\"", text[i]))
-+ text[i] = ' ';
-+ strncpy(buf, ignore_words, 1023);
-+ buf[1023] = 0;
-+ words = buf;
-+ while (words[0])
-+ add_ignoredword(newsplit(&words));
-+ strncpy(buf, text, 1023);
-+ buf[1023] = 0;
-+ words = buf;
-+ while (words[0]) {
-+ word = newsplit(&words);
-+ if (word_is_ignored(word))
-+ continue;
-+ l = findseen(word);
-+ if (l) {
-+ if (quietaiseens(chan)) {
-+ set_prefix(SLNOTPREFIX);
-+ dprintf(DP_HELP, "NOTICE %s :%s%s\n", nick, reply_prefix,
-+ do_seen(word, nick, uhost, chan, 0));
-+ } else {
-+ set_prefix(SLPUBPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", chan, reply_prefix,
-+ do_seen(word, nick, uhost, chan, 0));
-+ }
-+ add_seenreq(word, nick, uhost, chan, now);
-+ free_ignoredwords();
-+ Tcl_AppendResult(irp, "1", NULL);
-+ return TCL_OK;
-+ }
-+ }
-+ free_ignoredwords();
-+ Tcl_AppendResult(irp, "0", NULL);
-+ return TCL_OK;
-+}
-+
-+static tcl_cmds mytcls[] =
-+{
-+ {"*pubm:seen", tcl_pubmseen},
-+ {"*chjn:gseen", gseen_chjn},
-+ {"*chpt:gseen", gseen_chpt},
-+ {0, 0}
-+};
-+
-+static void add_ignoredword(char *word)
-+{
-+ ignoredword *l, *nl;
-+
-+ l = ignoredwords;
-+ while (l && l->next)
-+ l = l->next;
-+ nl = nmalloc(sizeof(ignoredword));
-+ nl->word = nmalloc(strlen(word) + 1);
-+ strcpy(nl->word, word);
-+ nl->next = NULL;
-+ if (ignoredwords)
-+ l->next = nl;
-+ else
-+ ignoredwords = nl;
-+}
-+
-+static void free_ignoredwords()
-+{
-+ ignoredword *l, *ll;
-+
-+ l = ignoredwords;
-+ while (l) {
-+ ll = l->next;
-+ nfree(l->word);
-+ nfree(l);
-+ l = ll;
-+ }
-+ ignoredwords = NULL;
-+}
-+
-+static int expmem_ignoredwords()
-+{
-+ ignoredword *l;
-+ int size = 0;
-+
-+ for (l = ignoredwords; l; l = l->next) {
-+ size += sizeof(ignoredword);
-+ size += strlen(l->word) + 1;
-+ }
-+ return size;
-+}
-+
-+static int word_is_ignored(char *word)
-+{
-+ ignoredword *l;
-+
-+ for (l = ignoredwords; l; l = l->next)
-+ if (!strcasecmp(l->word, word))
-+ return 1;
-+ return 0;
-+}
-diff -Nur src/mod/gseen.mod/datahandling.c src/mod/gseen.mod/datahandling.c
---- src/mod/gseen.mod/datahandling.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/datahandling.c 2002-10-26 13:17:48.000000000 +0200
-@@ -0,0 +1,151 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+
-+static void write_seens()
-+{
-+ seenreq *r;
-+ seenreq_by *b;
-+ FILE *f;
-+ char s[125];
-+
-+ Context;
-+ /* putlog(LOG_MISC, "*", "Saving seen data..."); */
-+ if (!gseenfile[0])
-+ return;
-+ sprintf(s, "%s~new", gseenfile);
-+ f = fopen(s, "w");
-+ chmod(s, 0600);
-+ if (f == NULL) {
-+ putlog(LOG_MISC, "*", "ERROR writing gseen file.");
-+ return;
-+ }
-+ fprintf(f, "# gseen data file v1.\n");
-+ write_seen_tree_target = f;
-+ btree_getall(&seentree, write_seen_tree);
-+ for (r = requests; r; r = r->next)
-+ for (b = r->by; b; b = b->next)
-+ /* @ nick by host chan when */
-+ fprintf(f, "@ %s %s %s %s %lu\n", r->nick, b->who, b->host, b->chan,
-+ b->when);
-+ fclose(f);
-+ unlink(gseenfile);
-+ movefile(s, gseenfile);
-+ /* putlog(LOG_MISC, "*", "Done."); */
-+ return;
-+}
-+
-+static void read_seens()
-+{
-+ FILE *f;
-+ char buf[512], *s, *type, *nick, *host, *chan, *msg, *by;
-+ time_t when;
-+ int spent, iType, i;
-+
-+ Context;
-+ f = fopen(gseenfile, "r");
-+ if (f == NULL) {
-+ putlog(LOG_MISC, "*", "Can't open gseen file, creating new database...");
-+ return;
-+ }
-+ while (!feof(f)) {
-+ buf[0] = 0;
-+ s = buf;
-+ fgets(s, 511, f);
-+ i = strlen(buf);
-+ if (buf[i - 1] == '\n')
-+ buf[i - 1] = 0;
-+ if ((buf[0] == 0) || (buf[0] == '#'))
-+ continue;
-+ type = newsplit(&s);
-+ if (!strcmp(type, "!")) {
-+ nick = newsplit(&s);
-+ host = newsplit(&s);
-+ chan = newsplit(&s);
-+ iType = atoi(newsplit(&s));
-+ when = (time_t) atoi(newsplit(&s));
-+ spent = atoi(newsplit(&s));
-+ msg = s;
-+ add_seen(iType, nick, host, chan, msg, when, spent);
-+ } else if (!strcmp(type, "@")) {
-+ nick = newsplit(&s);
-+ by = newsplit(&s);
-+ host = newsplit(&s);
-+ chan = newsplit(&s);
-+ when = (time_t) atoi(newsplit(&s));
-+ add_seenreq(nick, by, host, chan, when);
-+ }
-+ }
-+ fclose(f);
-+ Context;
-+ return;
-+}
-+
-+static void purge_seens()
-+{
-+ seenreq *r, *rr;
-+ seenreq_by *b, *bb;
-+
-+ Context;
-+ if (!expire_seens)
-+ return;
-+ btree_getall_expanded(&seentree, purge_seen_tree);
-+ debug0("purge done");
-+ r = requests;
-+ rr = NULL;
-+ while (r) {
-+ b = r->by;
-+ bb = NULL;
-+ while (b) {
-+ if ((now - b->when) > (expire_seens * 86400)) {
-+ debug2("request for %s from %s has expired.", r->nick, b->who);
-+ nfree(b->who);
-+ nfree(b->host);
-+ nfree(b->chan);
-+ if (bb) {
-+ bb->next = b->next;
-+ nfree(b);
-+ b = bb->next;
-+ } else {
-+ r->by = b->next;
-+ nfree(b);
-+ b = r->by;
-+ }
-+ } else {
-+ bb = b;
-+ b = b->next;
-+ }
-+ }
-+ if (!r->by) {
-+ debug1("no further seen requests for %s, deleting", r->nick);
-+ nfree(r->nick);
-+ if (rr) {
-+ rr->next = r->next;
-+ nfree(r);
-+ r = rr->next;
-+ } else {
-+ requests = r->next;
-+ nfree(r);
-+ r = requests;
-+ }
-+ } else {
-+ rr = r;
-+ r = r->next;
-+ }
-+ }
-+}
-diff -Nur src/mod/gseen.mod/do_seen.c src/mod/gseen.mod/do_seen.c
---- src/mod/gseen.mod/do_seen.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/do_seen.c 2002-10-26 13:17:50.000000000 +0200
-@@ -0,0 +1,840 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+/* do_seen(): Checks if someone matches the mask, and returns the reply
-+ * mask : first paramater (e.g. "G`Quann", "G`Quann", "*!*@*.isp.de", ...)
-+ * nick : nick of the one, who triggered the command
-+ * uhost: user@host of nick
-+ * chan : chan, where the command was triggered
-+ * bns :
-+ * 1 : do a botnet-seen if no matches are found
-+ * 0 : don't do a botnet-seen
-+ * -1 : return NULL instead of text, if no matches were found
-+ * (necessary for botnet seen)
-+ */
-+static char *do_seen(char *mask, char *nick, char *uhost, char *chan, int bns)
-+{
-+ char hostbuf[UHOSTLEN + 1], *host, *newhost, *tmp, *dur;
-+ seendat *l;
-+ gseenres *r;
-+ int wild, nr;
-+ char bnquery[256];
-+ struct userrec *u;
-+ struct laston_info *li;
-+ struct chanset_t *ch;
-+
-+ Context;
-+ start_seentime_calc();
-+ if (seen_reply) {
-+ nfree(seen_reply);
-+ seen_reply = NULL;
-+ }
-+ l = NULL;
-+ li = NULL;
-+ host = hostbuf;
-+ newhost = NULL;
-+ mask = newsplit(&mask);
-+ glob_query = mask;
-+ while (mask[0] == ' ')
-+ mask++;
-+ if (!mask[0]) {
-+ return SLNOPARAM;
-+ }
-+ if (strchr(mask, '?') || strchr(mask, '*')) {
-+ // if wildcard-searches ares not allowed, then either return
-+ // NULL (for botnet-seen), or a appropriate warning
-+ if (!wildcard_search) {
-+ if (bns == -1)
-+ return NULL;
-+ else
-+ return SLNOWILDCARDS;
-+ } else
-+ wild = 1;
-+ } else {
-+ if (strlen(mask) > seen_nick_len) // don't process if requested nick is too long
-+ return SLTOOLONGNICK; // (e.g. stop stupid jokes)
-+ if (!strcasecmp(mask, nick)) {
-+ return SLMIRROR;
-+ }
-+ // check if the nick is on the current channel
-+ if (onchan(mask, chan))
-+ return SLONCHAN;
-+ if ((glob_othernick = handonchan(mask, chan)))
-+ return SLHANDONCHAN;
-+ // check if it is on any other channel
-+ if ((ch = onanychan(mask))) {
-+#if EGG_IS_MIN_VER(10500)
-+ if (!secretchan(ch->dname)) {
-+ glob_otherchan = ch->dname;
-+ return SLONOTHERCHAN;
-+ }
-+#else
-+ if (!secretchan(ch->name)) {
-+ glob_otherchan = ch->name;
-+ return SLONOTHERCHAN;
-+ }
-+#endif
-+ }
-+ // check if the user who uses this handle is on the channel under
-+ // a different nick
-+ if ((ch = handonanychan(mask))) {
-+#if EGG_IS_MIN_VER(10500)
-+ if (!secretchan(ch->dname)) {
-+ glob_otherchan = ch->dname;
-+ return SLONOTHERCHAN;
-+ }
-+#else
-+ if (!secretchan(ch->name)) {
-+ glob_otherchan = ch->name;
-+ return SLONOTHERCHAN;
-+ }
-+#endif
-+ }
-+ add_seenreq(mask, nick, uhost, chan, now);
-+ wild = 0;
-+ l = findseen(mask);
-+ // if there's a result, and if we don't want to search for the same user
-+ // under a different nick, just make a do_seennick on the result
-+ if (l && !fuzzy_search) {
-+ tmp = do_seennick(l);
-+ end_seentime_calc();
-+ return tmp;
-+ }
-+ if (!l) {
-+ u = get_user_by_handle(userlist, mask);
-+ if (u) {
-+ li = get_user(&USERENTRY_LASTON, u);
-+ }
-+ if (!u || !li) {
-+ if (bns == -1) { // if bns is 0, then do_seen() was triggered by
-+ end_seentime_calc(); // a botnet seen function, which needs a clear
-+ return NULL; // NULL to detect if there was a result or not
-+ }
-+ tmp = SLNOTSEEN;
-+ if (bns && ((strlen(mask) + strlen(nick) + strlen(uhost)
-+ + strlen(chan) + 20) < 255)) {
-+ debug0("trying botnet seen");
-+ if (bnsnick)
-+ nfree(bnsnick);
-+ if (bnschan)
-+ nfree(bnschan);
-+ bnsnick = nmalloc(strlen(nick) + 1);
-+ strcpy(bnsnick, nick);
-+ bnschan = nmalloc(strlen(chan) + 1);
-+ strcpy(bnschan, chan);
-+ sprintf(bnquery, "gseen_req %s %s %s %s", mask, nick, uhost, chan);
-+ botnet_send_zapf_broad(-1, botnetnick, NULL, bnquery);
-+ }
-+ } else {
-+ // we have a matching handle, no seen-entry, but a laston entry
-+ // in the userbase, so let's just return that one.
-+ dur = gseen_duration(now - li->laston);
-+ glob_laston = dur;
-+ tmp = SLPOORSEEN;
-+ seen_reply = nmalloc(strlen(tmp) + 1);
-+ strcpy(seen_reply, tmp);
-+ end_seentime_calc();
-+ return seen_reply;
-+ }
-+ end_seentime_calc();
-+ return tmp;
-+ }
-+ // now prepare the host for fuzzy-search
-+ if (strlen(l->host) < UHOSTLEN) {
-+ maskstricthost(l->host, host);
-+ host = strchr(host, '!') + 1; // strip nick from host for faster search
-+ } else {
-+ end_seentime_calc();
-+ return "error, too long host";
-+ }
-+ }
-+ if (l && (l->type == SEEN_CHPT)) {
-+ tmp = do_seennick(l);
-+ end_seentime_calc();
-+ return tmp;
-+ }
-+ numresults = 0;
-+ // wildmatch_seens uses a global var to store hosts in it
-+ // (to prevent massive nmalloc/nfree-usage), so don't forget
-+ // to initialize and free it
-+ temp_wildmatch_host = my_malloc(1);
-+ wildmatch_seens(host, mask, wild);
-+ my_free(temp_wildmatch_host);
-+ temp_wildmatch_host = NULL;
-+ if (!results) {
-+ end_seentime_calc();
-+ if (bns == -1)
-+ return NULL; // let the botnet seen function know, that seen failed
-+ return SLNOMATCH;
-+ }
-+ if (numresults >= max_matches) {
-+ end_seentime_calc();
-+ free_seenresults();
-+ return SLTOOMANYMATCHES;
-+ }
-+ sortresults();
-+ if (strcasecmp(results->seen->nick, mask)) {
-+ // if the user's latest nick is not the nick for which we were searching,
-+ // say that there were multiple matches and display the latest one
-+ if (numresults == 1)
-+ tmp = SLONEMATCH;
-+ else if (numresults <= 5)
-+ tmp = SLLITTLEMATCHES;
-+ else
-+ tmp = SLMANYMATCHES;
-+ seen_reply = nmalloc(strlen(tmp) + 1);
-+ strcpy(seen_reply, tmp);
-+ nr = 0;
-+ for (r = results; (r && (nr < 5)); r = r->next) {
-+ nr++;
-+ if (nr > 1) {
-+ seen_reply = nrealloc(seen_reply, 1 + strlen(seen_reply) + 1 + strlen(r->seen->nick) + 1);
-+ strcat(seen_reply, ", ");
-+ } else {
-+ seen_reply = nrealloc(seen_reply, 1 + strlen(seen_reply) + strlen(r->seen->nick) + 1);
-+ strcat(seen_reply, " ");
-+ }
-+ strcat(seen_reply, r->seen->nick);
-+ }
-+ tmp = do_seennick(results->seen);
-+ seen_reply = nrealloc(seen_reply, 2 + strlen(seen_reply) + strlen(tmp) + 1);
-+ sprintf(seen_reply, "%s. %s", seen_reply, tmp);
-+ } else { // first result is the nick which we were searching for
-+ // just return the info for this nick and don't care about other results
-+ tmp = do_seennick(results->seen);
-+ seen_reply = nmalloc(strlen(tmp) + 1);
-+ strcpy(seen_reply, tmp);
-+ }
-+ free_seenresults();
-+ end_seentime_calc();
-+ return seen_reply;
-+}
-+
-+/* do_seennick():
-+ * takes a seen-dataset and produces the corresponding reply basically
-+ * by referencing to the lang entry with the same number as the seen-type.
-+ */
-+static char *do_seennick(seendat *l)
-+{
-+// char buf[256], *msg;
-+ int stype;
-+
-+ Context;
-+ if (!l) {
-+ debug0("ERROR! Tryed to do a seennick on a NULL pointer!");
-+ return "ERROR! seendat == NULL!!!";
-+ }
-+ glob_seendat = l;
-+ // l->type is the basic language-entry-number
-+ stype = l->type + 100;
-+ // in some cases, we might need a special reply, so modify the
-+ // number if neccessary
-+ switch (l->type) {
-+ case SEEN_JOIN:
-+ if (!onchan(l->nick, l->chan))
-+ stype += 20;
-+ break;
-+ case SEEN_PART:
-+ /* nothing to do here */
-+ break;
-+ case SEEN_SIGN:
-+ /* nothing again */
-+ break;
-+ case SEEN_NICK:
-+ if (!onchan(l->msg, l->chan))
-+ stype += 20;
-+ break;
-+ case SEEN_NCKF:
-+ if (!onchan(l->nick, l->chan))
-+ stype += 20;
-+ break;
-+ case SEEN_KICK:
-+/* msg = buf;
-+ strncpy(buf, l->msg, 255);
-+ msg[255] = 0;
-+ sglobpunisher = newsplit(&msg);
-+ sglobreason = msg; */
-+ break;
-+ case SEEN_SPLT:
-+ /* nothing to do here */
-+ break;
-+ case SEEN_REJN:
-+ if (!onchan(l->nick, l->chan))
-+ stype += 20;
-+ break;
-+ case SEEN_CHJN:
-+ case SEEN_CHPT:
-+ if (!strcmp(l->chan, "0"))
-+ stype += 20;
-+ break;
-+ default:
-+ stype = 140;
-+ }
-+ return getslang(stype);
-+}
-+
-+/* findseens():
-+ * interface for webseen.mod
-+ * find all results for a query and return a pointer to this list
-+ * (basically the core of do_seen())
-+ */
-+static gseenres *findseens(char *mask, int *ret, int fuzzy)
-+{
-+ char hostbuf[UHOSTLEN + 1], *host, *newhost;
-+ seendat *l;
-+ int wild;
-+
-+ Context;
-+ start_seentime_calc();
-+ *ret = WS_OK;
-+ l = NULL;
-+ host = hostbuf;
-+ newhost = NULL;
-+ mask = newsplit(&mask);
-+ while (mask[0] == ' ')
-+ mask++;
-+ if (!mask[0]) {
-+ *ret = WS_NOPARAM;
-+ return NULL;
-+ }
-+ if (strchr(mask, '?') || strchr(mask, '*')) {
-+ // if wildcard-searches ares not allowed, then either return
-+ // NULL (for botnet-seen), or a appropriate warning
-+ if (!wildcard_search) {
-+ *ret = WS_NOWILDCARDS;
-+ return NULL;
-+ }
-+ wild = 1;
-+ } else {
-+ if (strlen(mask) > seen_nick_len) { // don't process if requested nick is too long
-+ *ret = WS_TOOLONGNICK; // (e.g. stop stupid jokes)
-+ return NULL;
-+ }
-+ add_seenreq(mask, "www-user", "unknown_host", "webinterface", now);
-+ wild = 0;
-+ l = findseen(mask);
-+ // if there's a result, and if we don't want to search for the same user
-+ // under a different nick, just return this result
-+ if (l && (!fuzzy_search || !fuzzy)) {
-+ numresults = 1;
-+ add_seenresult(l);
-+ end_seentime_calc();
-+ return results;
-+ }
-+ if (!l) {
-+ // no matching user was found :(
-+ *ret = WS_NORESULT;
-+ end_seentime_calc();
-+ return NULL;
-+ }
-+ // now prepare the host for fuzzy-search
-+ if (strlen(l->host) < UHOSTLEN) {
-+ maskstricthost(l->host, host);
-+ host = strchr(host, '!') + 1; // strip nick from host for faster search
-+ } else {
-+ *ret = WS_TOOLONGHOST;
-+ end_seentime_calc();
-+ return NULL;
-+ }
-+ }
-+ if (l && (l->type == SEEN_CHPT)) {
-+ numresults = 1;
-+ add_seenresult(l);
-+ end_seentime_calc();
-+ return results;
-+ }
-+ numresults = 0;
-+ // wildmatch_seens uses a global var to store hosts in it
-+ // (to prevent massive nmalloc/nfree-usage), so don't forget
-+ // to initialize and free it
-+ temp_wildmatch_host = my_malloc(1);
-+ wildmatch_seens(host, mask, wild);
-+ my_free(temp_wildmatch_host);
-+ temp_wildmatch_host = NULL;
-+ if (!results) {
-+ // no match :(
-+ *ret = WS_NORESULT;
-+ end_seentime_calc();
-+ return NULL;
-+ }
-+ if (numresults >= max_matches) {
-+ free_seenresults();
-+ *ret = WS_TOOMANYMATCHES;
-+ end_seentime_calc();
-+ return NULL;
-+ }
-+ sortresults();
-+ *ret = 0;
-+ end_seentime_calc();
-+ return results;
-+}
-+
-+
-+char seenstats_reply[512];
-+static char *do_seenstats()
-+{
-+ glob_totalnicks = count_seens();
-+ glob_totalbytes = gseen_expmem();
-+ sprintf(seenstats_reply, "%s", SLSEENSTATS);
-+ return seenstats_reply;
-+}
-+
-+// add an seen result (to the top of the list)
-+static void add_seenresult(seendat *seen)
-+{
-+ gseenres *nl;
-+
-+ numresults++;
-+ if (numresults > max_matches)
-+ return;
-+ nl = nmalloc(sizeof(gseenres));
-+ nl->seen = seen;
-+ nl->next = results;
-+ results = nl;
-+}
-+
-+static int expmem_seenresults()
-+{
-+ int bytes = 0;
-+ gseenres *l;
-+
-+ for (l = results; l; l = l->next)
-+ bytes += sizeof(gseenres);
-+ return bytes;
-+}
-+
-+static void free_seenresults()
-+{
-+ gseenres *l, *ll;
-+
-+ l = results;
-+ while (l) {
-+ ll = l->next;
-+ nfree(l);
-+ l = ll;
-+ }
-+ results = NULL;
-+}
-+
-+static void sortresults()
-+{
-+ int again = 1;
-+ gseenres *last, *p, *c, *n;
-+ int a, b;
-+
-+ Context;
-+ again = 1;
-+ last = NULL;
-+ while ((results != last) && (again)) {
-+ p = NULL;
-+ c = results;
-+ n = c->next;
-+ again = 0;
-+ while (n != last) {
-+ if (!c || !n)
-+ a = b = 0;
-+ else
-+ a = c->seen->when;
-+ b = n->seen->when;
-+ if (a < b) {
-+ again = 1;
-+ c->next = n->next;
-+ n->next = c;
-+ if (p == NULL)
-+ results = n;
-+ else
-+ p->next = n;
-+ }
-+ p = c;
-+ c = n;
-+ n = n->next;
-+ }
-+ last = c;
-+ }
-+ Context;
-+ return;
-+}
-+
-+static void sortrequests(seenreq *l)
-+{
-+ int again = 1;
-+ seenreq_by *last, *p, *c, *n;
-+ int a, b;
-+
-+ Context;
-+ again = 1;
-+ last = NULL;
-+ while ((l->by != last) && (again)) {
-+ p = NULL;
-+ c = l->by;
-+ n = c->next;
-+ again = 0;
-+ while (n != last) {
-+ if (!c || !n)
-+ a = b = 0;
-+ else
-+ a = c->when;
-+ b = n->when;
-+ if (a < b) {
-+ again = 1;
-+ c->next = n->next;
-+ n->next = c;
-+ if (p == NULL)
-+ l->by = n;
-+ else
-+ p->next = n;
-+ }
-+ p = c;
-+ c = n;
-+ n = n->next;
-+ }
-+ last = c;
-+ }
-+ Context;
-+ return;
-+}
-+
-+/* stolen from tcl_duration in tclmisc.c */
-+char gs_duration_temp[256];
-+static char *gseen_duration(int seconds)
-+{
-+ char s[256];
-+ time_t sec;
-+
-+ sec = seconds;
-+ s[0] = 0;
-+ if (sec < 1) {
-+ snprintf(gs_duration_temp, sizeof(gs_duration_temp), "%s", SLSOMETIME);
-+ return gs_duration_temp;
-+ }
-+ if (sec < 60) {
-+ sprintf(gs_duration_temp, "%d %s", (int) (sec / 1),
-+ ((int) (sec / 1) > 1) ? SLSECONDS : SLSECOND);
-+ return gs_duration_temp;
-+ }
-+ if (sec >= 31536000) {
-+ sprintf(s, "%d %s ", (int) (sec / 31536000),
-+ ((int) (sec / 31536000) > 1) ? SLYEARS : SLYEAR);
-+ sec -= (((int) (sec / 31536000)) * 31536000);
-+ }
-+ if (sec >= 604800) {
-+ sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 604800),
-+ ((int) (sec / 604800) > 1) ? SLWEEKS : SLWEEK);
-+ sec -= (((int) (sec / 604800)) * 604800);
-+ }
-+ if (sec >= 86400) {
-+ sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 86400),
-+ ((int) (sec / 86400) > 1) ? SLDAYS : SLDAY);
-+ sec -= (((int) (sec / 86400)) * 86400);
-+ }
-+ if (sec >= 3600) {
-+ sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 3600),
-+ ((int) (sec / 3600) > 1) ? SLHOURS : SLHOUR);
-+ sec -= (((int) (sec / 3600)) * 3600);
-+ }
-+ if (sec >= 60) {
-+ sprintf(&s[strlen(s)], "%d %s ", (int) (sec / 60),
-+ ((int) (sec / 60) > 1) ? SLMINUTES : SLMINUTE);
-+ sec -= (((int) (sec / 60)) * 60);
-+ }
-+ strcpy(gs_duration_temp, s);
-+ if (gs_duration_temp[strlen(gs_duration_temp) - 1] == ' ')
-+ gs_duration_temp[strlen(gs_duration_temp) - 1] = 0;
-+ return gs_duration_temp;
-+}
-+
-+static int onchan(char *nick, char *chan)
-+{
-+ struct chanset_t *ch;
-+ memberlist *m;
-+
-+ ch = findchan_by_dname(chan);
-+ if (!ch)
-+ return 0;
-+ m = ismember(ch, nick);
-+ if (!m)
-+ return 0;
-+ else if (chan_issplit(m))
-+ return 0;
-+ else
-+ return 1;
-+}
-+
-+/* handonchan():
-+ * checks if the given user is on the channel and returns its nick
-+ */
-+static char *handonchan(char *hand, char *chan)
-+{
-+ struct chanset_t *ch;
-+ memberlist *m;
-+
-+ ch = findchan_by_dname(chan);
-+ if (!ch)
-+ return 0;
-+ if (ch->channel.members > 0) {
-+ for (m = ch->channel.member; m; m = m->next) {
-+ if (m->user) {
-+ if (m->user->handle && !rfc_casecmp(m->user->handle, hand))
-+ return m->nick;
-+ }
-+ }
-+ }
-+ return NULL;
-+}
-+
-+/* onanychan():
-+ * checks if the given nickname is on any of the bot's chans.
-+ */
-+static struct chanset_t *onanychan(char *nick)
-+{
-+ struct chanset_t *ch;
-+ memberlist *m;
-+
-+ for (ch = chanset; ch; ch = ch->next) {
-+ m = ismember(ch, nick);
-+ if (m && !chan_issplit(m))
-+ return ch;
-+ }
-+ return NULL;
-+}
-+
-+/* handonanychan():
-+ * checks if the given user is on any channel (no matter under which nick)
-+ */
-+static struct chanset_t *handonanychan(char *hand)
-+{
-+ struct chanset_t *ch;
-+ memberlist *m;
-+
-+ for (ch = chanset; ch; ch = ch->next) {
-+ if (ch->channel.members > 0) {
-+ for (m = ch->channel.member; m; m = m->next) {
-+ if (m->user) {
-+ if (m->user->handle && !rfc_casecmp(m->user->handle, hand))
-+ return ch;
-+ }
-+ }
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static void add_seenreq(char *nick, char *from, char *host, char *chan,
-+ time_t when)
-+{
-+ seenreq *l, *nl;
-+ seenreq_by *b, *nb;
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (!tell_seens)
-+ return;
-+ if (strcmp(chan, "[partyline]") && secretchan(chan))
-+ chan = buf;
-+ for (l = requests; l; l = l->next) {
-+ if (!strcasecmp(nick, l->nick)) {
-+ for (b = l->by; b; b = b->next) {
-+ if (!strcasecmp(from, b->who)) {
-+ nfree(b->chan);
-+ b->chan = nmalloc(strlen(chan) + 1);
-+ strcpy(b->chan, chan);
-+ b->when = when;
-+ return;
-+ }
-+ }
-+ b = l->by;
-+ while (b && b->next)
-+ b = b->next;
-+ nb = nmalloc(sizeof(seenreq_by));
-+ nb->who = nmalloc(strlen(from) + 1);
-+ strcpy(nb->who, from);
-+ nb->host = nmalloc(strlen(host) + 1);
-+ strcpy(nb->host, host);
-+ nb->chan = nmalloc(strlen(chan) + 1);
-+ strcpy(nb->chan, chan);
-+ nb->when = when;
-+ nb->next = NULL;
-+ if (l->by)
-+ b->next = nb;
-+ else
-+ l->by = nb;
-+ return;
-+ }
-+ }
-+ nb = nmalloc(sizeof(seenreq_by));
-+ nb->who = nmalloc(strlen(from) + 1);
-+ strcpy(nb->who, from);
-+ nb->host = nmalloc(strlen(host) + 1);
-+ strcpy(nb->host, host);
-+ nb->chan = nmalloc(strlen(chan) + 1);
-+ strcpy(nb->chan, chan);
-+ nb->when = when;
-+ nb->next = NULL;
-+ l = requests;
-+ while (l && l->next)
-+ l = l->next;
-+ nl = nmalloc(sizeof(seenreq));
-+ nl->nick = nmalloc(strlen(nick) + 1);
-+ strcpy(nl->nick, nick);
-+ nl->by = nb;
-+ nl->next = NULL;
-+ if (requests)
-+ l->next = nl;
-+ else
-+ requests = nl;
-+}
-+
-+static int expmem_seenreq()
-+{
-+ seenreq *l;
-+ seenreq_by *b;
-+ int size;
-+
-+ size = 0;
-+ for (l = requests; l; l = l->next) {
-+ size += sizeof(seenreq);
-+ size += strlen(l->nick) + 1;
-+ for (b = l->by; b; b = b->next) {
-+ size += sizeof(seenreq_by);
-+ size += strlen(b->who) + 1;
-+ size += strlen(b->host) + 1;
-+ size += strlen(b->chan) + 1;
-+ }
-+ }
-+ return size;
-+}
-+
-+static int count_seenreq(seenreq_by *b)
-+{
-+ seenreq_by *l;
-+ int nr;
-+
-+ nr = 0;
-+ for (l = b; l; l = l->next)
-+ nr++;
-+ return nr;
-+}
-+
-+static void free_seenreq()
-+{
-+ seenreq *l, *ll;
-+ seenreq_by *b, *bb;
-+
-+ Context;
-+ l = requests;
-+ while (l) {
-+ b = l->by;
-+ while (b) {
-+ bb = b->next;
-+ nfree(b->who);
-+ nfree(b->host);
-+ nfree(b->chan);
-+ nfree(b);
-+ b = bb;
-+ }
-+ ll = l->next;
-+ nfree(l->nick);
-+ nfree(l);
-+ l = ll;
-+ }
-+ requests = NULL;
-+}
-+
-+static void report_seenreq(char *channel, char *nick)
-+{
-+ seenreq *l, *ll;
-+ seenreq_by *b, *bb;
-+ char *reply, *tmp;
-+ int nr;
-+
-+ if (!tell_seens)
-+ return;
-+ ll = NULL;
-+ l = requests;
-+ reply = NULL;
-+ while (l) {
-+ if (!strcasecmp(l->nick, nick)) {
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, channel));
-+ glob_nick = nick;
-+ nr = count_seenreq(l->by);
-+ if (nr == 1) {
-+ glob_seenrequest = l;
-+ dprintf(DP_HELP, "NOTICE %s :%s\n", l->nick, SLONELOOK);
-+ } else {
-+ sortrequests(l);
-+ glob_seenrequest = l;
-+ glob_seenrequests = nr;
-+ tmp = SLMORELOOKS;
-+ reply = nmalloc(strlen(tmp) + 1);
-+ strcpy(reply, tmp);
-+ nr = 0;
-+ for (b = l->by; b; b = b->next) {
-+ nr++;
-+ reply = nrealloc(reply, strlen(reply) + ((nr == 1) ? 1 : 2) + strlen(b->who) + 1);
-+ sprintf(reply, "%s%s%s", reply, (nr == 1) ? " " : ", ", b->who);
-+ }
-+ tmp = SLLASTLOOK;
-+ reply = nrealloc(reply, strlen(reply) + 2 + strlen(tmp) + 1);
-+ sprintf(reply, "%s. %s", reply, tmp);
-+ dprintf(DP_HELP, "NOTICE %s :%s\n", l->nick, reply);
-+ nfree(reply);
-+ }
-+ b = l->by;
-+ while (b) {
-+ bb = b->next;
-+ nfree(b->who);
-+ nfree(b->host);
-+ nfree(b->chan);
-+ nfree(b);
-+ b = bb;
-+ }
-+ nfree(l->nick);
-+ if (ll)
-+ ll->next = l->next;
-+ else
-+ requests = l->next;
-+ nfree(l);
-+ if (ll)
-+ l = ll->next;
-+ else
-+ l = requests;
-+ } else {
-+ ll = l;
-+ l = l->next;
-+ }
-+ }
-+}
-+
-+static void start_seentime_calc()
-+{
-+ struct timeval t;
-+
-+ gettimeofday(&t, NULL);
-+ glob_presearch = (float) t.tv_sec + (((float) t.tv_usec) / 1000000);
-+}
-+
-+static void end_seentime_calc()
-+{
-+ struct timeval t;
-+
-+ gettimeofday(&t, NULL);
-+ glob_aftersearch = (float) t.tv_sec + (((float) t.tv_usec) / 1000000);
-+ glob_total_searchtime += glob_aftersearch - glob_presearch;
-+ glob_total_queries++;
-+}
-diff -Nur src/mod/gseen.mod/generic_binary_tree.c src/mod/gseen.mod/generic_binary_tree.c
---- src/mod/gseen.mod/generic_binary_tree.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/generic_binary_tree.c 2002-10-26 13:17:51.000000000 +0200
-@@ -0,0 +1,311 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#define GENERIC_BINARY_TREE 1
-+
-+struct generic_binary_tree {
-+ void *root;
-+ int (*comparedata) (void *data1, void *data2);
-+ int (*expmemdata) (void *data);
-+ void (*freedata) (void *data);
-+};
-+
-+struct generic_binary_tree_node {
-+ void *data;
-+ void *left;
-+ void *right;
-+};
-+
-+static void btree_add(struct generic_binary_tree *, void *);
-+static int btree_expmem(struct generic_binary_tree *);
-+static int btree_recursive_expmem(struct generic_binary_tree *, struct generic_binary_tree_node *);
-+static void *btree_get(struct generic_binary_tree *, void *t);
-+static void btree_freetree(struct generic_binary_tree *);
-+static void btree_recursive_free(struct generic_binary_tree *,
-+ struct generic_binary_tree_node *);
-+static void btree_getall(struct generic_binary_tree *, void (*) (void *));
-+static void btree_recursive_getall(struct generic_binary_tree_node *,
-+ void (*) (void *));
-+static void btree_getall_expanded(struct generic_binary_tree *tree, void (*) (void *));
-+static void btree_recursive_getall_expanded(struct generic_binary_tree_node *,
-+ void (*) (void *));
-+static void btree_remove(struct generic_binary_tree *, void *);
-+
-+static void btree_add(struct generic_binary_tree *tree, void *data)
-+{
-+ struct generic_binary_tree_node *node, *lastnode;
-+ int cmp, lastcmp;
-+
-+ Assert(tree);
-+ Assert(data);
-+ cmp = lastcmp = 0;
-+ node = tree->root;
-+ lastnode = NULL;
-+ while (node) {
-+ cmp = tree->comparedata(node->data, data);
-+ if (!cmp) {
-+ // item is identical -> free old data and insert new
-+ tree->freedata(node->data);
-+ node->data = data;
-+ return;
-+ }
-+ lastnode = node;
-+ lastcmp = cmp;
-+ if (cmp < 0)
-+ node = node->left;
-+ else
-+ node = node->right;
-+ }
-+ node = nmalloc(sizeof(struct generic_binary_tree_node));
-+ node->left = NULL;
-+ node->right = NULL;
-+ node->data = data;
-+ if (!lastnode)
-+ tree->root = node;
-+ else {
-+ Assert(lastcmp);
-+ if (lastcmp < 0) {
-+ Assert(!lastnode->left);
-+ lastnode->left = node;
-+ } else {
-+ Assert(!lastnode->right);
-+ lastnode->right = node;
-+ }
-+ }
-+}
-+
-+static int btree_expmem(struct generic_binary_tree *tree)
-+{
-+ int size = 0;
-+
-+ Assert(tree);
-+ size += btree_recursive_expmem(tree, tree->root);
-+ return size;
-+}
-+
-+static int btree_recursive_expmem(struct generic_binary_tree *tree, struct generic_binary_tree_node *node)
-+{
-+ int size = 0;
-+
-+ if (!node)
-+ return 0;
-+ size += sizeof(struct generic_binary_tree_node);
-+ size += tree->expmemdata(node->data);
-+ size += btree_recursive_expmem(tree, node->left);
-+ size += btree_recursive_expmem(tree, node->right);
-+ return size;
-+}
-+
-+static void *btree_get(struct generic_binary_tree *tree, void *what)
-+{
-+ struct generic_binary_tree_node *node;
-+ int cmp;
-+
-+ node = tree->root;
-+ while (node) {
-+ cmp = tree->comparedata(node->data, what);
-+ if (!cmp)
-+ return node->data;
-+ if (cmp < 0)
-+ node = node->left;
-+ else
-+ node = node->right;
-+ }
-+ return NULL;
-+}
-+
-+static void btree_freetree(struct generic_binary_tree *tree)
-+{
-+ btree_recursive_free(tree, tree->root);
-+}
-+
-+static void btree_recursive_free(struct generic_binary_tree *tree,
-+ struct generic_binary_tree_node *node)
-+{
-+ if (!node)
-+ return;
-+ btree_recursive_free(tree, node->left);
-+ btree_recursive_free(tree, node->right);
-+ tree->freedata(node->data);
-+ nfree(node);
-+}
-+
-+/* btree_getall():
-+ * calls the specified function for each item in the tree.
-+ * NOTE: getall() calls the proc _before_ it proceeds into recursion. This way,
-+ * one can savely store the tree into a file without mixing up its form.
-+ * But if you delete an item from the called prcedure, this function
-+ * WILL crash. Use btree_getall() expanded instead.
-+ */
-+static void btree_getall(struct generic_binary_tree *tree, void (*func) (void *))
-+{
-+ Assert(tree);
-+ btree_recursive_getall(tree->root, func);
-+}
-+
-+static void btree_recursive_getall(struct generic_binary_tree_node *node,
-+ void (*func) (void *))
-+{
-+ if (!node)
-+ return;
-+ // first call the function, then proceed into recursion
-+ // this way, the tree keeps in form if its saved to a file, for example
-+ Assert(func);
-+ func(node->data);
-+
-+ btree_recursive_getall(node->left, func);
-+ btree_recursive_getall(node->right, func);
-+}
-+
-+/* btree_getall_expanded():
-+ * the same as btree_getall(), but calls the function after the greatest level of recursion
-+ * has been reached. The node-pointers won't be accessed anymore when the first function
-+ * gets called. You can savely use this to free items.
-+ */
-+static void btree_getall_expanded(struct generic_binary_tree *tree, void (*func) (void *))
-+{
-+ Assert(tree);
-+ btree_recursive_getall_expanded(tree->root, func);
-+}
-+
-+static void btree_recursive_getall_expanded(struct generic_binary_tree_node *node,
-+ void (*func) (void *))
-+{
-+ if (!node)
-+ return;
-+ btree_recursive_getall_expanded(node->left, func);
-+ btree_recursive_getall_expanded(node->right, func);
-+
-+ Assert(func);
-+ func(node->data);
-+}
-+
-+static void btree_remove(struct generic_binary_tree *tree, void *data)
-+{
-+ struct generic_binary_tree_node *node, *last, *largenode, *lastlarge;
-+ int ret, lastret;
-+
-+ Assert(tree);
-+ Assert(data);
-+ last = NULL;
-+ lastret = 0;
-+ node = tree->root;
-+ while (node) {
-+ ret = tree->comparedata(node->data, data);
-+ if (ret == 0)
-+ break;
-+ last = node;
-+ lastret = ret;
-+ if (ret < 0)
-+ node = node->left;
-+ else
-+ node = node->right;
-+ }
-+ if (!node) // oops, item not found
-+ return;
-+ if (!node->left && !node->right) {
-+ // *freu* no sub-branches! We can easily delete this item.
-+ if (last) {
-+ if (lastret < 0)
-+ last->left = NULL;
-+ else
-+ last->right = NULL;
-+ } else
-+ tree->root = NULL;
-+ } else if (!node->left) {
-+ // also pretty easy. Just connect the child to the parent.
-+ if (last) {
-+ if (lastret < 0)
-+ last->left = node->right;
-+ else
-+ last->right = node->right;
-+ } else
-+ tree->root = node->right;
-+ } else if (!node->right) {
-+ // same as above, but mirrored
-+ if (last) {
-+ if (lastret < 0)
-+ last->left = node->left;
-+ else
-+ last->right = node->left;
-+ } else
-+ tree->root = node->left;
-+ } else {
-+ // aaargh... two sub-trees! The world is not fair... *sigh*
-+ debug0("argl... worst case, two subtrees. :( Let's pray...");
-+ // now we take the largest item from the left subtree and replace the
-+ // doomed node with it.
-+ // since it is the largest val, the tree remains valid and doesn't
-+ // get deformed too much.
-+
-+ // at first, we have to find this node and cut it from the tree
-+ largenode = node->left;
-+ lastlarge = NULL;
-+ while (largenode && largenode->right) {
-+ lastlarge = largenode;
-+ largenode = largenode->right;
-+ }
-+
-+ // only set largenode->left to node->left if largenode exists.
-+ // otherwise node->left points to largenode, which would result
-+ // in a nice short-circuit
-+ // If it does not exist, just leave largenode->left as it is because we just
-+ // move largenode one level up, so it can keep its left subtree.
-+ if (lastlarge) {
-+ lastlarge->right = largenode->left;
-+ largenode->left = node->left;
-+ }
-+
-+ // now connect node's subtrees to it
-+ largenode->right = node->right;
-+
-+ // and finally replace node with largenode
-+ if (last) {
-+ if (lastret < 0)
-+ last->left = largenode;
-+ else
-+ last->right = largenode;
-+ } else
-+ tree->root = largenode;
-+ }
-+ // finally kill the node... we shouldn't need it anymore
-+ tree->freedata(node->data);
-+ nfree(node);
-+ node = NULL;
-+}
-+
-+#ifdef BTREE_WITHOPTIMIZE
-+static void btree_optimize(struct generic_binary_tree *tree,
-+ struct generic_binary_tree_node *node,
-+ struct generic_binary_tree_node *last,
-+ int limit)
-+{
-+/* int leftdepth, rightdepth;
-+
-+ if (!node)
-+ return;
-+ btree_optimize(tree, node->left, node, last, limit);
-+ btree_optimize(tree, node->right, node, last, limit);
-+ leftdepth = btree_depth(node->left);
-+ rightdepth = btree_depth(node->right);
-+ if ((leftdepth - rightdepth) > limit) {
-+
-+ }
-+*/
-+}
-+#endif
-diff -Nur src/mod/gseen.mod/global_vars.c src/mod/gseen.mod/global_vars.c
---- src/mod/gseen.mod/global_vars.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/global_vars.c 2002-10-26 13:18:09.000000000 +0200
-@@ -0,0 +1,34 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+static char *glob_query, *glob_laston, *glob_otherchan, *glob_othernick;
-+static char *glob_remotebot, *glob_nick;
-+static struct slang_header *glob_slang;
-+static seendat *glob_seendat;
-+static seenreq *glob_seenrequest;
-+static int glob_seenrequests, glob_totalnicks, glob_totalbytes;
-+
-+static void reset_global_vars()
-+{
-+ glob_query = glob_laston = glob_otherchan = glob_othernick = NULL;
-+ glob_remotebot = glob_nick = NULL;
-+ glob_seendat = NULL;
-+ glob_slang = NULL;
-+ glob_seenrequest = NULL;
-+ glob_seenrequests = glob_totalnicks = glob_totalbytes = 0;
-+}
-diff -Nur src/mod/gseen.mod/gseen.c src/mod/gseen.mod/gseen.c
---- src/mod/gseen.mod/gseen.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/gseen.c 2002-10-26 14:24:48.000000000 +0200
-@@ -0,0 +1,328 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#define MAKING_GSEEN
-+#define MODULE_NAME "gseen"
-+#define MODULE_VERSION "1.1.1 dev3"
-+#define MODULE_NUMVERSION 10100
-+#include "../module.h"
-+#include "../irc.mod/irc.h"
-+#include "../server.mod/server.h"
-+#include "../channels.mod/channels.h"
-+#include <stdlib.h>
-+#include <sys/stat.h>
-+#include <time.h> /* for time_t */
-+
-+#undef global
-+static Function *global = NULL, *irc_funcs = NULL, *server_funcs = NULL, *channels_funcs = NULL;
-+
-+#ifndef EGG_IS_MIN_VER
-+#define EGG_IS_MIN_VER(ver) ((ver) <= 10400)
-+#endif
-+
-+#ifndef EGG_IS_MAX_VER
-+#define EGG_IS_MAX_VER(ver) ((ver) >= 10400)
-+#endif
-+
-+#ifndef Context
-+#define Context context
-+#endif
-+
-+#ifndef findchan_by_dname
-+#define findchan_by_dname findchan
-+#endif
-+
-+#include "gseen.h"
-+#include "seenlang.h"
-+
-+static struct slang_header *coreslangs = NULL;
-+static gseenres *results = NULL;
-+static seenreq *requests = NULL;
-+static ignoredword *ignoredwords = NULL;
-+static char *bnsnick = NULL;
-+static char *bnschan = NULL;
-+static char *seen_reply = NULL;
-+static char *temp_wildmatch_host;
-+static int numresults = 0;
-+static double glob_presearch, glob_aftersearch;
-+int numseens, glob_total_queries;
-+double glob_total_searchtime;
-+
-+static char gseenfile[121] = "gseen.dat";
-+static char no_pub[121];
-+static char quiet_seen[121];
-+static char quiet_ai_seen[121];
-+static char no_log[121];
-+static char ignore_words[1024];
-+static char default_slang[21] = "eng";
-+static int gseen_numversion = MODULE_NUMVERSION;
-+static int save_seens = 60;
-+static int save_seens_temp = 1;
-+static int expire_seens = 60;
-+static int maxseen_thr = 0;
-+static int maxseen_time = 0;
-+static int seenflood_thr = 0;
-+static time_t seenflood_time = 0;
-+static int use_handles = 0;
-+static int tell_seens = 1;
-+static int botnet_seen = 1;
-+int fuzzy_search = 1; // search for the same user under a differnt nick
-+static int wildcard_search = 1;// allow wildcard seaching? ("*!*@*.isp.de")
-+static int max_matches = 500; // break if there are more than X matches
-+static int hide_secret_chans = 1; // #chan (+secret) => [secret]
-+static int seen_nick_len = 32;
-+
-+#include "global_vars.c"
-+#define SLANG_NOTYPES 1
-+#define SLANG_NOFACTS 1
-+#define SLANG_NOGETALL 1
-+#define SLANG_NOVALIDATE 1
-+#include "slang.c"
-+#include "slang_gseen_commands.c"
-+#include "generic_binary_tree.c"
-+#include "seentree.c"
-+#include "datahandling.c"
-+#include "sensors.c"
-+#include "do_seen.c"
-+#include "gseencmds.c"
-+#include "ai.c"
-+#include "misc.c"
-+#include "tclcmds.c"
-+
-+static int gseen_expmem()
-+{
-+ int size = 0;
-+
-+ size += seentree_expmem();
-+ size += expmem_seenresults();
-+ size += expmem_seenreq();
-+ size += expmem_ignoredwords();
-+ size += slang_expmem(coreslangs);
-+ size += slang_glob_expmem();
-+ size += slang_chanlang_expmem(chanlangs);
-+ if (bnsnick)
-+ size += strlen(bnsnick) + 1;
-+ if (bnschan)
-+ size += strlen(bnschan) + 1;
-+ if (seen_reply) {
-+ size += strlen(seen_reply) + 1;
-+ }
-+ return size;
-+}
-+
-+static void free_gseen()
-+{
-+ seentree_free();
-+ slang_free(coreslangs);
-+ slang_chanlang_free(chanlangs);
-+ if (seen_reply)
-+ nfree(seen_reply);
-+ return;
-+}
-+
-+/* a report on the module status */
-+static void gseen_report(int idx, int details)
-+{
-+ int size = 0;
-+
-+ Context;
-+ if (details) {
-+ size = gseen_expmem();
-+ dprintf(idx, " using %d bytes\n", size);
-+ }
-+}
-+
-+static void gseen_minutely ()
-+{
-+ if (save_seens_temp >= save_seens) {
-+ write_seens();
-+ save_seens_temp = 1;
-+ } else
-+ save_seens_temp++;
-+}
-+
-+static void gseen_daily ()
-+{
-+ Context;
-+ purge_seens();
-+}
-+
-+static tcl_strings my_tcl_strings[] =
-+{
-+ {"gseenfile", gseenfile, 121, 0},
-+ {"ai-seen-ignore", ignore_words, 1024, 0},
-+ {"no-pub-seens", no_pub, 121, 0},
-+ {"quiet-seens", quiet_seen, 121, 0},
-+ {"quiet-ai-seens", quiet_ai_seen, 121, 0},
-+ {"no-log", no_log, 121, 0},
-+ {"no-seendata", no_log, 121, 0},
-+ {"default-slang", default_slang, 20, 0},
-+ {0, 0, 0, 0}
-+};
-+
-+static tcl_ints my_tcl_ints[] =
-+{
-+ {"save-seens", &save_seens, 0},
-+ {"expire-seens", &expire_seens, 0},
-+ {"use-handles", &use_handles, 0},
-+ {"tell-seens", &tell_seens, 0},
-+ {"botnet-seens", &botnet_seen, 0},
-+ {"max-matches", &max_matches, 0},
-+ {"fuzzy-search", &fuzzy_search, 0},
-+ {"wildcard-search", &wildcard_search, 0},
-+ {"hide-secret-chans", &hide_secret_chans, 0},
-+ {"seen-nick-len", &seen_nick_len, 0},
-+ {0, 0, 0}
-+};
-+
-+static tcl_coups my_tcl_coups[] =
-+{
-+ {"max-seens", &maxseen_thr, &maxseen_time},
-+ {0, 0, 0},
-+};
-+
-+static char *gseen_close()
-+{
-+ Context;
-+ write_seens();
-+ slang_glob_free();
-+ free_gseen();
-+ free_seenreq();
-+ free_seenresults();
-+ free_ignoredwords();
-+ if (bnsnick)
-+ nfree(bnsnick);
-+ if (bnschan)
-+ nfree(bnschan);
-+ rem_tcl_strings(my_tcl_strings);
-+ rem_tcl_ints(my_tcl_ints);
-+ rem_tcl_coups(my_tcl_coups);
-+ rem_tcl_commands(mytcls);
-+ rem_tcl_commands(gseentcls);
-+ rem_tcl_commands(seendebugtcls);
-+ rem_tcl_commands(gseentcls);
-+ rem_builtins(H_dcc, mydcc);
-+ rem_builtins(H_join, seen_join);
-+ rem_builtins(H_kick, seen_kick);
-+ rem_builtins(H_nick, seen_nick);
-+ rem_builtins(H_part, seen_part);
-+ rem_builtins(H_sign, seen_sign);
-+ rem_builtins(H_splt, seen_splt);
-+ rem_builtins(H_rejn, seen_rejn);
-+ rem_builtins(H_pub, seen_pub);
-+ rem_builtins(H_msg, seen_msg);
-+ rem_builtins(H_bot, seen_bot);
-+ del_hook(HOOK_MINUTELY, (Function) gseen_minutely);
-+ del_hook(HOOK_DAILY, (Function) gseen_daily);
-+ module_undepend(MODULE_NAME);
-+ return NULL;
-+}
-+
-+char *gseen_start();
-+
-+static Function gseen_table[] =
-+{
-+ (Function) gseen_start,
-+ (Function) gseen_close,
-+ (Function) gseen_expmem,
-+ (Function) gseen_report,
-+ /* 4 - 7 */
-+ (Function) findseens,
-+ (Function) free_seenresults,
-+ (Function) gseen_duration,
-+ (Function) & glob_seendat,
-+ (Function) & numresults,
-+ (Function) & fuzzy_search,
-+ (Function) & numseens,
-+ (Function) & glob_total_queries,
-+ (Function) & glob_total_searchtime,
-+ (Function) & gseen_numversion,
-+};
-+
-+char *gseen_start(Function * global_funcs)
-+{
-+ global = global_funcs;
-+ Context;
-+ module_register(MODULE_NAME, gseen_table, 1, 1);
-+ if (!(irc_funcs = module_depend(MODULE_NAME, "irc", 1, 0)))
-+ return "You need the irc module to use the gseen module.";
-+ if (!(server_funcs = module_depend(MODULE_NAME, "server", 1, 0)))
-+ return "You need the server module to use the gseen module.";
-+ if (!(channels_funcs = module_depend(MODULE_NAME, "channels", 1, 0)))
-+ return "You need the channels module to use the gseen module.";
-+ if (!module_depend(MODULE_NAME, "eggdrop", 107, 0)) {
-+ if (!module_depend(MODULE_NAME, "eggdrop", 106, 0)) {
-+ if (!module_depend(MODULE_NAME, "eggdrop", 105, 0)) {
-+ if (!module_depend(MODULE_NAME, "eggdrop", 104, 0)) {
-+ module_undepend(MODULE_NAME);
-+ return "This module requires eggdrop1.4.0 or later";
-+ }
-+ }
-+ }
-+ }
-+ chanlangs = NULL;
-+ coreslangs = NULL;
-+ slang_glob_init();
-+
-+ results = NULL;
-+ requests = NULL;
-+ ignoredwords = NULL;
-+ bnsnick = NULL;
-+ bnschan = NULL;
-+ seen_reply = NULL;
-+
-+ numresults = 0;
-+ numseens = 0;
-+ glob_total_queries = 0;
-+ glob_total_searchtime = 0.0;
-+ ignore_words[0] = 0;
-+ no_pub[0] = 0;
-+ quiet_seen[0] = 0;
-+ no_log[0] = 0;
-+ seentree_init();
-+ add_tcl_strings(my_tcl_strings);
-+ add_tcl_ints(my_tcl_ints);
-+ add_tcl_coups(my_tcl_coups);
-+ add_tcl_commands(mytcls);
-+ add_tcl_commands(seendebugtcls);
-+ add_tcl_commands(gseentcls);
-+ add_builtins(H_dcc, mydcc);
-+ add_builtins(H_join, seen_join);
-+ add_builtins(H_kick, seen_kick);
-+ add_builtins(H_nick, seen_nick);
-+ add_builtins(H_part, seen_part);
-+ add_builtins(H_sign, seen_sign);
-+ add_builtins(H_sign, seen_sign);
-+ add_builtins(H_splt, seen_splt);
-+ add_builtins(H_rejn, seen_rejn);
-+ add_builtins(H_pub, seen_pub);
-+ add_builtins(H_msg, seen_msg);
-+ add_builtins(H_bot, seen_bot);
-+ read_seens();
-+ add_hook(HOOK_MINUTELY, (Function) gseen_minutely);
-+ add_hook(HOOK_DAILY, (Function) gseen_daily);
-+#if EGG_IS_MIN_VER(10503)
-+ initudef(1, "noseendata", 1);
-+ initudef(1, "quietseens", 1);
-+ initudef(1, "quietaiseens", 1);
-+ initudef(1, "nopubseens", 1);
-+#endif
-+ glob_slang_cmd_list = slang_commands_list_add(glob_slang_cmd_list, slang_text_gseen_command_table);
-+ putlog(LOG_MISC, "*", "gseen.mod v%s loaded.", MODULE_VERSION);
-+ return NULL;
-+}
-diff -Nur src/mod/gseen.mod/gseen.conf src/mod/gseen.mod/gseen.conf
---- src/mod/gseen.mod/gseen.conf 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/gseen.conf 2002-10-26 13:17:54.000000000 +0200
-@@ -0,0 +1,147 @@
-+
-+######
-+#####
-+### General Settings
-+#####
-+######
-+
-+# the file where the seen data will be backuped.
-+# WARNING: set this _before_ the module is loaded.
-+set gseenfile "gseen.dat"
-+
-+# now load the module
-+loadmodule gseen
-+
-+# load the English language file
-+loadseenslang "en" "English" language/gseen.en.lang
-+
-+# load the German language file
-+loadseenslang "de" "Deutsch" language/gseen.de.lang
-+
-+# set the default language to english...
-+set default-slang "en"
-+
-+# ... but let #xwp use the german langfile
-+setchanseenlang #xwp "de"
-+
-+# the char that marks public commands (!seen, etc...)
-+# "" is a valid option
-+set cmdchar "!"
-+
-+# delete data sets that are older than x days
-+set expire-seens 60
-+
-+# only answer x seen requests in y seconds to prevent flooding
-+set max-seens 7:60
-+
-+# tell users if someone was !seen'ing for them
-+set tell-seens 1
-+
-+# check if the user was online under a different nick
-+set fuzzy-search 1
-+
-+# allow user to include wildcards in the search?
-+set wildcard-search 1
-+
-+# break search if there are more than x matches
-+set max-matches 250
-+
-+# forward a request to other bots, if a !seen returned no result?
-+set botnet-seens 1
-+
-+# store channels, which are +secret on the bot as [secret]?
-+set hide-secret-chans 1
-+
-+# backup the seen data every x minutes
-+set save-seens 60
-+
-+######
-+#####
-+### AI Settings
-+#####
-+######
-+
-+# this setting configures on which sentences your bot should
-+# attempt to do an ai-seen. Each of them is a simple wildcard
-+# mask. Set this to "" if you want to deactivate ai-seens or
-+# create more precise masks if the bots reacts too often.
-+set ai-seen-binds {
-+ "${nick}*seen*"
-+ "${botnet-nick}*seen*"
-+ "${nick}*gesehen*"
-+ "${botnet-nick}*gesehen*"
-+}
-+
-+# this is just the same as above, but if triggered it will
-+# not do an ai-seen, but display its seen-stats.
-+set ai-seenstats-binds {
-+ "${nick}*seenstats*"
-+ "${botnet-nick}*seenstats*"
-+}
-+
-+# when doing an AI seen, ignore the following words (otherwise
-+# the bot might give weird answers like "<bot> nick, bot was last seen..." :)
-+set ai-seen-ignore "$nick ${botnet-nick} seen"
-+
-+######
-+#####
-+### special stuff (can be ignored in most cases)
-+#####
-+######
-+
-+# if the user is known by the bot, log their handle instead of the nick
-+# (not recommended, might cause confusion by the users)
-+set use-handles 0
-+
-+######
-+#####
-+### outdated settings (only important for eggdropv1.4 users)
-+#####
-+######
-+
-+# channels where you do not want your bot to reply to public queries
-+set no-pub-seens ""
-+
-+# channels where you want your bot to send replies via notice to the user and
-+# not to the channel
-+set quiet-seens ""
-+
-+# same as quiet-seens but for AI seen
-+set quiet-ai-seens ""
-+
-+# channels where you do not want your bot to log seen data
-+set no-seendata ""
-+
-+
-+###############################################################################
-+# end of configuration
-+# just ignore everything below ^_^
-+###############################################################################
-+
-+bind chjn - * *chjn:gseen
-+bind chpt - * *chpt:gseen
-+
-+catch "unbind pub - !seen *pub:!seen"
-+catch "unbind pub - !seennick *pub:!seennick"
-+catch "unbind pub - !seenstats *pub:!seenstats"
-+bind pub - ${cmdchar}seen *pub:!seen
-+bind pub - ${cmdchar}seennick *pub:!seennick
-+bind pub - ${cmdchar}seenstats *pub:!seenstats
-+
-+foreach bnd [binds pubm] {
-+ if {([lindex $bnd 2] == "*pubm:seen") || ([lindex $bnd 2] == "*pub:!seenstats")} {
-+ unbind [lindex $bnd 0] [lindex $bnd 1] [lindex $bnd 2] [lindex $bnd 4]
-+ }
-+}
-+
-+if {${ai-seen-binds} != ""} {
-+ foreach mask ${ai-seen-binds} {
-+ bind pubm -|- "% [subst $mask]" *pubm:seen
-+ }
-+}
-+
-+if {${ai-seenstats-binds} != ""} {
-+ foreach mask ${ai-seenstats-binds} {
-+ bind pubm -|- "% [subst $mask]" *pub:!seenstats
-+ }
-+}
-diff -Nur src/mod/gseen.mod/language/gseen.de.lang src/mod/gseen.mod/language/gseen.de.lang
---- src/mod/gseen.mod/language/gseen.de.lang 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/language/gseen.de.lang 2002-10-26 13:18:12.000000000 +0200
-@@ -0,0 +1,131 @@
-+#####################################################################
-+#
-+# Deutsche Sprachdatei für GSeen.Mod v1.1.0
-+#
-+# Der Text in dieser Datei kann nach belieben verändert werden. Du
-+# kannst Tags hinzufügen oder entfernen, wie es Dir gefällt. Die Tags
-+# müssen nicht in einer bestimmten Reihenfolge oder Anzahl vorkommen.
-+#
-+# Wenn Du mehr als eine Zeile pro ID angibst, dann wird bei der
-+# Antwort per Zufall eine daraus ausgewählt. (das funktioniert nicht
-+# bei den Zeiteinheiten)
-+#
-+# Falls Du denkst, daß hier noch ein paar wichtige Tags fehlen, dann
-+# schick mir einfach eine email. Vielleicht füge ich sie dann in der
-+# nächsten Version hinzu.
-+#
-+# Eine komplette Liste der Verfügbaren Tags befindet sich am Ende von
-+# slang_gseen_commands.c (leider ohne Erklährungen)
-+#
-+#####################################################################
-+
-+#
-+## Zeiteinheiten
-+#
-+# jeweils in Singular und Plural
-+#
-+D 0 Jahr
-+D 1 Jahre
-+D 2 Woche
-+D 3 Wochen
-+D 4 Tag
-+D 5 Tage
-+D 6 Stunde
-+D 7 Stunden
-+D 8 Minute
-+D 9 Minuten
-+D 10 Sekunde
-+D 11 Sekunden
-+# falls ein üngültiger Zeitwert angegeben war, dann wird dieser Text ausgegeben:
-+D 12 einiger Zeit
-+
-+
-+#
-+## Präfixe
-+#
-+# Dieses Fragment wird jeweils vor eine Antwort gesetzt. Dadurch
-+# ist beispielsweise bei öffentlichen Anfragen ersichtlich, für
-+# wen die Antwort ist.
-+# Achtung: Die Nummer muss auf jeden Fall definiert werden. Sie muss
-+# zwar keinen Text beinhalten, aber wenn sie nicht vorhanden
-+# ist, dann gibt es eine Fehlermeldung
-+
-+# für Antworten, die in den Channel geschrieben werden:
-+10 <?nick/?>,
-+# für Antworten, die per NOTICE an den User geschickt werden:
-+11
-+# für Antworten auf Anfragen, die per "/msg <bot> seen" erfolgt sind:
-+12
-+# und für Antworten auf der Partyline:
-+13
-+
-+#
-+## Fehlermeldungen
-+#
-+54 weißt Du was ein Parameter ist? ^_^
-+54 ich würde Dir ja gerne helfen, aber solange Du nicht sagst, nach wem Du suchst, kann ich nicht viel tun.
-+54 meinst Du nicht, es wäre geschickter zu sagen, nach wem Du überhaupt suchst?
-+54 42.
-+55 sehe ich etwa wie ein Spiegel aus? ^_^
-+55 Spieglein, Spieglein an der Wand...
-+55 leidest Du etwa unter multiplen Persönlichkeiten? *eg*
-+56 also wenn Du <?query/?> jetzt hier nicht sehen kannst, dann brauchst Du sicherlich eine neue Brille ^_^
-+56 ich muss mir unbedingt mal die Tarnkappe von <?query/?> ausleihen. Scheint ja prima zu funktioneren.
-+56 schau Dir bitte nochmal ganz genau an, wer grade alles im Channel ist.
-+57 Tut mir leid, aber Wildcards ('?', oder '*') sind bei der Suche nicht erlaubt.
-+58 Öhm... naja... etwas arg lang, dieser Nick... :)
-+
-+#
-+## Kein Ergebnis
-+#
-+65 Ich kann mich nicht daran erinnern, <?query/?> gesehen zu haben...
-+65 <?query/?>? Hmm... ich bin mir nicht sicher... vielleicht... eventuell... nein, kenne ich nicht.
-+65 der Name sagt mir nichts. Hast Du Dich vielleicht vertippt?
-+66 Ich hab' <?query/?> seit <?laston/?> nicht mehr gesehen.
-+67 Sorry, aber zu deiner Anfrage passt nichts in meiner Datenbank :(
-+68 Autschi, das gab viel zu viele Ergebnisse. Bitte formuliere deine Suche etwas genauer.
-+
-+73 <?query/?> ist grade unter dem Nick "<?othernick/?>" in diesem Channel zu finden.
-+74 <?query/?> ist gerade in <?otherchan/?>.
-+75 Deine Anfrage führte zu genau einem Ergebnis:
-+76 Immerhin <?numresults/?> Treffer ergab deine Anfrage:
-+77 Wow, auf deine Anfrage passen sogar <?numresults/?> Einträge in meiner Datenbank! Dies sind die 5 aktuellsten:
-+
-+#
-+## falls ein anderer Bot etwas gefunden hat:
-+#
-+85 <?remotebot/?> sagt:
-+
-+#
-+## die eigentliche Information
-+#
-+101 Ich habe <?snick/?> (<?shost/?>) zuletzt <?schan/?> vor <?swhen/?> betreten sehen (<?stime/?>). <?snick/?> ist noch immer da.
-+121 Ich habe <?snick/?> (<?shost/?>) zuletzt <?schan/?> vor <?swhen/?> betreten sehen (<?stime/?>), aber <?snick/?> verschwand mysteriöserweise.
-+102 Ich habe <?snick/?> (<?shost/?>) zuletzt <?schan/?> vor <?swhen/?> nach <?spent/?> verchatteter Zeit verlassen sehen (<?stime/?>)
-+103 Ich habe <?snick/?> (<?shost/?>) zuletzt in <?schan/?> gesehen, als er/sie vor <?swhen/?> (<?stime/?>) nach <?spent/?> das IRC verließ ("<?smsg/?>").
-+104 Zuletzt habe ich <?snick/?> (<?shost/?>) vor <?swhen/?> in <?schan/?> gesehen, den Nick zu <?snick2/?> wechselnd. <?snick2/?> ist noch immer dort.
-+124 <?snick/?> (<?shost/?>) was last seen changing his/her nick to <?snick2/?> on <?schan/?> <?swhen/?> ago (<?stime/?>), but <?snick2/?> mysteriously dematerialized.
-+105 Zuletzt habe ich <?snick/?> (<?shost/?>) vor <?swhen/?> in <?schan/?> gesehen, den Nick von <?snick2/?> wechselnd. <?snick/?> ist noch immer dort.
-+125 <?snick/?> (<?shost/?>) was last seen changing his/her nick from <?snick2/?> on <?schan/?> <?swhen/?> ago (<?stime/?>), but <?snick/?> mysteriously dematerialized.
-+106 Zuletzt habe ich <?snick/?> (<?shost/?>) gesehen, als er vor <?swhen/?> (<?stime/?>) von <?punisher/?> aus <?schan/?> gejagt wurde. (<?kickreason/?>)
-+107 <?snick/?> (<?shost/?>) habe ich zuletzt vor <?swhen/?> gesehen, als er/sie von <?schan/?> aus in einem Netsplit verschwand.
-+108 <?snick/?> (<?shost/?>) habe ich zuletzt vor <?swhen/?> gesehen, als er/sie nach einem Netsplit in <?schan/?> zurück kam. <?snick/?> ist noch immer dort.
-+128 <?snick/?> (<?shost/?>) habe ich zuletzt vor <?swhen/?> gesehen, als er/sie nach einem Netsplit in <?schan/?> zurück kam. Allerdings konnte <?snick/?> dem Gott der Netsplits nicht endgültig entkommen und ist wieder verschollen...
-+109 <?snick/?> was last seen joining the botnet channel <?schan/?> on <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+129 <?snick/?> was last seen joining the partyline on <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+110 <?snick/?> was last seen leaving the botnet channel <?schan/?> from <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+130 <?snick/?> was last seen leaving the partyline from <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+140 <?snick/?> (<?shost/?>) was last seen on <?schan/?> <?swhen/?> ago (<?stime/?>).
-+
-+#
-+## Seen-Mitteilungen
-+#
-+170 <?rnick/?> (<?rhost/?>) scheint vor <?rwhen/?> (<?rtime/?>) in <?rchan/?> auf der Suche nach Dir gewesen zu sein.
-+171 <?requests/?> Leute haben sich nach Dir erkundigt:
-+172 Der/die letzte war <?rnick/?> (<?rhost/?>) in <?rchan/?> vor <?rwhen/?> (<?rtime/?>).
-+
-+#
-+## Statistiken
-+#
-+180 Momentan sind <?totalnicks/?> Nicks in meiner Datenbank. Gesamter Speicherverbrauch: <?totalbytes/?> Bytes
-+180 In meiner Datenbank befinden sich <?totalnicks/?> Nicks und verbrauchen <?totalbytes/?> Bytes Speicher.
-diff -Nur src/mod/gseen.mod/language/gseen.en.lang src/mod/gseen.mod/language/gseen.en.lang
---- src/mod/gseen.mod/language/gseen.en.lang 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/language/gseen.en.lang 2002-10-26 13:18:13.000000000 +0200
-@@ -0,0 +1,131 @@
-+#####################################################################
-+#
-+# Default English langfile for GSeen.Mod v1.1.0
-+#
-+# Just edit the text below to fit your needs. You can add or remove
-+# any tag just like you want, they do not need to appear in a special
-+# order (or number).
-+#
-+# If you enter more than one line per ID, then a random one will be
-+# chosen for each reply. (this does not work for the time strings)
-+#
-+# If you think you need more tags, just email me and maybe I'll add
-+# them in the next release.
-+#
-+# A complete list of available Tags can be found at the end of the
-+# file slang_gseen_commands.c (unfortunately, it does not contain any
-+# descriptions for the tags)
-+#
-+#####################################################################
-+
-+#
-+## time string
-+#
-+# each time string in singular and plural
-+#
-+D 0 year
-+D 1 years
-+D 2 week
-+D 3 weeks
-+D 4 day
-+D 5 days
-+D 6 hour
-+D 7 hours
-+D 8 minute
-+D 9 minutes
-+D 10 second
-+D 11 seconds
-+# if an invalid time value was supplied, output the following string
-+D 12 some time
-+
-+#
-+## Prefixes
-+#
-+# These are the prefixes of the replies. By default, there's only
-+# a prefix for public requests (so you know for whom the answer is),
-+# but you can also define prefixes for other requests.
-+
-+# for replies in the channel:
-+10 <?nick/?>,
-+# for replies via notice:
-+11
-+# for replies via PRIVMSG
-+12
-+# for replies on the partyline
-+13
-+
-+#
-+## error messages
-+#
-+54 do you know what a parameter is?
-+54 don't you think it would be more reasonable to say for whom you are searching?
-+54 42.
-+55 do I look like a mirror? ^_^
-+55 mirror mirror on the wall...
-+55 do you have a split personality? *eg*
-+56 if you can't see <?query/?> here right now, you probably need new glasses. ^_^
-+56 please look a bit closer at the memberlist of this channel.
-+57 I'm sorry, but wildcards ('?' or '*') are not allowed in a search.
-+58 Hum... don't you think this nick is a bit long? ^_^
-+58 you know that the length of nicks is limited, don't you?
-+
-+#
-+## no result
-+#
-+65 I don't remember seeing <?query/?>.
-+65 <?query/?>? hmm... I'm trying to remember... maybe... I'm not sure... no. I don't remember <?query/?>.
-+66 I haven't seen <?query/?> for <?laston/?>.
-+67 I found no matches to your query.
-+67 I'm sorry, but your search didn't return any results.
-+68 Ouch, your search returned way too many matches. Please refine it.
-+
-+#
-+## victim is online
-+#
-+73 <?query/?> is <?othernick/?>, who is on this channel right now.
-+74 <?query/?> is on <?otherchan/?> right now.
-+
-+#
-+## results found
-+#
-+75 I found one match to your query:
-+76 I found <?numresults/?> matches to your query:
-+77 I found <?numresults/?> matches to your query. These are the 5 most recent ones:
-+
-+#
-+## results found by another bot in the botnet
-+#
-+85 <?remotebot/?> says:
-+
-+#
-+## the core info
-+#
-+101 <?snick/?> (<?shost/?>) was last seen joining <?schan/?> <?swhen/?> ago (<?stime/?>). <?snick/?> is still there.
-+121 <?snick/?> (<?shost/?>) was last seen joining <?schan/?> <?swhen/?> ago (<?stime/?>), but <?snick/?> mysteriously dematerialized.
-+102 <?snick/?> (<?shost/?>) was last seen parting <?schan/?> <?swhen/?> ago (<?stime/?>), after spending <?spent/?> there.
-+103 <?snick/?> (<?shost/?>) was last seen quitting <?schan/?> <?swhen/?> ago (<?stime/?>) stating "<?smsg/?>" after spending <?spent/?> there.
-+104 <?snick/?> (<?shost/?>) was last seen changing his/her nick to <?snick2/?> on <?schan/?> <?swhen/?> ago (<?stime/?>). <?snick2/?> is still there.
-+124 <?snick/?> (<?shost/?>) was last seen changing his/her nick to <?snick2/?> on <?schan/?> <?swhen/?> ago (<?stime/?>), but <?snick2/?> mysteriously dematerialized.
-+105 <?snick/?> (<?shost/?>) was last seen changing his/her nick from <?snick2/?> on <?schan/?> <?swhen/?> ago (<?stime/?>). <?snick/?> is still there.
-+125 <?snick/?> (<?shost/?>) was last seen changing his/her nick from <?snick2/?> on <?schan/?> <?swhen/?> ago (<?stime/?>), but <?snick/?> mysteriously dematerialized.
-+106 <?snick/?> (<?shost/?>) was last seen being kicked from <?schan/?> by <?punisher/?> (<?kickreason/?>) <?swhen/?> ago (<?stime/?>), after spending <?spent/?> there.
-+107 <?snick/?> (<?shost/?>) was last seen splitting from <?schan/?> <?swhen/?> ago (<?stime/?>), after spending <?spent/?> there.
-+108 <?snick/?> (<?shost/?>) was last seen rejoining <?schan/?> from a netsplit <?swhen/?> ago (<?stime/?>) <?snick/?> is still there.
-+128 <?snick/?> (<?shost/?>) was last seen rejoining <?schan/?> from a netsplit <?swhen/?> ago (<?stime/?>), but the god of netsplits didn't let him escape, so he's not here now.
-+109 <?snick/?> was last seen joining the botnet channel <?schan/?> on <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+129 <?snick/?> was last seen joining the partyline on <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+110 <?snick/?> was last seen leaving the botnet channel <?schan/?> from <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+130 <?snick/?> was last seen leaving the partyline from <?bnbot/?> <?swhen/?> ago (<?stime/?>).
-+140 <?snick/?> (<?shost/?>) was last seen on <?schan/?> <?swhen/?> ago (<?stime/?>).
-+
-+#
-+## seen notification
-+#
-+170 <?rnick/?> (<?rhost/?>) was looking for you on <?rchan/?> <?rwhen/?> ago (<?rtime/?>).
-+171 There have been <?requests/?> users looking for you:
-+172 The last one was <?rnick/?> (<?rhost/?>) on <?rchan/?> <?rwhen/?> ago (<?rtime/?>).
-+
-+#
-+## seen stats
-+#
-+180 I'm currently tracking <?totalnicks/?> nicks using <?totalbytes/?> bytes.
-diff -Nur src/mod/gseen.mod/gseen.h src/mod/gseen.mod/gseen.h
---- src/mod/gseen.mod/gseen.h 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/gseen.h 2002-10-26 13:17:55.000000000 +0200
-@@ -0,0 +1,157 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+/* #define USE_MEMDEBUG 1 */
-+
-+#define SEEN_JOIN 1
-+#define SEEN_PART 2
-+#define SEEN_SIGN 3
-+#define SEEN_NICK 4
-+#define SEEN_NCKF 5
-+#define SEEN_KICK 6
-+#define SEEN_SPLT 7
-+#define SEEN_REJN 8
-+#define SEEN_CHPT 9
-+#define SEEN_CHJN 10
-+
-+typedef struct gseen_data {
-+ int type;
-+ char *nick;
-+ char *host;
-+ char *chan;
-+ char *msg;
-+ time_t when;
-+ int spent;
-+} seendat;
-+
-+typedef struct gseen_result {
-+ struct gseen_result *next;
-+ seendat *seen;
-+} gseenres;
-+
-+typedef struct gseen_requests {
-+ struct gseen_requests *next;
-+ char *who;
-+ char *host;
-+ char *chan;
-+ time_t when;
-+} seenreq_by;
-+
-+typedef struct gseen_request {
-+ struct gseen_request *next;
-+ char *nick;
-+ struct gseen_requests *by;
-+} seenreq;
-+
-+typedef struct gseen_ignorewords {
-+ struct gseen_ignorewords *next;
-+ char *word;
-+} ignoredword;
-+
-+#ifdef MAKING_GSEEN
-+static int gseen_expmem();
-+static void free_gseen();
-+static int get_spent(char *, char *);
-+static void write_seens();
-+static void read_seens();
-+static char *do_seen(char *, char *, char *, char *, int);
-+static void add_seenresult(seendat *);
-+static int expmem_seenresults();
-+static void free_seenresults();
-+static void sortresults();
-+static char *do_seennick(seendat *);
-+static int onchan(char *, char *);
-+static char *handonchan(char *, char *);
-+static struct chanset_t *onanychan(char *);
-+static struct chanset_t *handonanychan(char *);
-+static char *do_seenstats();
-+static void add_seenreq(char *, char *, char *, char *, time_t);
-+static int expmem_seenreq();
-+static void free_seenreq();
-+static void sortrequests(seenreq *);
-+static void report_seenreq(char *, char *);
-+static int count_seenreq(seenreq_by *b);
-+static int expmem_ignoredwords();
-+static void free_ignoredwords();
-+static void add_ignoredword(char *word);
-+static int word_is_ignored(char *word);
-+static void purge_seens();
-+static int seenflood();
-+static int secretchan(char *);
-+static int nopub(char *);
-+static int quietseen(char *);
-+static int quietaiseens(char *);
-+static int nolog(char *);
-+static void start_seentime_calc();
-+static void end_seentime_calc();
-+#endif
-+
-+
-+#ifdef MAKING_GSEEN
-+
-+// tree stuff
-+static void maskstricthost(const char *, char *);
-+#endif
-+
-+// interface for webseen
-+#define WS_OK 0
-+#define WS_NORESULT 1
-+#define WS_NOPARAM 2
-+#define WS_NOWILDCARDS 3
-+#define WS_TOOLONGNICK 4
-+#define WS_TOOMANYMATCHES 5
-+#define WS_TOOLONGHOST 6
-+
-+#ifndef MAKING_GSEEN
-+#define findseens ((gseenres *(*)(char *, int *, int))gseen_funcs[4])
-+#define free_seenresults ((void (*)())gseen_funcs[5])
-+#define gseen_duration ((char *(*)(int))gseen_funcs[6])
-+#define numresults (*(int *)(gseen_funcs[12]))
-+#define fuzzy_search (*(int *)(gseen_funcs[13]))
-+#define numseens (*(int *)(gseen_funcs[15]))
-+#define glob_total_queries (*(int *)(gseen_funcs[16]))
-+#define glob_total_searchtime (*(double *)(gseen_funcs[17]))
-+#define gseen_numversion (*(int *)(gseen_funcs[19]))
-+#else
-+static gseenres *findseens(char *, int *, int);
-+static char *gseen_duration(int);
-+#endif
-+
-+#ifdef MAKING_GSEEN
-+
-+#ifdef malloc
-+#undef malloc
-+#endif
-+#ifdef free
-+#undef free
-+#endif
-+#ifdef realloc
-+#undef realloc
-+#endif
-+
-+#ifdef USE_MEMDEBUG
-+#define my_malloc nmalloc
-+#define my_free nfree
-+#define my_realloc nrealloc
-+#else
-+#define my_malloc malloc
-+#define my_free free
-+#define my_realloc realloc
-+#endif
-+
-+#endif
-diff -Nur src/mod/gseen.mod/gseencmds.c src/mod/gseen.mod/gseencmds.c
---- src/mod/gseen.mod/gseencmds.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/gseencmds.c 2002-10-26 13:17:56.000000000 +0200
-@@ -0,0 +1,420 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#define PREFIX_LENGTH 20
-+
-+static char reply_prefix[PREFIX_LENGTH + 1];
-+#define set_prefix(x) strncpy(reply_prefix, x, PREFIX_LENGTH); \
-+ reply_prefix[PREFIX_LENGTH] = 0;
-+
-+static int seenflood()
-+{
-+ if (!maxseen_thr || !maxseen_time)
-+ return 0;
-+ if ((now - seenflood_time) > maxseen_time) {
-+ seenflood_time = now;
-+ seenflood_thr = 0;
-+ }
-+ seenflood_thr++;
-+ if (seenflood_thr > maxseen_thr)
-+ return 1;
-+ else
-+ return 0;
-+}
-+
-+static int nopub(char *chan)
-+{
-+ char buf[121], *b;
-+
-+ Context;
-+ strncpy(buf, no_pub, 120);
-+ buf[120] = 0;
-+ b = buf;
-+ while (b[0])
-+ if (!strcasecmp(chan, newsplit(&b)))
-+ return 1;
-+#if EGG_IS_MIN_VER(10503)
-+ if (ngetudef("nopubseens", chan))
-+ return 1;
-+#endif
-+ return 0;
-+}
-+
-+static int quietseen(char *chan)
-+{
-+ char buf[121], *b;
-+
-+ Context;
-+ strncpy(buf, quiet_seen, 120);
-+ buf[120] = 0;
-+ b = buf;
-+ while (b[0])
-+ if (!strcasecmp(chan, newsplit(&b)))
-+ return 1;
-+#if EGG_IS_MIN_VER(10503)
-+ if (ngetudef("quietseens", chan))
-+ return 1;
-+#endif
-+ return 0;
-+}
-+
-+static int cmd_seen(struct userrec *u, int idx, char *par)
-+{
-+ char *query;
-+
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, default_slang);
-+ glob_nick = dcc[idx].nick;
-+ query = newsplit(&par);
-+ glob_query = query;
-+ set_prefix(SLDCCPREFIX);
-+ putlog(LOG_CMDS, "*", "#%s# seen %s", dcc[idx].nick, par);
-+ dprintf(idx, "%s%s\n", reply_prefix, do_seen(query, dcc[idx].nick,
-+ dcc[idx].host, "[partyline]", botnet_seen));
-+ return 0;
-+}
-+
-+static int cmd_seenstats(struct userrec *u, int idx, char *par)
-+{
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, default_slang);
-+ glob_nick = dcc[idx].nick;
-+ set_prefix(SLDCCPREFIX);
-+ putlog(LOG_CMDS, "*", "#%s# seenstats", dcc[idx].nick);
-+ dprintf(idx, "%s%s\n", reply_prefix, do_seenstats());
-+ return 0;
-+}
-+
-+static int cmd_purgeseens(struct userrec *u, int idx, char *par)
-+{
-+ Context;
-+ purge_seens();
-+ putlog(LOG_CMDS, "*", "#%s# purgeseens", dcc[idx].nick);
-+ return 0;
-+}
-+
-+static int pub_seen(char *nick, char *host, char *hand,
-+ char *channel, char *text)
-+{
-+ char *dest;
-+#if EGG_IS_MIN_VER(10500)
-+ struct chanset_t *chan;
-+#endif
-+
-+ Context;
-+ if (seenflood() || nopub(channel))
-+ return 0;
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, channel));
-+ glob_nick = nick;
-+ putlog(LOG_CMDS, "*", "<<%s>> !%s! seen %s", nick, hand, text);
-+ if (quietseen(channel)) {
-+ set_prefix(SLNOTPREFIX);
-+ dprintf(DP_HELP, "NOTICE %s :%s%s\n", nick, reply_prefix,
-+ do_seen(newsplit(&text), nick, host, channel, botnet_seen));
-+ return 0;
-+ }
-+#if EGG_IS_MIN_VER(10500)
-+ chan = findchan_by_dname(channel);
-+ if (chan)
-+ dest = chan->name;
-+ else
-+ dest = channel;
-+#else
-+ dest = channel;
-+#endif
-+ set_prefix(SLPUBPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", dest, reply_prefix,
-+ do_seen(newsplit(&text), nick, host, channel, botnet_seen));
-+ return 0;
-+}
-+
-+static int pub_seenstats(char *nick, char *host, char *hand,
-+ char *channel, char *text)
-+{
-+ char *dest;
-+#if EGG_IS_MIN_VER(10500)
-+ struct chanset_t *chan;
-+#endif
-+
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ if (nopub(channel))
-+ return 0;
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, channel));
-+ glob_nick = nick;
-+ putlog(LOG_CMDS, "*", "<<%s>> !%s! seenstats", nick, hand);
-+ if (quietseen(channel)) {
-+ set_prefix(SLNOTPREFIX);
-+ dprintf(DP_HELP, "NOTICE %s :%s%s\n", nick, reply_prefix, do_seenstats());
-+ return 0;
-+ }
-+#if EGG_IS_MIN_VER(10500)
-+ chan = findchan_by_dname(channel);
-+ if (chan)
-+ dest = chan->name;
-+ else
-+ dest = channel;
-+#else
-+ dest = channel;
-+#endif
-+ set_prefix(SLPUBPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", dest, reply_prefix, do_seenstats());
-+ return 1;
-+}
-+
-+static int msg_seen(char *nick, char *uhost, struct userrec *u, char *text)
-+{
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ reset_global_vars();
-+ glob_slang = slang_getbynick(coreslangs, nick);
-+ glob_nick = nick;
-+ putlog(LOG_CMDS, "*", "(%s!%s) !%s! seen %s", nick, uhost, u ? u->handle : "*", text);
-+ set_prefix(SLMSGPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", nick, reply_prefix,
-+ do_seen(newsplit(&text), nick, uhost, "[/msg]", botnet_seen));
-+ return 1;
-+}
-+
-+static int pub_seennick(char *nick, char *host, char *hand,
-+ char *channel, char *text)
-+{
-+ seendat *l;
-+ char *dest;
-+#if EGG_IS_MIN_VER(10500)
-+ struct chanset_t *chan;
-+#endif
-+
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ if (nopub(channel))
-+ return 0;
-+ putlog(LOG_CMDS, "*", "<<%s>> !%s! seennick %s", nick, hand, text);
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, channel));
-+ glob_nick = nick;
-+#if EGG_IS_MIN_VER(10500)
-+ chan = findchan_by_dname(channel);
-+ if (chan)
-+ dest = chan->name;
-+ else
-+ dest = channel;
-+#else
-+ dest = channel;
-+#endif
-+ text = newsplit(&text);
-+ l = findseen(text);
-+ if (!l) {
-+ glob_query = text;
-+ if (quietseen(channel)) {
-+ set_prefix(SLNOTPREFIX);
-+ dprintf(DP_HELP, "NOTICE %s :%s%s\n", nick, reply_prefix, SLNOTSEEN);
-+ } else {
-+ set_prefix(SLPUBPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", dest, reply_prefix, SLNOTSEEN);
-+ }
-+ return 0;
-+ }
-+ if (quietseen(channel)) {
-+ set_prefix(SLNOTPREFIX);
-+ dprintf(DP_HELP, "NOTICE %s :%s%s\n", nick, reply_prefix, do_seennick(l));
-+ } else {
-+ set_prefix(SLPUBPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", dest, reply_prefix, do_seennick(l));
-+ }
-+ return 0;
-+}
-+
-+static int msg_seennick(char *nick, char *uhost, struct userrec *u, char *text)
-+{
-+ seendat *l;
-+
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ putlog(LOG_CMDS, "*", "(%s!%s) !%s! seennick %s", nick, uhost, u ? u->handle : "*", text);
-+ reset_global_vars();
-+ glob_slang = slang_getbynick(coreslangs, nick);
-+ glob_nick = nick;
-+ set_prefix(SLMSGPREFIX);
-+ text = newsplit(&text);
-+ l = findseen(text);
-+ if (!l) {
-+ glob_query = text;
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", nick, reply_prefix, SLNOTSEEN);
-+ return 0;
-+ }
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s\n", nick, reply_prefix, do_seennick(l));
-+ return 0;
-+}
-+
-+static int cmd_seennick(struct userrec *u, int idx, char *text)
-+{
-+ seendat *l;
-+
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ putlog(LOG_CMDS, "*", "#%s# seennick %s", dcc[idx].nick, text);
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, default_slang);
-+ glob_nick = dcc[idx].nick;
-+ set_prefix(SLMSGPREFIX);
-+ text = newsplit(&text);
-+ l = findseen(text);
-+ if (!l) {
-+ glob_query = text;
-+ dprintf(idx, "%s%s\n", reply_prefix, SLNOTSEEN);
-+ return 0;
-+ }
-+ dprintf(idx, "%s%s\n", reply_prefix, do_seennick(l));
-+ return 0;
-+}
-+
-+static int bot_gseen_req(char *bot, char *code, char *par)
-+{
-+ char *mask, *nick, *uhost, *chan, *reply;
-+ char tosend[256];
-+ int i;
-+
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ i = nextbot(bot);
-+ if (i < 0) {
-+ debug1("Couldn't answer botnet-seen-request from %s: no such bot", bot);
-+ return 0;
-+ }
-+ mask = newsplit(&par);
-+ nick = newsplit(&par);
-+ uhost = newsplit(&par);
-+ chan = newsplit(&par);
-+ reset_global_vars();
-+ glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, chan));
-+ glob_nick = nick;
-+ reply = do_seen(mask, nick, uhost, chan, -1);
-+ if (!reply)
-+ return 0;
-+ if ((strlen(nick) + strlen(chan) + strlen(reply)) < 255) {
-+ sprintf(tosend, "gseen_rep %s %s %s", nick, chan, reply);
-+ botnet_send_zapf(i, botnetnick, bot, tosend);
-+ }
-+ return 0;
-+}
-+
-+static int bot_gseen_rep(char *bot, char *code, char *par)
-+{
-+ char *nick, *chan, *reply;
-+ int i;
-+
-+ Context;
-+ if (seenflood())
-+ return 0;
-+ if (!bnsnick || !bnschan) {
-+ if (bnsnick)
-+ nfree(bnsnick);
-+ if (bnschan)
-+ nfree(bnschan);
-+ bnsnick = bnschan = NULL;
-+ return 0;
-+ }
-+ nick = newsplit(&par);
-+ chan = newsplit(&par);
-+ reset_global_vars();
-+ glob_remotebot = bot;
-+ glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, chan));
-+ glob_nick = nick;
-+ reply = par;
-+ if (strcmp(nick, bnsnick) || strcmp(chan, bnschan))
-+ return 0; /* unwanted reply */
-+ if (findchan(chan)) {
-+ if (nopub(chan)) {
-+ nfree(bnsnick);
-+ nfree(bnschan);
-+ bnsnick = bnschan = NULL;
-+ debug1("%s is nopub, bns-reply dropped", chan);
-+ return 0;
-+ }
-+ if (quietseen(chan)) {
-+ set_prefix(SLNOTPREFIX);
-+ dprintf(DP_HELP, "NOTICE %s :%s%s%s\n", nick, reply_prefix, SLRBOTSAYS, reply);
-+ } else {
-+ set_prefix(SLPUBPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s%s\n", chan, reply_prefix, SLRBOTSAYS, reply);
-+ }
-+ } else if (!strcmp(chan, "[/msg]")) {
-+ set_prefix(SLMSGPREFIX);
-+ dprintf(DP_HELP, "PRIVMSG %s :%s%s%s\n", nick, reply_prefix, SLRBOTSAYS, reply);
-+ } else if (!strcmp(chan, "[partyline]")) {
-+ for (i = 0; i < dcc_total; i++) {
-+ if ((!strcasecmp(nick, dcc[i].nick)) &&
-+ (dcc[i].type->flags & DCT_SIMUL)) {
-+ set_prefix(SLDCCPREFIX);
-+ dprintf(i, "%s%s%s\n", reply_prefix, SLRBOTSAYS, reply);
-+ break;
-+ }
-+ }
-+ } else
-+ debug1("Couldn't send received bns answer, no such chan %s", chan);
-+ nfree(bnsnick);
-+ nfree(bnschan);
-+ bnsnick = bnschan = NULL;
-+ return 0;
-+}
-+
-+static cmd_t mydcc[] =
-+{
-+ {"seen", "-|-", cmd_seen, NULL},
-+ {"seenstats", "-|-", cmd_seenstats, NULL},
-+ {"purgeseens", "m", cmd_purgeseens, NULL},
-+ {"seennick", "-|-", cmd_seennick, NULL},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_pub[] =
-+{
-+ {"!seen", "", pub_seen, 0},
-+ {"!seenstats", "", pub_seenstats, 0},
-+ {"!seennick", "", pub_seennick, 0},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_msg[] =
-+{
-+ {"seen", "", msg_seen, 0},
-+ {"seennick", "", msg_seennick, 0},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_bot[] =
-+{
-+ {"gseen_req", "", bot_gseen_req, 0},
-+ {"gseen_rep", "", bot_gseen_rep, 0},
-+ {0, 0, 0, 0}
-+};
-diff -Nur src/mod/gseen.mod/misc.c src/mod/gseen.mod/misc.c
---- src/mod/gseen.mod/misc.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/misc.c 2002-10-26 13:17:57.000000000 +0200
-@@ -0,0 +1,116 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+/* maskstricthost():
-+ * basically the same as maskhost() from src/misc.c, but _never_ stripts
-+ * "~+-^=" off the host
-+ * maskhost() version: * $Id: misc.c,v 1.30 2000/10/27 19:27:32 fabian Exp $
-+ */
-+static void maskstricthost(const char *s, char *nw)
-+{
-+ register const char *p, *q, *e, *f;
-+ int i;
-+
-+ *nw++ = '*';
-+ *nw++ = '!';
-+ p = (q = strchr(s, '!')) ? q + 1 : s;
-+ /* Strip of any nick, if a username is found, use last 8 chars */
-+ if ((q = strchr(p, '@'))) {
-+ int fl = 0;
-+
-+ if ((q - p) > 9) {
-+ nw[0] = '*';
-+ p = q - 7;
-+ i = 1;
-+ } else
-+ i = 0;
-+ while (*p != '@') {
-+ if (!fl && strchr("~+-^=", *p)) {
-+// if (strict_host)
-+ nw[i] = '?';
-+// else
-+// i--;
-+ } else
-+ nw[i] = *p;
-+ fl++;
-+ p++;
-+ i++;
-+ }
-+ nw[i++] = '@';
-+ q++;
-+ } else {
-+ nw[0] = '*';
-+ nw[1] = '@';
-+ i = 2;
-+ q = s;
-+ }
-+ nw += i;
-+ e = NULL;
-+ /* Now q points to the hostname, i point to where to put the mask */
-+ if ((!(p = strchr(q, '.')) || !(e = strchr(p + 1, '.'))) && !strchr(q, ':'))
-+ /* TLD or 2 part host */
-+ strcpy(nw, q);
-+ else {
-+ if (e == NULL) { /* IPv6 address? */
-+ const char *mask_str;
-+
-+ f = strrchr(q, ':');
-+ if (strchr(f, '.')) { /* IPv4 wrapped in an IPv6? */
-+ f = strrchr(f, '.');
-+ mask_str = ".*";
-+ } else /* ... no, true IPv6. */
-+ mask_str = ":*";
-+ strncpy(nw, q, f - q);
-+ /* No need to nw[f-q] = 0 here, as the strcpy below will
-+ * terminate the string for us.
-+ */
-+ nw += (f - q);
-+ strcpy(nw, mask_str);
-+ } else {
-+ for (f = e; *f; f++);
-+ f--;
-+ if (*f >= '0' && *f <= '9') { /* Numeric IP address */
-+ while (*f != '.')
-+ f--;
-+ strncpy(nw, q, f - q);
-+ /* No need to nw[f-q] = 0 here, as the strcpy below will
-+ * terminate the string for us.
-+ */
-+ nw += (f - q);
-+ strcpy(nw, ".*");
-+ } else { /* Normal host >= 3 parts */
-+ /* a.b.c -> *.b.c
-+ * a.b.c.d -> *.b.c.d if tld is a country (2 chars)
-+ * OR *.c.d if tld is com/edu/etc (3 chars)
-+ * a.b.c.d.e -> *.c.d.e etc
-+ */
-+ const char *x = strchr(e + 1, '.');
-+
-+ if (!x)
-+ x = p;
-+ else if (strchr(x + 1, '.'))
-+ x = e;
-+ else if (strlen(x) == 3)
-+ x = p;
-+ else
-+ x = e;
-+ sprintf(nw, "*%s", x);
-+ }
-+ }
-+ }
-+}
-diff -Nur src/mod/gseen.mod/seenlang.h src/mod/gseen.mod/seenlang.h
---- src/mod/gseen.mod/seenlang.h 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/seenlang.h 2002-10-26 13:17:58.000000000 +0200
-@@ -0,0 +1,61 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#define SLPUBPREFIX getslang(10)
-+#define SLNOTPREFIX getslang(11)
-+#define SLMSGPREFIX getslang(12)
-+#define SLDCCPREFIX getslang(13)
-+
-+#define SLNOPARAM getslang(54)
-+#define SLMIRROR getslang(55)
-+#define SLONCHAN getslang(56)
-+#define SLNOWILDCARDS getslang(57)
-+#define SLTOOLONGNICK getslang(58)
-+
-+#define SLNOTSEEN getslang(65)
-+#define SLPOORSEEN getslang(66)
-+#define SLNOMATCH getslang(67)
-+#define SLTOOMANYMATCHES getslang(68)
-+
-+#define SLHANDONCHAN getslang(73)
-+#define SLONOTHERCHAN getslang(74)
-+#define SLONEMATCH getslang(75)
-+#define SLLITTLEMATCHES getslang(76)
-+#define SLMANYMATCHES getslang(77)
-+
-+#define SLRBOTSAYS getslang(85)
-+
-+#define SLYEAR getdur(0)
-+#define SLYEARS getdur(1)
-+#define SLWEEK getdur(2)
-+#define SLWEEKS getdur(3)
-+#define SLDAY getdur(4)
-+#define SLDAYS getdur(5)
-+#define SLHOUR getdur(6)
-+#define SLHOURS getdur(7)
-+#define SLMINUTE getdur(8)
-+#define SLMINUTES getdur(9)
-+#define SLSECOND getdur(10)
-+#define SLSECONDS getdur(11)
-+#define SLSOMETIME getdur(12)
-+
-+#define SLONELOOK getslang(170)
-+#define SLMORELOOKS getslang(171)
-+#define SLLASTLOOK getslang(172)
-+
-+#define SLSEENSTATS getslang(180)
-diff -Nur src/mod/gseen.mod/seentree.c src/mod/gseen.mod/seentree.c
---- src/mod/gseen.mod/seentree.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/seentree.c 2002-10-26 13:18:10.000000000 +0200
-@@ -0,0 +1,213 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+static struct generic_binary_tree seentree;
-+
-+static void seentree_init();
-+static int seentree_expmem();
-+static void seentree_free();
-+static int compareseens(void *, void *);
-+static int expmemseen(void *);
-+static void add_seen(int, char *, char *, char *, char *,
-+ time_t, int);
-+static void freeseen(void *);
-+static seendat *findseen(char *);
-+static void wildmatch_seens(char *, char *, int);
-+static void process_wildmatch_seens(void *);
-+static void write_seen_tree(void *);
-+static void purge_seen_tree(void *);
-+static int count_seens();
-+static void _count_seens(void *);
-+
-+
-+static void seentree_init()
-+{
-+ seentree.root = NULL;
-+ seentree.comparedata = compareseens;
-+ seentree.expmemdata = expmemseen;
-+ seentree.freedata = freeseen;
-+}
-+
-+static int seentree_expmem()
-+{
-+ return btree_expmem(&seentree);
-+}
-+
-+static void seentree_free()
-+{
-+ btree_freetree(&seentree);
-+ seentree.root = NULL;
-+}
-+
-+static int compareseens(void *first, void *second)
-+{
-+ return rfc_casecmp(((seendat *) first)->nick, ((seendat *) second)->nick);
-+}
-+
-+// add another entry to the tree
-+static void add_seen(int type, char *nick, char *host, char *chan, char *msg,
-+ time_t when, int spent)
-+{
-+ seendat *newseen;
-+
-+ newseen = nmalloc(sizeof(seendat));
-+ newseen->type = type;
-+ newseen->nick = nmalloc(strlen(nick) + 1);
-+ strcpy(newseen->nick, nick);
-+ newseen->host = nmalloc(strlen(host) + 1);
-+ strcpy(newseen->host, host);
-+ newseen->chan = nmalloc(strlen(chan) + 1);
-+ strcpy(newseen->chan, chan);
-+ newseen->msg = nmalloc(strlen(msg) + 1);
-+ strcpy(newseen->msg, msg);
-+ newseen->when = when;
-+ newseen->spent = spent;
-+ btree_add(&seentree, newseen);
-+}
-+
-+static void freeseen(void *what)
-+{
-+ seendat *s = (seendat *) what;
-+
-+ Assert(s);
-+ Assert(s->nick);
-+ Assert(s->host);
-+ Assert(s->chan);
-+ Assert(s->msg);
-+
-+ nfree(s->nick);
-+ nfree(s->host);
-+ nfree(s->chan);
-+ nfree(s->msg);
-+ nfree(s);
-+}
-+
-+static int expmemseen(void *what)
-+{
-+ int size = 0;
-+ seendat *d = (seendat *) what;
-+
-+ size += sizeof(seendat);
-+ size += strlen(d->nick) + 1;
-+ size += strlen(d->host) + 1;
-+ size += strlen(d->chan) + 1;
-+ size += strlen(d->msg) + 1;
-+ return size;
-+}
-+
-+// finds a seen entry in the tree
-+seendat findseen_temp;
-+static seendat *findseen(char *nick)
-+{
-+ findseen_temp.nick = nick;
-+ return btree_get(&seentree, &findseen_temp);
-+}
-+
-+// function to find all nicks that match a host
-+// (calls btree_getall() which calls a target function for each item)
-+// host: user's hostmask (used if search query doesn't contain any wildcards)
-+// mask: search mask
-+// wild: defines if we want to use the mask, or host for the search
-+static char *wildmatch_host, *wildmatch_mask;
-+int wildmatch_wild;
-+static void wildmatch_seens(char *host, char *mask, int wild)
-+{
-+ wildmatch_host = host;
-+ wildmatch_mask = mask;
-+ wildmatch_wild = wild;
-+ btree_getall(&seentree, process_wildmatch_seens);
-+}
-+
-+/* process_wildmatch_seens():
-+ * gets called from the binary tree for each existing item.
-+ */
-+static void process_wildmatch_seens(void *data)
-+{
-+ seendat *s = (seendat *) data;
-+
-+ if ((numresults > max_matches) && (max_matches > 0)) // Don't return too many
-+ return; // matches...
-+ if (!wildmatch_wild) {
-+ if (wild_match(wildmatch_host, s->host))
-+ add_seenresult(s);
-+ } else {
-+ temp_wildmatch_host = my_realloc(temp_wildmatch_host, strlen(s->nick) + 1 + strlen(s->host) + 1);
-+ strcpy(temp_wildmatch_host, s->nick);
-+ strcat(temp_wildmatch_host, "!");
-+ strcat(temp_wildmatch_host, s->host);
-+ if (wild_match(wildmatch_mask, s->nick) || wild_match(wildmatch_mask, temp_wildmatch_host))
-+ add_seenresult(s);
-+ }
-+}
-+
-+// write seendata in the datafile
-+FILE *write_seen_tree_target;
-+static void write_seen_tree(void *data)
-+{
-+ seendat *node = (seendat *) data;
-+
-+ /* format: "! nick host chan type when spent msg" */
-+ fprintf(write_seen_tree_target, "! %s %s %s %d %lu %d %s\n", node->nick,
-+ node->host, node->chan, node->type, node->when, node->spent,
-+ node->msg);
-+}
-+
-+// recursive function to remove old data
-+// QUESTION: What happens if one of the nodes get moved by killseen()?
-+// Possible bug/crash?
-+// I think it should not be a problem. When killseen() is called the
-+// first time, recursion already reached its end and no pointers
-+// are accessed anymore. But I'm not sure... maybe I'm wrong.
-+static void purge_seen_tree(void *data)
-+{
-+ seendat *node = (seendat *) data;
-+
-+ if ((now - node->when) > (expire_seens * 86400)) {
-+ debug1("seen data for %s has expired.", node->nick);
-+ btree_remove(&seentree, node);
-+ }
-+}
-+
-+// counts the number of nicks in the database
-+static int count_seens_temp;
-+static int count_seens()
-+{
-+ count_seens_temp = 0;
-+ btree_getall(&seentree, _count_seens);
-+ return count_seens_temp;
-+}
-+
-+static void _count_seens(void *node)
-+{
-+ count_seens_temp++;
-+}
-+
-+static int tcl_killseen STDVAR
-+{
-+ Context;
-+ BADARGS(2, 2, " nick");
-+ findseen_temp.nick = argv[1];
-+ btree_remove(&seentree, &findseen_temp);
-+ return TCL_OK;
-+}
-+
-+static tcl_cmds seendebugtcls[] =
-+{
-+ {"killseen", tcl_killseen},
-+ {0, 0}
-+};
-diff -Nur src/mod/gseen.mod/sensors.c src/mod/gseen.mod/sensors.c
---- src/mod/gseen.mod/sensors.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/sensors.c 2002-10-26 13:18:00.000000000 +0200
-@@ -0,0 +1,273 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+static int get_spent(char *nick, char *chan)
-+{
-+ struct chanset_t *ch = NULL;
-+ memberlist *m = NULL;
-+
-+ int spent;
-+ ch = findchan_by_dname(chan);
-+ if (ch)
-+ m = ismember(ch, nick);
-+ if (m && m->joined)
-+ spent = now - m->joined;
-+ else
-+ spent = -1;
-+ return spent;
-+}
-+
-+static int secretchan(char *chan)
-+{
-+ struct chanset_t *ch;
-+
-+ ch = findchan_by_dname(chan);
-+ if (!ch)
-+ return 0;
-+ if (ch->status & CHAN_SECRET)
-+ return 1;
-+ return 0;
-+}
-+
-+static int nolog(char *chan)
-+{
-+ char buf[121], *b;
-+
-+ Context;
-+ strncpy(buf, no_log, 120);
-+ buf[120] = 0;
-+ b = buf;
-+ while (b[0])
-+ if (!strcasecmp(chan, newsplit(&b)))
-+ return 1;
-+#if EGG_IS_MIN_VER(10503)
-+ if (ngetudef("noseendata", chan))
-+ return 1;
-+#endif
-+ return 0;
-+}
-+
-+static int gseen_join(char *nick, char *uhost, char *hand, char *chan)
-+{
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ if (secretchan(chan))
-+ chan = buf;
-+ add_seen(SEEN_JOIN, nick, uhost, chan, "", now, get_spent(nick, chan));
-+ report_seenreq(chan, nick);
-+ if ((hand[0] == '*') && strcasecmp(nick, hand))
-+ report_seenreq(chan, hand);
-+ return 0;
-+}
-+
-+static int gseen_kick(char *nick, char *uhost, char *hand, char *chan,
-+ char *victim, char *reason)
-+{
-+ struct chanset_t *ch = NULL;
-+ memberlist *m = NULL;
-+ char msg[1024], *s;
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ ch = findchan_by_dname(chan);
-+ if (!ch) {
-+ debug2("Unable to seen %s getting kicked from %s", victim, chan);
-+ return 0;
-+ }
-+ if (secretchan(chan))
-+ chan = buf;
-+ s = msg;
-+ s[0] = 0;
-+ m = ismember(ch, victim);
-+ if (!m) {
-+ debug2("Unable to seen %s getting kicked from %s", victim, chan);
-+ return 0;
-+ }
-+ if ((strlen(nick) + strlen(reason) + 2) < 1024)
-+ sprintf(s, "%s %s", nick, reason);
-+ add_seen(SEEN_KICK, victim, m->userhost, chan, s, now,
-+ get_spent(victim, chan));
-+ return 0;
-+}
-+
-+static int gseen_nick(char *nick, char *uhost, char *hand, char *chan,
-+ char *newnick)
-+{
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ if (secretchan(chan))
-+ chan = buf;
-+ add_seen(SEEN_NICK, nick, uhost, chan, newnick, now, get_spent(nick, chan));
-+ if (!(use_handles && (hand[0] != '*')))
-+ add_seen(SEEN_NCKF, newnick, uhost, chan, nick, now, get_spent(nick, chan));
-+ report_seenreq(chan, newnick);
-+ if ((hand[0] != '*') && strcasecmp(newnick, hand))
-+ report_seenreq(chan, hand);
-+ return 0;
-+}
-+
-+#if EGG_IS_MIN_VER(10502)
-+static int gseen_part(char *nick, char *uhost, char *hand, char *chan,
-+ char *reason)
-+{
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ if (secretchan(chan))
-+ chan = buf;
-+ add_seen(SEEN_PART, nick, uhost, chan, reason, now, get_spent(nick, chan));
-+ return 0;
-+}
-+#else
-+static int gseen_part(char *nick, char *uhost, char *hand, char *chan)
-+{
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ if (secretchan(chan))
-+ chan = buf;
-+ add_seen(SEEN_PART, nick, uhost, chan, "", now, get_spent(nick, chan));
-+ return 0;
-+}
-+#endif
-+
-+static int gseen_sign(char *nick, char *uhost, char *hand, char *chan,
-+ char *reason)
-+{
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ if (secretchan(chan))
-+ chan = buf;
-+ add_seen(SEEN_SIGN, nick, uhost, chan, reason, now, get_spent(nick, chan));
-+ return 0;
-+}
-+
-+static int gseen_splt(char *nick, char *uhost, char *hand, char *chan)
-+{
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ if (secretchan(chan))
-+ chan = buf;
-+ add_seen(SEEN_SPLT, nick, uhost, chan, "", now, get_spent(nick, chan));
-+ return 0;
-+}
-+
-+static int gseen_rejn(char *nick, char *uhost, char *hand, char *chan)
-+{
-+ char buf[10] = "[secret]";
-+
-+ Context;
-+ if (nolog(chan))
-+ return 0;
-+ if (use_handles && (hand[0] != '*'))
-+ nick = hand;
-+ if (secretchan(chan))
-+ chan = buf;
-+ add_seen(SEEN_REJN, nick, uhost, chan, "", now, get_spent(nick, chan));
-+ return 0;
-+}
-+
-+static int gseen_chjn STDVAR
-+{
-+ Context;
-+ BADARGS(7, 7, " bot hand chan flag idx host");
-+ add_seen(SEEN_CHJN, argv[2], argv[6], argv[3], argv[1], now, -1);
-+ return 0;
-+}
-+
-+static int gseen_chpt STDVAR
-+{
-+ Context;
-+ BADARGS(5, 5, " bot hand idx chan");
-+ add_seen(SEEN_CHPT, argv[2], "unknown", argv[4], argv[1], now, -1);
-+ return 0;
-+}
-+
-+static cmd_t seen_kick[] =
-+{
-+ {"*", "", (Function) gseen_kick, "gseen"},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_nick[] =
-+{
-+ {"*", "", (Function) gseen_nick, "gseen"},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_join[] =
-+{
-+ {"*", "", (Function) gseen_join, "gseen"},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_part[] =
-+{
-+ {"*", "", (Function) gseen_part, "gseen"},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_sign[] =
-+{
-+ {"*", "", (Function) gseen_sign, "gseen"},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_splt[] =
-+{
-+ {"*", "", (Function) gseen_splt, "gseen"},
-+ {0, 0, 0, 0}
-+};
-+
-+static cmd_t seen_rejn[] =
-+{
-+ {"*", "", (Function) gseen_rejn, "gseen"},
-+ {0, 0, 0, 0}
-+};
-diff -Nur src/mod/gseen.mod/slang.c src/mod/gseen.mod/slang.c
---- src/mod/gseen.mod/slang.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/slang.c 2002-10-26 13:18:03.000000000 +0200
-@@ -0,0 +1,309 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+static struct slang_header *slang_find(struct slang_header *, char *);
-+
-+#include "slang_text.c"
-+#include "slang_multitext.c"
-+#include "slang_ids.c"
-+#ifndef SLANG_NOTYPES
-+#include "slang_types.c"
-+#endif
-+#include "slang_duration.c"
-+#ifndef SLANG_NOFACTS
-+#include "slang_facts_places.c"
-+#include "slang_facts.c"
-+#endif
-+#include "slang_chanlang.c"
-+
-+
-+struct slang_header {
-+ struct slang_header *next;
-+ char *lang;
-+ char *desc;
-+ struct slang_id *ids;
-+#ifndef SLANG_NOTYPES
-+ struct slang_type *types;
-+#endif
-+ struct slang_duration *durations;
-+};
-+
-+static void slang_glob_init()
-+{
-+ glob_slang_cmd_list = NULL;
-+}
-+
-+static int slang_glob_expmem()
-+{
-+ return slang_commands_list_expmem(glob_slang_cmd_list);
-+}
-+
-+static void slang_glob_free()
-+{
-+ slang_commands_list_free(glob_slang_cmd_list);
-+ glob_slang_cmd_list = NULL;
-+}
-+
-+static struct slang_header *slang_create(struct slang_header *list, char *lang, char *desc)
-+{
-+ struct slang_header *nslang, *l;
-+
-+ Assert(lang);
-+ debug2("Creating language '%s' starting by %d", lang, (int) list);
-+ for (nslang = list; nslang; nslang = nslang->next)
-+ if (!strcasecmp(nslang->lang, lang))
-+ return list;
-+ nslang = nmalloc(sizeof(struct slang_header));
-+ nslang->next = NULL;
-+ nslang->desc = NULL;
-+ nslang->lang = nmalloc(strlen(lang) + 1);
-+ strcpy(nslang->lang, lang);
-+ nslang->desc = nmalloc(strlen(desc) + 1);
-+ strcpy(nslang->desc, desc);
-+ nslang->ids = NULL;
-+#ifndef SLANG_NOTYPES
-+ nslang->types = NULL;
-+#endif
-+ nslang->durations = NULL;
-+ for (l = list; l && l->next; l = l->next);
-+ if (l)
-+ l->next = nslang;
-+ else {
-+ Assert(!list);
-+ list = nslang;
-+ }
-+ return list;
-+}
-+
-+static int slang_expmem(struct slang_header *what)
-+{
-+ int size = 0;
-+
-+ while (what) {
-+ size += sizeof(struct slang_header);
-+ size += strlen(what->lang) + 1;
-+ size += strlen(what->desc) + 1;
-+ size += slang_id_expmem(what->ids);
-+#ifndef SLANG_NOTYPES
-+ size += slang_type_expmem(what->types);
-+#endif
-+ size += slang_duration_expmem(what->durations);
-+ what = what->next;
-+ }
-+ return size;
-+}
-+
-+static void slang_free(struct slang_header *what)
-+{
-+ struct slang_header *next;
-+
-+ while (what) {
-+ next = what->next;
-+ slang_id_free(what->ids);
-+#ifndef SLANG_NOTYPES
-+ slang_type_free(what->types);
-+#endif
-+ slang_duration_free(what->durations);
-+ nfree(what->lang);
-+ nfree(what->desc);
-+ nfree(what);
-+ what = next;
-+ }
-+}
-+
-+static int slang_load(struct slang_header *slang, char *filename)
-+{
-+ FILE *f;
-+ char *buffer, *s;
-+ char *cmd, *sid, *strtol_ret;
-+#ifndef SLANG_NOTYPES
-+ char *type;
-+#endif
-+ int line, id;
-+
-+ Assert(slang);
-+ putlog(LOG_MISC, "*", "Loading language \"%s\" from %s...", slang->lang, filename);
-+ f = fopen(filename, "r");
-+ if (!f) {
-+ putlog(LOG_MISC, "*", "Couldn't open slangfile \"%s\"!", filename);
-+ return 0;
-+ }
-+ buffer = nmalloc(2000);
-+ line = 0;
-+ while (!feof(f)) {
-+ s = buffer;
-+ if (fgets(s, 2000, f)) {
-+ line++;
-+ // at first, kill those stupid line feeds and carriage returns...
-+ if (s[strlen(s) - 1] == '\n')
-+ s[strlen(s) - 1] = 0;
-+ if (s[strlen(s) - 1] == '\r')
-+ s[strlen(s) - 1] = 0;
-+ if (!s[0])
-+ continue;
-+ cmd = newsplit(&s);
-+
-+ if (!strcasecmp(cmd, "T")) {
-+#ifndef SLANG_NOTYPES
-+ type = newsplit(&s);
-+ slang->types = slang_type_add(slang->types, type, s);
-+#endif
-+ } else if (!strcasecmp(cmd, "D")) {
-+ sid = newsplit(&s);
-+ id = strtol(sid, &strtol_ret, 10);
-+ if (strtol_ret == sid) {
-+ putlog(LOG_MISC, "*", "ERROR in slangfile \"%s\", line %d: %s is not a valid "
-+ "duration index!", filename, line, sid);
-+ continue;
-+ }
-+ slang->durations = slang_duration_add(slang->durations, id, s);
-+ } else {
-+ id = strtol(cmd, &strtol_ret, 10);
-+ if (strtol_ret == cmd)
-+ continue;
-+ slang->ids = slang_id_add(slang->ids, id, s);
-+ }
-+ }
-+ }
-+ fclose(f);
-+ nfree(buffer);
-+ return 1;
-+}
-+
-+static struct slang_header *slang_find(struct slang_header *where, char *language)
-+{
-+ struct slang_header *slang = NULL;
-+
-+ // at first, search for the specified language
-+ for (slang = where; slang; slang = slang->next)
-+ if (!strcasecmp(slang->lang, language))
-+ return slang;
-+ // oops... language seems to be invalid. Let's find the default.
-+ Assert(default_slang);
-+ for (slang = where; slang; slang = slang->next)
-+ if (!strcasecmp(slang->lang, default_slang))
-+ return slang;
-+ // default_slang wasn't found either? *sigh*
-+ // Let's return the first known language then.
-+ return where;
-+}
-+
-+#ifndef SLANG_NOVALIDATE
-+/* slang_valid():
-+ * check if the given language is a valid one
-+ */
-+static int slang_valid(struct slang_header *where, char *language)
-+{
-+ struct slang_header *slang = NULL;
-+
-+ for (slang = where; slang; slang = slang->next)
-+ if (!strcasecmp(slang->lang, language))
-+ return 1;
-+ return 0;
-+}
-+#endif
-+
-+static char getslang_error[12];
-+static char *getslang(int id)
-+{
-+ char *text;
-+
-+ if (!glob_slang) {
-+ putlog(LOG_MISC, "*", "WARNING! No language selected! (getslang())");
-+ return "NOLANG";
-+ }
-+ text = slang_id_get(glob_slang->ids, id);
-+ if (!text) {
-+ snprintf(getslang_error, sizeof(getslang_error), "SLANG%d", id);
-+ return getslang_error;
-+ }
-+ return text;
-+}
-+
-+static char *getdur(int idx)
-+{
-+ char *text;
-+
-+ Assert((idx >= 0) && (idx < DURATIONS));
-+ if (!glob_slang) {
-+ putlog(LOG_MISC, "*", "WARNING! No language selected! (getdur())");
-+ return "NOLANG";
-+ }
-+ text = slang_duration_get(glob_slang->durations, idx);
-+ if (!text) {
-+ snprintf(getslang_error, sizeof(getslang_error), "DUR%d", idx);
-+ return getslang_error;
-+ }
-+ return text;
-+}
-+
-+#ifndef SLANG_NOTYPES
-+static char *getslangtype(char *type)
-+{
-+ char *stype;
-+
-+ if (!glob_slang) {
-+ putlog(LOG_MISC, "*", "WARNING! No language selected! (getslangtype())");
-+ return "NOLANG";
-+ }
-+ stype = slang_type_get(glob_slang->types, type);
-+ if (stype)
-+ return stype;
-+ else
-+ return type;
-+}
-+
-+static int slangtypetoi(char *slangtype)
-+{
-+ char *type;
-+
-+ if (!glob_slang) {
-+ putlog(LOG_MISC, "*", "WARNING! No language selected! (slangtypetoi())");
-+ return T_ERROR;
-+ }
-+ type = slang_type_slang2type(glob_slang->types, slangtype);
-+ if (type) {
-+ debug1("type: %s", type);
-+ return typetoi(type);
-+ } else
-+ return typetoi(slangtype);
-+}
-+#endif
-+
-+#ifndef SLANG_NOGETALL
-+static char *getslang_first(int id)
-+{
-+ char *text;
-+
-+ if (!glob_slang) {
-+ putlog(LOG_MISC, "*", "WARNING! No language selected! (getslang())");
-+ return "NOLANG";
-+ }
-+ text = slang_id_get_first(glob_slang->ids, id);
-+ if (!text) {
-+ snprintf(getslang_error, sizeof(getslang_error), "SLANG%d", id);
-+ return getslang_error;
-+ }
-+ return text;
-+}
-+
-+static char *getslang_next()
-+{
-+ return slang_id_get_next();
-+}
-+#endif
-diff -Nur src/mod/gseen.mod/slang_chanlang.c src/mod/gseen.mod/slang_chanlang.c
---- src/mod/gseen.mod/slang_chanlang.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/slang_chanlang.c 2002-10-26 13:18:02.000000000 +0200
-@@ -0,0 +1,113 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+struct slang_chanlang {
-+ struct slang_chanlang *next;
-+ char *chan;
-+ char *lang;
-+};
-+
-+static struct slang_chanlang *chanlangs = NULL;
-+
-+static struct slang_chanlang *slang_chanlang_add(struct slang_chanlang *, char *, char *);
-+static int slang_chanlang_expmem(struct slang_chanlang *);
-+static void slang_chanlang_free(struct slang_chanlang *);
-+static char *slang_chanlang_get(struct slang_chanlang *, char *);
-+
-+static struct slang_chanlang *slang_chanlang_add(struct slang_chanlang *where, char *chan, char *lang)
-+{
-+ struct slang_chanlang *item;
-+
-+ for (item = where; item; item = item->next)
-+ if (!rfc_casecmp(item->chan, chan))
-+ break;
-+ if (!item) {
-+ item = nmalloc(sizeof(struct slang_chanlang));
-+ item->chan = nmalloc(strlen(chan) + 1);
-+ strcpy(item->chan, chan);
-+ item->lang = nmalloc(strlen(lang) + 1);
-+ strcpy(item->lang, lang);
-+ item->next = where;
-+ where = item;
-+ } else {
-+ Assert(item->lang);
-+ item->lang = nrealloc(item->lang, strlen(lang) + 1);
-+ strcpy(item->lang, lang);
-+ }
-+ return where;
-+}
-+
-+static int slang_chanlang_expmem(struct slang_chanlang *what)
-+{
-+ int size = 0;
-+
-+ while (what) {
-+ Assert(what);
-+ Assert(what->chan);
-+ Assert(what->lang);
-+ size += sizeof(struct slang_chanlang);
-+ size += strlen(what->chan) + 1;
-+ size += strlen(what->lang) + 1;
-+ what = what->next;
-+ }
-+ return size;
-+}
-+
-+static void slang_chanlang_free(struct slang_chanlang *what)
-+{
-+ struct slang_chanlang *next;
-+
-+ while (what) {
-+ Assert(what);
-+ Assert(what->chan);
-+ Assert(what->lang);
-+ next = what->next;
-+ nfree(what->chan);
-+ nfree(what->lang);
-+ nfree(what);
-+ what = next;
-+ }
-+}
-+
-+static char *slang_chanlang_get(struct slang_chanlang *where, char *chan)
-+{
-+ while (where) {
-+ if (!rfc_casecmp(where->chan, chan))
-+ return where->lang;
-+ where = where->next;
-+ }
-+ return default_slang;
-+}
-+
-+/* slang_getbynick():
-+ * tries to find an appropriate language for nick by searching
-+ * him on a channel and using the language of this channel.
-+ */
-+static struct slang_header *slang_getbynick(struct slang_header *where, char *nick)
-+{
-+ struct chanset_t *chan;
-+
-+ for (chan = chanset; chan; chan = chan->next)
-+ if (ismember(chan, nick))
-+#if EGG_IS_MIN_VER(10500)
-+ return slang_find(where, slang_chanlang_get(chanlangs, chan->dname));
-+#else
-+ return slang_find(where, slang_chanlang_get(chanlangs, chan->name));
-+#endif
-+ return slang_find(where, default_slang);
-+}
-diff -Nur src/mod/gseen.mod/slang_duration.c src/mod/gseen.mod/slang_duration.c
---- src/mod/gseen.mod/slang_duration.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/slang_duration.c 2002-10-26 13:18:01.000000000 +0200
-@@ -0,0 +1,82 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#define DURATIONS 13
-+
-+struct slang_duration {
-+ char *durs[DURATIONS];
-+};
-+
-+static struct slang_duration *slang_duration_add(struct slang_duration *where, int idx, char *text)
-+{
-+ int i;
-+
-+ if ((idx < 0) || (idx >= DURATIONS)) {
-+ putlog(LOG_MISC, "*", "Warning: Invalid duration index \"%d\".", idx);
-+ return where;
-+ }
-+ debug2("Adding duration[%d]: %s", idx, text);
-+ if (!where) {
-+ where = nmalloc(sizeof(struct slang_duration));
-+ for (i = 0; i < DURATIONS; i++)
-+ where->durs[i] = NULL;
-+ }
-+ if (where->durs[idx])
-+ nfree(where->durs[idx]);
-+ where->durs[idx] = nmalloc(strlen(text) + 1);
-+ strcpy(where->durs[idx], text);
-+ return where;
-+}
-+
-+static int slang_duration_expmem(struct slang_duration *what)
-+{
-+ int i, size = 0;
-+
-+ if (!what)
-+ return 0;
-+ size += sizeof(struct slang_duration);
-+ for (i = 0; i < DURATIONS; i++)
-+ if (what->durs[i])
-+ size += strlen(what->durs[i]) + 1;
-+ return size;
-+}
-+
-+static void slang_duration_free(struct slang_duration *what)
-+{
-+ int i;
-+
-+ if (what) {
-+ for (i = 0; i < DURATIONS; i++)
-+ if (what->durs[i])
-+ nfree(what->durs[i]);
-+ nfree(what);
-+ }
-+}
-+
-+static char *slang_duration_get(struct slang_duration *where, int idx)
-+{
-+ if (!where) {
-+ debug0("no where");
-+ return NULL;
-+ }
-+ if ((idx < 0) || (idx >= DURATIONS)) {
-+ debug1("invalid duration index: %d", idx);
-+ return NULL;
-+ }
-+ return where->durs[idx];
-+}
-diff -Nur src/mod/gseen.mod/slang_gseen_commands.c src/mod/gseen.mod/slang_gseen_commands.c
---- src/mod/gseen.mod/slang_gseen_commands.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/slang_gseen_commands.c 2002-10-26 13:18:06.000000000 +0200
-@@ -0,0 +1,235 @@
-+static void slang_send_botnick()
-+{
-+ strncat(slang_text_buf, botname, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_query()
-+{
-+ if (glob_query)
-+ strncat(slang_text_buf, glob_query, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_laston()
-+{
-+ if (glob_laston)
-+ strncat(slang_text_buf, glob_laston, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_otherchan()
-+{
-+ if (glob_otherchan)
-+ strncat(slang_text_buf, glob_otherchan, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_othernick()
-+{
-+ if (glob_othernick)
-+ strncat(slang_text_buf, glob_othernick, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_remotebot()
-+{
-+ if (glob_remotebot)
-+ strncat(slang_text_buf, glob_remotebot, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_snick()
-+{
-+ if (glob_seendat)
-+ strncat(slang_text_buf, glob_seendat->nick, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_shost()
-+{
-+ if (glob_seendat)
-+ strncat(slang_text_buf, glob_seendat->host, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_schan()
-+{
-+ if (glob_seendat)
-+ strncat(slang_text_buf, glob_seendat->chan, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_swhen()
-+{
-+ char *dur;
-+
-+ if (glob_seendat) {
-+ dur = gseen_duration(now - glob_seendat->when);
-+ strncat(slang_text_buf, dur, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_stime()
-+{
-+ time_t tt;
-+ char t[20];
-+
-+ if (glob_seendat) {
-+ tt = glob_seendat->when;
-+ strftime(t, 19, "%d.%m. %H:%M", localtime(&tt));
-+ strncat(slang_text_buf, t, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_spent()
-+{
-+ char *dur;
-+
-+ if (glob_seendat) {
-+ dur = gseen_duration(glob_seendat->spent);
-+ strncat(slang_text_buf, dur, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_smsg()
-+{
-+ if (glob_seendat)
-+ strncat(slang_text_buf, glob_seendat->msg, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_numresults()
-+{
-+ char buf[7];
-+
-+ snprintf(buf, sizeof(buf), "%d", numresults);
-+ strncat(slang_text_buf, buf, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_punisher()
-+{
-+ char *reason;
-+ int len;
-+
-+ if (glob_seendat) {
-+ reason = strchr(glob_seendat->msg, ' ');
-+ if (!reason)
-+ strncat(slang_text_buf, glob_seendat->msg, sizeof(slang_text_buf));
-+ else {
-+ len = (int) reason - (int) glob_seendat->msg;
-+ strncat(slang_text_buf, glob_seendat->msg, (sizeof(slang_text_buf) < len) ? sizeof(slang_text_buf) : len);
-+ }
-+ }
-+}
-+
-+static void slang_send_kickreason()
-+{
-+ char *reason;
-+
-+ if (glob_seendat) {
-+ reason = strchr(glob_seendat->msg, ' ');
-+ if (reason)
-+ strncat(slang_text_buf, reason, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_rnick()
-+{
-+ if (glob_seenrequest) {
-+ Assert(glob_seenrequest->by);
-+ Assert(glob_seenrequest->by->who);
-+ strncat(slang_text_buf, glob_seenrequest->by->who, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_rchan()
-+{
-+ if (glob_seenrequest) {
-+ Assert(glob_seenrequest->by);
-+ Assert(glob_seenrequest->by->chan);
-+ strncat(slang_text_buf, glob_seenrequest->by->chan, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_rhost()
-+{
-+ if (glob_seenrequest) {
-+ Assert(glob_seenrequest->by);
-+ Assert(glob_seenrequest->by->host);
-+ strncat(slang_text_buf, glob_seenrequest->by->host, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_rtime()
-+{
-+ time_t tt;
-+ char t[20];
-+
-+ if (glob_seenrequest) {
-+ Assert(glob_seenrequest->by);
-+ tt = glob_seenrequest->by->when;
-+ strftime(t, sizeof(t), "%d.%m. %H:%M", localtime(&tt));
-+ strncat(slang_text_buf, t, sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_rwhen()
-+{
-+ if (glob_seenrequest) {
-+ Assert(glob_seenrequest->by);
-+ strncat(slang_text_buf, gseen_duration(now - glob_seenrequest->by->when), sizeof(slang_text_buf));
-+ }
-+}
-+
-+static void slang_send_requests()
-+{
-+ char buf[7];
-+
-+ snprintf(buf, sizeof(buf), "%d", glob_seenrequests);
-+ strncat(slang_text_buf, buf, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_totalnicks()
-+{
-+ char buf[7];
-+
-+ snprintf(buf, sizeof(buf), "%d", glob_totalnicks);
-+ strncat(slang_text_buf, buf, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_totalbytes()
-+{
-+ char buf[20];
-+
-+ snprintf(buf, sizeof(buf), "%d", glob_totalbytes);
-+ strncat(slang_text_buf, buf, sizeof(slang_text_buf));
-+}
-+
-+static void slang_send_nick()
-+{
-+ if (glob_nick)
-+ strncat(slang_text_buf, glob_nick, sizeof(slang_text_buf));
-+}
-+
-+struct slang_text_commands slang_text_gseen_command_table[] =
-+{
-+ {"botnick", slang_send_botnick},
-+ {"query", slang_send_query},
-+ {"laston", slang_send_laston},
-+ {"otherchan", slang_send_otherchan},
-+ {"othernick", slang_send_othernick},
-+ {"remotebot", slang_send_remotebot},
-+ {"snick", slang_send_snick},
-+ {"swhen", slang_send_swhen},
-+ {"stime", slang_send_stime},
-+ {"shost", slang_send_shost},
-+ {"schan", slang_send_schan},
-+ {"spent", slang_send_spent},
-+ {"smsg", slang_send_smsg},
-+ {"numresults", slang_send_numresults},
-+ {"snick2", slang_send_smsg},
-+ {"bnbot", slang_send_smsg},
-+ {"punisher", slang_send_punisher},
-+ {"kickreason", slang_send_kickreason},
-+ {"rnick", slang_send_rnick},
-+ {"rchan", slang_send_rchan},
-+ {"rhost", slang_send_rhost},
-+ {"rtime", slang_send_rtime},
-+ {"rwhen", slang_send_rwhen},
-+ {"requests", slang_send_requests},
-+ {"totalnicks", slang_send_totalnicks},
-+ {"totalbytes", slang_send_totalbytes},
-+ {"nick", slang_send_nick},
-+ {0, 0}
-+};
-diff -Nur src/mod/gseen.mod/slang_ids.c src/mod/gseen.mod/slang_ids.c
---- src/mod/gseen.mod/slang_ids.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/slang_ids.c 2002-10-26 13:18:04.000000000 +0200
-@@ -0,0 +1,104 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+struct slang_id {
-+ struct slang_id *next;
-+ int id;
-+ struct slang_multitext *mtext;
-+};
-+
-+static struct slang_id* slang_id_add(struct slang_id *, int, char *);
-+static int slang_id_expmem(struct slang_id *);
-+static void slang_id_free(struct slang_id *);
-+static char *slang_id_get(struct slang_id *, int);
-+
-+static struct slang_id* slang_id_add(struct slang_id *where, int id, char *text)
-+{
-+ struct slang_id *newitem;
-+
-+ newitem = NULL;
-+ if (where) {
-+ for (newitem = where; newitem; newitem = newitem->next)
-+ if (newitem->id == id)
-+ break;
-+ }
-+ if (!newitem) {
-+ newitem = nmalloc(sizeof(struct slang_id));
-+ newitem->next = NULL;
-+ newitem->id = id;
-+ newitem->mtext = NULL;
-+ if (where)
-+ newitem->next = where;
-+ else
-+ newitem->next = NULL;
-+ where = newitem;
-+ }
-+ newitem->mtext = slang_mtext_add(newitem->mtext, text);
-+ return where;
-+}
-+
-+static int slang_id_expmem(struct slang_id *what)
-+{
-+ int size = 0;
-+
-+ for (; what; what = what->next) {
-+ size += sizeof(struct slang_id);
-+ size += slang_multitext_expmem(what->mtext);
-+ }
-+ return size;
-+}
-+
-+static void slang_id_free(struct slang_id *what)
-+{
-+ struct slang_id *next;
-+
-+ while (what) {
-+ next = what->next;
-+ slang_multitext_free(what->mtext);
-+ nfree(what);
-+ what = next;
-+ }
-+}
-+
-+static char *slang_id_get(struct slang_id *where, int i)
-+{
-+ while (where) {
-+ if (where->id == i)
-+ return slang_multitext_getrandomtext(where->mtext);
-+ where = where->next;
-+ }
-+ return NULL;
-+}
-+
-+#ifndef SLANG_NOGETALL
-+static char *slang_id_get_first(struct slang_id *where, int id)
-+{
-+ while (where) {
-+ if (where->id == id) {
-+ return slang_multitext_get_first(where->mtext);
-+ }
-+ where = where->next;
-+ }
-+ return NULL;
-+}
-+
-+static char *slang_id_get_next()
-+{
-+ return slang_multitext_get_next();
-+}
-+#endif
-diff -Nur src/mod/gseen.mod/slang_multitext.c src/mod/gseen.mod/slang_multitext.c
---- src/mod/gseen.mod/slang_multitext.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/slang_multitext.c 2002-10-26 13:18:05.000000000 +0200
-@@ -0,0 +1,151 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+struct slang_mt_content {
-+ struct slang_mt_content *next;
-+ struct slang_text *text;
-+};
-+
-+struct slang_multitext {
-+ int nr;
-+ struct slang_mt_content *contents;
-+};
-+
-+static struct slang_multitext *slang_mtext_add(struct slang_multitext *, char *);
-+static int slang_multitext_expmem(struct slang_multitext *);
-+static void slang_multitext_free(struct slang_multitext *);
-+static char *slang_multitext_getrandomtext(struct slang_multitext *);
-+#ifndef SLANG_NOTYPES
-+static struct slang_text *slang_multitext_find(struct slang_multitext *, char *);
-+#endif
-+#ifndef SLANG_NOGETALL
-+static char *slang_multitext_get_first(struct slang_multitext *);
-+static char *slang_multitext_get_next();
-+#endif
-+
-+static struct slang_multitext *slang_mtext_add(struct slang_multitext *where, char *text)
-+{
-+ struct slang_mt_content *oc, *nc;
-+
-+ if (!where) {
-+ where = nmalloc(sizeof(struct slang_multitext));
-+ where->nr = 0;
-+ where->contents = NULL;
-+ }
-+ nc = nmalloc(sizeof(struct slang_mt_content));
-+ nc->next = NULL;
-+ nc->text = slang_text_parse(text);
-+ for (oc = where->contents; oc && oc->next; oc = oc->next);
-+ if (oc) {
-+ Assert(!oc->next);
-+ oc->next = nc;
-+ } else
-+ where->contents = nc;
-+ where->nr++;
-+ return where;
-+}
-+
-+static int slang_multitext_expmem(struct slang_multitext *what)
-+{
-+ struct slang_mt_content *content;
-+ int size = 0;
-+
-+ if (!what) {
-+ debug0("WARNING! slang_multitext_expmem() called with NULL pointer!");
-+ return 0;
-+ }
-+ size += sizeof(struct slang_multitext);
-+ for (content = what->contents; content; content = content->next) {
-+ size += sizeof(struct slang_mt_content);
-+ size += slang_text_expmem(content->text);
-+ }
-+ return size;
-+}
-+
-+static void slang_multitext_free(struct slang_multitext *what)
-+{
-+ struct slang_mt_content *content, *next;
-+
-+ if (!what) {
-+ debug0("WARNING! slang_multitext_free() called with NULL pointer!");
-+ return;
-+ }
-+ content = what->contents;
-+ while (content) {
-+ next = content->next;
-+ slang_text_free(content->text);
-+ nfree(content);
-+ content = next;
-+ }
-+ nfree(what);
-+}
-+
-+static char *slang_multitext_getrandomtext(struct slang_multitext *where)
-+{
-+ struct slang_mt_content *content;
-+ unsigned long x;
-+
-+ if (!where)
-+ return NULL;
-+ x = random() % where->nr;
-+ for (content = where->contents; content; content = content->next)
-+ if (!x)
-+ return slang_text_get(content->text);
-+ else
-+ x--;
-+ // we should never reach this part
-+ debug0("warning: getrandomtext didn't find anything!");
-+ return NULL;
-+}
-+
-+#ifndef SLANG_NOTYPES
-+static struct slang_text *slang_multitext_find(struct slang_multitext *where, char *what)
-+{
-+ struct slang_mt_content *content;
-+
-+ Assert(where);
-+ for (content = where->contents; content; content = content->next) {
-+ Assert(content->text);
-+ if (!slang_text_strcasecmp(content->text, what))
-+ return content->text;
-+ }
-+ return NULL;
-+}
-+#endif
-+
-+#ifndef SLANG_NOGETALL
-+static struct slang_mt_content *glob_mtext_content;
-+static char *slang_multitext_get_first(struct slang_multitext *where)
-+{
-+ Assert(where);
-+ glob_mtext_content = where->contents;
-+ if (glob_mtext_content)
-+ return slang_text_get(glob_mtext_content->text);
-+ else
-+ return NULL;
-+}
-+
-+static char *slang_multitext_get_next()
-+{
-+ glob_mtext_content = glob_mtext_content->next;
-+ if (glob_mtext_content)
-+ return slang_text_get(glob_mtext_content->text);
-+ else
-+ return NULL;
-+}
-+#endif
-diff -Nur src/mod/gseen.mod/slang_text.c src/mod/gseen.mod/slang_text.c
---- src/mod/gseen.mod/slang_text.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/slang_text.c 2002-10-26 13:18:07.000000000 +0200
-@@ -0,0 +1,200 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+struct slang_text {
-+ struct slang_text *next;
-+ char *string;
-+ void (*command) ();
-+};
-+
-+struct slang_text_commands {
-+ char *command;
-+ void (*targetfunc) ();
-+};
-+
-+struct slang_command_list {
-+ struct slang_command_list *next;
-+ struct slang_text_commands *commands;
-+};
-+
-+static struct slang_text *slang_text_parse(char *);
-+static struct slang_text *slang_text_create(struct slang_text *);
-+static void slang_text_add_string(struct slang_text *, char *);
-+static void slang_text_add_command(struct slang_text *, char *);
-+static void slang_text_free(struct slang_text *);
-+static int slang_text_expmem(struct slang_text *);
-+static char *slang_text_get(struct slang_text *);
-+#ifndef SLANG_NOTYPES
-+static int slang_text_strcasecmp(struct slang_text *, char *);
-+#endif
-+
-+static struct slang_text *slang_text_parse(char *text)
-+{
-+ char *cmdstart, *cmdend;
-+ struct slang_text *firstitem, *item;
-+
-+ firstitem = slang_text_create(NULL);
-+ item = firstitem;
-+ while ((cmdstart = strstr(text, "<?"))) {
-+ cmdstart[0] = 0;
-+ slang_text_add_string(item, text);
-+ item = slang_text_create(item);
-+ text += 2;
-+ cmdstart += 2;
-+ cmdend = strstr(cmdstart, "/?>");
-+ if (!cmdend) {
-+ putlog(LOG_MISC, "*", "ERROR parsing slang text: unterminated command \"%s\"!", cmdstart);
-+ break;
-+ }
-+ cmdend[0] = 0;
-+ slang_text_add_command(item, cmdstart);
-+ item = slang_text_create(item);
-+ text = cmdend + 3;
-+ }
-+ slang_text_add_string(item, text);
-+ return firstitem;
-+}
-+
-+static struct slang_text *slang_text_create(struct slang_text *where)
-+{
-+ struct slang_text *newpart;
-+
-+ newpart = nmalloc(sizeof(struct slang_text));
-+ newpart->next = NULL;
-+ newpart->string = NULL;
-+ newpart->command = NULL;
-+ while (where && where->next)
-+ where = where->next;
-+ if (where)
-+ where->next = newpart;
-+ return newpart;
-+}
-+
-+static void slang_text_add_string(struct slang_text *item, char *s)
-+{
-+ Assert(item);
-+ Assert(!item->string);
-+ item->string = nmalloc(strlen(s) + 1);
-+ strcpy(item->string, s);
-+}
-+
-+static void slang_text_free(struct slang_text *item)
-+{
-+ if (!item)
-+ return;
-+ slang_text_free(item->next);
-+ if (item->string)
-+ nfree(item->string);
-+ nfree(item);
-+}
-+
-+static int slang_text_expmem(struct slang_text *item)
-+{
-+ int size = 0;
-+
-+ while (item) {
-+ size += sizeof(struct slang_text);
-+ if (item->string)
-+ size += strlen(item->string) + 1;
-+ item = item->next;
-+ }
-+ return size;
-+}
-+
-+#ifndef SLANG_NOTYPES
-+static int slang_text_strcasecmp(struct slang_text *item, char *text)
-+{
-+ Assert(item);
-+ debug2("s_t_sc: '%s', '%s'", text, item->string);
-+ if (item->command || item->next)
-+ return 1;
-+ return strcasecmp(item->string, text);
-+}
-+#endif
-+
-+static char slang_text_buf[500];
-+static char *slang_text_get(struct slang_text *item)
-+{
-+ slang_text_buf[0] = 0;
-+ while (item) {
-+ if (item->string)
-+ strncat(slang_text_buf, item->string, sizeof(slang_text_buf));
-+ else if (item->command)
-+ item->command();
-+ item = item->next;
-+ }
-+ return slang_text_buf;
-+}
-+
-+/*****************************************************/
-+
-+
-+static struct slang_command_list *glob_slang_cmd_list;
-+
-+static struct slang_command_list *slang_commands_list_add(struct slang_command_list *where, struct slang_text_commands *what)
-+{
-+ struct slang_command_list *newcommandlist;
-+
-+ newcommandlist = nmalloc(sizeof(struct slang_command_list));
-+ newcommandlist->commands = what;
-+ newcommandlist->next = where;
-+ return newcommandlist;
-+}
-+
-+static int slang_commands_list_expmem(struct slang_command_list *what)
-+{
-+ int size = 0;
-+
-+ while (what) {
-+ size += sizeof(struct slang_command_list);
-+ what = what->next;
-+ }
-+ return size;
-+}
-+
-+static void slang_commands_list_free(struct slang_command_list *what)
-+{
-+ struct slang_command_list *next;
-+
-+ while (what) {
-+ next = what->next;
-+ nfree(what);
-+ what = next;
-+ }
-+}
-+
-+static void slang_text_add_command(struct slang_text *item, char *s)
-+{
-+ struct slang_command_list *cmdlist;
-+ char *cmd;
-+ int i;
-+
-+ cmd = newsplit(&s);
-+ i = 0;
-+ for (cmdlist = glob_slang_cmd_list; cmdlist; cmdlist = cmdlist->next) {
-+ for (i = 0; 1; i++) {
-+ if (!cmdlist->commands[i].command)
-+ break;
-+ if (!strcasecmp(cmdlist->commands[i].command, cmd)) {
-+ item->command = cmdlist->commands[i].targetfunc;
-+ return;
-+ }
-+ }
-+ }
-+ putlog(LOG_MISC, "*", "ERROR! Unknown slang-command: '%s'", cmd);
-+}
-diff -Nur src/mod/gseen.mod/tclcmds.c src/mod/gseen.mod/tclcmds.c
---- src/mod/gseen.mod/tclcmds.c 1970-01-01 01:00:00.000000000 +0100
-+++ src/mod/gseen.mod/tclcmds.c 2002-10-26 13:18:08.000000000 +0200
-@@ -0,0 +1,53 @@
-+/*
-+ * Copyright (C) 2000,2001 Florian Sander
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+static int tcl_setchanseenlang STDVAR
-+{
-+ Context;
-+ BADARGS(3, 3, " channel language");
-+ chanlangs = slang_chanlang_add(chanlangs, argv[1], argv[2]);
-+ return TCL_OK;
-+}
-+
-+static int tcl_loadseenslang STDVAR
-+{
-+// int ret = 0;
-+ char *shortname, *longname, *filename;
-+ struct slang_header *slang;
-+
-+ Context;
-+ BADARGS(4, 4, " language description langfile");
-+ shortname = argv[1];
-+ longname = argv[2];
-+ filename = argv[3];
-+ coreslangs = slang_create(coreslangs, shortname, longname);
-+ slang = slang_find(coreslangs, shortname);
-+ Assert(slang);
-+ if (!slang_load(slang, filename)) {
-+ Tcl_AppendResult(irp, "Couldn't open seenslang file!!!", NULL);
-+ return TCL_ERROR;
-+ }
-+ return TCL_OK;
-+}
-+
-+static tcl_cmds gseentcls[] =
-+{
-+ {"loadseenslang", tcl_loadseenslang},
-+ {"setchanseenlang", tcl_setchanseenlang},
-+ {0, 0}
-+};