]> jfr.im git - irc/quakenet/newserv.git/commitdiff
sync with latest qabot code
authorfroo <redacted>
Thu, 2 Jun 2005 18:29:00 +0000 (19:29 +0100)
committerfroo <redacted>
Thu, 2 Jun 2005 18:29:00 +0000 (19:29 +0100)
qabot/Makefile
qabot/qabot.c
qabot/qabot.h
qabot/qabot_bot.c
qabot/qabot_chancommands.c
qabot/qabot_commands.c
qabot/qabot_dbase.c
qabot/qabot_help.c

index 12fab2278275e5ac131a58bc6a87d5e303b7c8ef..f158aebfb646dd97358651bb894735f7bc15e649 100644 (file)
@@ -1,6 +1,6 @@
-
-.PHONY: all
-all: qabot.so
-
-qabot.so: qabot.o qabot_bot.o qabot_chancommands.o qabot_commands.o qabot_dbase.o qabot_help.o qabot_texts.o
-       ld -shared -Bdynamic -o $@ $^
+\r
+.PHONY: all\r
+all: qabot.so\r
+\r
+qabot.so: qabot.o qabot_bot.o qabot_chancommands.o qabot_commands.o qabot_dbase.o qabot_help.o\r
+       ld -shared -Bdynamic -o $@ $^\r
index a24a6f9c442a8cc212da03ac55006c46d1003885..31f9d34bfb70aa59865b25f2454ab9a39fe29ec7 100644 (file)
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <time.h>
-
-#include "../nick/nick.h"
-#include "../localuser/localuserchannel.h"
-#include "../core/hooks.h"
-#include "../core/schedule.h"
-#include "../lib/array.h"
-#include "../lib/base64.h"
-#include "../lib/irc_string.h"
-#include "../lib/splitline.h"
-
-#include "qabot.h"
-
-time_t qab_startime;
-int qabot_nickext;
-int qabot_spam_nickext;
-int qabot_chanext;
-nick* qabot_nick = 0;
-CommandTree* qabot_commands;
-CommandTree* qabot_chancommands;
-qab_bot* qab_bots = 0;
-unsigned long qab_lastq_crc = 0;
-int qab_lastq_count = 0;
-qab_bot* qabot_currentbot = 0;
-channel* qabot_currentchan = 0;
-
-void _init() {
-  qab_startime = time(0);
-  
-  registerhook(HOOK_NICK_LOSTNICK, qabot_lostnick);
-  registerhook(HOOK_CHANNEL_PART, qabot_channel_part);
-  
-  qabot_commands = newcommandtree();
-  addcommandtotree(qabot_commands, "showcommands", 0, 0, qabot_doshowcommands);
-  addcommandtotree(qabot_commands, "help", QAUFLAG_STAFF, 1, qabot_dohelp);
-  addcommandtotree(qabot_commands, "hello", 0, 0, qabot_dohello);
-  addcommandtotree(qabot_commands, "save", QAUFLAG_ADMIN, 0, qabot_dosave);
-  addcommandtotree(qabot_commands, "listbots", QAUFLAG_STAFF, 0, qabot_dolistbots);
-  addcommandtotree(qabot_commands, "listusers", QAUFLAG_STAFF, 0, qabot_dolistusers);
-  addcommandtotree(qabot_commands, "showbot", QAUFLAG_STAFF, 1, qabot_doshowbot);
-  addcommandtotree(qabot_commands, "addbot", QAUFLAG_STAFF, 6, qabot_doaddbot);
-  addcommandtotree(qabot_commands, "delbot", QAUFLAG_STAFF, 1, qabot_dodelbot);
-  addcommandtotree(qabot_commands, "adduser", QAUFLAG_ADMIN, 2, qabot_doadduser);
-  addcommandtotree(qabot_commands, "changelev", QAUFLAG_ADMIN, 2, qabot_dochangelev);
-  addcommandtotree(qabot_commands, "deluser", QAUFLAG_ADMIN, 1, qabot_dodeluser);
-  addcommandtotree(qabot_commands, "whois", QAUFLAG_STAFF, 1, qabot_dowhois);
-  addcommandtotree(qabot_commands, "status", QAUFLAG_DEVELOPER, 0, qabot_dostatus);
-  
-  qabot_chancommands = newcommandtree();
-  addcommandtotree(qabot_chancommands, "answer", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochananswer);
-  addcommandtotree(qabot_chancommands, "block", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanblock);
-  addcommandtotree(qabot_chancommands, "clear", QAC_STAFFCHAN, 0, qabot_dochanclear);
-  addcommandtotree(qabot_chancommands, "closechan", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanclosechan);
-  addcommandtotree(qabot_chancommands, "config", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanconfig);
-  addcommandtotree(qabot_chancommands, "help", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 1, qabot_dochanhelp);
-  addcommandtotree(qabot_chancommands, "listblocks", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanlistblocks);
-  addcommandtotree(qabot_chancommands, "mic", QAC_STAFFCHAN, 0, qabot_dochanmic);
-  addcommandtotree(qabot_chancommands, "moo", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanmoo);
-  addcommandtotree(qabot_chancommands, "offtopic", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 30, qabot_dochanofftopic);
-  addcommandtotree(qabot_chancommands, "openchan", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanopenchan);
-  addcommandtotree(qabot_chancommands, "ping", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanping);
-  addcommandtotree(qabot_chancommands, "reset", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 1, qabot_dochanreset);
-  addcommandtotree(qabot_chancommands, "spam", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 30, qabot_dochanspam);
-  addcommandtotree(qabot_chancommands, "status", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanstatus);
-  addcommandtotree(qabot_chancommands, "unblock", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanunblock);
-  addcommandtotree(qabot_chancommands, "listtexts", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanlisttexts);
-  addcommandtotree(qabot_chancommands, "showsection", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanshowsection);
-  addcommandtotree(qabot_chancommands, "addtext", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanaddtext);
-  addcommandtotree(qabot_chancommands, "deltext", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 1, qabot_dochandeltext);
-  addcommandtotree(qabot_chancommands, "addsection", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanaddsection);
-  addcommandtotree(qabot_chancommands, "delsection", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochandelsection);
-  addcommandtotree(qabot_chancommands, "record", QAC_STAFFCHAN, 2, qabot_dochanrecord);
-
-  if ((qabot_nickext = registernickext("QABOT")) == -1) {
-    return;
-  }
-  
-  if ((qabot_spam_nickext = registernickext("QABOT_SPAM")) == -1) {
-    return;
-  }
-  
-  qabot_loaddb();
-
-  scheduleoneshot(time(NULL) + 1, &qabot_createfakeuser, NULL);
-  scheduleoneshot(time(NULL) + QABOT_SAVEWAIT, &qabot_savetimer, NULL);
-}
-
-void _fini() {
-  deregisterhook(HOOK_NICK_LOSTNICK, qabot_lostnick);
-  deregisterhook(HOOK_CHANNEL_PART, qabot_channel_part);
-  
-  deleteschedule(0, qabot_savetimer, NULL);
-  
-  qabot_savedb();
-  
-  while (qab_bots)
-    qabot_delbot(qab_bots);
-
-  if (qabot_nickext != -1)
-    releasenickext(qabot_nickext);
-  
-  if (qabot_spam_nickext != -1)
-    releasenickext(qabot_spam_nickext);
-
-  if (qabot_nick) {
-      deregisterlocaluser(qabot_nick, "Module unloaded.");
-      qabot_nick = NULL;
-  }
-
-  while (qabot_users)
-    qabot_squelchuser(qabot_users);
-  
-  deletecommandfromtree(qabot_commands, "showcommands", qabot_doshowcommands);
-  deletecommandfromtree(qabot_commands, "help", qabot_dohelp);
-  deletecommandfromtree(qabot_commands, "hello", qabot_dohello);
-  deletecommandfromtree(qabot_commands, "save", qabot_dosave);
-  deletecommandfromtree(qabot_commands, "listbots", qabot_dolistbots);
-  deletecommandfromtree(qabot_commands, "listusers", qabot_dolistusers);
-  deletecommandfromtree(qabot_commands, "showbot", qabot_doshowbot);
-  deletecommandfromtree(qabot_commands, "addbot", qabot_doaddbot);
-  deletecommandfromtree(qabot_commands, "delbot", qabot_dodelbot);
-  deletecommandfromtree(qabot_commands, "adduser", qabot_doadduser);
-  deletecommandfromtree(qabot_commands, "changelev", qabot_dochangelev);
-  deletecommandfromtree(qabot_commands, "deluser", qabot_dodeluser);
-  deletecommandfromtree(qabot_commands, "whois", qabot_dowhois);
-  deletecommandfromtree(qabot_commands, "status", qabot_dostatus);
-  destroycommandtree(qabot_commands);
-  
-  deletecommandfromtree(qabot_chancommands, "answer", qabot_dochananswer);
-  deletecommandfromtree(qabot_chancommands, "block", qabot_dochanblock);
-  deletecommandfromtree(qabot_chancommands, "clear", qabot_dochanclear);
-  deletecommandfromtree(qabot_chancommands, "closechan", qabot_dochanclosechan);
-  deletecommandfromtree(qabot_chancommands, "config", qabot_dochanconfig);
-  deletecommandfromtree(qabot_chancommands, "help", qabot_dochanhelp);
-  deletecommandfromtree(qabot_chancommands, "listblocks", qabot_dochanlistblocks);
-  deletecommandfromtree(qabot_chancommands, "mic", qabot_dochanmic);
-  deletecommandfromtree(qabot_chancommands, "moo", qabot_dochanmoo);
-  deletecommandfromtree(qabot_chancommands, "offtopic", qabot_dochanofftopic);
-  deletecommandfromtree(qabot_chancommands, "openchan", qabot_dochanopenchan);
-  deletecommandfromtree(qabot_chancommands, "ping", qabot_dochanping);
-  deletecommandfromtree(qabot_chancommands, "reset", qabot_dochanreset);
-  deletecommandfromtree(qabot_chancommands, "spam", qabot_dochanspam);
-  deletecommandfromtree(qabot_chancommands, "status", qabot_dochanstatus);
-  deletecommandfromtree(qabot_chancommands, "unblock", qabot_dochanunblock);
-  deletecommandfromtree(qabot_chancommands, "listtexts", qabot_dochanlisttexts);
-  deletecommandfromtree(qabot_chancommands, "showsection", qabot_dochanshowsection);
-  deletecommandfromtree(qabot_chancommands, "addtext", qabot_dochanaddtext);
-  deletecommandfromtree(qabot_chancommands, "deltext", qabot_dochandeltext);
-  deletecommandfromtree(qabot_chancommands, "addsection", qabot_dochanaddsection);
-  deletecommandfromtree(qabot_chancommands, "delsection", qabot_dochandelsection);
-  deletecommandfromtree(qabot_chancommands, "record", qabot_dochanrecord);
-  destroycommandtree(qabot_chancommands);
-}
-
-void qabot_lostnick(int hooknum, void* arg) {
-  nick* np = (nick*)arg;
-  qab_bot* b;
-  
-  if (!qab_bots)
-    return;
-  
-  if (!IsAccount(np))
-    return;
-  
-  for (b = qab_bots; b; b = b->next) {
-    if (b->micnumeric == np->numeric) {
-      b->micnumeric = 0;
-      sendmessagetochannel(b->np, b->staff_chan->channel, "%s deactivated.", 
-        bot->recording_section ? "Recorder" : "Mic");
-      if (!b->lastspam && !b->recording_section)
-        qabot_spamstored((void*)b);
-      b->recording_section = 0;
-    }
-  }
-}
-
-void qabot_channel_part(int hooknum, void* arg) {
-  channel* cp = (channel*)((void**)arg)[0];
-  nick* np = (nick*)((void**)arg)[1];
-  qab_bot* b;
-  
-  if (!qab_bots)
-    return;
-  
-  if (!IsAccount(np))
-    return;
-  
-  for (b = qab_bots; b; b = b->next) {
-    if ((b->micnumeric == np->numeric) && (b->staff_chan->channel == cp)) {
-      b->micnumeric = 0;
-      sendmessagetochannel(b->np, b->staff_chan->channel, "%s deactivated.", 
-        b->recording_section ? "Recorder" : "Mic");
-      if (!b->lastspam && !b->recording_section)
-        qabot_spamstored((void*)b);
-      b->recording_section = 0;
-    }
-  }
-}
-
-void qabot_createfakeuser(void* arg) {
-  channel* cp;
-  
-  if ((qabot_nick = registerlocaluser(QABOT_NICK, QABOT_USER, QABOT_HOST,
-    QABOT_NAME, QABOT_ACCT, QABOT_UMDE, &qabot_handler))) {
-    if ((cp = findchannel(QABOT_HOMECHAN))) {
-      localjoinchannel(qabot_nick, cp);
-      localgetops(qabot_nick, cp);
-    }
-    else
-    localcreatechannel(qabot_nick, QABOT_HOMECHAN);
-  }
-}
-
-void qabot_handler(nick* me, int type, void** args) {
-  nick* sender;
-  Command* cmd;
-  channel* cp;
-  char* cargv[50];
-  int cargc;
-  qab_user* u;
-
-  switch (type) {
-  case LU_PRIVMSG:
-  case LU_SECUREMSG:
-    sender = (nick*)args[0];
-
-    if (!strncmp("\001VERSION", args[1], 8)) {
-      sendnoticetouser(qabot_nick, sender, "\001VERSION %s\001", QABOT_NAME);
-      return;
-    }
-
-       cargc = splitline((char*)args[1], cargv, 50, 0);
-       cmd = findcommandintree(qabot_commands, cargv[0], 1);
-       if (!cmd) {
-         sendnoticetouser(qabot_nick, sender, "Unknown command.");
-         return;
-    }
-
-    if (!IsAccount(sender)) {
-      sendnoticetouser(qabot_nick, sender, "You must be authed to use this command.");
-         return;
-       }
-
-       u = qabot_getuser(sender->authname);
-       if (cmd->level) {
-      if (!u) {
-        sendnoticetouser(qabot_nick, sender, "You need an account to use this command.");
-        return;
-         }
-
-         if ((cmd->level & QAUFLAG_STAFF) && !QAIsStaff(u)) {
-        sendnoticetouser(qabot_nick, sender, "You do not have access to this command.");
-        return;
-      }
-
-      if ((cmd->level & QAUFLAG_ADMIN) && !QAIsAdmin(u)) {
-        sendnoticetouser(qabot_nick, sender, "You do not have access to this command.");
-        return;
-      }
-      
-      if ((cmd->level & QAUFLAG_DEVELOPER) && !QAIsDeveloper(u)) {
-        sendnoticetouser(qabot_nick, sender, "You do not have access to this command.");
-        return;
-      }
-    }
-    
-    if (cmd->maxparams < (cargc-1)) {
-      rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));
-      cargc=(cmd->maxparams) + 1;
-    }
-    
-    (cmd->handler)((void*)sender, cargc - 1, &(cargv[1]));
-
-    break;
-
-  case LU_KILLED:
-    qabot_nick = NULL;
-    scheduleoneshot(time(NULL) + 1, &qabot_createfakeuser, NULL);
-    break;
-
-  case LU_KICKED:
-    cp = (channel*)args[1];
-    if (cp) {
-      localjoinchannel(qabot_nick, cp);
-      localgetops(qabot_nick, cp);
-    }
-    break;
-  }
-}
-
-void qabot_child_handler(nick* me, int type, void** args) {
-  nick* sender;
-  channel* cp;
-  qab_bot* bot = me->exts[qabot_nickext];
-  char* text;
-  Command* cmd;
-  char* cargv[50];
-  int cargc;
-  
-  if (!bot) {
-    return;
-  }
-  
-  switch (type) {
-  case LU_CHANMSG:
-    sender = (nick*)args[0];
-    cp = (channel*)args[1];
-    text = (char*)args[2];
-    
-    if (*text == '!') {
-      cargc = splitline((char*)(++text), cargv, 50, 0);
-         cmd = findcommandintree(qabot_chancommands, cargv[0], 1);
-         if (!cmd) {
-           sendnoticetouser(me, sender, "Unknown command.");
-           return;
-      }
-      
-      if ((cp->index == bot->staff_chan) && !(cmd->level & QAC_STAFFCHAN)) {
-        sendnoticetouser(me, sender, "This command cannot be used in the staff channel.");
-        return;
-      }
-      
-      if ((cp->index == bot->question_chan) && !(cmd->level & QAC_QUESTIONCHAN)) {
-        sendnoticetouser(me, sender, "This command cannot be used in the question channel.");
-        return;
-      }
-      
-      if (cmd->maxparams < (cargc-1)) {
-        rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));
-        cargc=(cmd->maxparams) + 1;
-      }
-      
-      qabot_currentbot = bot;
-      qabot_currentchan = cp;
-      
-      (cmd->handler)((void*)sender, cargc - 1, &(cargv[1]));
-    }
-    else if ((*text != '!') && (bot->micnumeric == sender->numeric) && (cp->index == bot->staff_chan)) {
-      bot->lastmic = time(NULL);
-      if (bot->lastspam) {
-        qab_spam* s;
-        
-        s = (qab_spam*)malloc(sizeof(qab_spam));
-        s->message = strdup(text);
-        s->next = 0;
-        bot->lastspam->next = s;
-        bot->lastspam = s;
-      }
-      else {
-        if ((bot->spamtime + bot->spam_interval) < time(0)) {
-          sendmessagetochannel(me, bot->public_chan->channel, "%s", text);
-          bot->spammed++;
-          bot->spamtime = time(0);
-        }
-        else {
-          qab_spam* s;
-          
-          s = (qab_spam*)malloc(sizeof(qab_spam));
-          s->message = strdup(text);
-          s->next = 0;
-          bot->nextspam = bot->lastspam = s;
-          scheduleoneshot(bot->spamtime + bot->spam_interval, qabot_spam, (void*)bot);
-        }
-      }
-    }
-    break;
-  
-  case LU_PRIVMSG:
-  case LU_SECUREMSG:
-    sender = (nick*)args[0];
-    text = (char*)args[1];
-    time_t lastmsg;
-    
-    lastmsg = (time_t)sender->exts[qabot_spam_nickext];
-    
-    if ((lastmsg + bot->ask_wait) > time(0)) {
-      sendnoticetouser(me, sender, "You have already sent a question recently, please wait at least %d seconds between asking questions.", bot->ask_wait);
-      return;
-    }
-    else {
-      char hostbuf[NICKLEN + USERLEN + HOSTLEN + 3];
-      qab_block* b;
-      qab_question* q;
-      unsigned long crc;
-      int len;
-      
-      sendnoticetouser(me, sender, "Your question has been relayed to the %s staff.", bot->public_chan->name->content);
-      
-      if (!getnumerichandlefromchanhash(bot->public_chan->channel->users, sender->numeric))
-        return;
-      
-      if (*text == '<')
-        text++;
-      
-      len = strlen(text);
-      if ((len > 0) && (text[len - 1] == '>')) {
-        text[len - 1] = '\0';
-        len--;
-      }
-      
-      if ((len < 5) || !strchr(text, ' ') || (*text == 1))
-        return;
-      
-      if ((bot->flags & QAB_AUTHEDONLY) && !IsAccount(sender))
-        return;
-      
-      if (bot->flags & QAB_CONTROLCHAR) {
-        char* ch;
-        
-        for (ch = text; *ch; ch++)
-          if ((*ch == 2) || (*ch == 3) || (*ch == 22) || (*ch == 27) || (*ch == 31))
-            return;
-      }
-      else if (bot->flags & QAB_COLOUR) {
-        char* ch;
-        
-        for (ch = text; *ch; ch++)
-          if (*ch == 3)
-            return;
-      }
-      
-      if (bot->flags & QAB_FLOODDETECT) {
-        crc = crc32i(text);
-        if (crc == qab_lastq_crc) {
-          qab_lastq_count++;
-          if (qab_lastq_count >= 3) {
-            if ((qab_lastq_count == 3) || ((qab_lastq_count % 10) == 0))
-              sendmessagetochannel(me, bot->question_chan->channel, "WARNING: Possible question flood detected%s", (bot->flags & QAB_FLOODSTOP) ? " - AUTO IGNORED." : ".");
-            if (bot->flags & QAB_FLOODSTOP)
-              return;
-          }
-        }
-        else {
-          qab_lastq_crc = crc;
-          qab_lastq_count = 1;
-        }
-      }
-      
-      sprintf(hostbuf,"%s!%s@%s", sender->nick, sender->ident, sender->host->name->content);
-      
-      for (b = bot->blocks; b; b = b->next) {
-        switch (b->type) {
-        case QABBLOCK_ACCOUNT:
-          if (IsAccount(sender) && !ircd_strncmp(sender->authname, b->blockstr, ACCOUNTLEN))
-            return;
-          break;
-          
-        case QABBLOCK_HOST:
-          if (!match(b->blockstr, hostbuf))
-            return;
-          break;
-          
-        case QABBLOCK_TEXT:
-          if (!match(b->blockstr, text))
-            return;
-          break;
-        }
-      }
-      
-      sender->exts[qabot_spam_nickext] = (void*)time(0);
-      
-      q = (qab_question*)malloc(sizeof(qab_question));
-      q->id = ++bot->lastquestionID;
-      q->question = strdup(text);
-      q->flags = QAQ_NEW;
-      strncpy(q->nick, sender->nick, NICKLEN);
-      q->nick[NICKLEN] = '\0';
-      q->numeric = sender->numeric;
-      q->crc = (bot->flags & QAB_FLOODDETECT) ? crc : 0;
-      q->answer = 0;
-      q->next = bot->questions[q->id % QUESTIONHASHSIZE];
-      
-      bot->questions[q->id % QUESTIONHASHSIZE] = q;
-      
-      sendmessagetochannel(me, bot->question_chan->channel, "ID: %3d <%s> %s", q->id, visiblehostmask(sender, hostbuf), text);
-      
-      if ((bot->flags & QAB_LINEBREAK) && ((bot->lastquestionID % 10) == 0))
-        sendmessagetochannel(me, bot->question_chan->channel, "-----------------------------------");
-    }
-    break;
-    
-  case LU_KILLED:
-    bot->np = NULL;
-    scheduleoneshot(time(NULL) + 1, &qabot_createbotfakeuser, (void*)bot);
-    break;
-
-  case LU_KICKED:
-    cp = (channel*)args[1];
-    if (cp) {
-      localjoinchannel(bot->np, cp);
-      localgetops(bot->np, cp);
-    }
-    break;
-  
-  default:
-    break;
-  }
-}
-
-char* qabot_getvictim(nick* np, char* target) {
-  if (*target != '#') {
-    nick* victim;
-    
-    if (!(victim = getnickbynick(target))) {
-      sendnoticetouser(qabot_nick, np, "No such nickname.");
-      return 0;
-    }
-    
-    if (!IsAccount(victim)) {
-      sendnoticetouser(qabot_nick, np, "%s is not authed.", victim->nick);
-      return 0;
-    }
-    
-    return victim->authname;
-  }
-  
-  return target + 1;
-}
-
-const char* qabot_uflagtostr(flag_t flags) {
-  static char buf[20];
-  int i = 0;
-  
-  buf[i++] = '+';
-  
-  if (flags & QAUFLAG_ADMIN)     { buf[i++] = 'a'; }
-  if (flags & QAUFLAG_DEVELOPER) { buf[i++] = 'd'; }
-  if (flags & QAUFLAG_STAFF)     { buf[i++] = 's'; }
-  
-  buf[i] = '\0';
-  
-  return buf;
-}
-
-const char* qabot_formattime(time_t tme) {
-  static char buf[50];
-  struct tm* tmp;
-  
-  tmp = gmtime(&tme);
-  strftime(buf, 15, "%d/%m/%y %H:%M", tmp);
-  
-  return buf;
-}
-
-qab_bot* qabot_getcurrentbot() {
-  return qabot_currentbot;
-}
-
-channel* qabot_getcurrentchannel() {
-  return qabot_currentchan;
-}
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "../nick/nick.h"\r
+#include "../localuser/localuserchannel.h"\r
+#include "../core/hooks.h"\r
+#include "../core/schedule.h"\r
+#include "../lib/array.h"\r
+#include "../lib/base64.h"\r
+#include "../lib/irc_string.h"\r
+#include "../lib/splitline.h"\r
+\r
+#include "qabot.h"\r
+\r
+time_t qab_startime;\r
+int qabot_nickext;\r
+int qabot_spam_nickext;\r
+int qabot_chanext;\r
+nick* qabot_nick = 0;\r
+CommandTree* qabot_commands;\r
+CommandTree* qabot_chancommands;\r
+qab_bot* qab_bots = 0;\r
+unsigned long qab_lastq_crc = 0;\r
+int qab_lastq_count = 0;\r
+qab_bot* qabot_currentbot = 0;\r
+channel* qabot_currentchan = 0;\r
+\r
+void _init() {\r
+  qab_startime = time(0);\r
+  \r
+  registerhook(HOOK_NICK_LOSTNICK, qabot_lostnick);\r
+  registerhook(HOOK_CHANNEL_PART, qabot_channel_part);\r
+  \r
+  qabot_commands = newcommandtree();\r
+  addcommandtotree(qabot_commands, "showcommands", 0, 0, qabot_doshowcommands);\r
+  addcommandtotree(qabot_commands, "help", QAUFLAG_STAFF, 1, qabot_dohelp);\r
+  addcommandtotree(qabot_commands, "hello", 0, 0, qabot_dohello);\r
+  addcommandtotree(qabot_commands, "save", QAUFLAG_ADMIN, 0, qabot_dosave);\r
+  addcommandtotree(qabot_commands, "listbots", QAUFLAG_STAFF, 0, qabot_dolistbots);\r
+  addcommandtotree(qabot_commands, "listusers", QAUFLAG_STAFF, 0, qabot_dolistusers);\r
+  addcommandtotree(qabot_commands, "showbot", QAUFLAG_STAFF, 1, qabot_doshowbot);\r
+  addcommandtotree(qabot_commands, "addbot", QAUFLAG_STAFF, 6, qabot_doaddbot);\r
+  addcommandtotree(qabot_commands, "delbot", QAUFLAG_STAFF, 1, qabot_dodelbot);\r
+  addcommandtotree(qabot_commands, "adduser", QAUFLAG_ADMIN, 2, qabot_doadduser);\r
+  addcommandtotree(qabot_commands, "changelev", QAUFLAG_ADMIN, 2, qabot_dochangelev);\r
+  addcommandtotree(qabot_commands, "deluser", QAUFLAG_ADMIN, 1, qabot_dodeluser);\r
+  addcommandtotree(qabot_commands, "whois", QAUFLAG_STAFF, 1, qabot_dowhois);\r
+  addcommandtotree(qabot_commands, "status", QAUFLAG_DEVELOPER, 0, qabot_dostatus);\r
+  \r
+  qabot_chancommands = newcommandtree();\r
+  addcommandtotree(qabot_chancommands, "answer", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochananswer);\r
+  addcommandtotree(qabot_chancommands, "block", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanblock);\r
+  addcommandtotree(qabot_chancommands, "clear", QAC_STAFFCHAN, 0, qabot_dochanclear);\r
+  addcommandtotree(qabot_chancommands, "closechan", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanclosechan);\r
+  addcommandtotree(qabot_chancommands, "config", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanconfig);\r
+  addcommandtotree(qabot_chancommands, "help", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 1, qabot_dochanhelp);\r
+  addcommandtotree(qabot_chancommands, "listblocks", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanlistblocks);\r
+  addcommandtotree(qabot_chancommands, "mic", QAC_STAFFCHAN, 0, qabot_dochanmic);\r
+  addcommandtotree(qabot_chancommands, "moo", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanmoo);\r
+  addcommandtotree(qabot_chancommands, "offtopic", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 30, qabot_dochanofftopic);\r
+  addcommandtotree(qabot_chancommands, "openchan", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanopenchan);\r
+  addcommandtotree(qabot_chancommands, "ping", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanping);\r
+  addcommandtotree(qabot_chancommands, "reset", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 1, qabot_dochanreset);\r
+  addcommandtotree(qabot_chancommands, "spam", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 30, qabot_dochanspam);\r
+  addcommandtotree(qabot_chancommands, "status", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 0, qabot_dochanstatus);\r
+  addcommandtotree(qabot_chancommands, "unblock", QAC_QUESTIONCHAN|QAC_STAFFCHAN, 2, qabot_dochanunblock);\r
+\r
+  if ((qabot_nickext = registernickext("QABOT")) == -1) {\r
+    return;\r
+  }\r
+  \r
+  if ((qabot_spam_nickext = registernickext("QABOT_SPAM")) == -1) {\r
+    return;\r
+  }\r
+  \r
+  qabot_loaddb();\r
+\r
+  scheduleoneshot(time(NULL) + 1, &qabot_createfakeuser, NULL);\r
+  scheduleoneshot(time(NULL) + QABOT_SAVEWAIT, &qabot_savetimer, NULL);\r
+}\r
+\r
+void _fini() {\r
+  deregisterhook(HOOK_NICK_LOSTNICK, qabot_lostnick);\r
+  deregisterhook(HOOK_CHANNEL_PART, qabot_channel_part);\r
+  \r
+  deleteschedule(0, qabot_savetimer, NULL);\r
+  \r
+  qabot_savedb();\r
+  \r
+  while (qab_bots)\r
+    qabot_delbot(qab_bots);\r
+\r
+  if (qabot_nickext != -1)\r
+    releasenickext(qabot_nickext);\r
+  \r
+  if (qabot_spam_nickext != -1)\r
+    releasenickext(qabot_spam_nickext);\r
+\r
+  if (qabot_nick) {\r
+      deregisterlocaluser(qabot_nick, "Module unloaded.");\r
+      qabot_nick = NULL;\r
+  }\r
+\r
+  while (qabot_users)\r
+    qabot_squelchuser(qabot_users);\r
+  \r
+  deletecommandfromtree(qabot_commands, "showcommands", qabot_doshowcommands);\r
+  deletecommandfromtree(qabot_commands, "help", qabot_dohelp);\r
+  deletecommandfromtree(qabot_commands, "hello", qabot_dohello);\r
+  deletecommandfromtree(qabot_commands, "save", qabot_dosave);\r
+  deletecommandfromtree(qabot_commands, "listbots", qabot_dolistbots);\r
+  deletecommandfromtree(qabot_commands, "listusers", qabot_dolistusers);\r
+  deletecommandfromtree(qabot_commands, "showbot", qabot_doshowbot);\r
+  deletecommandfromtree(qabot_commands, "addbot", qabot_doaddbot);\r
+  deletecommandfromtree(qabot_commands, "delbot", qabot_dodelbot);\r
+  deletecommandfromtree(qabot_commands, "adduser", qabot_doadduser);\r
+  deletecommandfromtree(qabot_commands, "changelev", qabot_dochangelev);\r
+  deletecommandfromtree(qabot_commands, "deluser", qabot_dodeluser);\r
+  deletecommandfromtree(qabot_commands, "whois", qabot_dowhois);\r
+  deletecommandfromtree(qabot_commands, "status", qabot_dostatus);\r
+  destroycommandtree(qabot_commands);\r
+  \r
+  deletecommandfromtree(qabot_chancommands, "answer", qabot_dochananswer);\r
+  deletecommandfromtree(qabot_chancommands, "block", qabot_dochanblock);\r
+  deletecommandfromtree(qabot_chancommands, "clear", qabot_dochanclear);\r
+  deletecommandfromtree(qabot_chancommands, "closechan", qabot_dochanclosechan);\r
+  deletecommandfromtree(qabot_chancommands, "config", qabot_dochanconfig);\r
+  deletecommandfromtree(qabot_chancommands, "help", qabot_dochanhelp);\r
+  deletecommandfromtree(qabot_chancommands, "listblocks", qabot_dochanlistblocks);\r
+  deletecommandfromtree(qabot_chancommands, "mic", qabot_dochanmic);\r
+  deletecommandfromtree(qabot_chancommands, "moo", qabot_dochanmoo);\r
+  deletecommandfromtree(qabot_chancommands, "offtopic", qabot_dochanofftopic);\r
+  deletecommandfromtree(qabot_chancommands, "openchan", qabot_dochanopenchan);\r
+  deletecommandfromtree(qabot_chancommands, "ping", qabot_dochanping);\r
+  deletecommandfromtree(qabot_chancommands, "reset", qabot_dochanreset);\r
+  deletecommandfromtree(qabot_chancommands, "spam", qabot_dochanspam);\r
+  deletecommandfromtree(qabot_chancommands, "status", qabot_dochanstatus);\r
+  deletecommandfromtree(qabot_chancommands, "unblock", qabot_dochanunblock);\r
+  destroycommandtree(qabot_chancommands);\r
+}\r
+\r
+void qabot_lostnick(int hooknum, void* arg) {\r
+  nick* np = (nick*)arg;\r
+  qab_bot* b;\r
+  \r
+  if (!qab_bots)\r
+    return;\r
+  \r
+  if (!IsAccount(np))\r
+    return;\r
+  \r
+  for (b = qab_bots; b; b = b->next) {\r
+    if (b->micnumeric == np->numeric) {\r
+      b->micnumeric = 0;\r
+      sendmessagetochannel(b->np, b->staff_chan->channel, "Mic deactivated.");\r
+      if (!b->lastspam)\r
+        qabot_spamstored((void*)b);\r
+    }\r
+  }\r
+}\r
+\r
+void qabot_channel_part(int hooknum, void* arg) {\r
+  channel* cp = (channel*)((void**)arg)[0];\r
+  nick* np = (nick*)((void**)arg)[1];\r
+  qab_bot* b;\r
+  \r
+  if (!qab_bots)\r
+    return;\r
+  \r
+  if (!IsAccount(np))\r
+    return;\r
+  \r
+  for (b = qab_bots; b; b = b->next) {\r
+    if ((b->micnumeric == np->numeric) && (b->staff_chan->channel == cp)) {\r
+      b->micnumeric = 0;\r
+      sendmessagetochannel(b->np, b->staff_chan->channel, "Mic deactivated.");\r
+      if (!b->lastspam)\r
+        qabot_spamstored((void*)b);\r
+    }\r
+  }\r
+}\r
+\r
+void qabot_createfakeuser(void* arg) {\r
+  channel* cp;\r
+  \r
+  if ((qabot_nick = registerlocaluser(QABOT_NICK, QABOT_USER, QABOT_HOST,\r
+    QABOT_NAME, QABOT_ACCT, QABOT_UMDE, &qabot_handler))) {\r
+    if ((cp = findchannel(QABOT_HOMECHAN))) {\r
+      localjoinchannel(qabot_nick, cp);\r
+      localgetops(qabot_nick, cp);\r
+    }\r
+    else\r
+    localcreatechannel(qabot_nick, QABOT_HOMECHAN);\r
+  }\r
+}\r
+\r
+void qabot_handler(nick* me, int type, void** args) {\r
+  nick* sender;\r
+  Command* cmd;\r
+  channel* cp;\r
+  char* cargv[50];\r
+  int cargc;\r
+  qab_user* u;\r
+\r
+  switch (type) {\r
+  case LU_PRIVMSG:\r
+  case LU_SECUREMSG:\r
+    sender = (nick*)args[0];\r
+\r
+    if (!strncmp("\001VERSION", args[1], 8)) {\r
+      sendnoticetouser(qabot_nick, sender, "\001VERSION %s\001", QABOT_NAME);\r
+      return;\r
+    }\r
+\r
+       cargc = splitline((char*)args[1], cargv, 50, 0);\r
+       cmd = findcommandintree(qabot_commands, cargv[0], 1);\r
+       if (!cmd) {\r
+         sendnoticetouser(qabot_nick, sender, "Unknown command.");\r
+         return;\r
+    }\r
+\r
+    if (!IsAccount(sender)) {\r
+      sendnoticetouser(qabot_nick, sender, "You must be authed to use this command.");\r
+         return;\r
+       }\r
+\r
+       u = qabot_getuser(sender->authname);\r
+       if (cmd->level) {\r
+      if (!u) {\r
+        sendnoticetouser(qabot_nick, sender, "You need an account to use this command.");\r
+        return;\r
+         }\r
+\r
+         if ((cmd->level & QAUFLAG_STAFF) && !QAIsStaff(u)) {\r
+        sendnoticetouser(qabot_nick, sender, "You do not have access to this command.");\r
+        return;\r
+      }\r
+\r
+      if ((cmd->level & QAUFLAG_ADMIN) && !QAIsAdmin(u)) {\r
+        sendnoticetouser(qabot_nick, sender, "You do not have access to this command.");\r
+        return;\r
+      }\r
+      \r
+      if ((cmd->level & QAUFLAG_DEVELOPER) && !QAIsDeveloper(u)) {\r
+        sendnoticetouser(qabot_nick, sender, "You do not have access to this command.");\r
+        return;\r
+      }\r
+    }\r
+    \r
+    if (cmd->maxparams < (cargc-1)) {\r
+      rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));\r
+      cargc=(cmd->maxparams) + 1;\r
+    }\r
+    \r
+    (cmd->handler)((void*)sender, cargc - 1, &(cargv[1]));\r
+\r
+    break;\r
+\r
+  case LU_KILLED:\r
+    qabot_nick = NULL;\r
+    scheduleoneshot(time(NULL) + 1, &qabot_createfakeuser, NULL);\r
+    break;\r
+\r
+  case LU_KICKED:\r
+    cp = (channel*)args[1];\r
+    if (cp) {\r
+      localjoinchannel(qabot_nick, cp);\r
+      localgetops(qabot_nick, cp);\r
+    }\r
+    break;\r
+  }\r
+}\r
+\r
+void qabot_child_handler(nick* me, int type, void** args) {\r
+  nick* sender;\r
+  channel* cp;\r
+  qab_bot* bot = me->exts[qabot_nickext];\r
+  char* text;\r
+  Command* cmd;\r
+  char* cargv[50];\r
+  int cargc;\r
+  \r
+  if (!bot) {\r
+    return;\r
+  }\r
+  \r
+  switch (type) {\r
+  case LU_CHANMSG:\r
+    sender = (nick*)args[0];\r
+    cp = (channel*)args[1];\r
+    text = (char*)args[2];\r
+    \r
+    if (*text == '!') {\r
+      cargc = splitline((char*)(++text), cargv, 50, 0);\r
+         cmd = findcommandintree(qabot_chancommands, cargv[0], 1);\r
+         if (!cmd) {\r
+           sendnoticetouser(me, sender, "Unknown command.");\r
+           return;\r
+      }\r
+      \r
+      if ((cp->index == bot->staff_chan) && !(cmd->level & QAC_STAFFCHAN)) {\r
+        sendnoticetouser(me, sender, "This command cannot be used in the staff channel.");\r
+        return;\r
+      }\r
+      \r
+      if ((cp->index == bot->question_chan) && !(cmd->level & QAC_QUESTIONCHAN)) {\r
+        sendnoticetouser(me, sender, "This command cannot be used in the question channel.");\r
+        return;\r
+      }\r
+      \r
+      if (cmd->maxparams < (cargc-1)) {\r
+        rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));\r
+        cargc=(cmd->maxparams) + 1;\r
+      }\r
+      \r
+      qabot_currentbot = bot;\r
+      qabot_currentchan = cp;\r
+      \r
+      (cmd->handler)((void*)sender, cargc - 1, &(cargv[1]));\r
+    }\r
+    else if ((*text != '!') && (bot->micnumeric == sender->numeric) && (cp->index == bot->staff_chan)) {\r
+      bot->lastmic = time(NULL);\r
+      if (bot->lastspam) {\r
+        qab_spam* s;\r
+        \r
+        s = (qab_spam*)malloc(sizeof(qab_spam));\r
+        s->message = strdup(text);\r
+        s->next = 0;\r
+        bot->lastspam->next = s;\r
+        bot->lastspam = s;\r
+      }\r
+      else {\r
+        if ((bot->spamtime + bot->spam_interval) < time(0)) {\r
+          sendmessagetochannel(me, bot->public_chan->channel, "%s", text);\r
+          bot->spammed++;\r
+          bot->spamtime = time(0);\r
+        }\r
+        else {\r
+          qab_spam* s;\r
+          \r
+          s = (qab_spam*)malloc(sizeof(qab_spam));\r
+          s->message = strdup(text);\r
+          s->next = 0;\r
+          bot->nextspam = bot->lastspam = s;\r
+          scheduleoneshot(bot->spamtime + bot->spam_interval, qabot_spam, (void*)bot);\r
+        }\r
+      }\r
+    }\r
+    break;\r
+  \r
+  case LU_PRIVMSG:\r
+  case LU_SECUREMSG:\r
+    sender = (nick*)args[0];\r
+    text = (char*)args[1];\r
+    time_t lastmsg;\r
+    \r
+    lastmsg = (time_t)sender->exts[qabot_spam_nickext];\r
+    \r
+    if ((lastmsg + bot->ask_wait) > time(0)) {\r
+      sendnoticetouser(me, sender, "You have already sent a question recently, please wait at least %d seconds between asking questions.", bot->ask_wait);\r
+      return;\r
+    }\r
+    else {\r
+      char hostbuf[NICKLEN + USERLEN + HOSTLEN + 3];\r
+      qab_block* b;\r
+      qab_question* q;\r
+      unsigned long crc;\r
+      int len;\r
+      \r
+      sendnoticetouser(me, sender, "Your question has been relayed to the %s staff.", bot->public_chan->name->content);\r
+      \r
+      if (!getnumerichandlefromchanhash(bot->public_chan->channel->users, sender->numeric))\r
+        return;\r
+      \r
+      if (*text == '<')\r
+        text++;\r
+      \r
+      len = strlen(text);\r
+      if ((len > 0) && (text[len - 1] == '>')) {\r
+        text[len - 1] = '\0';\r
+        len--;\r
+      }\r
+      \r
+      if ((len < 5) || !strchr(text, ' ') || (*text == 1))\r
+        return;\r
+      \r
+      if ((bot->flags & QAB_AUTHEDONLY) && !IsAccount(sender))\r
+        return;\r
+      \r
+      if (bot->flags & QAB_CONTROLCHAR) {\r
+        char* ch;\r
+        \r
+        for (ch = text; *ch; ch++)\r
+          if ((*ch == 2) || (*ch == 3) || (*ch == 22) || (*ch == 27) || (*ch == 31))\r
+            return;\r
+      }\r
+      else if (bot->flags & QAB_COLOUR) {\r
+        char* ch;\r
+        \r
+        for (ch = text; *ch; ch++)\r
+          if (*ch == 3)\r
+            return;\r
+      }\r
+      \r
+      if (bot->flags & QAB_FLOODDETECT) {\r
+        crc = crc32i(text);\r
+        if (crc == qab_lastq_crc) {\r
+          qab_lastq_count++;\r
+          if (qab_lastq_count >= 3) {\r
+            if ((qab_lastq_count == 3) || ((qab_lastq_count % 10) == 0))\r
+              sendmessagetochannel(me, bot->question_chan->channel, "WARNING: Possible question flood detected%s", (bot->flags & QAB_FLOODSTOP) ? " - AUTO IGNORED." : ".");\r
+            if (bot->flags & QAB_FLOODSTOP)\r
+              return;\r
+          }\r
+        }\r
+        else {\r
+          qab_lastq_crc = crc;\r
+          qab_lastq_count = 1;\r
+        }\r
+      }\r
+      \r
+      sprintf(hostbuf,"%s!%s@%s", sender->nick, sender->ident, sender->host->name->content);\r
+      \r
+      for (b = bot->blocks; b; b = b->next) {\r
+        switch (b->type) {\r
+        case QABBLOCK_ACCOUNT:\r
+          if (IsAccount(sender) && !ircd_strncmp(sender->authname, b->blockstr, ACCOUNTLEN))\r
+            return;\r
+          break;\r
+          \r
+        case QABBLOCK_HOST:\r
+          if (!match(b->blockstr, hostbuf))\r
+            return;\r
+          break;\r
+          \r
+        case QABBLOCK_TEXT:\r
+          if (!match(b->blockstr, text))\r
+            return;\r
+          break;\r
+        }\r
+      }\r
+      \r
+      sender->exts[qabot_spam_nickext] = (void*)time(0);\r
+      \r
+      q = (qab_question*)malloc(sizeof(qab_question));\r
+      q->id = ++bot->lastquestionID;\r
+      q->question = strdup(text);\r
+      q->flags = QAQ_NEW;\r
+      strncpy(q->nick, sender->nick, NICKLEN);\r
+      q->nick[NICKLEN] = '\0';\r
+      q->numeric = sender->numeric;\r
+      q->crc = (bot->flags & QAB_FLOODDETECT) ? crc : 0;\r
+      q->answer = 0;\r
+      q->next = bot->questions[q->id % QUESTIONHASHSIZE];\r
+      \r
+      bot->questions[q->id % QUESTIONHASHSIZE] = q;\r
+      \r
+      sendmessagetochannel(me, bot->question_chan->channel, "ID: %3d <%s> %s", q->id, visiblehostmask(sender, hostbuf), text);\r
+      \r
+      if ((bot->flags & QAB_LINEBREAK) && ((bot->lastquestionID % 10) == 0))\r
+        sendmessagetochannel(me, bot->question_chan->channel, "-----------------------------------");\r
+    }\r
+    break;\r
+    \r
+  case LU_KILLED:\r
+    bot->np = NULL;\r
+    scheduleoneshot(time(NULL) + 1, &qabot_createbotfakeuser, (void*)bot);\r
+    break;\r
+\r
+  case LU_KICKED:\r
+    cp = (channel*)args[1];\r
+    if (cp) {\r
+      localjoinchannel(bot->np, cp);\r
+      localgetops(bot->np, cp);\r
+    }\r
+    break;\r
+  \r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+char* qabot_getvictim(nick* np, char* target) {\r
+  if (*target != '#') {\r
+    nick* victim;\r
+    \r
+    if (!(victim = getnickbynick(target))) {\r
+      sendnoticetouser(qabot_nick, np, "No such nickname.");\r
+      return 0;\r
+    }\r
+    \r
+    if (!IsAccount(victim)) {\r
+      sendnoticetouser(qabot_nick, np, "%s is not authed.", victim->nick);\r
+      return 0;\r
+    }\r
+    \r
+    return victim->authname;\r
+  }\r
+  \r
+  return target + 1;\r
+}\r
+\r
+const char* qabot_uflagtostr(flag_t flags) {\r
+  static char buf[20];\r
+  int i = 0;\r
+  \r
+  buf[i++] = '+';\r
+  \r
+  if (flags & QAUFLAG_ADMIN)     { buf[i++] = 'a'; }\r
+  if (flags & QAUFLAG_DEVELOPER) { buf[i++] = 'd'; }\r
+  if (flags & QAUFLAG_STAFF)     { buf[i++] = 's'; }\r
+  \r
+  buf[i] = '\0';\r
+  \r
+  return buf;\r
+}\r
+\r
+const char* qabot_formattime(time_t tme) {\r
+  static char buf[50];\r
+  struct tm* tmp;\r
+  \r
+  tmp = gmtime(&tme);\r
+  strftime(buf, 15, "%d/%m/%y %H:%M", tmp);\r
+  \r
+  return buf;\r
+}\r
+\r
+qab_bot* qabot_getcurrentbot() {\r
+  return qabot_currentbot;\r
+}\r
+\r
+channel* qabot_getcurrentchannel() {\r
+  return qabot_currentchan;\r
+}\r
index 743d1ad0fa37e655a8b5cfa506dc8d6d97a9c098..78f2498e3ebfaee1682da106d31263be2e6da7c5 100644 (file)
-/* qabot.h */
-#ifndef _QABOT_H
-#define _QABOT_H
-
-#define QABOT_NICK        "QABot"
-#define QABOT_USER        "qabot"
-#define QABOT_HOST        "quakenet.org"
-#define QABOT_NAME        "Question & Answer Bot v1.0"
-#define QABOT_ACCT        "QABot"
-#define QABOT_UMDE        UMODE_SERVICE|UMODE_OPER|UMODE_INV|UMODE_ACCOUNT
-#define QABOT_CHILD_UMODE UMODE_INV
-#define TUTOR_NAME        "#tutorial bot"
-#define TUTOR_ACCOUNT     "Tutor"
-
-#define QABOT_HOMECHAN "#qnet.pr"
-
-#define QAUFLAG_STAFF     0x01
-#define QAUFLAG_ADMIN     0x02
-#define QAUFLAG_DEVELOPER 0x04
-
-#define QAIsStaff(x)     ((x)->flags & (QAUFLAG_STAFF|QAUFLAG_ADMIN|QAUFLAG_DEVELOPER))
-#define QAIsAdmin(x)     ((x)->flags & (QAUFLAG_ADMIN|QAUFLAG_DEVELOPER))
-#define QAIsDeveloper(x) ((x)->flags & QAUFLAG_DEVELOPER)
-
-#define QUESTIONINTERVAL       30
-#define SPAMINTERVAL           10
-#define ASKWAIT                30
-#define QUEUEDQUESTIONINTERVAL 2
-#define QUESTIONHASHSIZE       1000
-
-#define QABOT_SAVEWAIT 3600
-
-#define QABOT_MICTIMEOUT  180
-
-#define QAB_CONTROLCHAR 0x01
-#define QAB_COLOUR      0x02
-#define QAB_AUTHEDONLY  0x04
-#define QAB_LINEBREAK   0x08
-#define QAB_FLOODDETECT 0x10
-#define QAB_FLOODSTOP   0x20
-#define QAB_BLOCKMARK   0x40
-/*#define QAB_
-#define QAB_*/
-
-#define QABBLOCK_ACCOUNT 0
-#define QABBLOCK_HOST    1
-#define QABBLOCK_TEXT    2
-
-#define QAQ_NEW      0x00
-#define QAQ_ANSWERED 0x01
-#define QAQ_OFFTOPIC 0x02
-#define QAQ_SPAM     0x03
-#define QAQ_QSTATE   0x07
-
-#define QAC_QUESTIONCHAN 0x01
-#define QAC_STAFFCHAN    0x02
-
-#define DEFAULTBOTFLAGS QAB_CONTROLCHAR|QAB_COLOUR|QAB_LINEBREAK|QAB_FLOODSTOP
-
-typedef struct qab_user {
-  char             authname[ACCOUNTLEN + 1];
-  flag_t           flags;
-  time_t           created;
-
-  struct qab_user* next;
-  struct qab_user* prev;
-} qab_user;
-
-typedef struct qab_spam {
-  char*            message;
-  
-  struct qab_spam* next;
-} qab_spam;
-
-typedef struct qab_question {
-  int                  id;
-  char*                question;
-  flag_t               flags;
-  char                 nick[NICKLEN + 1];
-  unsigned long        numeric;
-  unsigned long        crc;
-  char*                answer;
-  
-  struct qab_question* next;
-} qab_question;
-
-typedef struct qab_answer {
-  qab_question*      question;
-  char               nick[NICKLEN + 1];
-  
-  struct qab_answer* next;
-} qab_answer;
-
-typedef struct qab_block {
-  char              type;
-  char              creator[ACCOUNTLEN + 1];
-  time_t            created;
-  char*             blockstr;
-
-  struct qab_block* next;
-  struct qab_block* prev;
-} qab_block;
-
-typedef struct qab_textsection {
-  qab_spam*               lines;
-  qab_spam*               lines_tail;
-  int                     line_count;
-  
-  struct qab_textsection* next;
-  struct qab_textsection* prev;
-} qab_textsection;
-
-typedef struct qab_text {
-  char             name[NICKLEN + 1];
-  qab_textsection* sections;
-  qab_textsection* sections_tail;
-  int              section_count;
-  
-  struct qab_text* next;
-  struct qab_text* prev;
-} qab_text;
-
-typedef struct qab_bot {
-  char             nick[NICKLEN + 1];
-  char             user[USERLEN + 1];
-  char*            host;
-  
-  nick*            np;
-  
-  chanindex*       public_chan;
-  chanindex*       question_chan;
-  chanindex*       staff_chan;
-  
-  flag_t           flags;
-  
-  /*int              question_interval;*/
-  int              spam_interval;
-  int              ask_wait;
-  int              queued_question_interval;
-  
-  time_t           lastmic;
-  int              mic_timeout;
-  
-  qab_block*       blocks;
-  int              block_count;
-  
-  qab_question*    questions[QUESTIONHASHSIZE];
-  int              lastquestionID;
-  int              answered;
-  
-  int              spammed;
-  
-  qab_spam*        nextspam;
-  qab_spam*        lastspam;
-  time_t           spamtime;
-  
-  qab_answer*      answers;
-  
-  unsigned long    micnumeric;
-  
-  qab_textsection* recording_section;
-  qab_text*        texts;
-
-  struct qab_bot*  next;
-  struct qab_bot*  prev;
-} qab_bot;
-
-extern time_t qab_startime;
-extern int qabot_nickext;
-extern int qabot_spam_nickext;
-extern int qabot_chanext;
-extern nick* qabot_nick;
-extern CommandTree* qabot_commands;
-extern qab_user* qabot_users;
-extern qab_bot* qab_bots;
-extern unsigned long qab_lastq_crc;
-extern int qab_lastq_count;
-
-/* qabot.c */
-void qabot_lostnick(int hooknum, void* arg);
-void qabot_channel_part(int hooknum, void* arg);
-void qabot_createfakeuser(void* arg);
-void qabot_handler(nick* me, int type, void** args);
-void qabot_child_handler(nick* me, int type, void** args);
-char* qabot_getvictim(nick* np, char* target);
-const char* qabot_uflagtostr(flag_t flags);
-const char* qabot_formattime(time_t tme);
-
-/* qabot_bot.c */
-qab_bot* qabot_getbot();
-int qabot_addbot(char* nickname, char* user, char* host, char* pub_chan, char* qu_chan, char* stff_chan, flag_t flags, int spam_interval, int ask_wait, int queued_question_interval, nick* sender);
-void qabot_delbot(qab_bot* bot);
-channel* qabot_getchannel(char* channel_name);
-void qabot_spam(void* arg);
-void qabot_spamstored(void* arg);
-void qabot_createbotfakeuser(void* arg);
-qab_bot* qabot_getcurrentbot();
-channel* qabot_getcurrentchannel();
-void qabot_timer(void* arg);
-
-/* qabot_chancommands.c */
-int qabot_dochananswer(void* np, int cargc, char** cargv);
-int qabot_dochanblock(void* np, int cargc, char** cargv);
-int qabot_dochanclear(void* np, int cargc, char** cargv);
-int qabot_dochanclosechan(void* np, int cargc, char** cargv);
-int qabot_dochanconfig(void* np, int cargc, char** cargv);
-int qabot_dochanhelp(void* np, int cargc, char** cargv);
-int qabot_dochanlistblocks(void* np, int cargc, char** cargv);
-int qabot_dochanmic(void* np, int cargc, char** cargv);
-int qabot_dochanmoo(void* np, int cargc, char** cargv);
-int qabot_dochanofftopic(void* np, int cargc, char** cargv);
-int qabot_dochanopenchan(void* np, int cargc, char** cargv);
-int qabot_dochanping(void* np, int cargc, char** cargv);
-int qabot_dochanreset(void* np, int cargc, char** cargv);
-int qabot_dochanspam(void* np, int cargc, char** cargv);
-int qabot_dochanstatus(void* np, int cargc, char** cargv);
-int qabot_dochanunblock(void* np, int cargc, char** cargv);
-int qabot_dochanlisttexts(void* np, int cargc, char** cargv);
-int qabot_dochanshowsection(void* np, int cargc, char** cargv);
-int qabot_dochanaddtext(void* np, int cargc, char** cargv);
-int qabot_dochandeltext(void* np, int cargc, char** cargv);
-int qabot_dochanaddsection(void* np, int cargc, char** cargv);
-int qabot_dochandelsection(void* np, int cargc, char** cargv);
-int qabot_dochanrecord(void* np, int cargc, char** cargv);
-
-/* qabot_commands.c */
-int qabot_doshowcommands(void* sender, int cargc, char** cargv);
-int qabot_dohelp(void* sender, int cargc, char** cargv);
-int qabot_dohello(void* sender, int cargc, char** cargv);
-int qabot_dosave(void* sender, int cargc, char** cargv);
-int qabot_dolistbots(void* sender, int cargc, char** cargv);
-int qabot_dolistusers(void* sender, int cargc, char** cargv);
-int qabot_doshowbot(void* sender, int cargc, char** cargv);
-int qabot_doaddbot(void* sender, int cargc, char** cargv);
-int qabot_dodelbot(void* sender, int cargc, char** cargv);
-int qabot_doadduser(void* sender, int cargc, char** cargv);
-int qabot_dodeluser(void* sender, int cargc, char** cargv);
-int qabot_dochangelev(void* sender, int cargc, char** cargv);
-int qabot_dowhois(void* sender, int cargc, char** cargv);
-int qabot_dostatus(void* sender, int cargc, char** cargv);
-
-/* qabot_dbase.c */
-void qabot_loaddb();
-void qabot_savedb();
-void qabot_savetimer(void* arg);
-void qabot_adduser(const char* authname, flag_t flags, time_t created);
-void qabot_deluser(const char* authname);
-void qabot_squelchuser(qab_user* user);
-qab_user* qabot_getuser(const char* authname);
-qab_bot* qabot_findbot(const char* nickname);
-
-/* qabot_help.c */
-int qabot_showhelp(nick* np, char* arg);
-
-/* qabot_texts.c */
-void qabot_freetext(qab_bot* bot, qab_text* text);
-void qabot_freesection(qab_text* text, qab_textsection* section);
-
-#endif
+/* qabot.h */\r
+#ifndef _QABOT_H\r
+#define _QABOT_H\r
+\r
+#define QABOT_NICK        "QABot"\r
+#define QABOT_USER        "qabot"\r
+#define QABOT_HOST        "quakenet.org"\r
+#define QABOT_NAME        "Question & Answer Bot v1.0"\r
+#define QABOT_ACCT        "QABot"\r
+#define QABOT_UMDE        UMODE_SERVICE|UMODE_OPER|UMODE_INV|UMODE_ACCOUNT\r
+#define QABOT_CHILD_UMODE UMODE_INV\r
+#define TUTOR_NAME        "#tutorial bot"\r
+#define TUTOR_ACCOUNT     "Tutor"\r
+\r
+#define QABOT_HOMECHAN "#qnet.pr"\r
+\r
+#define QAUFLAG_STAFF     0x01\r
+#define QAUFLAG_ADMIN     0x02\r
+#define QAUFLAG_DEVELOPER 0x04\r
+\r
+#define QAIsStaff(x)     ((x)->flags & (QAUFLAG_STAFF|QAUFLAG_ADMIN|QAUFLAG_DEVELOPER))\r
+#define QAIsAdmin(x)     ((x)->flags & (QAUFLAG_ADMIN|QAUFLAG_DEVELOPER))\r
+#define QAIsDeveloper(x) ((x)->flags & QAUFLAG_DEVELOPER)\r
+\r
+#define QUESTIONINTERVAL       30\r
+#define SPAMINTERVAL           10\r
+#define ASKWAIT                30\r
+#define QUEUEDQUESTIONINTERVAL 2\r
+#define QUESTIONHASHSIZE       1000\r
+\r
+#define QABOT_SAVEWAIT 3600\r
+\r
+#define QABOT_MICTIMEOUT  180\r
+\r
+#define QAB_CONTROLCHAR 0x01\r
+#define QAB_COLOUR      0x02\r
+#define QAB_AUTHEDONLY  0x04\r
+#define QAB_LINEBREAK   0x08\r
+#define QAB_FLOODDETECT 0x10\r
+#define QAB_FLOODSTOP   0x20\r
+#define QAB_BLOCKMARK   0x40\r
+/*#define QAB_\r
+#define QAB_*/\r
+\r
+#define QABBLOCK_ACCOUNT 0\r
+#define QABBLOCK_HOST    1\r
+#define QABBLOCK_TEXT    2\r
+\r
+#define QAQ_NEW      0x00\r
+#define QAQ_ANSWERED 0x01\r
+#define QAQ_OFFTOPIC 0x02\r
+#define QAQ_SPAM     0x03\r
+#define QAQ_QSTATE   0x07\r
+\r
+#define QAC_QUESTIONCHAN 0x01\r
+#define QAC_STAFFCHAN    0x02\r
+\r
+#define DEFAULTBOTFLAGS QAB_CONTROLCHAR|QAB_COLOUR|QAB_LINEBREAK|QAB_FLOODSTOP\r
+\r
+typedef struct qab_user {\r
+  char             authname[ACCOUNTLEN + 1];\r
+  flag_t           flags;\r
+  time_t           created;\r
+\r
+  struct qab_user* next;\r
+  struct qab_user* prev;\r
+} qab_user;\r
+\r
+typedef struct qab_spam {\r
+  char*            message;\r
+  \r
+  struct qab_spam* next;\r
+} qab_spam;\r
+\r
+typedef struct qab_question {\r
+  int                  id;\r
+  char*                question;\r
+  flag_t               flags;\r
+  char                 nick[NICKLEN + 1];\r
+  unsigned long        numeric;\r
+  unsigned long        crc;\r
+  char*                answer;\r
+  \r
+  struct qab_question* next;\r
+} qab_question;\r
+\r
+typedef struct qab_answer {\r
+  qab_question*      question;\r
+  char               nick[NICKLEN + 1];\r
+  \r
+  struct qab_answer* next;\r
+} qab_answer;\r
+\r
+typedef struct qab_block {\r
+  char     type;\r
+  char              creator[ACCOUNTLEN + 1];\r
+  time_t            created;\r
+  char*             blockstr;\r
+\r
+  struct qab_block* next;\r
+  struct qab_block* prev;\r
+} qab_block;\r
+\r
+typedef struct qab_bot {\r
+  char            nick[NICKLEN + 1];\r
+  char            user[USERLEN + 1];\r
+  char*           host;\r
+  \r
+  nick*           np;\r
+  \r
+  chanindex*      public_chan;\r
+  chanindex*      question_chan;\r
+  chanindex*      staff_chan;\r
+  \r
+  flag_t          flags;\r
+  \r
+  /*int             question_interval;*/\r
+  int             spam_interval;\r
+  int             ask_wait;\r
+  int             queued_question_interval;\r
+  \r
+  time_t          lastmic;\r
+  int             mic_timeout;\r
+  \r
+  qab_block*      blocks;\r
+  int             block_count;\r
+  \r
+  qab_question*   questions[QUESTIONHASHSIZE];\r
+  int             lastquestionID;\r
+  int             answered;\r
+  \r
+  int             spammed;\r
+  \r
+  qab_spam*       nextspam;\r
+  qab_spam*       lastspam;\r
+  time_t          spamtime;\r
+  \r
+  qab_answer*     answers;\r
+  \r
+  unsigned long   micnumeric;\r
+\r
+  struct qab_bot* next;\r
+  struct qab_bot* prev;\r
+} qab_bot;\r
+\r
+extern time_t qab_startime;\r
+extern int qabot_nickext;\r
+extern int qabot_spam_nickext;\r
+extern int qabot_chanext;\r
+extern nick* qabot_nick;\r
+extern CommandTree* qabot_commands;\r
+extern qab_user* qabot_users;\r
+extern qab_bot* qab_bots;\r
+extern unsigned long qab_lastq_crc;\r
+extern int qab_lastq_count;\r
+\r
+/* qabot.c */\r
+void qabot_lostnick(int hooknum, void* arg);\r
+void qabot_channel_part(int hooknum, void* arg);\r
+void qabot_createfakeuser(void* arg);\r
+void qabot_handler(nick* me, int type, void** args);\r
+void qabot_child_handler(nick* me, int type, void** args);\r
+char* qabot_getvictim(nick* np, char* target);\r
+const char* qabot_uflagtostr(flag_t flags);\r
+const char* qabot_formattime(time_t tme);\r
+\r
+/* qabot_bot.c */\r
+qab_bot* qabot_getbot();\r
+int qabot_addbot(char* nickname, char* user, char* host, char* pub_chan, char* qu_chan, char* stff_chan, flag_t flags, int spam_interval, int ask_wait, int queued_question_interval, nick* sender);\r
+void qabot_delbot(qab_bot* bot);\r
+channel* qabot_getchannel(char* channel_name);\r
+void qabot_spam(void* arg);\r
+void qabot_spamstored(void* arg);\r
+void qabot_createbotfakeuser(void* arg);\r
+qab_bot* qabot_getcurrentbot();\r
+channel* qabot_getcurrentchannel();\r
+void qabot_timer(void* arg);\r
+\r
+/* qabot_chancommands.c */\r
+int qabot_dochananswer(void* np, int cargc, char** cargv);\r
+int qabot_dochanblock(void* np, int cargc, char** cargv);\r
+int qabot_dochanclear(void* np, int cargc, char** cargv);\r
+int qabot_dochanclosechan(void* np, int cargc, char** cargv);\r
+int qabot_dochanconfig(void* np, int cargc, char** cargv);\r
+int qabot_dochanhelp(void* np, int cargc, char** cargv);\r
+int qabot_dochanlistblocks(void* np, int cargc, char** cargv);\r
+int qabot_dochanmic(void* np, int cargc, char** cargv);\r
+int qabot_dochanmoo(void* np, int cargc, char** cargv);\r
+int qabot_dochanofftopic(void* np, int cargc, char** cargv);\r
+int qabot_dochanopenchan(void* np, int cargc, char** cargv);\r
+int qabot_dochanping(void* np, int cargc, char** cargv);\r
+int qabot_dochanreset(void* np, int cargc, char** cargv);\r
+int qabot_dochanspam(void* np, int cargc, char** cargv);\r
+int qabot_dochanstatus(void* np, int cargc, char** cargv);\r
+int qabot_dochanunblock(void* np, int cargc, char** cargv);\r
+\r
+/* qabot_commands.c */\r
+int qabot_doshowcommands(void* sender, int cargc, char** cargv);\r
+int qabot_dohelp(void* sender, int cargc, char** cargv);\r
+int qabot_dohello(void* sender, int cargc, char** cargv);\r
+int qabot_dosave(void* sender, int cargc, char** cargv);\r
+int qabot_dolistbots(void* sender, int cargc, char** cargv);\r
+int qabot_dolistusers(void* sender, int cargc, char** cargv);\r
+int qabot_doshowbot(void* sender, int cargc, char** cargv);\r
+int qabot_doaddbot(void* sender, int cargc, char** cargv);\r
+int qabot_dodelbot(void* sender, int cargc, char** cargv);\r
+int qabot_doadduser(void* sender, int cargc, char** cargv);\r
+int qabot_dodeluser(void* sender, int cargc, char** cargv);\r
+int qabot_dochangelev(void* sender, int cargc, char** cargv);\r
+int qabot_dowhois(void* sender, int cargc, char** cargv);\r
+int qabot_dostatus(void* sender, int cargc, char** cargv);\r
+\r
+/* qabot_dbase.c */\r
+void qabot_loaddb();\r
+void qabot_savedb();\r
+void qabot_savetimer(void* arg);\r
+void qabot_adduser(const char* authname, flag_t flags, time_t created);\r
+void qabot_deluser(const char* authname);\r
+void qabot_squelchuser(qab_user* user);\r
+qab_user* qabot_getuser(const char* authname);\r
+\r
+/* qabot_help.c */\r
+int qabot_showhelp(nick* np, char* arg);\r
+\r
+#endif\r
index 1b6e209ee95ef39a3a80fa18c46b29cfed57edea..3818b2933d6dd2115721b1a66c5a78e1a831afe1 100644 (file)
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#include "../nick/nick.h"
-#include "../localuser/localuserchannel.h"
-#include "../core/hooks.h"
-#include "../core/schedule.h"
-#include "../lib/array.h"
-#include "../lib/base64.h"
-#include "../lib/irc_string.h"
-#include "../lib/splitline.h"
-
-#include "qabot.h"
-
-qab_bot* qabot_getbot() {
-  qab_bot* bot;
-  int i;
-  
-  bot = (qab_bot*)malloc(sizeof(qab_bot));
-  bot->nick[0] = '\0';
-  bot->user[0] = '\0';
-  bot->host = 0;
-  bot->np = 0;
-  bot->public_chan = 0;
-  bot->question_chan = 0;
-  bot->staff_chan = 0;
-  bot->blocks = 0;
-  bot->block_count = 0;
-  
-  bot->spammed = 0;
-  
-  bot->flags = DEFAULTBOTFLAGS;
-  
-  /*bot->question_interval = QUESTIONINTERVAL;*/
-  bot->spam_interval = SPAMINTERVAL;
-  bot->ask_wait = ASKWAIT;
-  bot->queued_question_interval = QUEUEDQUESTIONINTERVAL;
-  
-  bot->lastquestionID = 0;
-  bot->answered = 0;
-  
-  for (i = 0; i < QUESTIONHASHSIZE; i++)
-    bot->questions[i] = 0;
-  
-  bot->nextspam = 0;
-  bot->lastspam = 0;
-  bot->spamtime = 0;
-  bot->answers = 0;
-  
-  bot->micnumeric = 0;
-  
-  bot->recording_section = 0;
-  bot->texts = 0;
-  
-  bot->next = 0;
-  bot->prev = 0;
-}
-
-int qabot_addbot(char* nickname, char* user, char* host, char* pub_chan, char* qu_chan, char* stff_chan, flag_t flags, int spam_interval, 
-  int ask_wait, int queued_question_interval, nick* sender) {
-  qab_bot* bot;
-  channel* cp;
-  
-  if (*pub_chan != '#') {
-    if (sender)
-      sendnoticetouser(qabot_nick, sender, "Invalid public channel.");
-    return 0;
-  }
-  
-  if (*qu_chan != '#') {
-    if (sender)
-      sendnoticetouser(qabot_nick, sender, "Invalid question channel.");
-    return 0;
-  }
-  
-  if (*stff_chan != '#') {
-    if (sender)
-      sendnoticetouser(qabot_nick, sender, "Invalid staff channel.");
-    return 0;
-  }
-  
-  for (bot = qab_bots; bot; bot = bot->next) {
-    if (!ircd_strcmp(bot->nick, nickname)) {
-      if (sender)
-        sendnoticetouser(qabot_nick, sender, "That QABot already exists.");
-      return 0;
-    }
-    
-    if (!ircd_strcmp(bot->public_chan->name->content, pub_chan)) {
-      if (sender)
-        sendnoticetouser(qabot_nick, sender, "That public channel is already in use by %s.", bot->nick);
-      return 0;
-    }
-    
-    if (!ircd_strcmp(bot->question_chan->name->content, qu_chan)) {
-      if (sender)
-        sendnoticetouser(qabot_nick, sender, "That question channel is already in use by %s.", bot->nick);
-      return 0;
-    }
-    
-    if (!ircd_strcmp(bot->staff_chan->name->content, stff_chan)) {
-      if (sender)
-        sendnoticetouser(qabot_nick, sender, "That staff channel is already in use by %s.", bot->nick);
-      return 0;
-    }
-  }
-  
-  bot = qabot_getbot();
-  strncpy(bot->nick, nickname, NICKLEN);
-  bot->nick[NICKLEN] = '\0';
-  strncpy(bot->user, user, USERLEN);
-  bot->user[USERLEN] = '\0';
-  bot->host = strdup(host);
-  if (!ircd_strcmp(nickname, "Tutor"))
-    bot->np = registerlocaluser(nickname, user, host, TUTOR_NAME, TUTOR_ACCOUNT, QABOT_CHILD_UMODE|UMODE_ACCOUNT, &qabot_child_handler);
-  else
-    bot->np = registerlocaluser(nickname, user, host, QABOT_NAME, NULL, QABOT_CHILD_UMODE, &qabot_child_handler);
-  
-  bot->flags = flags;
-  bot->spam_interval = spam_interval;
-  bot->ask_wait = ask_wait;
-  bot->queued_question_interval = queued_question_interval;
-  
-  bot->mic_timeout = QABOT_MICTIMEOUT;
-  
-  bot->lastmic = 0;
-  
-  if ((cp = findchannel(pub_chan))) {
-    localjoinchannel(bot->np, cp);
-    localgetops(bot->np, cp);
-    bot->public_chan = cp->index;
-  }
-  else {
-    localcreatechannel(bot->np, pub_chan);
-    cp = findchannel(pub_chan);
-    bot->public_chan = cp->index;
-  }
-  
-  if ((cp = findchannel(qu_chan))) {
-    localjoinchannel(bot->np, cp);
-    bot->question_chan = cp->index;
-  }
-  else {
-    localcreatechannel(bot->np, qu_chan);
-    cp = findchannel(qu_chan);
-    bot->question_chan = cp->index;
-  }
-  
-  if (!IsModerated(cp)) {
-    irc_send("%s M %s +m\r\n", mynumeric->content, cp->index->name->content);
-    SetModerated(cp);
-  }
-  
-  if ((cp = findchannel(stff_chan))) {
-    localjoinchannel(bot->np, cp);
-    localgetops(bot->np, cp);
-    bot->staff_chan = cp->index;
-  }
-  else {
-    localcreatechannel(bot->np, stff_chan);
-    cp = findchannel(stff_chan);
-    bot->staff_chan = cp->index;
-  }
-  
-  bot->next = qab_bots;
-  if (qab_bots)
-    qab_bots->prev = bot;
-  qab_bots = bot;
-  
-  bot->np->exts[qabot_nickext] = (void*)bot;
-  
-  scheduleoneshot(time(NULL) + 10, &qabot_timer, (void*)bot);
-  
-  return 1;
-}
-
-void qabot_delbot(qab_bot* bot) {
-  qab_block* b;
-  qab_question* q;
-  qab_spam* s;
-  qab_spam* ns;
-  qab_answer* a;
-  qab_answer* na;
-  int i;
-  
-  deleteschedule(0, qabot_spam, (void*)bot);
-  deleteschedule(0, qabot_spamstored, (void*)bot);
-  deleteschedule(0, qabot_createbotfakeuser, (void*)bot);
-  deleteschedule(0, qabot_timer, (void*)bot);
-  
-  while (bot->texts)
-    qabot_freetext(bot, texts);
-          
-  while (bot->blocks) {
-    b = bot->blocks;
-    bot->blocks = bot->blocks->next;
-    if (b->blockstr)
-      free(b->blockstr);
-    free(b);
-  }
-  
-  for (i = 0; i < QUESTIONHASHSIZE; i++) {
-    while (bot->questions[i]) {
-      q = bot->questions[i];
-      bot->questions[i] = bot->questions[i]->next;
-      if (q->question)
-        free(q->question);
-      if (q->answer)
-        free(q->answer);
-      free(q);
-    }
-  }
-  
-  for (s = bot->nextspam; s; s = ns) {
-    ns = s->next;
-    free(s->message);
-    free(s);
-  }
-  
-  for (a = bot->answers; a; a = na) {
-    na = a->next;
-    free(a);
-  }
-  
-  if (bot->host)
-    free(bot->host);
-  deregisterlocaluser(bot->np, "Bot deleted.");
-  
-  if (bot->next)
-    bot->next->prev = bot->prev;
-  if (bot->prev)
-    bot->prev->next = bot->next;
-  else
-    qab_bots = bot->next;
-  
-  free(bot);
-}
-
-void qabot_spam(void* arg) {
-  qab_bot* bot = (qab_bot*)arg;
-  qab_spam* s;
-  
-  if (!bot->nextspam)
-    return;
-  
-  if (bot->np) {
-    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s", bot->nextspam->message);
-    bot->spammed++;
-  }
-  
-  s = bot->nextspam;
-  bot->nextspam = s->next;
-  
-  free(s->message);
-  free(s);
-  
-  bot->spamtime = time(0);
-  
-  if (bot->nextspam)
-    scheduleoneshot(bot->spamtime + bot->spam_interval, qabot_spam, (void*)bot);
-  else {
-    bot->lastspam = 0;
-    if (!bot->micnumeric)
-      qabot_spamstored((void*)bot);
-  }
-}
-
-void qabot_spamstored(void* arg) {
-  qab_bot* bot = (qab_bot*)arg;
-  qab_answer* a;
-  
-  if (!bot->answers)
-    return;
-  
-  if (bot->np) {
-    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s asked: %s", bot->answers->question->nick, 
-      bot->answers->question->question);
-    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s answered: %s", bot->answers->nick, 
-    bot->answers->question->answer);
-  }
-  
-  a = bot->answers;
-  bot->answers = a->next;
-  
-  free(a);
-  
-  if (bot->answers)
-    scheduleoneshot(time(0) + bot->queued_question_interval, qabot_spamstored, (void*)bot);
-}
-
-void qabot_createbotfakeuser(void* arg) {
-  qab_bot* bot = (qab_bot*)arg;
-  
-  if (bot->np)
-    return;
-  
-  bot->np = registerlocaluser(bot->nick, bot->user, bot->host, QABOT_NAME, NULL, QABOT_CHILD_UMODE, &qabot_child_handler);
-  
-  bot->np->exts[qabot_nickext] = (void*)bot;
-  
-  if (bot->public_chan->channel) {
-    localjoinchannel(bot->np, bot->public_chan->channel);
-    localgetops(bot->np, bot->public_chan->channel);
-  }
-  else
-    localcreatechannel(bot->np, bot->public_chan->name->content);
-  
-  if (bot->question_chan->channel) {
-    localjoinchannel(bot->np, bot->question_chan->channel);
-    localgetops(bot->np, bot->question_chan->channel);
-  }
-  else
-    localcreatechannel(bot->np, bot->question_chan->name->content);
-  
-  if (bot->staff_chan->channel) {
-    localjoinchannel(bot->np, bot->staff_chan->channel);
-    localgetops(bot->np, bot->staff_chan->channel);
-  }
-  else
-    localcreatechannel(bot->np, bot->staff_chan->name->content);
-}
-
-void qabot_timer(void* arg) {
-  qab_bot* bot = (qab_bot*)arg;
-  
-  if (!bot)
-    return;
-  
-  if (bot->micnumeric && (bot->mic_timeout > 0) && (time(NULL) >= (bot->lastmic + bot->mic_timeout))) {
-    bot->micnumeric = 0;
-    
-    sendmessagetochannel(bot->np, bot->staff_chan->channel, "%s deactivated (idle timeout).", 
-      bot->recording_section ? "Recorder" : "Mic");
-    if (!bot->lastspam && !bot->recording_section)
-      qabot_spamstored((void*)bot);
-    
-    bot->recording_section = 0;
-  }
-  
-  scheduleoneshot(time(NULL) + 10, &qabot_timer, (void*)bot);
-}
+#include <stdio.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "../nick/nick.h"\r
+#include "../localuser/localuserchannel.h"\r
+#include "../core/hooks.h"\r
+#include "../core/schedule.h"\r
+#include "../lib/array.h"\r
+#include "../lib/base64.h"\r
+#include "../lib/irc_string.h"\r
+#include "../lib/splitline.h"\r
+\r
+#include "qabot.h"\r
+\r
+qab_bot* qabot_getbot() {\r
+  qab_bot* bot;\r
+  int i;\r
+  \r
+  bot = (qab_bot*)malloc(sizeof(qab_bot));\r
+  bot->nick[0] = '\0';\r
+  bot->user[0] = '\0';\r
+  bot->host = 0;\r
+  bot->np = 0;\r
+  bot->public_chan = 0;\r
+  bot->question_chan = 0;\r
+  bot->staff_chan = 0;\r
+  bot->blocks = 0;\r
+  bot->block_count = 0;\r
+  \r
+  bot->spammed = 0;\r
+  \r
+  bot->flags = DEFAULTBOTFLAGS;\r
+  \r
+  /*bot->question_interval = QUESTIONINTERVAL;*/\r
+  bot->spam_interval = SPAMINTERVAL;\r
+  bot->ask_wait = ASKWAIT;\r
+  bot->queued_question_interval = QUEUEDQUESTIONINTERVAL;\r
+  \r
+  bot->lastquestionID = 0;\r
+  bot->answered = 0;\r
+  \r
+  for (i = 0; i < QUESTIONHASHSIZE; i++)\r
+    bot->questions[i] = 0;\r
+  \r
+  bot->nextspam = 0;\r
+  bot->lastspam = 0;\r
+  bot->spamtime = 0;\r
+  bot->answers = 0;\r
+  \r
+  bot->micnumeric = 0;\r
+  \r
+  bot->next = 0;\r
+  bot->prev = 0;\r
+}\r
+\r
+int qabot_addbot(char* nickname, char* user, char* host, char* pub_chan, char* qu_chan, char* stff_chan, flag_t flags, int spam_interval, \r
+  int ask_wait, int queued_question_interval, nick* sender) {\r
+  qab_bot* bot;\r
+  channel* cp;\r
+  \r
+  if (*pub_chan != '#') {\r
+    if (sender)\r
+      sendnoticetouser(qabot_nick, sender, "Invalid public channel.");\r
+    return 0;\r
+  }\r
+  \r
+  if (*qu_chan != '#') {\r
+    if (sender)\r
+      sendnoticetouser(qabot_nick, sender, "Invalid question channel.");\r
+    return 0;\r
+  }\r
+  \r
+  if (*stff_chan != '#') {\r
+    if (sender)\r
+      sendnoticetouser(qabot_nick, sender, "Invalid staff channel.");\r
+    return 0;\r
+  }\r
+  \r
+  for (bot = qab_bots; bot; bot = bot->next) {\r
+    if (!ircd_strcmp(bot->nick, nickname)) {\r
+      if (sender)\r
+        sendnoticetouser(qabot_nick, sender, "That QABot already exists.");\r
+      return 0;\r
+    }\r
+    \r
+    if (!ircd_strcmp(bot->public_chan->name->content, pub_chan)) {\r
+      if (sender)\r
+        sendnoticetouser(qabot_nick, sender, "That public channel is already in use by %s.", bot->nick);\r
+      return 0;\r
+    }\r
+    \r
+    if (!ircd_strcmp(bot->question_chan->name->content, qu_chan)) {\r
+      if (sender)\r
+        sendnoticetouser(qabot_nick, sender, "That question channel is already in use by %s.", bot->nick);\r
+      return 0;\r
+    }\r
+    \r
+    if (!ircd_strcmp(bot->staff_chan->name->content, stff_chan)) {\r
+      if (sender)\r
+        sendnoticetouser(qabot_nick, sender, "That staff channel is already in use by %s.", bot->nick);\r
+      return 0;\r
+    }\r
+  }\r
+  \r
+  bot = qabot_getbot();\r
+  strncpy(bot->nick, nickname, NICKLEN);\r
+  bot->nick[NICKLEN] = '\0';\r
+  strncpy(bot->user, user, USERLEN);\r
+  bot->user[USERLEN] = '\0';\r
+  bot->host = strdup(host);\r
+  if (!ircd_strcmp(nickname, "Tutor"))\r
+    bot->np = registerlocaluser(nickname, user, host, TUTOR_NAME, TUTOR_ACCOUNT, QABOT_CHILD_UMODE|UMODE_ACCOUNT, &qabot_child_handler);\r
+  else\r
+    bot->np = registerlocaluser(nickname, user, host, QABOT_NAME, NULL, QABOT_CHILD_UMODE, &qabot_child_handler);\r
+  \r
+  bot->flags = flags;\r
+  bot->spam_interval = spam_interval;\r
+  bot->ask_wait = ask_wait;\r
+  bot->queued_question_interval = queued_question_interval;\r
+  \r
+  bot->mic_timeout = QABOT_MICTIMEOUT;\r
+  \r
+  bot->lastmic = 0;\r
+  \r
+  if ((cp = findchannel(pub_chan))) {\r
+    localjoinchannel(bot->np, cp);\r
+    localgetops(bot->np, cp);\r
+    bot->public_chan = cp->index;\r
+  }\r
+  else {\r
+    localcreatechannel(bot->np, pub_chan);\r
+    cp = findchannel(pub_chan);\r
+    bot->public_chan = cp->index;\r
+  }\r
+  \r
+  if ((cp = findchannel(qu_chan))) {\r
+    localjoinchannel(bot->np, cp);\r
+    bot->question_chan = cp->index;\r
+  }\r
+  else {\r
+    localcreatechannel(bot->np, qu_chan);\r
+    cp = findchannel(qu_chan);\r
+    bot->question_chan = cp->index;\r
+  }\r
+  \r
+  if (!IsModerated(cp)) {\r
+    irc_send("%s M %s +m\r\n", mynumeric->content, cp->index->name->content);\r
+    SetModerated(cp);\r
+  }\r
+  \r
+  if ((cp = findchannel(stff_chan))) {\r
+    localjoinchannel(bot->np, cp);\r
+    localgetops(bot->np, cp);\r
+    bot->staff_chan = cp->index;\r
+  }\r
+  else {\r
+    localcreatechannel(bot->np, stff_chan);\r
+    cp = findchannel(stff_chan);\r
+    bot->staff_chan = cp->index;\r
+  }\r
+  \r
+  bot->next = qab_bots;\r
+  if (qab_bots)\r
+    qab_bots->prev = bot;\r
+  qab_bots = bot;\r
+  \r
+  bot->np->exts[qabot_nickext] = (void*)bot;\r
+  \r
+  scheduleoneshot(time(NULL) + 10, &qabot_timer, (void*)bot);\r
+  \r
+  return 1;\r
+}\r
+\r
+void qabot_delbot(qab_bot* bot) {\r
+  qab_block* b;\r
+  qab_question* q;\r
+  qab_spam* s;\r
+  qab_spam* ns;\r
+  qab_answer* a;\r
+  qab_answer* na;\r
+  int i;\r
+  \r
+  deleteschedule(0, qabot_spam, (void*)bot);\r
+  deleteschedule(0, qabot_spamstored, (void*)bot);\r
+  deleteschedule(0, qabot_createbotfakeuser, (void*)bot);\r
+  deleteschedule(0, qabot_timer, (void*)bot);\r
+          \r
+  while (bot->blocks) {\r
+    b = bot->blocks;\r
+    bot->blocks = bot->blocks->next;\r
+    if (b->blockstr)\r
+      free(b->blockstr);\r
+    free(b);\r
+  }\r
+  \r
+  for (i = 0; i < QUESTIONHASHSIZE; i++) {\r
+    while (bot->questions[i]) {\r
+      q = bot->questions[i];\r
+      bot->questions[i] = bot->questions[i]->next;\r
+      if (q->question)\r
+        free(q->question);\r
+      if (q->answer)\r
+        free(q->answer);\r
+      free(q);\r
+    }\r
+  }\r
+  \r
+  for (s = bot->nextspam; s; s = ns) {\r
+    ns = s->next;\r
+    free(s->message);\r
+    free(s);\r
+  }\r
+  \r
+  for (a = bot->answers; a; a = na) {\r
+    na = a->next;\r
+    free(a);\r
+  }\r
+  \r
+  if (bot->host)\r
+    free(bot->host);\r
+  deregisterlocaluser(bot->np, "Bot deleted.");\r
+  \r
+  if (bot->next)\r
+    bot->next->prev = bot->prev;\r
+  if (bot->prev)\r
+    bot->prev->next = bot->next;\r
+  else\r
+    qab_bots = bot->next;\r
+  \r
+  free(bot);\r
+}\r
+\r
+void qabot_spam(void* arg) {\r
+  qab_bot* bot = (qab_bot*)arg;\r
+  qab_spam* s;\r
+  \r
+  if (!bot->nextspam)\r
+    return;\r
+  \r
+  if (bot->np) {\r
+    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s", bot->nextspam->message);\r
+    bot->spammed++;\r
+  }\r
+  \r
+  s = bot->nextspam;\r
+  bot->nextspam = s->next;\r
+  \r
+  free(s->message);\r
+  free(s);\r
+  \r
+  bot->spamtime = time(0);\r
+  \r
+  if (bot->nextspam)\r
+    scheduleoneshot(bot->spamtime + bot->spam_interval, qabot_spam, (void*)bot);\r
+  else {\r
+    bot->lastspam = 0;\r
+    if (!bot->micnumeric)\r
+      qabot_spamstored((void*)bot);\r
+  }\r
+}\r
+\r
+void qabot_spamstored(void* arg) {\r
+  qab_bot* bot = (qab_bot*)arg;\r
+  qab_answer* a;\r
+  \r
+  if (!bot->answers)\r
+    return;\r
+  \r
+  if (bot->np) {\r
+    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s asked: %s", bot->answers->question->nick, \r
+      bot->answers->question->question);\r
+    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s answered: %s", bot->answers->nick, \r
+    bot->answers->question->answer);\r
+  }\r
+  \r
+  a = bot->answers;\r
+  bot->answers = a->next;\r
+  \r
+  free(a);\r
+  \r
+  if (bot->answers)\r
+    scheduleoneshot(time(0) + bot->queued_question_interval, qabot_spamstored, (void*)bot);\r
+}\r
+\r
+void qabot_createbotfakeuser(void* arg) {\r
+  qab_bot* bot = (qab_bot*)arg;\r
+  \r
+  if (bot->np)\r
+    return;\r
+  \r
+  bot->np = registerlocaluser(bot->nick, bot->user, bot->host, QABOT_NAME, NULL, QABOT_CHILD_UMODE, &qabot_child_handler);\r
+  \r
+  bot->np->exts[qabot_nickext] = (void*)bot;\r
+  \r
+  if (bot->public_chan->channel) {\r
+    localjoinchannel(bot->np, bot->public_chan->channel);\r
+    localgetops(bot->np, bot->public_chan->channel);\r
+  }\r
+  else\r
+    localcreatechannel(bot->np, bot->public_chan->name->content);\r
+  \r
+  if (bot->question_chan->channel) {\r
+    localjoinchannel(bot->np, bot->question_chan->channel);\r
+    localgetops(bot->np, bot->question_chan->channel);\r
+  }\r
+  else\r
+    localcreatechannel(bot->np, bot->question_chan->name->content);\r
+  \r
+  if (bot->staff_chan->channel) {\r
+    localjoinchannel(bot->np, bot->staff_chan->channel);\r
+    localgetops(bot->np, bot->staff_chan->channel);\r
+  }\r
+  else\r
+    localcreatechannel(bot->np, bot->staff_chan->name->content);\r
+}\r
+\r
+void qabot_timer(void* arg) {\r
+  qab_bot* bot = (qab_bot*)arg;\r
+  \r
+  if (!bot)\r
+    return;\r
+  \r
+  if (bot->micnumeric && (bot->mic_timeout > 0) && (time(NULL) >= (bot->lastmic + bot->mic_timeout))) {\r
+    bot->micnumeric = 0;\r
+    \r
+    sendmessagetochannel(bot->np, bot->staff_chan->channel, "Mic deactivated (idle timeout).");\r
+    if (!bot->lastspam)\r
+      qabot_spamstored((void*)bot);\r
+  }\r
+  \r
+  scheduleoneshot(time(NULL) + 10, &qabot_timer, (void*)bot);\r
+}\r
index 98a65017c2ade33fdad1859d015fd862aa6e677e..2b27cd7c3c0e0c022d0d8c6e51f00cad9658ebcf 100644 (file)
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#include "../nick/nick.h"
-#include "../localuser/localuserchannel.h"
-#include "../core/hooks.h"
-#include "../core/schedule.h"
-#include "../lib/array.h"
-#include "../lib/base64.h"
-#include "../lib/irc_string.h"
-#include "../lib/splitline.h"
-
-#include "qabot.h"
-
-int qabot_dochananswer(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  int id;
-  char* ch;
-  qab_question* q;
-  
-  if (cargc < 2) {
-    sendnoticetouser(bot->np, sender, "Syntax: !answer <id> <answer>");
-    return CMD_ERROR;
-  }
-  
-  id = strtol(cargv[0], NULL, 10);
-  ch = cargv[1];
-  
-  if ((id < 1) || (id > bot->lastquestionID)) {
-    sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
-    return CMD_ERROR;
-  }
-  
-  for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
-    if (q->id == id)
-      break;
-  
-  if (!q) {
-    sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
-    return CMD_ERROR;
-  }
-  
-  switch (q->flags & QAQ_QSTATE) {
-  case QAQ_ANSWERED:
-    sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
-    return CMD_ERROR;
-    
-  case QAQ_OFFTOPIC:
-    sendnoticetouser(bot->np, sender, "Question %d has been marked as off-topic.", id);
-    return CMD_ERROR;
-  
-  case QAQ_SPAM:
-    sendnoticetouser(bot->np, sender, "Question %d has been marked as spam.", id);
-    return CMD_ERROR;
-  
-  default:
-    break;
-  }
-  
-  q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_ANSWERED;
-  q->answer = strdup(ch);
-  
-  bot->answered++;
-  
-  if (!bot->nextspam && !bot->micnumeric) {
-    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s asked: %s", q->nick, q->question);
-    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s answers: %s", sender->nick, ch);
-  }
-  else {
-    qab_answer* a;
-    
-    a = (qab_answer*)malloc(sizeof(qab_answer));
-    a->question = q;
-    strncpy(a->nick, sender->nick, NICKLEN);
-    a->nick[NICKLEN] = '\0';
-    a->next = bot->answers;
-    bot->answers = a;
-    
-    sendnoticetouser(bot->np, sender, "Can't send your answer right now. Answer was stored and will be sent later on.");
-    return CMD_OK;
-  }
-  
-  sendnoticetouser(bot->np, sender, "Answer to question %d has been sent and stored.", id);
-  
-  return CMD_OK;
-}
-
-int qabot_dochanblock(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  qab_block* b;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !block [-q|-t] <account|mask>");
-    return CMD_ERROR;
-  }
-  
-  if (cargc > 1) {
-    if (!ircd_strncmp(cargv[0], "-q", 2)) {
-      /* account block */
-      char* target = cargv[1];
-      
-      if (*target == '#') {
-        target++;
-        
-        if (strchr(target, '*') || strchr(target, '?')) {
-          sendnoticetouser(bot->np, sender, "Wildcard account blocks are not supported.");
-          return CMD_ERROR;
-        }
-      }
-      else {
-        nick* tnick;
-        
-        if (!(tnick = getnickbynick(target))) {
-          sendnoticetouser(bot->np, sender, "Couldn't find user %s.", target);
-          return CMD_ERROR;
-        }
-        
-        if (!IsAccount(tnick)) {
-           sendnoticetouser(bot->np, sender, "%s is not authed.", tnick->nick);
-           return CMD_ERROR;
-        }
-        
-        target = tnick->authname;
-      }
-      
-      b = (qab_block*)malloc(sizeof(qab_block));
-      b->type = QABBLOCK_ACCOUNT;
-      b->created = time(0);
-      strncpy(b->creator, IsAccount(sender) ? sender->authname : "UNKNOWN", ACCOUNTLEN);
-      b->creator[ACCOUNTLEN] = '\0';
-      b->blockstr = strdup(target);
-      b->prev = 0;
-      b->next = bot->blocks;
-      if (bot->blocks)
-        bot->blocks->prev = b;
-      bot->blocks = b;
-      bot->block_count++;
-      
-      sendnoticetouser(bot->np, sender, "Now blocking all messages from users with accountname %s.", target);
-      
-      if (bot->flags & QAB_BLOCKMARK) {
-        qab_question* q;
-        int i, spamqcount = 0;
-        nick* qnick;
-        
-        for (i = 0; i < QUESTIONHASHSIZE; i++) {
-          for (q = bot->questions[i]; q; q = q->next) {
-            if ((q->flags & QAQ_QSTATE) != QAQ_NEW)
-              continue;
-            
-            if (!(qnick = getnickbynumeric(q->numeric)))
-              continue;
-            
-            if (!IsAccount(qnick))
-              continue;
-            
-            if (ircd_strcmp(qnick->authname, b->blockstr))
-              continue;
-            
-            q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
-            spamqcount++;
-          }
-        }
-        
-        sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");
-      }
-    }
-    else if (!ircd_strncmp(cargv[0], "-t", 2)) {
-      /* text block */
-      char* mask = cargv[1];
-      
-      b = (qab_block*)malloc(sizeof(qab_block));
-      b->type = QABBLOCK_TEXT;
-      b->created = time(0);
-      strncpy(b->creator, sender->authname, ACCOUNTLEN);
-      b->creator[ACCOUNTLEN] = '\0';
-      b->blockstr = strdup(mask);
-      b->prev = 0;
-      b->next = bot->blocks;
-      if (bot->blocks)
-        bot->blocks->prev = b;
-      bot->blocks = b;
-      bot->block_count++;
-      
-      sendnoticetouser(bot->np, sender, "Now blocking all questions which match %s.", mask);
-      
-      if (bot->flags & QAB_BLOCKMARK) {
-        qab_question* q;
-        int i, spamqcount = 0;
-        
-        for (i = 0; i < QUESTIONHASHSIZE; i++) {
-          for (q = bot->questions[i]; q; q = q->next) {
-            if ((q->flags & QAQ_QSTATE) != QAQ_NEW)
-              continue;
-            
-            if (match(b->blockstr, q->question))
-              continue;
-            
-            q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
-            spamqcount++;
-          }
-        }
-        
-        sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");
-      }
-    }
-    else {
-      sendnoticetouser(bot->np, sender, "Invalid flag.");
-      return CMD_ERROR;
-    }
-  }
-  else {
-    /* hostmask block */
-    char* mask = cargv[0];
-    
-    if (!strchr(mask, '@') || !strchr(mask, '!')) {
-      sendnoticetouser(bot->np, sender, "%s is not a valid hostmask.", mask);
-      return;
-    }
-    
-    b = (qab_block*)malloc(sizeof(qab_block));
-    b->type = QABBLOCK_HOST;
-    b->created = time(0);
-    strncpy(b->creator, sender->authname, ACCOUNTLEN);
-    b->creator[ACCOUNTLEN] = '\0';
-    b->blockstr = strdup(mask);
-    b->prev = 0;
-    b->next = bot->blocks;
-    if (bot->blocks)
-      bot->blocks->prev = b;
-    bot->blocks = b;
-    bot->block_count++;
-    
-    sendnoticetouser(bot->np, sender, "Now blocking all messages from users with a hostmask matching %s.", mask);
-    
-    if (bot->flags & QAB_BLOCKMARK) {
-        qab_question* q;
-        int i, spamqcount = 0;
-        nick* qnick;
-        char hostbuf[NICKLEN + USERLEN + HOSTLEN + 3];
-        
-        for (i = 0; i < QUESTIONHASHSIZE; i++) {
-          for (q = bot->questions[i]; q; q = q->next) {
-            if ((q->flags & QAQ_QSTATE) != QAQ_NEW)
-              continue;
-            
-            if (!(qnick = getnickbynumeric(q->numeric)))
-              continue;
-            
-            sprintf(hostbuf, "%s!%s@%s", qnick->nick, qnick->ident, qnick->host->name->content);
-            
-            if (match(b->blockstr, hostbuf))
-              continue;
-            
-            q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
-            spamqcount++;
-          }
-        }
-        
-        sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");
-      }
-  }
-  
-  return CMD_OK;
-}
-
-int qabot_dochanclear(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  qab_spam* s;
-  qab_spam* ns;
-  qab_answer* a;
-  qab_answer* na;
-  
-  if (bot->recording_section) {
-    sendmessagetochannel(bot->np, cp, "Deactivate recorder before using clear.");
-    return CMD_ERROR;
-  }
-  
-  for (s = bot->nextspam; s; s = ns) {
-    ns = s->next;
-    free(s->message);
-    free(s);
-  }
-  
-  bot->nextspam = bot->lastspam = 0;
-  
-  sendmessagetochannel(bot->np, cp, "Cleared message buffer.");
-  if (bot->micnumeric) {
-    bot->micnumeric = 0;
-    sendmessagetochannel(bot->np, cp, "Mic deactivated.");
-  }
-  
-  return CMD_OK;
-}
-
-int qabot_dochanclosechan(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  modechanges changes;
-  
-  localsetmodeinit(&changes, bot->public_chan->channel, bot->np);
-  localdosetmode_simple(&changes, CHANMODE_INVITEONLY, 0);
-  localsetmodeflush(&changes, 1);
-  sendnoticetouser(bot->np, sender, "Public channel has been closed.");
-  
-  return CMD_OK;
-}
-
-int qabot_dochanconfig(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  char* opt;
-  char* value;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !config <option> [<value>]");
-    sendnoticetouser(bot->np, sender, "Displays or sets configuration option. Valid options are:");
-    sendnoticetouser(bot->np, sender, "blockcontrol - Block questions containing control chars.");
-    sendnoticetouser(bot->np, sender, "blockcolour  - Block questions containing colour.");
-    sendnoticetouser(bot->np, sender, "blockmark    - Mark questions affected by blocks as spam.");
-    sendnoticetouser(bot->np, sender, "authedonly   - Accept questions from authed users only.");
-    sendnoticetouser(bot->np, sender, "linebreak    - Separate questions with line breaks.");
-    sendnoticetouser(bot->np, sender, "flooddetect  - Attempt to detect floodclone spam.");
-    sendnoticetouser(bot->np, sender, "floodblock   - Automatically block floodclone spam.");
-    sendnoticetouser(bot->np, sender, "spamint      - Text spam interval.");
-    sendnoticetouser(bot->np, sender, "nickblockint - Time to wait before sending another question.");
-    sendnoticetouser(bot->np, sender, "queuedqint   - Queued answer spam interval.");
-    sendnoticetouser(bot->np, sender, "mictimeout   - Idle time before mic is automatically disabled.");
-    return CMD_ERROR;
-  }
-  
-  opt = cargv[0];
-  if (cargc == 2)
-    value = cargv[1];
-  else
-    value = 0;
-  
-  if (!ircd_strcmp(opt, "blockcontrol")) {
-    if (value) {
-      if (!ircd_strcmp(value, "on")) {
-        bot->flags |= QAB_CONTROLCHAR;
-        sendnoticetouser(bot->np, sender, "Questions containing control characters will now be blocked.");
-      }
-      else if (!ircd_strcmp(value, "off")) {
-        bot->flags &= (~QAB_CONTROLCHAR);
-        sendnoticetouser(bot->np, sender, "Questions containing control characters will no longer be blocked.");
-      }
-      else
-        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Control characters are currently %s blocked.", (bot->flags & QAB_CONTROLCHAR) ? "being" : "not being");
-  }
-  else if (!ircd_strcmp(opt, "blockcolour")) {
-    if (value) {
-      if (!ircd_strcmp(value, "on")) {
-        bot->flags |= QAB_COLOUR;
-        sendnoticetouser(bot->np, sender, "Questions containing colour will now be blocked.");
-      }
-      else if (!ircd_strcmp(value, "off")) {
-        bot->flags &= (~QAB_COLOUR);
-        sendnoticetouser(bot->np, sender, "Questions containing colour will no longer be blocked.");
-      }
-      else
-        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Colours are currently %s blocked.", (bot->flags & QAB_COLOUR) ? "being" : "not being");
-  }
-  else if (!ircd_strcmp(opt, "blockmark")) {
-    if (value) {
-      if (!ircd_strcmp(value, "on")) {
-        bot->flags |= QAB_BLOCKMARK;
-        sendnoticetouser(bot->np, sender, "New blocks will automatically mark affected questions as spam.");
-      }
-      else if (!ircd_strcmp(value, "off")) {
-        bot->flags &= (~QAB_BLOCKMARK);
-        sendnoticetouser(bot->np, sender, "New blocks will no longer automatically mark affected questions as spam.");
-      }
-      else
-        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Blocks are currently %smarking affected questions as spam.", (bot->flags & QAB_BLOCKMARK) ? "" : "not ");
-  }
-  else if (!ircd_strcmp(opt, "authedonly")) {
-    if (value) {
-      if (!ircd_strcmp(value, "on")) {
-        bot->flags |= QAB_AUTHEDONLY;
-        sendnoticetouser(bot->np, sender, "Questions from unauthed users will now be blocked.");
-      }
-      else if (!ircd_strcmp(value, "off")) {
-        bot->flags &= (~QAB_AUTHEDONLY);
-        sendnoticetouser(bot->np, sender, "Questions from unauthed users will no longer be blocked.");
-      }
-      else
-        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Unauthed users may currently %ssend questions.", (bot->flags & QAB_AUTHEDONLY) ? "NOT " : "");
-  }
-  else if (!ircd_strcmp(opt, "linebreak")) {
-    if (value) {
-      if (!ircd_strcmp(value, "on")) {
-        bot->flags |= QAB_LINEBREAK;
-        sendnoticetouser(bot->np, sender, "Line breaks are now enabled.");
-      }
-      else if (!ircd_strcmp(value, "off")) {
-        bot->flags &= (~QAB_LINEBREAK);
-        sendnoticetouser(bot->np, sender, "Line breaks are now disabled.");
-      }
-      else
-        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Line breaks are currently %s.", (bot->flags & QAB_LINEBREAK) ? "enabled" : "disabled");
-  }
-  else if (!ircd_strcmp(opt, "flooddetect")) {
-    if (value) {
-      if (!ircd_strcmp(value, "on")) {
-        bot->flags |= QAB_FLOODDETECT;
-        sendnoticetouser(bot->np, sender, "Flood detection is now enabled.");
-      }
-      else if (!ircd_strcmp(value, "off")) {
-        bot->flags &= (~QAB_FLOODDETECT);
-        sendnoticetouser(bot->np, sender, "Flood detection is now disabled.");
-      }
-      else
-        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Flood detection is currently %s.", (bot->flags & QAB_FLOODDETECT) ? "enabled" : "disabled");
-  }
-  else if (!ircd_strcmp(opt, "floodblock")) {
-    if (value) {
-      if (!ircd_strcmp(value, "on")) {
-        bot->flags |= QAB_FLOODSTOP;
-        sendnoticetouser(bot->np, sender, "Flood blocking is now enabled.");
-      }
-      else if (!ircd_strcmp(value, "off")) {
-        bot->flags &= (~QAB_FLOODSTOP);
-        sendnoticetouser(bot->np, sender, "Flood blocking is now disabled.");
-      }
-      else
-        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Flood blocking is currently %s.", (bot->flags & QAB_FLOODSTOP) ? "enabled" : "disabled");
-  }
-  else if (!ircd_strcmp(opt, "mictimeout")) {
-    if (value) {
-      int v = (int)strtol(value, NULL, 10);
-      
-      if ((v < 0) || (v > 300)) {
-        sendnoticetouser(bot->np, sender, "Value must be between 0 (off) and 300.");
-        return CMD_ERROR;
-      }
-      
-      bot->mic_timeout = v;
-      sendnoticetouser(bot->np, sender, "Value set.");
-    }
-    else {
-      if (bot->mic_timeout)
-        sendnoticetouser(bot->np, sender, "Mic timeout is currently %d second%s.", bot->mic_timeout, (bot->mic_timeout == 1) ? "" : "s");
-      else
-        sendnoticetouser(bot->np, sender, "Mic timeout is currently disabled.");
-    }
-  }
-  else if (!ircd_strcmp(opt, "spamint")) {
-    if (value) {
-      int v = (int)strtol(value, NULL, 10);
-      
-      if ((v < 1) || (v > 30)) {
-        sendnoticetouser(bot->np, sender, "Value must be between 1 and 30.");
-        return CMD_ERROR;
-      }
-      
-      bot->spam_interval = v;
-      sendnoticetouser(bot->np, sender, "Value set.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Spam interval is currently %d second%s.", bot->spam_interval, (bot->spam_interval == 1) ? "" : "s");
-  }
-  else if (!ircd_strcmp(opt, "nickblockint")) {
-    if (value) {
-      int v = (int)strtol(value, NULL, 10);
-      
-      if ((v < 1) || (v > 300)) {
-        sendnoticetouser(bot->np, sender, "Value must be between 1 and 300.");
-        return CMD_ERROR;
-      }
-      
-      bot->ask_wait = v;
-      sendnoticetouser(bot->np, sender, "Value set.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Nick block interval is currently %d second%s.", bot->ask_wait, (bot->ask_wait == 1) ? "" : "s");
-  }
-  else if (!ircd_strcmp(opt, "queuedqint")) {
-    if (value) {
-      int v = (int)strtol(value, NULL, 10);
-      
-      if ((v < 1) || (v > 20)) {
-        sendnoticetouser(bot->np, sender, "Value must be between 1 and 20.");
-        return CMD_ERROR;
-      }
-      
-      bot->queued_question_interval = v;
-      sendnoticetouser(bot->np, sender, "Value set.");
-    }
-    else
-      sendnoticetouser(bot->np, sender, "Queued question interval is currently %d second%s.", bot->queued_question_interval, (bot->queued_question_interval == 1) ? "" : "s");
-  }
-  else
-    sendnoticetouser(bot->np, sender, "Invalid configuration option.");
-  
-  return CMD_OK;
-}
-
-int qabot_dochanhelp(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  char* ch;
-  
-  if (cargc < 1)
-    ch = "";
-  else
-    ch = cargv[0];
-  
-  if (*ch) {
-    if (!ircd_strcmp(ch, "mic")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !mic");
-      sendnoticetouser(bot->np, sender, "Turn the microphone on or off. When turned on, anything said by the microphone holder is relayed to %s.", bot->public_chan->name->content);
-    }
-    else if (!ircd_strcmp(ch, "clear")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !clear");
-      sendnoticetouser(bot->np, sender, "Clear currently queued text to relay, and turn off the microphone.");
-    }
-    else if (!ircd_strcmp(ch, "ping")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !ping");
-      sendnoticetouser(bot->np, sender, "Pings the bot.");
-    }
-    else if (!ircd_strcmp(ch, "config")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !config <option|help> [<value>]");
-      sendnoticetouser(bot->np, sender, "Display or set bot configuration options.");
-    }
-    else if (!ircd_strcmp(ch, "answer")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !answer <id> <answer>");
-      sendnoticetouser(bot->np, sender, "Answer a question.");
-    }
-    else if (!ircd_strcmp(ch, "block")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !block [<-q|-t>] <mask>");
-      sendnoticetouser(bot->np, sender, "Add a block, where:");
-      sendnoticetouser(bot->np, sender, "-q: blocks a Q account.");
-      sendnoticetouser(bot->np, sender, "-t: blocks question text.");
-      sendnoticetouser(bot->np, sender, "No flag results in a hostmask block.");
-    }
-    else if (!ircd_strcmp(ch, "listblocks")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !listblocks");
-      sendnoticetouser(bot->np, sender, "View the currently added blocks.");
-    }
-    else if (!ircd_strcmp(ch, "spam")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !spam <id>");
-      sendnoticetouser(bot->np, sender, "Mark a question as spam. This stops it being answered.");
-    }
-    else if (!ircd_strcmp(ch, "offtopic")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !offtopic <id>");
-      sendnoticetouser(bot->np, sender, "Mark a question as off-topic. This stops it being answered.");
-    }
-    else if (!ircd_strcmp(ch, "unblock")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !unblock [<-q|-t>] <mask>");
-      sendnoticetouser(bot->np, sender, "Removes a block. See \"!help block\" for a description of the flags.");
-    }
-    else if (!ircd_strcmp(ch, "reset")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !reset <all|questions|blocks|stats>");
-      sendnoticetouser(bot->np, sender, "Reset the questions, blocks or both; or the stats.");
-    }
-    else if (!ircd_strcmp(ch, "closechan")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !closechan");
-      sendnoticetouser(bot->np, sender, "Closes the public channel.");
-    }
-    else if (!ircd_strcmp(ch, "openchan")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !openchan");
-      sendnoticetouser(bot->np, sender, "Opens the public channel.");
-    }
-    else if (!ircd_strcmp(ch, "status")) {
-      sendnoticetouser(bot->np, sender, "Syntax: !status");
-      sendnoticetouser(bot->np, sender, "Displays some status information and statistics.");
-    }
-    else if (!ircd_strcmp(ch, "help")) {
-      sendnoticetouser(bot->np, sender, "Syntax !help [<command>]");
-      sendnoticetouser(bot->np, sender, "List available commands or view help for a particular command.");
-    }
-    else {
-      sendnoticetouser(bot->np, sender, "No help available for '%s'.", ch);
-    }
-  }
-  else {
-    sendnoticetouser(bot->np, sender, "The following channel commands are recognised:");
-    sendnoticetouser(bot->np, sender, "!answer     - Answer a question.");
-    sendnoticetouser(bot->np, sender, "!block      - Block a hostmask, account or string.");
-    sendnoticetouser(bot->np, sender, "!clear      - Clear currently queued text to spam.");
-    sendnoticetouser(bot->np, sender, "!closechan  - Close the public channel.");
-    sendnoticetouser(bot->np, sender, "!config     - Display or set bot configuration options.");
-    sendnoticetouser(bot->np, sender, "!help       - List commands or view the help for a command");
-    sendnoticetouser(bot->np, sender, "!listblocks - List currently added blocks.");
-    sendnoticetouser(bot->np, sender, "!mic        - Turn the microphone on or off.");
-    sendnoticetouser(bot->np, sender, "!offtopic   - Mark a question or questions as off-topic.");
-    sendnoticetouser(bot->np, sender, "!openchan   - Open the public channel.");
-    sendnoticetouser(bot->np, sender, "!ping       - Ping the bot.");
-    sendnoticetouser(bot->np, sender, "!reset      - Clear all blocks, questions or both.");
-    sendnoticetouser(bot->np, sender, "!spam       - Mark a question or questions as spam.");
-    sendnoticetouser(bot->np, sender, "!status     - Display some status statistics.");
-    sendnoticetouser(bot->np, sender, "!unblock    - Remove a block.");
-    sendnoticetouser(bot->np, sender, "End of list.");
-  }
-  
-  return CMD_OK;
-}
-
-int qabot_dochanlistblocks(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  qab_block* b;
-  
-  if (!(b = bot->blocks)) {
-    sendnoticetouser(bot->np, sender, "There are no blocks currently added.");
-    return;
-  }
-  
-  sendnoticetouser(bot->np, sender, "Type: Hostmask/Account/Textmask:");
-  
-  for (; b; b = b->next) {
-    if (b->type == QABBLOCK_ACCOUNT)
-      sendnoticetouser(bot->np, sender, "A     %s", b->blockstr);
-    else if (b->type == QABBLOCK_HOST)
-      sendnoticetouser(bot->np, sender, "H     %s", b->blockstr);
-    else
-      sendnoticetouser(bot->np, sender, "T     %s", b->blockstr);
-  }
-  
-  sendnoticetouser(bot->np, sender, "End of list.");
-  
-  return CMD_OK;
-}
-
-int qabot_dochanmic(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  
-  if (bot->recording_section)
-    sendmessagetochannel(bot->np, cp, "Deactivate recorder before attempting to use mic.");
-  else if (bot->micnumeric) {
-    if (bot->micnumeric == sender->numeric) {
-      bot->micnumeric = 0;
-      sendmessagetochannel(bot->np, cp, "Mic deactivated.");
-      if (!bot->lastspam)
-        qabot_spamstored((void*)bot);
-    }
-    else {
-      bot->lastmic = time(NULL);
-      bot->micnumeric = sender->numeric;
-      sendmessagetochannel(bot->np, cp, "%s now has the mic. Anything said by %s will be relayed in %s.", 
-        sender->nick, sender->nick, bot->public_chan->name->content);
-      deleteschedule(0, qabot_spamstored, (void*)bot);
-    }
-  }
-  else {
-    bot->lastmic = time(NULL);
-    bot->micnumeric = sender->numeric;
-    sendmessagetochannel(bot->np, cp, "Mic activated. Anything said by %s will be relayed in %s.", 
-      sender->nick, bot->public_chan->name->content);
-    deleteschedule(0, qabot_spamstored, (void*)bot);
-  }
-  
-  return CMD_OK;
-}
-
-int qabot_dochanmoo(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  char moostr[50];
-  int i, moocount = 5 + (rand() % 40);
-  
-  moostr[0] = 'm';
-  for (i = 1; i < moocount; i++)
-    moostr[i] = ((rand() % 100) > 50) ? 'o': '0';
-  moostr[i] = '\0';
-  
-  sendmessagetochannel(bot->np, cp, "%s", moostr);
-  
-  return CMD_OK;
-}
-
-int qabot_dochanofftopic(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  int id;
-  int i;
-  qab_question* q;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");
-    return CMD_ERROR;
-  }
-  
-  for (i = 0; i < cargc; i++) {
-    id = strtol(cargv[i], NULL, 10);
-    
-    if ((id < 1) || (id > bot->lastquestionID)) {
-      sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
-      continue;
-    }
-    
-    for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
-      if (q->id == id)
-        break;         
-    
-    if (!q) {
-      sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
-      continue;
-    }
-    
-    switch (q->flags & QAQ_QSTATE) {
-    case QAQ_ANSWERED:
-      sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
-      continue;
-    
-    case QAQ_OFFTOPIC:
-      sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);
-      continue;
-    
-    case QAQ_SPAM:
-      sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);
-      continue;
-    
-    default:
-      break;
-    }
-    
-    q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_OFFTOPIC;
-    sendnoticetouser(bot->np, sender, "Question %d has been marked as off-topic.", id);
-  }
-  
-  return CMD_OK;
-}
-
-int qabot_dochanopenchan(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  modechanges changes;
-  
-  localsetmodeinit(&changes, bot->public_chan->channel, bot->np);
-  localdosetmode_simple(&changes, CHANMODE_MODERATE|CHANMODE_DELJOINS, CHANMODE_INVITEONLY);
-  localsetmodeflush(&changes, 1);
-  sendnoticetouser(bot->np, sender, "Public channel has been opened.");
-  
-  return CMD_OK;
-}
-
-int qabot_dochanping(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  
-  sendmessagetochannel(bot->np, cp, "pong!");
-  
-  return CMD_OK;
-}
-
-int qabot_dochanreset(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  int r = 0;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !reset <blocks|questions|stats|all>");
-    return CMD_ERROR;
-  }
-  
-  if (!ircd_strcmp(cargv[0], "blocks"))
-    r = 1;
-  else if (!ircd_strcmp(cargv[0], "questions"))
-    r = 2;
-  else if (!ircd_strcmp(cargv[0], "stats"))
-    r = 4;
-  else if (!ircd_strcmp(cargv[0], "all"))
-    r = 3;
-  else {
-    sendnoticetouser(bot->np, sender, "Unknown parameter: %s.", cargv[0]);
-    return;
-  }
-  
-  if (r & 1) {
-    qab_block* b;
-   
-    while (bot->blocks) {
-      b = bot->blocks;
-      bot->blocks = bot->blocks->next;
-      if (b->blockstr)
-        free(b->blockstr);
-      free(b);
-    }
-    
-    bot->block_count = 0;
-    
-    sendnoticetouser(bot->np, sender, "Reset (blocks): Done.");
-  }
-  
-  if (r & 2) {
-    qab_question* q;
-    int i;
-    
-    for (i = 0; i < QUESTIONHASHSIZE; i++) {
-      while (bot->questions[i]) {
-        q = bot->questions[i];
-        bot->questions[i] = bot->questions[i]->next;
-        if (q->question)
-          free(q->question);
-        if (q->answer)
-          free(q->answer);
-        free(q);
-      }
-    }
-    
-    bot->lastquestionID = 0;
-    bot->answered = 0;
-    
-    sendnoticetouser(bot->np, sender, "Reset (questions): Done.");
-  }
-  
-  if (r & 4) {
-    bot->answered = 0;
-    bot->spammed = 0;
-    sendnoticetouser(bot->np, sender, "Reset (stats): Done.");
-  }
-  
-  return CMD_OK;
-}
-
-int qabot_dochanspam(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  int id;
-  int i;
-  qab_question* q;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");
-    return CMD_ERROR;
-  }
-  
-  for (i = 0; i < cargc; i++) {
-    id = strtol(cargv[i], NULL, 10);
-    
-    if ((id < 1) || (id > bot->lastquestionID)) {
-      sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);
-      continue;
-    }
-    
-    for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)
-      if (q->id == id)
-        break;         
-    
-    if (!q) {
-      sendnoticetouser(bot->np, sender, "Can't find question %d.", id);
-      continue;
-    }
-    
-    switch (q->flags & QAQ_QSTATE) {
-    case QAQ_ANSWERED:
-      sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);
-      continue;
-    
-    case QAQ_OFFTOPIC:
-      sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);
-      continue;
-    
-    case QAQ_SPAM:
-      sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);
-      continue;
-    
-    default:
-      break;
-    }
-    
-    q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;
-    sendnoticetouser(bot->np, sender, "Question %d has been marked as spam.", id);
-  }
-  
-  return CMD_OK;
-}
-
-int qabot_dochanstatus(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  
-  sendnoticetouser(bot->np, sender, "Lines spammed:            %d", bot->spammed);
-  sendnoticetouser(bot->np, sender, "Questions asked:          %d", bot->lastquestionID);
-  sendnoticetouser(bot->np, sender, "Questions answered:       %d", bot->answered);
-  sendnoticetouser(bot->np, sender, "Blocks:                   %d", bot->block_count);
-  /*sendnoticetouser(bot->np, sender, "Question interval:        %d seconds", bot->question_interval);*/
-  sendnoticetouser(bot->np, sender, "Spam interval:            %d seconds", bot->spam_interval);
-  sendnoticetouser(bot->np, sender, "Nick block interval:      %d seconds", bot->ask_wait);
-  sendnoticetouser(bot->np, sender, "Queued question interval: %d seconds", bot->queued_question_interval);
-  sendnoticetouser(bot->np, sender, "Block control chars:      %s", (bot->flags & QAB_CONTROLCHAR) ? "Yes" : "No");
-  sendnoticetouser(bot->np, sender, "Block colour:             %s", (bot->flags & QAB_COLOUR) ? "Yes" : "No");
-  sendnoticetouser(bot->np, sender, "Authed users only:        %s", (bot->flags & QAB_AUTHEDONLY) ? "Yes" : "No");
-  sendnoticetouser(bot->np, sender, "Line break:               %s", (bot->flags & QAB_LINEBREAK) ? "Yes" : "No");
-  sendnoticetouser(bot->np, sender, "Question flood detection: %s", (bot->flags & QAB_FLOODDETECT) ? "Yes" : "No");
-  sendnoticetouser(bot->np, sender, "Question flood blocking:  %s", (bot->flags & QAB_FLOODSTOP) ? "Yes" : "No");
-  sendnoticetouser(bot->np, sender, "Blocks mark as spam:      %s", (bot->flags & QAB_BLOCKMARK) ? "Yes" : "No");
-  if (bot->micnumeric) {
-    nick* mnick = getnickbynumeric(bot->micnumeric);
-    
-    sendnoticetouser(bot->np, np, "Mic:                      Enabled (%s)", mnick ? mnick->nick : "UNKNOWN");
-  }
-  else
-    sendnoticetouser(bot->np, np, "Mic:                      Disabled");
-  sendnoticetouser(bot->np, sender, "Mic timeout:              %d", bot->mic_timeout);
-  /*sendnoticetouser(bot->np, sender, "");*/
-  
-  return CMD_OK;
-}
-
-int qabot_dochanunblock(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  char* ch;
-  qab_block* b;
-  char type = -1;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !unblock [-q|-t] <account|mask>");
-    return CMD_ERROR;
-  }
-  
-  if (cargc > 1) {
-    if (!ircd_strncmp(cargv[0], "-q", 2)) {
-      type = QABBLOCK_ACCOUNT;
-      ch = cargv[1];
-      
-      if (*ch == '#')
-        ch++;
-    }
-    else if (!ircd_strncmp(cargv[0], "-t", 2)) {
-      type = QABBLOCK_TEXT;
-      ch = cargv[1];
-    }
-    else {
-      sendnoticetouser(bot->np, sender, "Invalid flag.");
-      return CMD_ERROR;
-    }
-  }
-  else {
-    type = QABBLOCK_HOST;
-    ch = cargv[0];
-  }
-  
-  for (b = bot->blocks; b; b = b->next) {
-    if (b->type != type)
-      continue;
-    
-    if (!ircd_strcmp(b->blockstr, ch)) {
-      if (b->next)
-        b->next->prev = b->prev;
-      if (b->prev)
-        b->prev->next = b->next;
-      else
-        bot->blocks = b->next;
-      
-      free(b->blockstr);
-      free(b);
-      
-      bot->block_count--;
-      
-      sendnoticetouser(bot->np, sender, "Block removed.");
-      return CMD_OK;
-    }
-  }
-  
-  sendnoticetouser(bot->np, sender, "No such block.");
-  
-  return CMD_ERROR;
-}
-
-int qabot_dochanlisttexts(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  qab_text* texts = bot->texts;
-  
-  if (!texts) {
-    sendnoticetouser(bot->np, sender, "There are no texts added.");
-    return CMD_ERROR;
-  }
-  
-  sendnoticetouser(bot->np, sender, "Name:           Sections:");
-  for (; texts; texts = texts->next) {
-    sendnoticetouser(bot->np, sender, "%-15s %d", texts->name, texts->section_count);
-  }
-  
-  sendnoticetouser(bot->np, sender, "End of list.");
-  
-  return CMD_OK;
-}
-
-int qabot_dochanshowsection(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  qab_text* texts = bot->texts;
-  qab_textsection* section;
-  int count = 0;
-  
-  if (cargc < 2) {
-    sendnoticetouser(bot->np, sender, "Syntax: !showsection <text name> <section number>");
-    return CMD_ERROR;
-  }
-  
-  if (!texts) {
-    sendnoticetouser(bot->np, sender, "There are no texts added.");
-    return CMD_ERROR;
-  }
-  
-  id = (int)strtol(cargv[1]);
-  
-  for (; texts; texts = texts->next) {
-    if (!ircd_strcmp(texts->name, cargv[0])) {
-      for (section = texts->sections; section && (count <= section->section_count); section = section->next) {
-        if (++count == id) {
-          qab_spam* lines;
-          int lineno = 0;
-          
-          sendnoticetouser(bot->np, sender, "Section %d (of text %s) contents:", count, texts->name);
-          for (lines = section->lines; lines; lines = lines->next)
-            sendnoticetouser(bot->np, sender, "%-2d> %s", ++lineno, lines->message);
-          sendnoticetouser(bot->np, sender, "End of section.");
-            
-          return CMD_OK;
-        }
-      }
-      sendnoticetouser(bot->np, sender, "No such section.");
-      return CMD_ERROR;
-    }
-  }
-  
-  sendnoticetouser(bot->np, sender, "No such text.");
-  
-  return CMD_ERROR;
-}
-
-int qabot_dochanaddtext(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  qab_text* texts = bot->texts;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !addtext <text name>");
-    return CMD_ERROR;
-  }
-  
-  for (; texts; texts = texts->next) {
-    if (!ircd_strcmp(texts->name, cargv[0])) {
-      sendnoticetouser(bot->np, sender, "A text with this name already exists.");
-      return CMD_ERROR;
-    }
-  }
-  
-  texts = (qab_text*)malloc(sizeof(qab_text));
-  strncpy(texts->name, cargc[0], NICKLEN);
-  texts->name[NICKLEN] = '\0';
-  texts->sections = 0;
-  texts->sections_tail = 0;
-  texts->section_count = 0;
-  texts->next = bot->texts;
-  texts->prev = 0;
-  if (bot->texts)
-    bot->texts->prev = texts;
-  bot->texts = texts;
-  
-  sendnoticetouser(bot->np, sender, "Added text '%s'.", texts->name);
-  
-  return CMD_OK;
-}
-
-int qabot_dochandeltext(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  qab_text* texts = bot->texts;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !deltext <text name>");
-    return CMD_ERROR;
-  }
-  
-  for (; texts; texts = texts->next) {
-    if (!ircd_strcmp(texts->name, cargv[0])) {
-      sendnoticetouser(bot->np, sender, "Text '%s' deleted.", texts->name);
-      qabot_freetext(bot, texts);
-      return CMD_OK;
-    }
-  }
-  
-  sendnoticetouser(bot->np, sender, "No such text.");
-  
-  return CMD_ERROR;
-}
-
-int qabot_dochanaddsection(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  qab_text* texts = bot->texts;
-  qab_textsection* section;
-  
-  if (cargc < 1) {
-    sendnoticetouser(bot->np, sender, "Syntax: !addsection <text name> [<section number>]");
-    return CMD_ERROR;
-  }
-  
-  for (; texts; texts = texts->next) {
-    if (!ircd_strcmp(texts->name, cargv[0])) {
-      int num;
-      if (cargc == 1 || !texts->sections_tail) {
-        section = (qab_textsection*)malloc(sizeof(qab_textsection));
-        section->lines = 0;
-        section->lines_tail = 0;
-        section->line_count = 0;
-        section->prev = 0;
-        section->next = 0;
-        texts->sections = section;
-        texts->sections_tail = section;
-        texts->section_count++;
-        num = 1;
-      }
-      else {
-      }
-      
-      sendnoticetouser(bot->np, sender, "Section %d added.", num);
-      return CMD_OK;
-    }
-  }
-  
-  sendnoticetouser(bot->np, sender, "No such text.");
-  
-  return CMD_ERROR;
-}
-
-int qabot_dochandelsection(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  qab_text* texts = bot->texts;
-  qab_textsection* section;
-  
-  if (cargc < 2) {
-    sendnoticetouser(bot->np, sender, "Syntax: !delsection <text name> <section number>");
-    return CMD_ERROR;
-  }
-  
-  for (; texts; texts = texts->next) {
-    if (!ircd_strcmp(texts->name, cargv[0])) {
-      for (section = texts->sections; section && (count <= section->section_count); section = section->next) {
-        if (++count == id) {
-          qabot_freesection(texts, section);
-          sendnoticetouser(bot->np, sender, "Section deleted.");
-          return CMD_OK;
-        }
-      }
-      sendnoticetouser(bot->np, sender, "No such section.");
-      return CMD_ERROR;
-    }
-  }
-  
-  sendnoticetouser(bot->np, sender, "No such text.");
-  
-  return CMD_ERROR;
-}
-
-int qabot_dochanrecord(void* np, int cargc, char** cargv) {
-  nick* sender = (nick*)np;
-  qab_bot* bot = qabot_getcurrentbot();
-  channel* cp = qabot_getcurrentchannel();
-  
-  if (bot->recording_section) {
-    if (bot->micnumeric == sender->numeric) {
-      bot->micnumeric = 0;
-      bot->recording_section = 0;
-      sendmessagetochannel(bot->np, cp, "Recorder deactivated.");
-    }
-    else {
-      sendmessagetochannel(bot->np, cp, "The recorder is already in use.");
-    }
-  }
-  else if (bot->micnumeric)
-    sendmessagetochannel(bot->np, cp, "Deactivate mic before attempting to use recorder.");
-  else if (cargc >= 2) {
-    qab_text* texts = bot->texts;
-    qab_textsection* section;
-    int id = (int)strtol(cargv[1]);
-    
-    for (; texts; texts = texts->next) {
-      if (!ircd_strcmp(texts->name, cargv[0])) {
-        for (section = texts->sections; section && (count <= section->section_count); section = section->next) {
-          if (++count == id) {
-            bot->lastmic = time(NULL);
-            bot->micnumeric = sender->numeric;
-            bot->recording_section = count;
-            sendmessagetochannel(bot->np, cp, "Recorder activated. Anything said by %s will be relayed in %s.", 
-              sender->nick, bot->public_chan->name->content);
-            deleteschedule(0, qabot_spamstored, (void*)bot);
-            return CMD_OK;
-          }
-        }
-        sendnoticetouser(bot->np, sender, "No such section.");
-        return CMD_ERROR;
-      }
-    }
-    
-    sendnoticetouser(bot->np, sender, "No such text.");
-    return CMD_ERROR;
-  }
-  else
-    sendmessagetochannel(bot->np, cp, "syntax: !record [<text name> <section number>]");
-  
-  return CMD_OK;
-}
+#include <stdio.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "../nick/nick.h"\r
+#include "../localuser/localuserchannel.h"\r
+#include "../core/hooks.h"\r
+#include "../core/schedule.h"\r
+#include "../lib/array.h"\r
+#include "../lib/base64.h"\r
+#include "../lib/irc_string.h"\r
+#include "../lib/splitline.h"\r
+\r
+#include "qabot.h"\r
+\r
+int qabot_dochananswer(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  int id;\r
+  char* ch;\r
+  qab_question* q;\r
+  \r
+  if (cargc < 2) {\r
+    sendnoticetouser(bot->np, sender, "Syntax: !answer <id> <answer>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  id = strtol(cargv[0], NULL, 10);\r
+  ch = cargv[1];\r
+  \r
+  if ((id < 1) || (id > bot->lastquestionID)) {\r
+    sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)\r
+    if (q->id == id)\r
+      break;\r
+  \r
+  if (!q) {\r
+    sendnoticetouser(bot->np, sender, "Can't find question %d.", id);\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  switch (q->flags & QAQ_QSTATE) {\r
+  case QAQ_ANSWERED:\r
+    sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);\r
+    return CMD_ERROR;\r
+    \r
+  case QAQ_OFFTOPIC:\r
+    sendnoticetouser(bot->np, sender, "Question %d has been marked as off-topic.", id);\r
+    return CMD_ERROR;\r
+  \r
+  case QAQ_SPAM:\r
+    sendnoticetouser(bot->np, sender, "Question %d has been marked as spam.", id);\r
+    return CMD_ERROR;\r
+  \r
+  default:\r
+    break;\r
+  }\r
+  \r
+  q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_ANSWERED;\r
+  q->answer = strdup(ch);\r
+  \r
+  bot->answered++;\r
+  \r
+  if (!bot->nextspam && !bot->micnumeric) {\r
+    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s asked: %s", q->nick, q->question);\r
+    sendmessagetochannel(bot->np, bot->public_chan->channel, "%s answers: %s", sender->nick, ch);\r
+  }\r
+  else {\r
+    qab_answer* a;\r
+    \r
+    a = (qab_answer*)malloc(sizeof(qab_answer));\r
+    a->question = q;\r
+    strncpy(a->nick, sender->nick, NICKLEN);\r
+    a->nick[NICKLEN] = '\0';\r
+    a->next = bot->answers;\r
+    bot->answers = a;\r
+    \r
+    sendnoticetouser(bot->np, sender, "Can't send your answer right now. Answer was stored and will be sent later on.");\r
+    return CMD_OK;\r
+  }\r
+  \r
+  sendnoticetouser(bot->np, sender, "Answer to question %d has been sent and stored.", id);\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanblock(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  qab_block* b;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(bot->np, sender, "Syntax: !block [-q|-t] <account|mask>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (cargc > 1) {\r
+    if (!ircd_strncmp(cargv[0], "-q", 2)) {\r
+      /* account block */\r
+      char* target = cargv[1];\r
+      \r
+      if (*target == '#') {\r
+        target++;\r
+        \r
+        if (strchr(target, '*') || strchr(target, '?')) {\r
+          sendnoticetouser(bot->np, sender, "Wildcard account blocks are not supported.");\r
+          return CMD_ERROR;\r
+        }\r
+      }\r
+      else {\r
+        nick* tnick;\r
+        \r
+        if (!(tnick = getnickbynick(target))) {\r
+          sendnoticetouser(bot->np, sender, "Couldn't find user %s.", target);\r
+          return CMD_ERROR;\r
+        }\r
+        \r
+        if (!IsAccount(tnick)) {\r
+           sendnoticetouser(bot->np, sender, "%s is not authed.", tnick->nick);\r
+           return CMD_ERROR;\r
+        }\r
+        \r
+        target = tnick->authname;\r
+      }\r
+      \r
+      b = (qab_block*)malloc(sizeof(qab_block));\r
+      b->type = QABBLOCK_ACCOUNT;\r
+      b->created = time(0);\r
+      strncpy(b->creator, IsAccount(sender) ? sender->authname : "UNKNOWN", ACCOUNTLEN);\r
+      b->creator[ACCOUNTLEN] = '\0';\r
+      b->blockstr = strdup(target);\r
+      b->prev = 0;\r
+      b->next = bot->blocks;\r
+      if (bot->blocks)\r
+        bot->blocks->prev = b;\r
+      bot->blocks = b;\r
+      bot->block_count++;\r
+      \r
+      sendnoticetouser(bot->np, sender, "Now blocking all messages from users with accountname %s.", target);\r
+      \r
+      if (bot->flags & QAB_BLOCKMARK) {\r
+        qab_question* q;\r
+        int i, spamqcount = 0;\r
+        nick* qnick;\r
+        \r
+        for (i = 0; i < QUESTIONHASHSIZE; i++) {\r
+          for (q = bot->questions[i]; q; q = q->next) {\r
+            if ((q->flags & QAQ_QSTATE) != QAQ_NEW)\r
+              continue;\r
+            \r
+            if (!(qnick = getnickbynumeric(q->numeric)))\r
+              continue;\r
+            \r
+            if (!IsAccount(qnick))\r
+              continue;\r
+            \r
+            if (ircd_strcmp(qnick->authname, b->blockstr))\r
+              continue;\r
+            \r
+            q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;\r
+            spamqcount++;\r
+          }\r
+        }\r
+        \r
+        sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");\r
+      }\r
+    }\r
+    else if (!ircd_strncmp(cargv[0], "-t", 2)) {\r
+      /* text block */\r
+      char* mask = cargv[1];\r
+      \r
+      b = (qab_block*)malloc(sizeof(qab_block));\r
+      b->type = QABBLOCK_TEXT;\r
+      b->created = time(0);\r
+      strncpy(b->creator, sender->authname, ACCOUNTLEN);\r
+      b->creator[ACCOUNTLEN] = '\0';\r
+      b->blockstr = strdup(mask);\r
+      b->prev = 0;\r
+      b->next = bot->blocks;\r
+      if (bot->blocks)\r
+        bot->blocks->prev = b;\r
+      bot->blocks = b;\r
+      bot->block_count++;\r
+      \r
+      sendnoticetouser(bot->np, sender, "Now blocking all questions which match %s.", mask);\r
+      \r
+      if (bot->flags & QAB_BLOCKMARK) {\r
+        qab_question* q;\r
+        int i, spamqcount = 0;\r
+        \r
+        for (i = 0; i < QUESTIONHASHSIZE; i++) {\r
+          for (q = bot->questions[i]; q; q = q->next) {\r
+            if ((q->flags & QAQ_QSTATE) != QAQ_NEW)\r
+              continue;\r
+            \r
+            if (match(b->blockstr, q->question))\r
+              continue;\r
+            \r
+            q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;\r
+            spamqcount++;\r
+          }\r
+        }\r
+        \r
+        sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");\r
+      }\r
+    }\r
+    else {\r
+      sendnoticetouser(bot->np, sender, "Invalid flag.");\r
+      return CMD_ERROR;\r
+    }\r
+  }\r
+  else {\r
+    /* hostmask block */\r
+    char* mask = cargv[0];\r
+    \r
+    if (!strchr(mask, '@') || !strchr(mask, '!')) {\r
+      sendnoticetouser(bot->np, sender, "%s is not a valid hostmask.", mask);\r
+      return;\r
+    }\r
+    \r
+    b = (qab_block*)malloc(sizeof(qab_block));\r
+    b->type = QABBLOCK_HOST;\r
+    b->created = time(0);\r
+    strncpy(b->creator, sender->authname, ACCOUNTLEN);\r
+    b->creator[ACCOUNTLEN] = '\0';\r
+    b->blockstr = strdup(mask);\r
+    b->prev = 0;\r
+    b->next = bot->blocks;\r
+    if (bot->blocks)\r
+      bot->blocks->prev = b;\r
+    bot->blocks = b;\r
+    bot->block_count++;\r
+    \r
+    sendnoticetouser(bot->np, sender, "Now blocking all messages from users with a hostmask matching %s.", mask);\r
+    \r
+    if (bot->flags & QAB_BLOCKMARK) {\r
+        qab_question* q;\r
+        int i, spamqcount = 0;\r
+        nick* qnick;\r
+        char hostbuf[NICKLEN + USERLEN + HOSTLEN + 3];\r
+        \r
+        for (i = 0; i < QUESTIONHASHSIZE; i++) {\r
+          for (q = bot->questions[i]; q; q = q->next) {\r
+            if ((q->flags & QAQ_QSTATE) != QAQ_NEW)\r
+              continue;\r
+            \r
+            if (!(qnick = getnickbynumeric(q->numeric)))\r
+              continue;\r
+            \r
+            sprintf(hostbuf,"%s!%s@%s", qnick->nick, qnick->ident, qnick->host->name->content);\r
+            \r
+            if (match(b->blockstr, hostbuf))\r
+              continue;\r
+            \r
+            q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;\r
+            spamqcount++;\r
+          }\r
+        }\r
+        \r
+        sendnoticetouser(bot->np, sender, "Block caused %d message%s to be marked as spam.", spamqcount, (spamqcount == 1) ? "" : "s");\r
+      }\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanclear(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  qab_spam* s;\r
+  qab_spam* ns;\r
+  qab_answer* a;\r
+  qab_answer* na;\r
+  \r
+  for (s = bot->nextspam; s; s = ns) {\r
+    ns = s->next;\r
+    free(s->message);\r
+    free(s);\r
+  }\r
+  \r
+  bot->nextspam = bot->lastspam = 0;\r
+  \r
+  sendmessagetochannel(bot->np, cp, "Cleared message buffer.");\r
+  if (bot->micnumeric) {\r
+    bot->micnumeric = 0;\r
+    sendmessagetochannel(bot->np, cp, "Mic deactivated.");\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanclosechan(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  modechanges changes;\r
+  \r
+  localsetmodeinit(&changes, bot->public_chan->channel, bot->np);\r
+  localdosetmode_simple(&changes, CHANMODE_INVITEONLY, 0);\r
+  localsetmodeflush(&changes, 1);\r
+  sendnoticetouser(bot->np, sender, "Public channel has been closed.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanconfig(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  char* opt;\r
+  char* value;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(bot->np, sender, "Syntax: !config <option> [<value>]");\r
+    sendnoticetouser(bot->np, sender, "Displays or sets configuration option. Valid options are:");\r
+    sendnoticetouser(bot->np, sender, "blockcontrol - Block questions containing control chars.");\r
+    sendnoticetouser(bot->np, sender, "blockcolour  - Block questions containing colour.");\r
+    sendnoticetouser(bot->np, sender, "blockmark    - Mark questions affected by blocks as spam.");\r
+    sendnoticetouser(bot->np, sender, "authedonly   - Accept questions from authed users only.");\r
+    sendnoticetouser(bot->np, sender, "linebreak    - Separate questions with line breaks.");\r
+    sendnoticetouser(bot->np, sender, "flooddetect  - Attempt to detect floodclone spam.");\r
+    sendnoticetouser(bot->np, sender, "floodblock   - Automatically block floodclone spam.");\r
+    sendnoticetouser(bot->np, sender, "spamint      - Text spam interval.");\r
+    sendnoticetouser(bot->np, sender, "nickblockint - Time to wait before sending another question.");\r
+    sendnoticetouser(bot->np, sender, "queuedqint   - Queued answer spam interval.");\r
+    sendnoticetouser(bot->np, sender, "mictimeout   - Idle time before mic is automatically disabled.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  opt = cargv[0];\r
+  if (cargc == 2)\r
+    value = cargv[1];\r
+  else\r
+    value = 0;\r
+  \r
+  if (!ircd_strcmp(opt, "blockcontrol")) {\r
+    if (value) {\r
+      if (!ircd_strcmp(value, "on")) {\r
+        bot->flags |= QAB_CONTROLCHAR;\r
+        sendnoticetouser(bot->np, sender, "Questions containing control characters will now be blocked.");\r
+      }\r
+      else if (!ircd_strcmp(value, "off")) {\r
+        bot->flags &= (~QAB_CONTROLCHAR);\r
+        sendnoticetouser(bot->np, sender, "Questions containing control characters will no longer be blocked.");\r
+      }\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Control characters are currently %s blocked.", (bot->flags & QAB_CONTROLCHAR) ? "being" : "not being");\r
+  }\r
+  else if (!ircd_strcmp(opt, "blockcolour")) {\r
+    if (value) {\r
+      if (!ircd_strcmp(value, "on")) {\r
+        bot->flags |= QAB_COLOUR;\r
+        sendnoticetouser(bot->np, sender, "Questions containing colour will now be blocked.");\r
+      }\r
+      else if (!ircd_strcmp(value, "off")) {\r
+        bot->flags &= (~QAB_COLOUR);\r
+        sendnoticetouser(bot->np, sender, "Questions containing colour will no longer be blocked.");\r
+      }\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Colours are currently %s blocked.", (bot->flags & QAB_COLOUR) ? "being" : "not being");\r
+  }\r
+  else if (!ircd_strcmp(opt, "blockmark")) {\r
+    if (value) {\r
+      if (!ircd_strcmp(value, "on")) {\r
+        bot->flags |= QAB_BLOCKMARK;\r
+        sendnoticetouser(bot->np, sender, "New blocks will automatically mark affected questions as spam.");\r
+      }\r
+      else if (!ircd_strcmp(value, "off")) {\r
+        bot->flags &= (~QAB_BLOCKMARK);\r
+        sendnoticetouser(bot->np, sender, "New blocks will no longer automatically mark affected questions as spam.");\r
+      }\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Blocks are currently %smarking affected questions as spam.", (bot->flags & QAB_BLOCKMARK) ? "" : "not ");\r
+  }\r
+  else if (!ircd_strcmp(opt, "authedonly")) {\r
+    if (value) {\r
+      if (!ircd_strcmp(value, "on")) {\r
+        bot->flags |= QAB_AUTHEDONLY;\r
+        sendnoticetouser(bot->np, sender, "Questions from unauthed users will now be blocked.");\r
+      }\r
+      else if (!ircd_strcmp(value, "off")) {\r
+        bot->flags &= (~QAB_AUTHEDONLY);\r
+        sendnoticetouser(bot->np, sender, "Questions from unauthed users will no longer be blocked.");\r
+      }\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Unauthed users may currently %ssend questions.", (bot->flags & QAB_AUTHEDONLY) ? "NOT " : "");\r
+  }\r
+  else if (!ircd_strcmp(opt, "linebreak")) {\r
+    if (value) {\r
+      if (!ircd_strcmp(value, "on")) {\r
+        bot->flags |= QAB_LINEBREAK;\r
+        sendnoticetouser(bot->np, sender, "Line breaks are now enabled.");\r
+      }\r
+      else if (!ircd_strcmp(value, "off")) {\r
+        bot->flags &= (~QAB_LINEBREAK);\r
+        sendnoticetouser(bot->np, sender, "Line breaks are now disabled.");\r
+      }\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Line breaks are currently %s.", (bot->flags & QAB_LINEBREAK) ? "enabled" : "disabled");\r
+  }\r
+  else if (!ircd_strcmp(opt, "flooddetect")) {\r
+    if (value) {\r
+      if (!ircd_strcmp(value, "on")) {\r
+        bot->flags |= QAB_FLOODDETECT;\r
+        sendnoticetouser(bot->np, sender, "Flood detection is now enabled.");\r
+      }\r
+      else if (!ircd_strcmp(value, "off")) {\r
+        bot->flags &= (~QAB_FLOODDETECT);\r
+        sendnoticetouser(bot->np, sender, "Flood detection is now disabled.");\r
+      }\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Flood detection is currently %s.", (bot->flags & QAB_FLOODDETECT) ? "enabled" : "disabled");\r
+  }\r
+  else if (!ircd_strcmp(opt, "floodblock")) {\r
+    if (value) {\r
+      if (!ircd_strcmp(value, "on")) {\r
+        bot->flags |= QAB_FLOODSTOP;\r
+        sendnoticetouser(bot->np, sender, "Flood blocking is now enabled.");\r
+      }\r
+      else if (!ircd_strcmp(value, "off")) {\r
+        bot->flags &= (~QAB_FLOODSTOP);\r
+        sendnoticetouser(bot->np, sender, "Flood blocking is now disabled.");\r
+      }\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Invalid option. Valid options are 'on' or 'off'.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Flood blocking is currently %s.", (bot->flags & QAB_FLOODSTOP) ? "enabled" : "disabled");\r
+  }\r
+  else if (!ircd_strcmp(opt, "mictimeout")) {\r
+    if (value) {\r
+      int v = (int)strtol(value, NULL, 10);\r
+      \r
+      if ((v < 0) || (v > 300)) {\r
+        sendnoticetouser(bot->np, sender, "Value must be between 0 (off) and 300.");\r
+        return CMD_ERROR;\r
+      }\r
+      \r
+      bot->mic_timeout = v;\r
+      sendnoticetouser(bot->np, sender, "Value set.");\r
+    }\r
+    else {\r
+      if (bot->mic_timeout)\r
+        sendnoticetouser(bot->np, sender, "Mic timeout is currently %d second%s.", bot->mic_timeout, (bot->mic_timeout == 1) ? "" : "s");\r
+      else\r
+        sendnoticetouser(bot->np, sender, "Mic timeout is currently disabled.");\r
+    }\r
+  }\r
+  else if (!ircd_strcmp(opt, "spamint")) {\r
+    if (value) {\r
+      int v = (int)strtol(value, NULL, 10);\r
+      \r
+      if ((v < 1) || (v > 30)) {\r
+        sendnoticetouser(bot->np, sender, "Value must be between 1 and 30.");\r
+        return CMD_ERROR;\r
+      }\r
+      \r
+      bot->spam_interval = v;\r
+      sendnoticetouser(bot->np, sender, "Value set.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Spam interval is currently %d second%s.", bot->spam_interval, (bot->spam_interval == 1) ? "" : "s");\r
+  }\r
+  else if (!ircd_strcmp(opt, "nickblockint")) {\r
+    if (value) {\r
+      int v = (int)strtol(value, NULL, 10);\r
+      \r
+      if ((v < 1) || (v > 300)) {\r
+        sendnoticetouser(bot->np, sender, "Value must be between 1 and 300.");\r
+        return CMD_ERROR;\r
+      }\r
+      \r
+      bot->ask_wait = v;\r
+      sendnoticetouser(bot->np, sender, "Value set.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Nick block interval is currently %d second%s.", bot->ask_wait, (bot->ask_wait == 1) ? "" : "s");\r
+  }\r
+  else if (!ircd_strcmp(opt, "queuedqint")) {\r
+    if (value) {\r
+      int v = (int)strtol(value, NULL, 10);\r
+      \r
+      if ((v < 1) || (v > 20)) {\r
+        sendnoticetouser(bot->np, sender, "Value must be between 1 and 20.");\r
+        return CMD_ERROR;\r
+      }\r
+      \r
+      bot->queued_question_interval = v;\r
+      sendnoticetouser(bot->np, sender, "Value set.");\r
+    }\r
+    else\r
+      sendnoticetouser(bot->np, sender, "Queued question interval is currently %d second%s.", bot->queued_question_interval, (bot->queued_question_interval == 1) ? "" : "s");\r
+  }\r
+  else\r
+    sendnoticetouser(bot->np, sender, "Invalid configuration option.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanhelp(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  char* ch;\r
+  \r
+  if (cargc < 1)\r
+    ch = "";\r
+  else\r
+    ch = cargv[0];\r
+  \r
+  if (*ch) {\r
+    if (!ircd_strcmp(ch, "mic")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !mic");\r
+      sendnoticetouser(bot->np, sender, "Turn the microphone on or off. When turned on, anything said by the microphone holder is relayed to %s.", bot->public_chan->name->content);\r
+    }\r
+    else if (!ircd_strcmp(ch, "clear")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !clear");\r
+      sendnoticetouser(bot->np, sender, "Clear currently queued text to relay, and turn off the microphone.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "ping")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !ping");\r
+      sendnoticetouser(bot->np, sender, "Pings the bot.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "config")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !config <option|help> [<value>]");\r
+      sendnoticetouser(bot->np, sender, "Display or set bot configuration options.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "answer")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !answer <id> <answer>");\r
+      sendnoticetouser(bot->np, sender, "Answer a question.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "block")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !block [<-q|-t>] <mask>");\r
+      sendnoticetouser(bot->np, sender, "Add a block, where:");\r
+      sendnoticetouser(bot->np, sender, "-q: blocks a Q account.");\r
+      sendnoticetouser(bot->np, sender, "-t: blocks question text.");\r
+      sendnoticetouser(bot->np, sender, "No flag results in a hostmask block.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "listblocks")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !listblocks");\r
+      sendnoticetouser(bot->np, sender, "View the currently added blocks.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "spam")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !spam <id>");\r
+      sendnoticetouser(bot->np, sender, "Mark a question as spam. This stops it being answered.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "offtopic")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !offtopic <id>");\r
+      sendnoticetouser(bot->np, sender, "Mark a question as off-topic. This stops it being answered.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "unblock")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !unblock [<-q|-t>] <mask>");\r
+      sendnoticetouser(bot->np, sender, "Removes a block. See \"!help block\" for a description of the flags.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "reset")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !reset <all|questions|blocks|stats>");\r
+      sendnoticetouser(bot->np, sender, "Reset the questions, blocks or both; or the stats.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "closechan")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !closechan");\r
+      sendnoticetouser(bot->np, sender, "Closes the public channel.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "openchan")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !openchan");\r
+      sendnoticetouser(bot->np, sender, "Opens the public channel.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "status")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax: !status");\r
+      sendnoticetouser(bot->np, sender, "Displays some status information and statistics.");\r
+    }\r
+    else if (!ircd_strcmp(ch, "help")) {\r
+      sendnoticetouser(bot->np, sender, "Syntax !help [<command>]");\r
+      sendnoticetouser(bot->np, sender, "List available commands or view help for a particular command.");\r
+    }\r
+    else {\r
+      sendnoticetouser(bot->np, sender, "No help available for '%s'.", ch);\r
+    }\r
+  }\r
+  else {\r
+    sendnoticetouser(bot->np, sender, "The following channel commands are recognised:");\r
+    sendnoticetouser(bot->np, sender, "!answer     - Answer a question.");\r
+    sendnoticetouser(bot->np, sender, "!block      - Block a hostmask, account or string.");\r
+    sendnoticetouser(bot->np, sender, "!clear      - Clear currently queued text to spam.");\r
+    sendnoticetouser(bot->np, sender, "!closechan  - Close the public channel.");\r
+    sendnoticetouser(bot->np, sender, "!config     - Display or set bot configuration options.");\r
+    sendnoticetouser(bot->np, sender, "!help       - List commands or view the help for a command");\r
+    sendnoticetouser(bot->np, sender, "!listblocks - List currently added blocks.");\r
+    sendnoticetouser(bot->np, sender, "!mic        - Turn the microphone on or off.");\r
+    sendnoticetouser(bot->np, sender, "!offtopic   - Mark a question or questions as off-topic.");\r
+    sendnoticetouser(bot->np, sender, "!openchan   - Open the public channel.");\r
+    sendnoticetouser(bot->np, sender, "!ping       - Ping the bot.");\r
+    sendnoticetouser(bot->np, sender, "!reset      - Clear all blocks, questions or both.");\r
+    sendnoticetouser(bot->np, sender, "!spam       - Mark a question or questions as spam.");\r
+    sendnoticetouser(bot->np, sender, "!status     - Display some status statistics.");\r
+    sendnoticetouser(bot->np, sender, "!unblock    - Remove a block.");\r
+    sendnoticetouser(bot->np, sender, "End of list.");\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanlistblocks(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  qab_block* b;\r
+  \r
+  if (!(b = bot->blocks)) {\r
+    sendnoticetouser(bot->np, sender, "There are no blocks currently added.");\r
+    return;\r
+  }\r
+  \r
+  sendnoticetouser(bot->np, sender, "Type: Hostmask/Account/Textmask:");\r
+  \r
+  for (; b; b = b->next) {\r
+    if (b->type == QABBLOCK_ACCOUNT)\r
+      sendnoticetouser(bot->np, sender, "A     %s", b->blockstr);\r
+    else if (b->type == QABBLOCK_HOST)\r
+      sendnoticetouser(bot->np, sender, "H     %s", b->blockstr);\r
+    else\r
+      sendnoticetouser(bot->np, sender, "T     %s", b->blockstr);\r
+  }\r
+  \r
+  sendnoticetouser(bot->np, sender, "End of list.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanmic(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  \r
+  if (bot->micnumeric) {\r
+    if (bot->micnumeric == sender->numeric) {\r
+      bot->micnumeric = 0;\r
+      sendmessagetochannel(bot->np, cp, "Mic deactivated.");\r
+      if (!bot->lastspam)\r
+        qabot_spamstored((void*)bot);\r
+    }\r
+    else {\r
+      bot->lastmic = time(NULL);\r
+      bot->micnumeric = sender->numeric;\r
+      sendmessagetochannel(bot->np, cp, "%s now has the mic. Anything said by %s will be relayed in %s.", \r
+        sender->nick, sender->nick, bot->public_chan->name->content);\r
+      deleteschedule(0, qabot_spamstored, (void*)bot);\r
+    }\r
+  }\r
+  else {\r
+    bot->lastmic = time(NULL);\r
+    bot->micnumeric = sender->numeric;\r
+    sendmessagetochannel(bot->np, cp, "Mic activated. Anything said by %s will be relayed in %s.", \r
+      sender->nick, bot->public_chan->name->content);\r
+    deleteschedule(0, qabot_spamstored, (void*)bot);\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanmoo(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  char moostr[50];\r
+  int i, moocount = 5 + (rand() % 40);\r
+  \r
+  moostr[0] = 'm';\r
+  for (i = 1; i < moocount; i++)\r
+    moostr[i] = ((rand() % 100) > 50) ? 'o': '0';\r
+  moostr[i] = '\0';\r
+  \r
+  sendmessagetochannel(bot->np, cp, "%s", moostr);\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanofftopic(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  int id;\r
+  int i;\r
+  qab_question* q;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  for (i = 0; i < cargc; i++) {\r
+    id = strtol(cargv[i], NULL, 10);\r
+    \r
+    if ((id < 1) || (id > bot->lastquestionID)) {\r
+      sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);\r
+      continue;\r
+    }\r
+    \r
+    for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)\r
+      if (q->id == id)\r
+        break;         \r
+    \r
+    if (!q) {\r
+      sendnoticetouser(bot->np, sender, "Can't find question %d.", id);\r
+      continue;\r
+    }\r
+    \r
+    switch (q->flags & QAQ_QSTATE) {\r
+    case QAQ_ANSWERED:\r
+      sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);\r
+      continue;\r
+    \r
+    case QAQ_OFFTOPIC:\r
+      sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);\r
+      continue;\r
+    \r
+    case QAQ_SPAM:\r
+      sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);\r
+      continue;\r
+    \r
+    default:\r
+      break;\r
+    }\r
+    \r
+    q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_OFFTOPIC;\r
+    sendnoticetouser(bot->np, sender, "Question %d has been marked as off-topic.", id);\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanopenchan(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  modechanges changes;\r
+  \r
+  localsetmodeinit(&changes, bot->public_chan->channel, bot->np);\r
+  localdosetmode_simple(&changes, CHANMODE_MODERATE|CHANMODE_DELJOINS, CHANMODE_INVITEONLY);\r
+  localsetmodeflush(&changes, 1);\r
+  sendnoticetouser(bot->np, sender, "Public channel has been opened.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanping(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  \r
+  sendmessagetochannel(bot->np, cp, "pong!");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanreset(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  int r = 0;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(bot->np, sender, "Syntax: !reset <blocks|questions|stats|all>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!ircd_strcmp(cargv[0], "blocks"))\r
+    r = 1;\r
+  else if (!ircd_strcmp(cargv[0], "questions"))\r
+    r = 2;\r
+  else if (!ircd_strcmp(cargv[0], "stats"))\r
+    r = 4;\r
+  else if (!ircd_strcmp(cargv[0], "all"))\r
+    r = 3;\r
+  else {\r
+    sendnoticetouser(bot->np, sender, "Unknown parameter: %s.", cargv[0]);\r
+    return;\r
+  }\r
+  \r
+  if (r & 1) {\r
+    qab_block* b;\r
+   \r
+    while (bot->blocks) {\r
+      b = bot->blocks;\r
+      bot->blocks = bot->blocks->next;\r
+      if (b->blockstr)\r
+        free(b->blockstr);\r
+      free(b);\r
+    }\r
+    \r
+    bot->block_count = 0;\r
+    \r
+    sendnoticetouser(bot->np, sender, "Reset (blocks): Done.");\r
+  }\r
+  \r
+  if (r & 2) {\r
+    qab_question* q;\r
+    int i;\r
+    \r
+    for (i = 0; i < QUESTIONHASHSIZE; i++) {\r
+      while (bot->questions[i]) {\r
+        q = bot->questions[i];\r
+        bot->questions[i] = bot->questions[i]->next;\r
+        if (q->question)\r
+          free(q->question);\r
+        if (q->answer)\r
+          free(q->answer);\r
+        free(q);\r
+      }\r
+    }\r
+    \r
+    bot->lastquestionID = 0;\r
+    bot->answered = 0;\r
+    \r
+    sendnoticetouser(bot->np, sender, "Reset (questions): Done.");\r
+  }\r
+  \r
+  if (r & 4) {\r
+    bot->answered = 0;\r
+    bot->spammed = 0;\r
+    sendnoticetouser(bot->np, sender, "Reset (stats): Done.");\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanspam(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  int id;\r
+  int i;\r
+  qab_question* q;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(bot->np, sender, "Syntax: !spam <id> [<id> ... <id>]");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  for (i = 0; i < cargc; i++) {\r
+    id = strtol(cargv[i], NULL, 10);\r
+    \r
+    if ((id < 1) || (id > bot->lastquestionID)) {\r
+      sendnoticetouser(bot->np, sender, "Invalid question ID %d.", id);\r
+      continue;\r
+    }\r
+    \r
+    for (q = bot->questions[id % QUESTIONHASHSIZE]; q; q = q->next)\r
+      if (q->id == id)\r
+        break;         \r
+    \r
+    if (!q) {\r
+      sendnoticetouser(bot->np, sender, "Can't find question %d.", id);\r
+      continue;\r
+    }\r
+    \r
+    switch (q->flags & QAQ_QSTATE) {\r
+    case QAQ_ANSWERED:\r
+      sendnoticetouser(bot->np, sender, "Question %d has already been answered.", id);\r
+      continue;\r
+    \r
+    case QAQ_OFFTOPIC:\r
+      sendnoticetouser(bot->np, sender, "Question %d has already been marked as off-topic.", id);\r
+      continue;\r
+    \r
+    case QAQ_SPAM:\r
+      sendnoticetouser(bot->np, sender, "Question %d has already been marked as spam.", id);\r
+      continue;\r
+    \r
+    default:\r
+      break;\r
+    }\r
+    \r
+    q->flags = ((q->flags) & ~QAQ_QSTATE) | QAQ_SPAM;\r
+    sendnoticetouser(bot->np, sender, "Question %d has been marked as spam.", id);\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanstatus(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  \r
+  sendnoticetouser(bot->np, sender, "Lines spammed:            %d", bot->spammed);\r
+  sendnoticetouser(bot->np, sender, "Questions asked:          %d", bot->lastquestionID);\r
+  sendnoticetouser(bot->np, sender, "Questions answered:       %d", bot->answered);\r
+  sendnoticetouser(bot->np, sender, "Blocks:                   %d", bot->block_count);\r
+  /*sendnoticetouser(bot->np, sender, "Question interval:        %d seconds", bot->question_interval);*/\r
+  sendnoticetouser(bot->np, sender, "Spam interval:            %d seconds", bot->spam_interval);\r
+  sendnoticetouser(bot->np, sender, "Nick block interval:      %d seconds", bot->ask_wait);\r
+  sendnoticetouser(bot->np, sender, "Queued question interval: %d seconds", bot->queued_question_interval);\r
+  sendnoticetouser(bot->np, sender, "Block control chars:      %s", (bot->flags & QAB_CONTROLCHAR) ? "Yes" : "No");\r
+  sendnoticetouser(bot->np, sender, "Block colour:             %s", (bot->flags & QAB_COLOUR) ? "Yes" : "No");\r
+  sendnoticetouser(bot->np, sender, "Authed users only:        %s", (bot->flags & QAB_AUTHEDONLY) ? "Yes" : "No");\r
+  sendnoticetouser(bot->np, sender, "Line break:               %s", (bot->flags & QAB_LINEBREAK) ? "Yes" : "No");\r
+  sendnoticetouser(bot->np, sender, "Question flood detection: %s", (bot->flags & QAB_FLOODDETECT) ? "Yes" : "No");\r
+  sendnoticetouser(bot->np, sender, "Question flood blocking:  %s", (bot->flags & QAB_FLOODSTOP) ? "Yes" : "No");\r
+  sendnoticetouser(bot->np, sender, "Blocks mark as spam:      %s", (bot->flags & QAB_BLOCKMARK) ? "Yes" : "No");\r
+  if (bot->micnumeric) {\r
+    nick* mnick = getnickbynumeric(bot->micnumeric);\r
+    \r
+    sendnoticetouser(bot->np, np, "Mic:                      Enabled (%s)", mnick ? mnick->nick : "UNKNOWN");\r
+  }\r
+  else\r
+    sendnoticetouser(bot->np, np, "Mic:                      Disabled");\r
+  sendnoticetouser(bot->np, sender, "Mic timeout:              %d", bot->mic_timeout);\r
+  /*sendnoticetouser(bot->np, sender, "");*/\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochanunblock(void* np, int cargc, char** cargv) {\r
+  nick* sender = (nick*)np;\r
+  qab_bot* bot = qabot_getcurrentbot();\r
+  channel* cp = qabot_getcurrentchannel();\r
+  char* ch;\r
+  qab_block* b;\r
+  char type = -1;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(bot->np, sender, "Syntax: !unblock [-q|-t] <account|mask>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (cargc > 1) {\r
+    if (!ircd_strncmp(cargv[0], "-q", 2)) {\r
+      type = QABBLOCK_ACCOUNT;\r
+      ch = cargv[1];\r
+      \r
+      if (*ch == '#')\r
+        ch++;\r
+    }\r
+    else if (!ircd_strncmp(cargv[0], "-t", 2)) {\r
+      type = QABBLOCK_TEXT;\r
+      ch = cargv[1];\r
+    }\r
+    else {\r
+      sendnoticetouser(bot->np, sender, "Invalid flag.");\r
+      return CMD_ERROR;\r
+    }\r
+  }\r
+  else {\r
+    type = QABBLOCK_HOST;\r
+    ch = cargv[0];\r
+  }\r
+  \r
+  for (b = bot->blocks; b; b = b->next) {\r
+    if (b->type != type)\r
+      continue;\r
+    \r
+    if (!ircd_strcmp(b->blockstr, ch)) {\r
+      if (b->next)\r
+        b->next->prev = b->prev;\r
+      if (b->prev)\r
+        b->prev->next = b->next;\r
+      else\r
+        bot->blocks = b->next;\r
+      \r
+      free(b->blockstr);\r
+      free(b);\r
+      \r
+      bot->block_count--;\r
+      \r
+      sendnoticetouser(bot->np, sender, "Block removed.");\r
+      return CMD_OK;\r
+    }\r
+  }\r
+  \r
+  sendnoticetouser(bot->np, sender, "No such block.");\r
+  \r
+  return CMD_ERROR;\r
+}\r
index 0e708842c330ad6cd190740e8873065ec166bbad..f7d7d7c5c6b7205a83f30091940bf2ccf60bfbab 100644 (file)
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#include "../nick/nick.h"
-#include "../localuser/localuserchannel.h"
-#include "../core/hooks.h"
-#include "../core/schedule.h"
-#include "../lib/array.h"
-#include "../lib/base64.h"
-#include "../lib/irc_string.h"
-#include "../lib/splitline.h"
-
-#include "qabot.h"
-
-int qabot_doshowcommands(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  Command* cmdlist[150];
-  int i, j;
-
-  sendnoticetouser(qabot_nick, np, "The following commands are registered at present:");
-  for (i = 0, j = getcommandlist(qabot_commands, cmdlist, 150); i < j; i++) {
-    if (cmdlist[i]->level)
-      sendnoticetouser(qabot_nick, np, "%s (%s)", cmdlist[i]->command->content, qabot_uflagtostr(cmdlist[i]->level));
-    else
-      sendnoticetouser(qabot_nick, np, "%s", cmdlist[i]->command->content);
-  }
-  sendnoticetouser(qabot_nick, np, "End of list.");
-
-  return CMD_OK;
-}
-
-int qabot_dohelp(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  
-  if (cargc < 1) {
-    sendnoticetouser(qabot_nick, np, "Syntax: help <command>");
-    return CMD_ERROR;
-  }
-  
-  return qabot_showhelp(np, cargv[0]);
-}
-
-int qabot_dohello(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-
-  if (!IsOper(np)) {
-    sendnoticetouser(qabot_nick, np, "You must be opered to use this command.");
-    return CMD_ERROR;
-  }
-
-  if (qabot_users) {
-    sendnoticetouser(qabot_nick, np, "This command cannot be used once the initial account has been created.");
-    return CMD_ERROR;
-  }
-  
-  qabot_adduser(np->authname, QAUFLAG_STAFF|QAUFLAG_ADMIN|QAUFLAG_DEVELOPER, time(0));
-  qabot_savedb();
-  sendnoticetouser(qabot_nick, np, "An account has been created with admin privileges.");
-
-  return CMD_OK;
-}
-
-int qabot_dosave(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  
-  sendnoticetouser(qabot_nick, np, "Saving...");
-  qabot_savedb();
-  sendnoticetouser(qabot_nick, np, "Done.");
-  
-  return CMD_OK;
-}
-
-int qabot_dolistbots(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  qab_bot* b;
-  
-  if (!qab_bots) {
-    sendnoticetouser(qabot_nick, np, "There are no bots currently added.");
-    return CMD_OK;
-  }
-  
-  sendnoticetouser(qabot_nick, np, "The following bots are added:");
-  for (b = qab_bots; b; b = b->next)
-    sendnoticetouser(qabot_nick, np, "%s (%s@%s)", b->nick, b->user, b->host);
-  sendnoticetouser(qabot_nick, np, "End of list.");
-}
-
-int qabot_dolistusers(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  qab_user* u;
-  
-  if (!qabot_users) {
-    sendnoticetouser(qabot_nick, np, "There are no users currently added.");
-    return CMD_OK;
-  }
-  
-  sendnoticetouser(qabot_nick, np, "The following users are added:");
-  for (u = qabot_users; u; u = u->next)
-    sendnoticetouser(qabot_nick, np, "%-15s (%s)", u->authname, qabot_uflagtostr(u->flags));
-  sendnoticetouser(qabot_nick, np, "End of list.");
-}
-
-int qabot_doshowbot(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  qab_bot* bot;
-  nick* botnick;
-  
-  if (cargc < 1) {
-    sendnoticetouser(qabot_nick, np, "Syntax: showbot <nick>");
-    return CMD_ERROR;
-  }
-  
-  if (!(botnick = getnickbynick(cargv[0]))) {
-    sendnoticetouser(qabot_nick, np, "No such nickname.");
-    return CMD_ERROR;
-  }
-  
-  bot = botnick->exts[qabot_nickext];
-  if (!bot) {
-    sendnoticetouser(qabot_nick, np, "%s is not a QABot.", botnick->nick);
-    return CMD_ERROR;
-  }
-  
-  sendnoticetouser(qabot_nick, np, "- Information for %s ---", bot->nick);
-  sendnoticetouser(qabot_nick, np, "User:                     %s", bot->user);
-  sendnoticetouser(qabot_nick, np, "Host:                     %s", bot->host);
-  sendnoticetouser(qabot_nick, np, "Public chan:              %s", bot->public_chan->name->content);
-  sendnoticetouser(qabot_nick, np, "Question chan:            %s", bot->question_chan->name->content);
-  sendnoticetouser(qabot_nick, np, "Staff chan:               %s", bot->staff_chan->name->content);
-  sendnoticetouser(qabot_nick, np, "Spam interval:            %d", bot->spam_interval);
-  sendnoticetouser(qabot_nick, np, "Nick block interval:      %d", bot->ask_wait);
-  sendnoticetouser(qabot_nick, np, "Queued question interval: %d", bot->queued_question_interval);  
-  sendnoticetouser(qabot_nick, np, "Lines spammed:            %d", bot->spammed);
-  sendnoticetouser(qabot_nick, np, "Questions asked:          %d", bot->lastquestionID);
-  sendnoticetouser(qabot_nick, np, "Questions answered:       %d", bot->answered);
-  sendnoticetouser(qabot_nick, np, "Blocks:                   %d", bot->block_count);
-  sendnoticetouser(qabot_nick, np, "Block control chars:      %s", (bot->flags & QAB_CONTROLCHAR) ? "Yes" : "No");
-  sendnoticetouser(qabot_nick, np, "Block colour:             %s", (bot->flags & QAB_COLOUR) ? "Yes" : "No");
-  sendnoticetouser(qabot_nick, np, "Authed users only:        %s", (bot->flags & QAB_AUTHEDONLY) ? "Yes" : "No");
-  sendnoticetouser(qabot_nick, np, "Line break:               %s", (bot->flags & QAB_LINEBREAK) ? "Yes" : "No");
-  sendnoticetouser(qabot_nick, np, "Question flood detection: %s", (bot->flags & QAB_FLOODDETECT) ? "Yes" : "No");
-  sendnoticetouser(qabot_nick, np, "Question flood blocking:  %s", (bot->flags & QAB_FLOODSTOP) ? "Yes" : "No");
-  sendnoticetouser(qabot_nick, np, "Blocks mark as spam:      %s", (bot->flags & QAB_BLOCKMARK) ? "Yes" : "No");
-  if (bot->micnumeric) {
-    nick* mnick = getnickbynumeric(bot->micnumeric);
-    
-    sendnoticetouser(qabot_nick, np, "Mic:                      Enabled (%s)", mnick ? mnick->nick : "UNKNOWN");
-  }
-  else
-    sendnoticetouser(qabot_nick, np, "Mic:                      Disabled");
-  sendnoticetouser(qabot_nick, sender, "Mic timeout:              %d", bot->mic_timeout);
-  sendnoticetouser(qabot_nick, np, "End of list.");
-  
-  return CMD_OK;
-}
-
-int qabot_doaddbot(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  qab_bot* bot;
-  channel* cp;
-  
-  if (cargc < 3) {
-    sendnoticetouser(qabot_nick, np, "Syntax: addbot <nick> <user> <host> <public channel> <question channel> <staff channel>");
-    return CMD_ERROR;
-  }
-  
-  if (!IsOper(np)) {
-    sendnoticetouser(qabot_nick, np, "You must be opered to use this command.");
-    return CMD_ERROR;
-  }
-  
-  if (!qabot_addbot(cargv[0], cargv[1], cargv[2], cargv[3], cargv[4], cargv[5], DEFAULTBOTFLAGS, SPAMINTERVAL, ASKWAIT, QUEUEDQUESTIONINTERVAL, np))
-    return CMD_ERROR;
-  
-  sendnoticetouser(qabot_nick, np, "Created %s!%s@%s (%s, %s, %s).", cargv[0], cargv[1], cargv[2], cargv[3], cargv[4], cargv[5]);
-  
-  return CMD_OK;
-}
-
-int qabot_dodelbot(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  nick* botnick;
-  qab_bot* bot;
-  
-  if (cargc < 1) {
-    sendnoticetouser(qabot_nick, np, "Syntax: delbot <nick>");
-    return CMD_ERROR;
-  }
-  
-  if (!IsOper(np)) {
-    sendnoticetouser(qabot_nick, np, "You must be opered to use this command.");
-    return CMD_ERROR;
-  }
-  
-  if (!(botnick = getnickbynick(cargv[0]))) {
-    sendnoticetouser(qabot_nick, np, "No such nickname.");
-    return CMD_ERROR;
-  }
-  
-  bot = botnick->exts[qabot_nickext];
-  if (!bot) {
-    sendnoticetouser(qabot_nick, np, "%s is not a QABot.", botnick->nick);
-    return CMD_ERROR;
-  }
-  
-  qabot_delbot(bot);
-  sendnoticetouser(qabot_nick, np, "Bot deleted.");
-  
-  return CMD_OK;
-}
-
-int qabot_doadduser(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  nick* target;
-  char* ch;
-  flag_t flags = 0;
-  char* victim;
-  
-  if (cargc < 2) {
-    sendnoticetouser(qabot_nick, np, "Syntax: adduser <nick> <flags>");
-    return CMD_ERROR;
-  }
-  
-  if (!(victim = qabot_getvictim(np, cargv[0])))
-    return CMD_ERROR;
-  
-  if (qabot_getuser(victim)) {
-    sendnoticetouser(qabot_nick, np, "Account %s already exists.", target->authname);
-    return CMD_ERROR;
-  }
-  
-  for (ch = cargv[1]; *ch; ch++) {
-    switch (*ch) {
-    case '+':
-      break;
-      
-    case 'a':
-      flags |= (QAUFLAG_ADMIN|QAUFLAG_STAFF);
-      break;
-      
-    case 'd':
-      flags |= (QAUFLAG_DEVELOPER|QAUFLAG_ADMIN|QAUFLAG_STAFF);
-      
-    case 's':
-      flags |= QAUFLAG_STAFF;
-      break;
-      
-    default:
-      sendnoticetouser(qabot_nick, np, "Unknown flag '%c'.", *ch);
-      return;
-    }
-  }
-  
-  qabot_adduser(victim, flags, time(0));
-  sendnoticetouser(qabot_nick, np, "Account created.");
-  
-  return CMD_OK;
-}
-
-int qabot_dodeluser(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  qab_user* u;
-  char* victim;
-  
-  if (cargc < 1) {
-    sendnoticetouser(qabot_nick, np, "Syntax: <account>");
-    return CMD_ERROR;
-  }
-  
-  if (!(victim = qabot_getvictim(np, cargv[0])))
-    return CMD_ERROR;
-  
-  if (!(u = qabot_getuser(victim))) {
-    sendnoticetouser(qabot_nick, np, "Account does not exist.");
-    return CMD_ERROR;
-  }
-  
-  if (!ircd_strcmp(u->authname, np->authname)) {
-    sendnoticetouser(qabot_nick, np, "You cannot delete your own account.");
-    return CMD_ERROR;
-  }
-  
-  qabot_squelchuser(u);
-  sendnoticetouser(qabot_nick, np, "Account deleted.");
-  
-  return CMD_OK;
-}
-
-int qabot_dochangelev(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  char* victim;
-  qab_user* u;
-  
-  if (cargc < 1) {
-    sendnoticetouser(qabot_nick, np, "Syntax: changelev <nick|#authname> <flags>");
-    return CMD_ERROR;
-  }
-  
-  if (!(victim = qabot_getvictim(np, cargv[0])))
-    return CMD_ERROR;
-  
-  if (!(u = qabot_getuser(victim))) {
-    sendnoticetouser(qabot_nick, np, "Account does not exist.");
-    return CMD_ERROR;
-  }
-  
-  sendnoticetouser(qabot_nick, np, "TODO: Finish this! :)");
-  
-  return CMD_OK;
-}
-
-int qabot_dowhois(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  char* victim;
-  qab_user* u;
-  
-  if (cargc < 1) {
-    sendnoticetouser(qabot_nick, np, "Syntax: whois <nick|#authname>");
-    return CMD_ERROR;
-  }
-  
-  if (!(victim = qabot_getvictim(np, cargv[0])))
-    return CMD_ERROR;
-  
-  if (!(u = qabot_getuser(victim))) {
-    sendnoticetouser(qabot_nick, np, "Account does not exist.");
-    return CMD_ERROR;
-  }
-  
-  sendnoticetouser(qabot_nick, np, "Account: %s", u->authname);
-  sendnoticetouser(qabot_nick, np, "Flags:   %s", qabot_uflagtostr(u->flags));
-  sendnoticetouser(qabot_nick, np, "Created: %s", qabot_formattime(u->created));
-  
-  return CMD_OK;
-}
-
-int qabot_dostatus(void* sender, int cargc, char** cargv) {
-  nick* np = (nick*)sender;
-  int botc = 0, blockc = 0, userc = 0, spamc = 0, qc = 0, qac = 0;
-  qab_bot* b;
-  qab_user* u;
-  
-  for (b = qab_bots; b; b = b->next) {
-    botc++;
-    blockc += b->block_count;
-    spamc += b->spammed;
-    qc += b->lastquestionID;
-    qac += b->answered;
-  }
-  
-  for (u = qabot_users; u; u = u->next)
-    userc++;
-  
-  sendnoticetouser(qabot_nick, np, "Up since:                 %s", qabot_formattime(qab_startime));
-  sendnoticetouser(qabot_nick, np, "Bots:                     %d", botc);
-  sendnoticetouser(qabot_nick, np, "Blocks:                   %d", blockc);
-  sendnoticetouser(qabot_nick, np, "Users:                    %d", userc);
-  sendnoticetouser(qabot_nick, np, "Total lines spammed:      %d", spamc);
-  sendnoticetouser(qabot_nick, np, "Total questions asked:    %d", qc);
-  sendnoticetouser(qabot_nick, np, "Total questions answered: %d", qac);
-  
-  return CMD_OK;
-}
+#include <stdio.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "../nick/nick.h"\r
+#include "../localuser/localuserchannel.h"\r
+#include "../core/hooks.h"\r
+#include "../core/schedule.h"\r
+#include "../lib/array.h"\r
+#include "../lib/base64.h"\r
+#include "../lib/irc_string.h"\r
+#include "../lib/splitline.h"\r
+\r
+#include "qabot.h"\r
+\r
+int qabot_doshowcommands(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  Command* cmdlist[150];\r
+  int i, j;\r
+\r
+  sendnoticetouser(qabot_nick, np, "The following commands are registered at present:");\r
+  for (i = 0, j = getcommandlist(qabot_commands, cmdlist, 150); i < j; i++) {\r
+    if (cmdlist[i]->level)\r
+      sendnoticetouser(qabot_nick, np, "%s (%s)", cmdlist[i]->command->content, qabot_uflagtostr(cmdlist[i]->level));\r
+    else\r
+      sendnoticetouser(qabot_nick, np, "%s", cmdlist[i]->command->content);\r
+  }\r
+  sendnoticetouser(qabot_nick, np, "End of list.");\r
+\r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dohelp(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: help <command>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  return qabot_showhelp(np, cargv[0]);\r
+}\r
+\r
+int qabot_dohello(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+\r
+  if (!IsOper(np)) {\r
+    sendnoticetouser(qabot_nick, np, "You must be opered to use this command.");\r
+    return CMD_ERROR;\r
+  }\r
+\r
+  if (qabot_users) {\r
+    sendnoticetouser(qabot_nick, np, "This command cannot be used once the initial account has been created.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  qabot_adduser(np->authname, QAUFLAG_STAFF|QAUFLAG_ADMIN|QAUFLAG_DEVELOPER, time(0));\r
+  qabot_savedb();\r
+  sendnoticetouser(qabot_nick, np, "An account has been created with admin privileges.");\r
+\r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dosave(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  \r
+  sendnoticetouser(qabot_nick, np, "Saving...");\r
+  qabot_savedb();\r
+  sendnoticetouser(qabot_nick, np, "Done.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dolistbots(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  qab_bot* b;\r
+  \r
+  if (!qab_bots) {\r
+    sendnoticetouser(qabot_nick, np, "There are no bots currently added.");\r
+    return CMD_OK;\r
+  }\r
+  \r
+  sendnoticetouser(qabot_nick, np, "The following bots are added:");\r
+  for (b = qab_bots; b; b = b->next)\r
+    sendnoticetouser(qabot_nick, np, "%s (%s@%s)", b->nick, b->user, b->host);\r
+  sendnoticetouser(qabot_nick, np, "End of list.");\r
+}\r
+\r
+int qabot_dolistusers(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  qab_user* u;\r
+  \r
+  if (!qabot_users) {\r
+    sendnoticetouser(qabot_nick, np, "There are no users currently added.");\r
+    return CMD_OK;\r
+  }\r
+  \r
+  sendnoticetouser(qabot_nick, np, "The following users are added:");\r
+  for (u = qabot_users; u; u = u->next)\r
+    sendnoticetouser(qabot_nick, np, "%-15s (%s)", u->authname, qabot_uflagtostr(u->flags));\r
+  sendnoticetouser(qabot_nick, np, "End of list.");\r
+}\r
+\r
+int qabot_doshowbot(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  qab_bot* bot;\r
+  nick* botnick;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: showbot <nick>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!(botnick = getnickbynick(cargv[0]))) {\r
+    sendnoticetouser(qabot_nick, np, "No such nickname.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  bot = botnick->exts[qabot_nickext];\r
+  if (!bot) {\r
+    sendnoticetouser(qabot_nick, np, "%s is not a QABot.", botnick->nick);\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  sendnoticetouser(qabot_nick, np, "- Information for %s ---", bot->nick);\r
+  sendnoticetouser(qabot_nick, np, "User:                     %s", bot->user);\r
+  sendnoticetouser(qabot_nick, np, "Host:                     %s", bot->host);\r
+  sendnoticetouser(qabot_nick, np, "Public chan:              %s", bot->public_chan->name->content);\r
+  sendnoticetouser(qabot_nick, np, "Question chan:            %s", bot->question_chan->name->content);\r
+  sendnoticetouser(qabot_nick, np, "Staff chan:               %s", bot->staff_chan->name->content);\r
+  sendnoticetouser(qabot_nick, np, "Spam interval:            %d", bot->spam_interval);\r
+  sendnoticetouser(qabot_nick, np, "Nick block interval:      %d", bot->ask_wait);\r
+  sendnoticetouser(qabot_nick, np, "Queued question interval: %d", bot->queued_question_interval);  \r
+  sendnoticetouser(qabot_nick, np, "Lines spammed:            %d", bot->spammed);\r
+  sendnoticetouser(qabot_nick, np, "Questions asked:          %d", bot->lastquestionID);\r
+  sendnoticetouser(qabot_nick, np, "Questions answered:       %d", bot->answered);\r
+  sendnoticetouser(qabot_nick, np, "Blocks:                   %d", bot->block_count);\r
+  sendnoticetouser(qabot_nick, np, "Block control chars:      %s", (bot->flags & QAB_CONTROLCHAR) ? "Yes" : "No");\r
+  sendnoticetouser(qabot_nick, np, "Block colour:             %s", (bot->flags & QAB_COLOUR) ? "Yes" : "No");\r
+  sendnoticetouser(qabot_nick, np, "Authed users only:        %s", (bot->flags & QAB_AUTHEDONLY) ? "Yes" : "No");\r
+  sendnoticetouser(qabot_nick, np, "Line break:               %s", (bot->flags & QAB_LINEBREAK) ? "Yes" : "No");\r
+  sendnoticetouser(qabot_nick, np, "Question flood detection: %s", (bot->flags & QAB_FLOODDETECT) ? "Yes" : "No");\r
+  sendnoticetouser(qabot_nick, np, "Question flood blocking:  %s", (bot->flags & QAB_FLOODSTOP) ? "Yes" : "No");\r
+  sendnoticetouser(qabot_nick, np, "Blocks mark as spam:      %s", (bot->flags & QAB_BLOCKMARK) ? "Yes" : "No");\r
+  if (bot->micnumeric) {\r
+    nick* mnick = getnickbynumeric(bot->micnumeric);\r
+    \r
+    sendnoticetouser(qabot_nick, np, "Mic:                      Enabled (%s)", mnick ? mnick->nick : "UNKNOWN");\r
+  }\r
+  else\r
+    sendnoticetouser(qabot_nick, np, "Mic:                      Disabled");\r
+  sendnoticetouser(qabot_nick, sender, "Mic timeout:              %d", bot->mic_timeout);\r
+  sendnoticetouser(qabot_nick, np, "End of list.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_doaddbot(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  qab_bot* bot;\r
+  channel* cp;\r
+  \r
+  if (cargc < 3) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: addbot <nick> <user> <host> <public channel> <question channel> <staff channel>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!IsOper(np)) {\r
+    sendnoticetouser(qabot_nick, np, "You must be opered to use this command.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!qabot_addbot(cargv[0], cargv[1], cargv[2], cargv[3], cargv[4], cargv[5], DEFAULTBOTFLAGS, SPAMINTERVAL, ASKWAIT, QUEUEDQUESTIONINTERVAL, np))\r
+    return CMD_ERROR;\r
+  \r
+  sendnoticetouser(qabot_nick, np, "Created %s!%s@%s (%s, %s, %s).", cargv[0], cargv[1], cargv[2], cargv[3], cargv[4], cargv[5]);\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dodelbot(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  nick* botnick;\r
+  qab_bot* bot;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: delbot <nick>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!IsOper(np)) {\r
+    sendnoticetouser(qabot_nick, np, "You must be opered to use this command.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!(botnick = getnickbynick(cargv[0]))) {\r
+    sendnoticetouser(qabot_nick, np, "No such nickname.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  bot = botnick->exts[qabot_nickext];\r
+  if (!bot) {\r
+    sendnoticetouser(qabot_nick, np, "%s is not a QABot.", botnick->nick);\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  qabot_delbot(bot);\r
+  sendnoticetouser(qabot_nick, np, "Bot deleted.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_doadduser(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  nick* target;\r
+  char* ch;\r
+  flag_t flags = 0;\r
+  char* victim;\r
+  \r
+  if (cargc < 2) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: adduser <nick> <flags>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!(victim = qabot_getvictim(np, cargv[0])))\r
+    return CMD_ERROR;\r
+  \r
+  if (qabot_getuser(victim)) {\r
+    sendnoticetouser(qabot_nick, np, "Account %s already exists.", target->authname);\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  for (ch = cargv[1]; *ch; ch++) {\r
+    switch (*ch) {\r
+    case '+':\r
+      break;\r
+      \r
+    case 'a':\r
+      flags |= (QAUFLAG_ADMIN|QAUFLAG_STAFF);\r
+      break;\r
+      \r
+    case 'd':\r
+      flags |= (QAUFLAG_DEVELOPER|QAUFLAG_ADMIN|QAUFLAG_STAFF);\r
+      \r
+    case 's':\r
+      flags |= QAUFLAG_STAFF;\r
+      break;\r
+      \r
+    default:\r
+      sendnoticetouser(qabot_nick, np, "Unknown flag '%c'.", *ch);\r
+      return;\r
+    }\r
+  }\r
+  \r
+  qabot_adduser(victim, flags, time(0));\r
+  sendnoticetouser(qabot_nick, np, "Account created.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dodeluser(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  qab_user* u;\r
+  char* victim;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: <account>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!(victim = qabot_getvictim(np, cargv[0])))\r
+    return CMD_ERROR;\r
+  \r
+  if (!(u = qabot_getuser(victim))) {\r
+    sendnoticetouser(qabot_nick, np, "Account does not exist.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!ircd_strcmp(u->authname, np->authname)) {\r
+    sendnoticetouser(qabot_nick, np, "You cannot delete your own account.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  qabot_squelchuser(u);\r
+  sendnoticetouser(qabot_nick, np, "Account deleted.");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dochangelev(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  char* victim;\r
+  qab_user* u;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: changelev <nick|#authname> <flags>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!(victim = qabot_getvictim(np, cargv[0])))\r
+    return CMD_ERROR;\r
+  \r
+  if (!(u = qabot_getuser(victim))) {\r
+    sendnoticetouser(qabot_nick, np, "Account does not exist.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  sendnoticetouser(qabot_nick, np, "TODO: Finish this! :)");\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dowhois(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  char* victim;\r
+  qab_user* u;\r
+  \r
+  if (cargc < 1) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: whois <nick|#authname>");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  if (!(victim = qabot_getvictim(np, cargv[0])))\r
+    return CMD_ERROR;\r
+  \r
+  if (!(u = qabot_getuser(victim))) {\r
+    sendnoticetouser(qabot_nick, np, "Account does not exist.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  sendnoticetouser(qabot_nick, np, "Account: %s", u->authname);\r
+  sendnoticetouser(qabot_nick, np, "Flags:   %s", qabot_uflagtostr(u->flags));\r
+  sendnoticetouser(qabot_nick, np, "Created: %s", qabot_formattime(u->created));\r
+  \r
+  return CMD_OK;\r
+}\r
+\r
+int qabot_dostatus(void* sender, int cargc, char** cargv) {\r
+  nick* np = (nick*)sender;\r
+  int botc = 0, blockc = 0, userc = 0, spamc = 0, qc = 0, qac = 0;\r
+  qab_bot* b;\r
+  qab_user* u;\r
+  \r
+  for (b = qab_bots; b; b = b->next) {\r
+    botc++;\r
+    blockc += b->block_count;\r
+    spamc += b->spammed;\r
+    qc += b->lastquestionID;\r
+    qac += b->answered;\r
+  }\r
+  \r
+  for (u = qabot_users; u; u = u->next)\r
+    userc++;\r
+  \r
+  sendnoticetouser(qabot_nick, np, "Up since:                 %s", qabot_formattime(qab_startime));\r
+  sendnoticetouser(qabot_nick, np, "Bots:                     %d", botc);\r
+  sendnoticetouser(qabot_nick, np, "Blocks:                   %d", blockc);\r
+  sendnoticetouser(qabot_nick, np, "Users:                    %d", userc);\r
+  sendnoticetouser(qabot_nick, np, "Total lines spammed:      %d", spamc);\r
+  sendnoticetouser(qabot_nick, np, "Total questions asked:    %d", qc);\r
+  sendnoticetouser(qabot_nick, np, "Total questions answered: %d", qac);\r
+  \r
+  return CMD_OK;\r
+}\r
index aeca5d82d86019cfe7567f98b49c4f5845804e1f..6988d7cc9983d340b15d24c03793c07428548c29 100644 (file)
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#include "../nick/nick.h"
-#include "../localuser/localuserchannel.h"
-#include "../core/hooks.h"
-#include "../core/schedule.h"
-#include "../lib/array.h"
-#include "../lib/base64.h"
-#include "../lib/irc_string.h"
-#include "../lib/splitline.h"
-
-#include "qabot.h"
-
-qab_user* qabot_users = 0;
-
-void qabot_loaddb() {
-  FILE* f;
-  char buf[2049];
-  char* args[100];
-  time_t created;
-  flag_t flags;
-  int spam_interval;
-  int ask_wait;
-  int queued_question_interval;
-  qab_bot* bot;
-  qab_block* b;
-  char blocktype;
-  
-  if (!(f = fopen("qab_users", "r")))
-    return;
-  
-  while (!feof(f)) {
-    if (fgets(buf, 2048, f)) {
-      buf[2048] = '\0';
-      if (splitline(buf, args, 50, 0) != 3) {
-        fclose(f);
-        return;
-      }
-      
-      flags = (flag_t)strtoul(args[1], NULL, 10);
-      created = strtoul(args[2], NULL, 10);
-      
-      qabot_adduser(args[0], flags, created);
-    }
-  }
-  
-  fclose(f);
-  
-  if (!(f = fopen("qab_bots", "r")))
-    return;
-  
-  while (!feof(f)) {
-    if (fgets(buf, 2048, f)) {
-      buf[2048] = '\0';
-      if (splitline(buf, args, 50, 0) != 10) {
-        fclose(f);
-        return;
-      }
-      
-      qabot_addbot(args[0], args[1], args[2], args[3], args[4], args[5], (flag_t)strtol(args[6], NULL, 10), 
-        (int)strtol(args[7], NULL, 10), (int)strtol(args[8], NULL, 10), (int)strtol(args[9], NULL, 10), 0);
-    }
-  }
-  
-  fclose(f);
-  
-  if (!(f = fopen("qab_blocks", "r")))
-    return;
-  
-  while (!feof(f)) {
-    if (fgets(buf, 2048, f)) {
-      buf[2048] = '\0';
-      if (splitline(buf, args, 50, 0) != 5) {
-        fclose(f);
-        return;
-      }
-      
-      /* args[0] = botname
-         args[1] = type
-         args[2] = creator
-         args[3] = created
-         args[4] = blockstr */
-      if (!strcmp(args[0], "q")) {
-        /* account block */
-        if (strchr(args[4], '*') || args[4](target, '?'))
-          continue; /* wildcard account blocks are not supported */
-        
-        blocktype = QABBLOCK_ACCOUNT;
-      }
-      else if (!strcmp(args[0], "t")) {
-        /* text block */
-        blocktype = QABBLOCK_TEXT;
-      }
-      else if (!strcmp(args[0], "h")) {
-        /* hostmask block */
-        blocktype = QABBLOCK_HOST;
-      }
-      else
-        continue; /* unknown block, lets skip and hope everything works out */
-      
-      if (!(bot = qabot_findbot(args[0])))
-        continue; /* no such bot added */
-      
-      b = (qab_block*)malloc(sizeof(qab_block));
-      b->type = blocktype;
-      b->created = (long)strol(args[3]);
-      strncpy(b->creator, args[2], ACCOUNTLEN);
-      b->creator[ACCOUNTLEN] = '\0';
-      b->blockstr = strdup(args[4]);
-      b->prev = 0;
-      b->next = bot->blocks;
-      if (bot->blocks)
-        bot->blocks->prev = b;
-      bot->blocks = b;
-      bot->block_count++;
-    }
-  }
-  
-  fclose(f);
-}
-
-void qabot_savedb() {
-  FILE* f;
-  qab_user* u;
-  qab_bot* b;
-  qab_block* block;
-  
-  if (!(f = fopen("qab_users", "w")))
-    return;
-  
-  for (u = qabot_users; u; u = u->next)
-    fprintf(f, "%s %d %ld\n", u->authname, (int)u->flags, u->created);
-  
-  fclose(f);
-  
-  if (!(f = fopen("qab_bots", "w")))
-    return;
-  
-  for (b = qab_bots; b; b = b->next)
-    fprintf(f, "%s %s %s %s %s %s %d %d %d %d\n", b->nick, b->user, b->host, b->public_chan->name->content, 
-      b->question_chan->name->content, b->staff_chan->name->content, (int)b->flags, b->spam_interval, 
-      b->ask_wait, b->queued_question_interval);
-  
-  fclose(f);
-  
-  if (!(f = fopen("qab_blocks", "w")))
-    return;
-  
-  for (b = qab_bots; b; b = b->next)
-    for (block = b->blocks; block; block = block->next)
-      fprintf(f, "%s %c %s %ld %s\n", b->nick, block->type == QABBLOCK_ACCOUNT ? 'q' : block->type == QABBLOCK_HOST ? 'h' : 't', 
-        block->creator, block->created, block->blockstr);
-  
-  fclose(f);
-}
-
-void qabot_savetimer(void* arg) {
-  qabot_savedb();
-}
-
-void qabot_adduser(const char* authname, flag_t flags, time_t created) {
-  qab_user* u;
-
-  if ((u = qabot_getuser(authname)))
-    return;
-
-  u = (qab_user*)malloc(sizeof(qab_user));
-  strncpy(u->authname, authname, ACCOUNTLEN);
-  u->authname[ACCOUNTLEN] = '\0';
-  u->flags = flags;
-  u->created = created;
-
-  u->prev = 0;
-  u->next = qabot_users;
-  if (qabot_users)
-    qabot_users->prev = u;
-  qabot_users = u;
-}
-
-void qabot_deluser(const char* authname) {
-  qab_user* u = qabot_getuser(authname);
-
-  if (!u)
-    return;
-
-  qabot_squelchuser(u);
-}
-
-void qabot_squelchuser(qab_user* user) {
-  if (user->next)
-    user->next->prev = user->prev;
-  if (user->prev)
-    user->prev->next = user->next;
-  else
-    qabot_users = user->next;
-
-  free(user);
-}
-
-qab_user* qabot_getuser(const char* authname) {
-  qab_user* u;
-
-  for (u = qabot_users; u; u = u->next)
-    if (!ircd_strcmp(u->authname, authname))
-      return u;
-
-  return 0;
-}
-
-qab_bot* qabot_findbot(const char* nickname) {
-  qab_bot* bot;
-  
-  for (bot = qab_bots; bot; bot = bot->next)
-    if (!ircd_strcmp(bot->nick, nickname))
-      return bot;
-  
-  return 0;
-}
+#include <stdio.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "../nick/nick.h"\r
+#include "../localuser/localuserchannel.h"\r
+#include "../core/hooks.h"\r
+#include "../core/schedule.h"\r
+#include "../lib/array.h"\r
+#include "../lib/base64.h"\r
+#include "../lib/irc_string.h"\r
+#include "../lib/splitline.h"\r
+\r
+#include "qabot.h"\r
+\r
+qab_user* qabot_users = 0;\r
+\r
+void qabot_loaddb() {\r
+  FILE* f;\r
+  char buf[2049];\r
+  char* args[100];\r
+  time_t created;\r
+  flag_t flags;\r
+  int spam_interval;\r
+  int ask_wait;\r
+  int queued_question_interval;\r
+  qab_bot* b;\r
+  \r
+  if (!(f = fopen("qab_users", "r")))\r
+    return;\r
+  \r
+  while (!feof(f)) {\r
+    if (fgets(buf, 2048, f)) {\r
+      buf[2048] = '\0';\r
+      if (splitline(buf, args, 50, 0) != 3) {\r
+        fclose(f);\r
+        return;\r
+      }\r
+      \r
+      flags = (flag_t)strtoul(args[1], NULL, 10);\r
+      created = strtoul(args[2], NULL, 10);\r
+      \r
+      qabot_adduser(args[0], flags, created);\r
+    }\r
+  }\r
+  \r
+  fclose(f);\r
+  \r
+  if (!(f = fopen("qab_bots", "r")))\r
+    return;\r
+  \r
+  while (!feof(f)) {\r
+    if (fgets(buf, 2048, f)) {\r
+      buf[2048] = '\0';\r
+      if (splitline(buf, args, 50, 0) != 10) {\r
+        fclose(f);\r
+        return;\r
+      }\r
+      \r
+      qabot_addbot(args[0], args[1], args[2], args[3], args[4], args[5], (flag_t)strtol(args[6], NULL, 10), \r
+        (int)strtol(args[7], NULL, 10), (int)strtol(args[8], NULL, 10), (int)strtol(args[9], NULL, 10), 0);\r
+    }\r
+  }\r
+  \r
+  fclose(f);\r
+}\r
+\r
+void qabot_savedb() {\r
+  FILE* f;\r
+  qab_user* u;\r
+  qab_bot* b;\r
+  \r
+  if (!(f = fopen("qab_users", "w")))\r
+    return;\r
+  \r
+  for (u = qabot_users; u; u = u->next)\r
+    fprintf(f, "%s %d %ld\n", u->authname, (int)u->flags, u->created);\r
+  \r
+  fclose(f);\r
+  \r
+  if (!(f = fopen("qab_bots", "w")))\r
+    return;\r
+  \r
+  for (b = qab_bots; b; b = b->next)\r
+    fprintf(f, "%s %s %s %s %s %s %d %d %d %d\n", b->nick, b->user, b->host, b->public_chan->name->content, \r
+      b->question_chan->name->content, b->staff_chan->name->content, (int)b->flags, b->spam_interval, \r
+      b->ask_wait, b->queued_question_interval);\r
+  \r
+  fclose(f);\r
+}\r
+\r
+void qabot_savetimer(void* arg) {\r
+  qabot_savedb();\r
+}\r
+\r
+void qabot_adduser(const char* authname, flag_t flags, time_t created) {\r
+  qab_user* u;\r
+\r
+  if ((u = qabot_getuser(authname)))\r
+    return;\r
+\r
+  u = (qab_user*)malloc(sizeof(qab_user));\r
+  strncpy(u->authname, authname, ACCOUNTLEN);\r
+  u->authname[ACCOUNTLEN] = '\0';\r
+  u->flags = flags;\r
+  u->created = created;\r
+\r
+  u->prev = 0;\r
+  u->next = qabot_users;\r
+  if (qabot_users)\r
+    qabot_users->prev = u;\r
+  qabot_users = u;\r
+}\r
+\r
+void qabot_deluser(const char* authname) {\r
+  qab_user* u = qabot_getuser(authname);\r
+\r
+  if (!u)\r
+    return;\r
+\r
+  qabot_squelchuser(u);\r
+}\r
+\r
+void qabot_squelchuser(qab_user* user) {\r
+  if (user->next)\r
+    user->next->prev = user->prev;\r
+  if (user->prev)\r
+    user->prev->next = user->next;\r
+  else\r
+    qabot_users = user->next;\r
+\r
+  free(user);\r
+}\r
+\r
+qab_user* qabot_getuser(const char* authname) {\r
+  qab_user* u;\r
+\r
+  for (u = qabot_users; u; u = u->next)\r
+    if (!ircd_strcmp(u->authname, authname))\r
+      return u;\r
+\r
+  return 0;\r
+}\r
index 7962477a1e41e26513516a3f45c1f23b90fa37ec..7f9cb2bef8769614e312e52dfb4a87af14e905d4 100644 (file)
@@ -1,85 +1,85 @@
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#include "../nick/nick.h"
-#include "../localuser/localuserchannel.h"
-#include "../core/hooks.h"
-#include "../core/schedule.h"
-#include "../lib/array.h"
-#include "../lib/base64.h"
-#include "../lib/irc_string.h"
-#include "../lib/splitline.h"
-
-#include "qabot.h"
-
-int qabot_showhelp(nick* np, char* arg) {
-  if (!ircd_strcmp(arg, "showcommands")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: showcommands");
-    sendnoticetouser(qabot_nick, np, "Display commands the bot provides.");
-  }
-  else if (!ircd_strcmp(arg, "help")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: help <command>");
-    sendnoticetouser(qabot_nick, np, "View help for a particular command.");
-  }
-  else if (!ircd_strcmp(arg, "hello")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: hello");
-    sendnoticetouser(qabot_nick, np, "Create the initial user account on the bot.");
-  }
-  else if (!ircd_strcmp(arg, "save")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: save");
-    sendnoticetouser(qabot_nick, np, "Save the user and bot databases.");
-  }
-  else if (!ircd_strcmp(arg, "listbots")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: listbots");
-    sendnoticetouser(qabot_nick, np, "List currently added bots.");
-  }
-  else if (!ircd_strcmp(arg, "listusers")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: listusers");
-    sendnoticetouser(qabot_nick, np, "List currently added users.");
-  }
-  else if (!ircd_strcmp(arg, "showbot")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: showbot <nick>");
-    sendnoticetouser(qabot_nick, np, "Show information about a particular bot.");
-  }
-  else if (!ircd_strcmp(arg, "addbot")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: addbot <nick> <user> <host> <public chan> <question chan> <staff chan>");
-    sendnoticetouser(qabot_nick, np, "Add a new bot.");
-  }
-  else if (!ircd_strcmp(arg, "delbot")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: delbot <nick>");
-    sendnoticetouser(qabot_nick, np, "Delete a bot.");
-  }
-  else if (!ircd_strcmp(arg, "adduser")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: adduser <nick|#authname> <flags>");
-    sendnoticetouser(qabot_nick, np, "Add a user. Flags may consist of:");
-    sendnoticetouser(qabot_nick, np, "+a: administrator");
-    sendnoticetouser(qabot_nick, np, "+d: developer");
-    sendnoticetouser(qabot_nick, np, "+s: staff");
-  }
-  else if (!ircd_strcmp(arg, "deluser")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: deluser <nick|#authname>");
-    sendnoticetouser(qabot_nick, np, "Delete a user.");
-  }
-  else if (!ircd_strcmp(arg, "changelev")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: changelev <nick|#authname> <flags>");
-    sendnoticetouser(qabot_nick, np, "Change a user's level. Flags may consist of:");
-    sendnoticetouser(qabot_nick, np, "+a: administrator");
-    sendnoticetouser(qabot_nick, np, "+d: developer");
-    sendnoticetouser(qabot_nick, np, "+s: staff");
-  }
-  else if (!ircd_strcmp(arg, "whois")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: whois <nick|#authname>");
-    sendnoticetouser(qabot_nick, np, "Display information about a particular user.");
-  }
-  else if (!ircd_strcmp(arg, "status")) {
-    sendnoticetouser(qabot_nick, np, "Syntax: status");
-    sendnoticetouser(qabot_nick, np, "Display some status information.");
-  }
-  else {
-    sendnoticetouser(qabot_nick, np, "No such command.");
-    return CMD_ERROR;
-  }
-  
-  return CMD_OK;
-}
+#include <stdio.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "../nick/nick.h"\r
+#include "../localuser/localuserchannel.h"\r
+#include "../core/hooks.h"\r
+#include "../core/schedule.h"\r
+#include "../lib/array.h"\r
+#include "../lib/base64.h"\r
+#include "../lib/irc_string.h"\r
+#include "../lib/splitline.h"\r
+\r
+#include "qabot.h"\r
+\r
+int qabot_showhelp(nick* np, char* arg) {\r
+  if (!ircd_strcmp(arg, "showcommands")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: showcommands");\r
+    sendnoticetouser(qabot_nick, np, "Display commands the bot provides.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "help")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: help <command>");\r
+    sendnoticetouser(qabot_nick, np, "View help for a particular command.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "hello")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: hello");\r
+    sendnoticetouser(qabot_nick, np, "Create the initial user account on the bot.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "save")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: save");\r
+    sendnoticetouser(qabot_nick, np, "Save the user and bot databases.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "listbots")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: listbots");\r
+    sendnoticetouser(qabot_nick, np, "List currently added bots.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "listusers")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: listusers");\r
+    sendnoticetouser(qabot_nick, np, "List currently added users.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "showbot")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: showbot <nick>");\r
+    sendnoticetouser(qabot_nick, np, "Show information about a particular bot.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "addbot")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: addbot <nick> <user> <host> <public chan> <question chan> <staff chan>");\r
+    sendnoticetouser(qabot_nick, np, "Add a new bot.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "delbot")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: delbot <nick>");\r
+    sendnoticetouser(qabot_nick, np, "Delete a bot.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "adduser")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: adduser <nick|#authname> <flags>");\r
+    sendnoticetouser(qabot_nick, np, "Add a user. Flags may consist of:");\r
+    sendnoticetouser(qabot_nick, np, "+a: administrator");\r
+    sendnoticetouser(qabot_nick, np, "+d: developer");\r
+    sendnoticetouser(qabot_nick, np, "+s: staff");\r
+  }\r
+  else if (!ircd_strcmp(arg, "deluser")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: deluser <nick|#authname>");\r
+    sendnoticetouser(qabot_nick, np, "Delete a user.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "changelev")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: changelev <nick|#authname> <flags>");\r
+    sendnoticetouser(qabot_nick, np, "Change a user's level. Flags may consist of:");\r
+    sendnoticetouser(qabot_nick, np, "+a: administrator");\r
+    sendnoticetouser(qabot_nick, np, "+d: developer");\r
+    sendnoticetouser(qabot_nick, np, "+s: staff");\r
+  }\r
+  else if (!ircd_strcmp(arg, "whois")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: whois <nick|#authname>");\r
+    sendnoticetouser(qabot_nick, np, "Display information about a particular user.");\r
+  }\r
+  else if (!ircd_strcmp(arg, "status")) {\r
+    sendnoticetouser(qabot_nick, np, "Syntax: status");\r
+    sendnoticetouser(qabot_nick, np, "Display some status information.");\r
+  }\r
+  else {\r
+    sendnoticetouser(qabot_nick, np, "No such command.");\r
+    return CMD_ERROR;\r
+  }\r
+  \r
+  return CMD_OK;\r
+}\r