]> jfr.im git - irc/quakenet/newserv.git/blobdiff - fakeusers/fakeusers.c
LUA: add function for channel chanop notice
[irc/quakenet/newserv.git] / fakeusers / fakeusers.c
index 41eb23bbb439e21a03793f89c79ae2875dc818d1..0e92560aaebddc7a5e53b72dcf66f6a3383f4a12 100644 (file)
 
 MODULE_VERSION("");
 
-/* #define SIT_CHANNEL "#qnet.fakeusers" */
 #define KILL_WAIT 10
 #define KILL_TIME 60
 
 typedef struct fakeuser {
-  nick *user;
-  time_t lastkill;
-  struct fakeuser *next;
-} fakeuser;
-
-typedef struct user_details {
   char nick[NICKLEN + 1];
   char ident[USERLEN + 1];
   char host[HOSTLEN + 1];
   char realname[REALLEN + 1];
+  nick *user;
   time_t lastkill;
-  struct user_details *next;
-  void *schedule;
-} user_details;
-
-fakeuser *fakeuserlist = NULL;
-user_details *killeduserlist = NULL;
-int fakeusercount = 0;
-int killedusercount = 0;
-
-void fakeuser_cleanup();
-int fakeuser_loaddb();
-void fakeusers_load(const DBAPIResult *res, void *arg);
-void fakeuser_handler(nick *user, int command, void **params);
-int fakeadd(void *sender, int cargc, char **cargv);
-int fakelist(void *sender, int cargc, char **cargv);
-int fakekill(void *sender, int cargc, char **cargv);
-void reconnectfake(void *details);
-
-int db_loaded = 0;
+  struct fakeuser *next;
+} fakeuser;
+
+static fakeuser *fakeuserlist;
 static DBAPIConn *nofudb;
 
-void _init() {
-  if (!fakeuser_loaddb())
-  {
-    Error("fakeuser", ERR_FATAL, "Cannot load database");
-    return;
-  }
-  registercontrolhelpcmd("fakeuser", NO_OPER, 4, &fakeadd, "Usage: FAKEUSER nick <ident> <host> <realname>\nCreates a fake user.");
-  registercontrolhelpcmd("fakelist", NO_OPER, 0, &fakelist, "Usage: FAKELIST\nLists all fake users.");
-  registercontrolhelpcmd("fakekill", NO_OPER, 2, &fakekill, "Usage: FAKEKILL nick <reason>\nRemoves a fake user");
-}
+static void reconnectfakeuser(void *arg);
 
-void _fini() {
-  fakeuser_cleanup();
-  deregistercontrolcmd("fakeuser", &fakeadd);
-  deregistercontrolcmd("fakelist", &fakelist);
-  deregistercontrolcmd("fakekill", &fakekill);
+static fakeuser *findfakeuserbynick(char *nick) {
+  fakeuser *fake;
+
+  for (fake = fakeuserlist; fake; fake = fake->next)
+    if (!ircd_strcmp(nick, fake->nick))
+      return fake;
+
+  return NULL;
 }
 
-void fakeuser_cleanup()
-{
-  fakeuser *fake;
-  user_details *killed;
-  void *next;
-  for (fake = fakeuserlist; fake; fake = next)
-  {
+static void fake_free(fakeuser *fake) {
+  fakeuser **pnext;
+
+  if (fake->user)
     deregisterlocaluser(fake->user, "Signing off");
-    next = fake->next;
-    free(fake);
-  }
-  for (killed = killeduserlist; killed; killed = next)
-  {
-    deleteschedule(killed->schedule, &reconnectfake, killed);
-    next = killed->next;
-    free(killed);
+
+  deleteschedule(NULL, &reconnectfakeuser, fake);
+  
+  for (pnext = &fakeuserlist; *pnext; pnext = &((*pnext)->next)) {
+    if (*pnext == fake) {
+      *pnext = fake->next;
+      break;
+    }
   }
-  fakeusercount = 0;
-  killedusercount = 0;
-  fakeuserlist = NULL;
-  killeduserlist = NULL;
+
+  free(fake);
 }
 
-int fakeuser_loaddb()
-{
-  if (!nofudb) {
-    nofudb = dbapi2open(DBAPI2_DEFAULT, "fakeusers");
-    if(!nofudb) {
-      Error("fakeuser", ERR_STOP, "Could not connect to database.");
-      return 0;
+static void fake_remove(fakeuser *fake) {
+  nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", fake->nick);
+  
+  fake_free(fake);
+}
+
+static void fakeuser_handler(nick *user, int command, void **params) {
+  if (command == LU_KILLED) {
+    fakeuser *fake;
+    time_t timenow = time(NULL);
+
+    fake = findfakeuserbynick(user->nick);
+
+    if (!fake) {
+      controlwall(NO_OPER, NL_FAKEUSERS, "Error: A fakeuser was killed, but wasn't found in the list");
+      Error("fakeuser", ERR_ERROR, "A fakeuser was killed, but wasn't found in the list");
+      return;
     }
-  }
 
-  db_loaded = 1;
+    fake->user = NULL;
 
-  nofudb->createtable(nofudb, NULL, NULL, 
-    "CREATE TABLE ? ("
-    "nick      VARCHAR(?)  NOT NULL,"
-    "ident     VARCHAR(?)  NOT NULL,"
-    "host      VARCHAR(?)  NOT NULL,"
-    "realname  VARCHAR(?)  NOT NULL,"
-    "PRIMARY KEY (nick))", "Tdddd", "fakeusers", NICKLEN, USERLEN, HOSTLEN, REALLEN);
+    if (timenow - fake->lastkill < KILL_TIME) {
+      controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) KILL'ed twice under in %d seconds. Removing.",
+                  fake->nick, fake->ident, fake->host, fake->realname, KILL_TIME);
+      fake_remove(fake);
+      return;
+    }
 
-  nofudb->query(nofudb, fakeusers_load, NULL,
-    "SELECT nick, ident, host, realname FROM ?", "T", "fakeusers");
+    fake->lastkill = timenow;
 
-  return 1;
+    scheduleoneshot(time(NULL) + KILL_WAIT, &reconnectfakeuser, fake);
+  }
 }
 
-void fakeusers_load(const DBAPIResult *res, void *arg) {
-  user_details details;
-
-  if(!res)
+static void reconnectfakeuser(void *arg) {
+  fakeuser *fake = arg;
+  nick *user;
+  
+  if (fake->user)
     return;
 
-  if(!res->success) {
-    Error("fakeuser", ERR_ERROR, "Error loading fakeuser list.");
-    res->clear(res);
+  if ((user = getnickbynick(fake->nick)) && (IsOper(user) || IsService(user) || IsXOper(user))) {
+    fake_remove(fake);
     return;
   }
 
-  details.lastkill = 0;
-  details.schedule = NULL;
-  while(res->next(res)) {
-    strlcpy(details.nick, res->get(res, 0), NICKLEN + 1);
-    strlcpy(details.ident, res->get(res, 1), USERLEN + 1);
-    strlcpy(details.host, res->get(res, 2), HOSTLEN + 1);
-    strlcpy(details.realname, res->get(res, 3), REALLEN + 1);
-    reconnectfake(&details);
-  }
-
-  res->clear(res);
+  fake->user = registerlocaluser(fake->nick, fake->ident, fake->host, fake->realname,
+                                 NULL, UMODE_INV | UMODE_DEAF, &fakeuser_handler);
 }
 
-user_details *getdetails(nick *user)
-{
-  user_details *details;
-  details = malloc(sizeof(user_details));
-  if (!details)
-    return NULL;
-  strlcpy(details->nick, user->nick, NICKLEN + 1);
-  strlcpy(details->ident, user->ident, USERLEN + 1);
-  strlcpy(details->host, user->host->name->content, HOSTLEN + 1);
-  strlcpy(details->realname, user->realname->name->content, REALLEN + 1);
-  details->schedule = NULL;
-  details->lastkill = 0;
-  return details;
-}
+static fakeuser *fake_add(const char *nick, const char *ident, const char *host, const char *realname) {
+  fakeuser *fake;
 
-#define ERR_EXISTS 1
-#define ERR_MEM 2
-#define ERR_WONTKILL 3
-int err_code;
+  fake = malloc(sizeof(fakeuser));
 
-nick *register_fakeuser(user_details *details)
-{
-  nick *user;
-  if ((user = getnickbynick(details->nick)) && (IsOper(user) || IsService(user) || IsXOper(user))) {
-    err_code = ERR_WONTKILL;
+  if (!fake)
     return NULL;
-  }
 
-  err_code = ERR_MEM;
-  return registerlocaluser(details->nick, details->ident, details->host, details->realname,
-    NULL, UMODE_INV | UMODE_DEAF, &fakeuser_handler);
+  strlcpy(fake->nick, nick, NICKLEN + 1);
+  strlcpy(fake->ident, ident, USERLEN + 1);
+  strlcpy(fake->host, host, HOSTLEN + 1);
+  strlcpy(fake->realname, realname, REALLEN + 1);
+
+  fake->user = NULL;
+  fake->lastkill = 0;
+
+  fake->next = fakeuserlist;
+  fakeuserlist = fake;
+
+  scheduleoneshot(time(NULL) + 1, reconnectfakeuser, fake);
+  
+  return fake;
 }
 
-fakeuser *ll_add(user_details *details) 
-// Adds to the (sorted) linked list
-{
-  fakeuser *fake, *newfake;
-  int cmp;
-
-  if (fakeuserlist)
-  {
-    cmp = ircd_strcmp(details->nick, fakeuserlist->user->nick);
-    if (!cmp)
-    {
-      err_code = ERR_EXISTS;
-      return NULL;
-    }
-  }
-  else
-    cmp = -1;
-  if (cmp < 0)
-  {
-    newfake = malloc(sizeof(fakeuser));
-    if (!newfake)
-    {
-      err_code = ERR_MEM;
-      return NULL;
-    }
-    newfake->user = register_fakeuser(details);
-    if (!newfake->user)
-    {
-      free(newfake);
-      return NULL;   //errcode already set by register_fakeuser
-    }
-    newfake->lastkill = details->lastkill;
-    newfake->next = fakeuserlist;
-    fakeuserlist = newfake;
-    fakeusercount++;
-    return newfake;
-  }
-  for (fake = fakeuserlist; fake->next; fake = fake->next)
-  {
-    cmp = ircd_strcmp(details->nick, fake->next->user->nick);
-    if (!cmp)
-    {
-      err_code = ERR_EXISTS;
-      return NULL;
-    }
-    if (cmp < 0)
-    {
-      newfake = malloc(sizeof(fakeuser));
-      if (!newfake)
-      {
-        err_code = ERR_MEM;
-        return NULL;
-      }
-      newfake->user = register_fakeuser(details);
-      if (!newfake->user)
-      {
-        free(newfake);
-        return NULL;   //errcode already set by register_fakeuser
-      }
-      newfake->lastkill = details->lastkill;
-      newfake->next = fake->next;
-      fake->next = newfake;
-      fakeusercount++;
-      return newfake;
-    }
-  }
-  newfake = malloc(sizeof(fakeuser));
-  if (!newfake)
-  {
-    err_code = ERR_MEM;
+static fakeuser *fake_create(const char *nick, const char *ident, const char *host, const char *realname) {
+  fakeuser *fake;
+  
+  fake = fake_add(nick, ident, host, realname);
+
+  if (!fake)
     return NULL;
-  }
-  newfake->user = register_fakeuser(details);
-  if (!newfake->user)
-  {
-    free(newfake);
-    return NULL;   //errcode already set by register_fakeuser
-  }
-  newfake->lastkill = details->lastkill;
-  newfake->next = NULL;
-  fake->next = newfake;
-  fakeusercount++;
-  return newfake;
+  
+  nofudb->squery(nofudb, "INSERT INTO ? (nick, ident, host, realname) VALUES (?,?,?,?)", "Tssss", "fakeusers",
+                 fake->nick, fake->ident, fake->host, fake->realname);
+
+  return fake;
 }
 
-void kll_add(user_details *details)
-//Adds to the (sorted) linked list of killed users
-{
-  int cmp;
-  user_details *killed;
+static void fakeusers_load(const DBAPIResult *res, void *arg) {
+  if (!res)
+    return;
 
-  if (killeduserlist)
-    cmp = ircd_strcmp(details->nick, killeduserlist->nick);
-  else
-    cmp = -1;
-  if (cmp < 0)  //Add to the start of the list
-  {
-    details->next = killeduserlist;
-    killeduserlist = details;
-    killedusercount++;
+  if (!res->success) {
+    Error("fakeuser", ERR_ERROR, "Error loading fakeuser list.");
+    res->clear(res);
     return;
   }
-  for (killed = killeduserlist; killed->next; killed = killed->next)
-  {
-    cmp = ircd_strcmp(details->nick, killed->next->nick);
-    if (cmp < 0)
-    {
-      details->next = killed->next;
-      killed->next = details;
-      killedusercount++;
-      return;
-    }
-  }
-  details->next = NULL;
-  killed->next = details;
-  killedusercount++;
-  return;
-}
 
-fakeuser *ll_remove(char *nickname)
-//Removes from the linked list
-{
-  fakeuser *fake, *rmfake;
-  int cmp;
+  while (res->next(res))
+    fake_add(res->get(res, 0), res->get(res, 1), res->get(res, 2), res->get(res, 3));
 
-  if (!fakeuserlist)
-    return NULL;
-  cmp = ircd_strcmp(nickname, fakeuserlist->user->nick);
-  if (cmp < 0)
-    return NULL;
-  if (!cmp)
-  {
-    rmfake = fakeuserlist;
-    fakeuserlist = fakeuserlist->next;
-    fakeusercount--;
-    rmfake->next = NULL;
-    return rmfake;
-  }
-  for (fake = fakeuserlist; fake->next; fake = fake->next)
-  {
-    rmfake = fake->next;
-    cmp = ircd_strcmp(nickname, rmfake->user->nick);
-    if (cmp < 0)
-      return NULL;
-    if (!cmp)
-    {
-      fake->next = rmfake->next;
-      fakeusercount--;
-      rmfake->next = NULL;
-      return rmfake;
-    }
-  }
-  return NULL;
+  res->clear(res);
 }
 
-user_details *kll_remove(char *nickname) //Removes from the killed user linked list
-{
-  user_details *details, *rmdetails;
-  int cmp;
+static int fakeuser_loaddb() {
+  if (!nofudb) {
+    nofudb = dbapi2open(DBAPI2_DEFAULT, "fakeusers");
 
-  if (!killeduserlist)
-    return NULL;
-  cmp = ircd_strcmp(nickname, killeduserlist->nick);
-  if (cmp < 0)
-    return NULL;
-  if (!cmp)
-  {
-    rmdetails = killeduserlist;
-    killeduserlist = killeduserlist->next;
-    rmdetails->next = NULL;
-    killedusercount--;
-    return rmdetails;
-  }
-  for (details = killeduserlist; details->next; details = details->next)
-  {
-    rmdetails = details->next;
-    cmp = ircd_strcmp(nickname, rmdetails->nick);
-    if (cmp < 0)
-      return NULL;
-    if (!cmp)
-    {
-      details->next = rmdetails->next;
-      rmdetails->next = NULL;
-      killedusercount--;
-      return rmdetails;
+    if (!nofudb) {
+      Error("fakeuser", ERR_STOP, "Could not connect to database.");
+      return 0;
     }
   }
-  return NULL;
-}
 
-void fakeuser_handler(nick *user, int command, void **params)
-{
-  if (command == LU_KILLED)
-  {
-    user_details *details;
-    fakeuser *item;
-    time_t timenow = time(NULL);
-
-    details = getdetails(user);
-    item = ll_remove(details->nick);
-    if (!item)
-    {
-      controlwall(NO_OPER, NL_FAKEUSERS, "Error: A fakeuser was killed, but wasn't found in the list");
-      Error("fakeuser", ERR_ERROR, "A fakeuser was killed, but wasn't found in the list");
-      return;
-    }
+  nofudb->createtable(nofudb, NULL, NULL,
+                      "CREATE TABLE ? ("
+                      "nick      VARCHAR(?)  NOT NULL,"
+                      "ident     VARCHAR(?)  NOT NULL,"
+                      "host      VARCHAR(?)  NOT NULL,"
+                      "realname  VARCHAR(?)  NOT NULL,"
+                      "PRIMARY KEY (nick))", "Tdddd", "fakeusers", NICKLEN, USERLEN, HOSTLEN, REALLEN);
 
-    details->lastkill = item->lastkill;
-    free(item);
+  nofudb->query(nofudb, fakeusers_load, NULL,
+                "SELECT nick, ident, host, realname FROM ?", "T", "fakeusers");
 
-    if (timenow - details->lastkill < KILL_TIME) {
-      controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) KILL'ed twice under in %d seconds. Removing.", details->nick, details->ident, details->host, details->realname, KILL_TIME);
-      nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", details->nick);
-      return;
-    }
-    details->lastkill = timenow;
-
-    /*
-    controlwalls(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) was KILL'ed", details->nick,
-                details->ident, details->host, details->realname);
-    */
-    details->schedule = scheduleoneshot(time(NULL) + KILL_WAIT, &reconnectfake, details);
-    if (!details->schedule)
-    {
-      Error("fakeuser", ERR_ERROR, "Couldn't reschedule fakeuser for reconnect");
-      free(details);
-      return;
-    }
-    kll_add(details);
-  }
+  return 1;
 }
 
-//Usage: FAKEUSER nick <ident> <host> <realname>
-int fakeadd(void *sender, int cargc, char **cargv)
-{
-  user_details details, *killed;
-  nick *newnick;
-  fakeuser *newfake;
+static int fakeadd(void *source, int cargc, char **cargv) {
+  nick *sender = source;
+  fakeuser *fake;
+  char *nick, *ident, *realname;
+  char host[HOSTLEN + 1];
 
   if (cargc == 0)
     return CMD_USAGE;
-  strlcpy(details.nick, cargv[0], NICKLEN + 1);
-  if (cargc < 4)
-    strlcpy(details.realname, cargv[0], REALLEN + 1);
-  else
-    strlcpy(details.realname, cargv[3], REALLEN + 1);
-  if (cargc < 3)
-  {
-    strlcpy(details.host, cargv[0], NICKLEN + 1);
-    strlcat(details.host, ".fakeusers.quakenet.org", HOSTLEN + 1);
+
+  fake = findfakeuserbynick(cargv[0]);
+
+  if (fake) {
+    controlreply(sender, "Fake User with nick %s already found", cargv[0]);
+    return CMD_ERROR;
   }
+
+  nick = cargv[0];
+
+  if (cargc < 4)
+    realname = cargv[0];
   else
-    strlcpy(details.host, cargv[2], HOSTLEN + 1);
+    realname = cargv[3];
+
+  if (cargc < 3) {
+    strlcpy(host, cargv[0], NICKLEN + 1);
+    strlcat(host, ".fakeusers.quakenet.org", HOSTLEN + 1);
+  } else
+    strlcpy(host, cargv[2], HOSTLEN + 1);
+
   if (cargc < 2)
-    strlcpy(details.ident, cargv[0], USERLEN + 1);
+    ident = cargv[0];
   else
-    strlcpy(details.ident, cargv[1], USERLEN + 1);
-
-  details.lastkill = 0;
-
-  newfake = ll_add(&details);
-  if (!newfake)
-  {
-    if (err_code == ERR_EXISTS)
-      controlreply(sender, "Error: fakeuser already exists");
-    else if (err_code == ERR_MEM)
-    {
-      controlreply(sender, "Error: memory error!!");
-      Error("fakeuser", ERR_STOP, "malloc error");
-    }
-    else if (err_code == ERR_WONTKILL)
-      controlreply(sender, "Nick already exists and I won't kill it");
-    else
-    {
-      controlreply(sender, "Unknown error when adding fakeuser");
-      Error("fakeuser", ERR_ERROR, "Unknown error when adding fakeuser");
-    }
+    ident = cargv[1];
+
+  fake = fake_create(nick, ident, host, realname);
+
+  if (!fake)
     return CMD_ERROR;
-  }
-  newnick = newfake->user;
-  if ((killed = kll_remove(newnick->nick)))  //Is this nickname scheduled to reconnect?
-  {
-    deleteschedule(killed->schedule, &reconnectfake, killed);
-    free(killed);
-    nofudb->squery(nofudb, "UPDATE ? SET ident=?, host=?, realname=? WHERE nick = ?", "Tssss", "fakeusers", newnick->ident, newnick->host->name->content, newnick->realname->name->content, newnick->nick);
-  }
-  else
-    nofudb->squery(nofudb, "INSERT INTO ? (nick, ident, host, realname) VALUES (?,?,?,?)", "Tssss", "fakeusers", newnick->nick, newnick->ident, newnick->host->name->content, newnick->realname->name->content);
-  controlreply(sender, "Added fake user %s", newnick->nick);
-  controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) added by %s/%s", newnick->nick, newnick->ident,
-              newnick->host->name->content, newnick->realname->name->content, ((nick*)sender)->nick, ((nick*)sender)->authname);
-#ifdef SIT_CHANNEL
-  {
-    channel *sitchannel;
-    if (!(sitchannel = findchannel(SIT_CHANNEL)))
-      sitchannel = createchannel(SIT_CHANNEL);
-    localjoinchannel(newnick, sitchannel);
-  }
-#endif
+
+  controlreply(sender, "Added fake user %s", fake->nick);
+  controlwall(NO_OPER, NL_FAKEUSERS, "%s added fake user: %s!%s@%s (%s)", controlid(sender),
+              fake->nick, fake->ident, fake->host, fake->realname);
+
+  scheduleoneshot(time(NULL) + 1, &reconnectfakeuser, fake);
+
   return CMD_OK;
 }
 
-//Usage: FAKELIST
-int fakelist(void *sender, int cargc, char **cargv)
-{
+static int fakelist(void *sender, int cargc, char **cargv) {
   fakeuser *fake;
-  if (fakeusercount == 1)
-    controlreply(sender, "1 fakeuser is currently connected");
-  else
-    controlreply(sender, "%d fakeusers are currently connected", fakeusercount);
-  for(fake = fakeuserlist; fake; fake = fake->next)
-    controlreply(sender, "%s!%s@%s (%s)", fake->user->nick, fake->user->ident,
-                 fake->user->host->name->content, fake->user->realname->name->content);
-  if (killeduserlist)
-  {
-    user_details *k_fake;
-    if (fakeusercount == 1)
-      controlreply(sender, "1 fakeuser is currently waiting to reconnect");
+  int fakeusercount = 0;
+
+  for (fake = fakeuserlist; fake; fake = fake->next) {
+    if (!fake->user)
+      controlreply(sender, "%s!%s@%s (%s) - RECONNECTING", fake->nick, fake->ident,
+                   fake->host, fake->realname);
     else
-      controlreply(sender, "%d fakeusers are currently waiting to reconnect", killedusercount);
-      for(k_fake = killeduserlist; k_fake; k_fake = k_fake->next)
-        controlreply(sender, "%s!%s@%s (%s)", k_fake->nick, k_fake->ident, k_fake->host, k_fake->realname);
+      controlreply(sender, "%s!%s@%s (%s)", fake->nick, fake->ident,
+                   fake->host, fake->realname);
+
+    fakeusercount++;
   }
+
+  controlreply(sender, "%d fakeusers are currently connected", fakeusercount);
+
   return CMD_OK;
 }
 
-//Usage: FAKEKILL nick <reason>
-int fakekill(void *sender, int cargc, char **cargv)
-{
+static int fakekill(void *sender, int cargc, char **cargv) {
   fakeuser *fake;
-  user_details *k_fake;
+
   if (cargc == 0)
     return CMD_USAGE;
-  if ((fake = ll_remove(cargv[0])))
-  {
-    nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", fake->user->nick);
-    controlreply(sender, "Killed fake user %s", fake->user->nick);
-    controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) removed by %s/%s", fake->user->nick, fake->user->ident,
-                fake->user->host->name->content, fake->user->realname->name->content, ((nick*)sender)->nick, ((nick*)sender)->authname);
-    if (cargc > 1)
-      deregisterlocaluser(fake->user, cargv[1]);
-    else
-      deregisterlocaluser(fake->user, "Signing off");
-    free(fake);
-    return CMD_OK;
-  }
-  if ((k_fake = kll_remove(cargv[0])))  //Fakeuser might be waiting to rejoin
-  {
-    nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", k_fake->nick);
-    controlreply(sender, "Killed fake user %s", k_fake->nick);
-    controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) removed by %s/%s", k_fake->nick,
-                k_fake->ident, k_fake->host, k_fake->realname, ((nick*)sender)->nick, ((nick*)sender)->authname);
-    free(k_fake);
-    return CMD_OK;
+
+  fake = findfakeuserbynick(cargv[0]);
+
+  if (!fake) {
+    controlreply(sender, "No Fake User with nick %s found", cargv[0]);
+    return CMD_ERROR;
   }
-  controlreply(sender, "No fakeuser with that nick exists");
-  return CMD_ERROR;
+
+  controlreply(sender, "Killed fake user %s", fake->nick);
+  controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) removed by %s/%s", fake->nick, fake->ident,
+              fake->host, fake->realname, ((nick *)sender)->nick, ((nick *)sender)->authname);
+
+  fake_remove(fake);
+
+  return CMD_OK;
 }
 
-void reconnectfake(void *details)
-//Called after the timeout period has expired since a fakeuser was killed, or on load
-{
-  fakeuser *fake;
-  user_details *u_details = details;
-  if (u_details->schedule)
-    kll_remove(u_details->nick); //Fakeuser was /kill'd
-  fake = ll_add(u_details);
-  if (u_details->schedule)
-    free(u_details);
-  if (!fake)
+void _init() {
+  if (!fakeuser_loaddb()) {
+    Error("fakeuser", ERR_FATAL, "Cannot load database");
     return;
-#ifdef SIT_CHANNEL
-  {
-    channel *sitchannel;
-    if (!(sitchannel = findchannel(SIT_CHANNEL)))
-      sitchannel = createchannel(SIT_CHANNEL);
-    localjoinchannel(fake->user, sitchannel);
   }
-#endif
+
+  registercontrolhelpcmd("fakeuser", NO_OPER, 4, &fakeadd, "Usage: FAKEUSER nick <ident> <host> <realname>\nCreates a fake user.");
+  registercontrolhelpcmd("fakelist", NO_OPER, 0, &fakelist, "Usage: FAKELIST\nLists all fake users.");
+  registercontrolhelpcmd("fakekill", NO_OPER, 2, &fakekill, "Usage: FAKEKILL nick\nRemoves a fake user");
+}
+
+void _fini() {
+  fakeuser *fake, *next;
+
+  for (fake = fakeuserlist; fake; fake = next) {
+    next = fake->next;
+    fake_free(fake);
+  }
+
+  deregistercontrolcmd("fakeuser", &fakeadd);
+  deregistercontrolcmd("fakelist", &fakelist);
+  deregistercontrolcmd("fakekill", &fakekill);
 }