]> jfr.im git - irc/quakenet/newserv.git/blobdiff - fakeusers/fakeusers.c
FAKEUSER: more tidyup
[irc/quakenet/newserv.git] / fakeusers / fakeusers.c
index 1e9f9f3b6c1700250b4c7f8875a27882308ef2bb..6fcedc234ff23fd2dd1eb060f7d98ae0fe87bef5 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;
+  struct fakeuser *next;
+} fakeuser;
 
 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);
 
-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 fakeuser_cleanup();
+static int fakeuser_loaddb();
+static void fakeusers_load(const DBAPIResult *res, void *arg);
+static void fakeuser_handler(nick *user, int command, void **params);
+static int fakeadd(void *sender, int cargc, char **cargv);
+static int fakelist(void *sender, int cargc, char **cargv);
+static int fakekill(void *sender, int cargc, char **cargv);
+static void schedulefakeuser(void *arg);
+static fakeuser *findfakeuserbynick(char *nick);
+static void fake_remove(char *nickname);
+static fakeuser *fake_add(fakeuser *details);
 
-void _fini() {
-  fakeuser_cleanup();
-  deregistercontrolcmd("fakeuser", &fakeadd);
-  deregistercontrolcmd("fakelist", &fakelist);
-  deregistercontrolcmd("fakekill", &fakekill);
-}
+static DBAPIConn *nofudb;
 
-void fakeuser_cleanup()
-{
+void fakeuser_cleanup() {
   fakeuser *fake;
-  user_details *killed;
   void *next;
-  for (fake = fakeuserlist; fake; fake = next)
-  {
+
+  for (fake = fakeuserlist; fake; fake = next) {
     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);
-  }
-  fakeusercount = 0;
-  killedusercount = 0;
+
   fakeuserlist = NULL;
-  killeduserlist = NULL;
 }
 
-int fakeuser_loaddb()
-{
+int fakeuser_loaddb() {
   if (!nofudb) {
     nofudb = dbapi2open(DBAPI2_DEFAULT, "fakeusers");
-    if(!nofudb) {
+
+    if (!nofudb) {
       Error("fakeuser", ERR_STOP, "Could not connect to database.");
       return 0;
     }
   }
 
-  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);
+  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);
 
   nofudb->query(nofudb, fakeusers_load, NULL,
-    "SELECT nick, ident, host, realname FROM ?", "T", "fakeusers");
+                "SELECT nick, ident, host, realname FROM ?", "T", "fakeusers");
 
   return 1;
 }
 
 void fakeusers_load(const DBAPIResult *res, void *arg) {
-  user_details details;
+  fakeuser fakeuser;
 
-  if(!res)
+  if (!res)
     return;
 
-  if(!res->success) {
+  if (!res->success) {
     Error("fakeuser", ERR_ERROR, "Error loading fakeuser list.");
     res->clear(res);
     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);
+  while (res->next(res)) {
+    strlcpy(fakeuser.nick, res->get(res, 0), NICKLEN + 1);
+    strlcpy(fakeuser.ident, res->get(res, 1), USERLEN + 1);
+    strlcpy(fakeuser.host, res->get(res, 2), HOSTLEN + 1);
+    strlcpy(fakeuser.realname, res->get(res, 3), REALLEN + 1);
+    fake_add(&fakeuser);
   }
 
+  scheduleoneshot(time(NULL) + 1, schedulefakeuser, NULL);
   res->clear(res);
 }
 
-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;
-}
-
-#define ERR_EXISTS 1
-#define ERR_MEM 2
-#define ERR_WONTKILL 3
-int err_code;
-
-nick *register_fakeuser(user_details *details)
-{
+nick *register_fakeuseronnet(fakeuser *details) {
   nick *user;
+
   if ((user = getnickbynick(details->nick)) && (IsOper(user) || IsService(user) || IsXOper(user))) {
-    err_code = ERR_WONTKILL;
     return NULL;
   }
 
-  err_code = ERR_MEM;
   return registerlocaluser(details->nick, details->ident, details->host, details->realname,
-    NULL, UMODE_INV | UMODE_DEAF, &fakeuser_handler);
+                           NULL, UMODE_INV | UMODE_DEAF, &fakeuser_handler);
 }
 
-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;
-    }
-  }
+fakeuser *fake_add(fakeuser *details) {
+  fakeuser *newfake;
+
   newfake = malloc(sizeof(fakeuser));
-  if (!newfake)
-  {
-    err_code = ERR_MEM;
+
+  if (!newfake) {
     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;
-}
 
-void kll_add(user_details *details)
-//Adds to the (sorted) linked list of killed users
-{
-  int cmp;
-  user_details *killed;
+  memcpy(newfake, details, sizeof(fakeuser));
 
-  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++;
-    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;
+  newfake->user = NULL;
+  newfake->lastkill = 0;
+
+  newfake->next = fakeuserlist;
+  fakeuserlist = newfake;
+  return newfake;
 }
 
-fakeuser *ll_remove(char *nickname)
-//Removes from the linked list
-{
-  fakeuser *fake, *rmfake;
-  int cmp;
+void fake_remove(char *nickname) {
+  fakeuser *fake, *prev;
 
-  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;
-}
+  for (fake = fakeuserlist; fake; fake = fake->next) {
+    if (!ircd_strcmp(nickname, fake->nick)) {
+      if (fake == fakeuserlist)
+        fakeuserlist = fake->next;
+      else
+        prev->next = fake->next;
 
-user_details *kll_remove(char *nickname) //Removes from the killed user linked list
-{
-  user_details *details, *rmdetails;
-  int cmp;
+      if(fake->user)
+        deregisterlocaluser(fake->user, "Signing off");
 
-  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;
+      free(fake);
+      return;
     }
+
+    prev = fake;
   }
-  return NULL;
 }
 
-void fakeuser_handler(nick *user, int command, void **params)
-{
-  if (command == LU_KILLED)
-  {
-    user_details *details;
+void fakeuser_handler(nick *user, int command, void **params) {
+  if (command == LU_KILLED) {
     fakeuser *item;
     time_t timenow = time(NULL);
 
-    details = getdetails(user);
-    item = ll_remove(details->nick);
-    if (!item)
-    {
+    item = findfakeuserbynick(user->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;
     }
 
-    details->lastkill = item->lastkill;
-    free(item);
+    item->user = NULL;
 
-    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);
+    if (timenow - item->lastkill < KILL_TIME) {
+      controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) KILL'ed twice under in %d seconds. Removing.", item->nick, item->ident, item->host, item->realname, KILL_TIME);
+      nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", item->nick);
+      fake_remove(item->nick);
       return;
     }
-    details->lastkill = timenow;
 
-    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);
+    item->lastkill = timenow;
+
+    scheduleoneshot(time(NULL) + KILL_WAIT, schedulefakeuser, item);
   }
 }
 
-//Usage: FAKEUSER nick <ident> <host> <realname>
-int fakeadd(void *sender, int cargc, char **cargv)
-{
-  user_details details, *killed;
-  nick *newnick;
-  fakeuser *newfake;
+int fakeadd(void *sender, int cargc, char **cargv) {
+  fakeuser newfake;
+  fakeuser *fake;
 
   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;
   }
+
+  strlcpy(newfake.nick, cargv[0], NICKLEN + 1);
+
+  if (cargc < 4)
+    strlcpy(newfake.realname, cargv[0], REALLEN + 1);
   else
-    strlcpy(details.host, cargv[2], HOSTLEN + 1);
+    strlcpy(newfake.realname, cargv[3], REALLEN + 1);
+
+  if (cargc < 3) {
+    strlcpy(newfake.host, cargv[0], NICKLEN + 1);
+    strlcat(newfake.host, ".fakeusers.quakenet.org", HOSTLEN + 1);
+  } else
+    strlcpy(newfake.host, cargv[2], HOSTLEN + 1);
+
   if (cargc < 2)
-    strlcpy(details.ident, cargv[0], USERLEN + 1);
+    strlcpy(newfake.ident, cargv[0], USERLEN + 1);
   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");
-    }
+    strlcpy(newfake.ident, cargv[1], USERLEN + 1);
+
+  fake = fake_add(&newfake);
+
+  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
+
+  nofudb->squery(nofudb, "INSERT INTO ? (nick, ident, host, realname) VALUES (?,?,?,?)", "Tssss", "fakeusers", fake->nick, fake->ident, fake->host, fake->realname);
+  controlreply(sender, "Added fake user %s", fake->nick);
+  controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) added by %s/%s", fake->nick, fake->ident,
+              fake->host, fake->realname, ((nick *)sender)->nick, ((nick *)sender)->authname);
+
+  scheduleoneshot(time(NULL) + 1, schedulefakeuser, fake);
   return CMD_OK;
 }
 
-//Usage: FAKELIST
-int fakelist(void *sender, int cargc, char **cargv)
-{
+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)
-{
+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;
+
+  nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", fake->nick);
+  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(cargv[0]);
+  return CMD_OK;
+}
+
+void schedulefakeuser(void *arg) {
+  fakeuser *fake;
+
+  for (fake = fakeuserlist; fake; fake = fake->next)
+    if (!fake->user)
+      fake->user = register_fakeuseronnet(fake);
 }
 
-void reconnectfake(void *details)
-//Called after the timeout period has expired since a fakeuser was killed, or on load
-{
+fakeuser *findfakeuserbynick(char *nick) {
   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)
+
+  for (fake = fakeuserlist; fake; fake = fake->next)
+    if (!ircd_strcmp(nick, fake->nick))
+      return fake;
+
+  return NULL;
+}
+
+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_cleanup();
+  deleteallschedules(schedulefakeuser);
+  deregistercontrolcmd("fakeuser", &fakeadd);
+  deregistercontrolcmd("fakelist", &fakelist);
+  deregistercontrolcmd("fakekill", &fakekill);
 }