Browse Source

Merge branch 'user-caching' into next

* user-caching:
  Clear out cached member pointers that are not used.
  Fill Auth user cache in set_chanlist
  Fix Auth::NewNick not swapping ht_nick cache
  fixup! 868aed83259e0aeb59b6fc216925a6f1272c7e65
  Use existing block to clear user
  Stop caching handles in auth
  Must clear Auth users in clear_chanlist
  Consolidate clear_chanlist logic
  Consolidate clearing member user pointers into clear_cached_users()
  Add missing cache setting/clearing on conf.bots
  Consolidate user cache filling
  Consolidate user pointer cache clearing
  Remove pointless check
  Add some missing user pointer invalidations in clear_usrlist
  Fix bot not auto-opping after just connecting.
  do_op: Don't try (and fail) to op right away with a delay.
  add_mode: Pass memberlist pointer if possible
Bryan Drewery 10 years ago
parent
commit
83edfdb155

+ 1 - 0
doc/UPDATES.md

@@ -22,6 +22,7 @@
   * Fix binary compat issue causing ptrace permission errors on Linux 3.4+
   * Fix binary compat issue causing ptrace permission errors on Linux 3.4+
   * Fix ban/exempt/invite masking not working with 10-char idents.
   * Fix ban/exempt/invite masking not working with 10-char idents.
   * Fallback to ISON if the server falsely claims to support MONITOR.
   * Fallback to ISON if the server falsely claims to support MONITOR.
+  * Fix bot not auto-opping after just connecting.
 
 
 # 1.4.6
 # 1.4.6
   * Disable demo TCL support by default to prevent confusion during build.
   * Disable demo TCL support by default to prevent confusion during build.

+ 54 - 45
src/auth.cc

@@ -1,4 +1,3 @@
-/* I hereby release this into the Public Domain - Bryan Drewery */
 /*
 /*
  * auth.c -- handles:
  * auth.c -- handles:
  *   auth system functions
  *   auth system functions
@@ -39,39 +38,31 @@
 
 
 #include "stat.h"
 #include "stat.h"
 
 
-bd::HashTable<bd::String, Auth*> Auth::ht_handle(10);
 bd::HashTable<bd::String, Auth*> Auth::ht_host(10);
 bd::HashTable<bd::String, Auth*> Auth::ht_host(10);
+bd::HashTable<bd::String, Auth*> Auth::ht_nick(10);
 
 
 Auth::Auth(const char *_nick, const char *_host, struct userrec *u)
 Auth::Auth(const char *_nick, const char *_host, struct userrec *u)
 {
 {
   Status(AUTHING);
   Status(AUTHING);
   strlcpy(nick, _nick, NICKLEN);
   strlcpy(nick, _nick, NICKLEN);
   strlcpy(host, _host, UHOSTLEN);
   strlcpy(host, _host, UHOSTLEN);
-  if (u) {
-    user = u;
-    strlcpy(handle, u->handle, sizeof(handle));
-  } else {
-    user = NULL;
-    handle[0] = '*';
-    handle[1] = 0;
-  }
-
+  user = u;
 
 
   ht_host[host] = this;
   ht_host[host] = this;
-  if (user)
-    ht_handle[handle] = this;
+  ht_nick[_nick] = this;
 
 
-  sdprintf(STR("New auth created! (%s!%s) [%s]"), nick, host, handle);
+  sdprintf(STR("New auth created! (%s!%s) [%s]"), nick, host,
+      u ? u->handle : "*");
   authtime = atime = now;
   authtime = atime = now;
   idx = -1;
   idx = -1;
 }
 }
 
 
 Auth::~Auth()
 Auth::~Auth()
 {
 {
-  sdprintf(STR("Removing auth: (%s!%s) [%s]"), nick, host, handle);
-  if (user)
-    ht_handle.remove(handle);
+  sdprintf(STR("Removing auth: (%s!%s) [%s]"), nick, host,
+      user ? user->handle : "*");
   ht_host.remove(host);
   ht_host.remove(host);
+  ht_nick.remove(nick);
 }
 }
 
 
 void Auth::MakeHash()
 void Auth::MakeHash()
@@ -88,7 +79,11 @@ void Auth::Done()
 }
 }
 
 
 void Auth::NewNick(const char *newnick) {
 void Auth::NewNick(const char *newnick) {
+  if (ht_nick.contains(nick)) {
+    Auth::ht_nick.remove(nick);
+  }
   strlcpy(nick, newnick, NICKLEN);
   strlcpy(nick, newnick, NICKLEN);
+  ht_nick[newnick] = this;
 }
 }
 
 
 Auth *Auth::Find(const char *_host)
 Auth *Auth::Find(const char *_host)
@@ -96,17 +91,8 @@ Auth *Auth::Find(const char *_host)
 
 
   if (ht_host.contains(_host)) {
   if (ht_host.contains(_host)) {
     Auth *auth = ht_host[_host];
     Auth *auth = ht_host[_host];
-    sdprintf(STR("Found auth: (%s!%s) [%s]"), auth->nick, auth->host, auth->handle);
-    return auth;
-  }
-  return NULL;
-}
-
-Auth *Auth::Find(const char *handle, bool _hand)
-{
-  if (ht_handle.contains(handle)) {
-    Auth *auth = ht_handle[handle];
-    sdprintf(STR("Found auth (by handle): %s (%s!%s)"), handle, auth->nick, auth->host);
+    sdprintf(STR("Found auth: (%s!%s) [%s]"), auth->nick, auth->host,
+        auth->user ? auth->user->handle : "*");
     return auth;
     return auth;
   }
   }
   return NULL;
   return NULL;
@@ -115,27 +101,44 @@ Auth *Auth::Find(const char *handle, bool _hand)
 static void auth_clear_users_block(const bd::String key, Auth* auth, void *param)
 static void auth_clear_users_block(const bd::String key, Auth* auth, void *param)
 {
 {
   if (auth->user) {
   if (auth->user) {
-    sdprintf(STR("Clearing USER for auth: (%s!%s) [%s]"), auth->nick, auth->host, auth->handle);
+    sdprintf(STR("Clearing USER for auth: (%s!%s) [%s]"), auth->nick,
+        auth->host, auth->user ? auth->user->handle : "*");
     auth->user = NULL;
     auth->user = NULL;
   }
   }
 }
 }
 
 
-void Auth::NullUsers()
+void Auth::NullUsers(const char *nick)
 {
 {
-  ht_host.each(auth_clear_users_block);
+  if (nick == NULL) {
+    ht_host.each(auth_clear_users_block);
+  } else {
+    if (ht_nick.contains(nick)) {
+      Auth *auth = ht_nick[nick];
+      auth_clear_users_block(nick, auth, NULL);
+    }
+  }
 }
 }
 
 
 static void auth_fill_users_block(const bd::String key, Auth* auth, void* param)
 static void auth_fill_users_block(const bd::String key, Auth* auth, void* param)
 {
 {
-  if (strcmp(auth->handle, "*")) {
-    sdprintf(STR("Filling USER for auth: (%s!%s) [%s]"), auth->nick, auth->host, auth->handle);
-    auth->user = get_user_by_handle(userlist, auth->handle);
-  }
+  char from[NICKLEN + UHOSTLEN];
+
+  sdprintf(STR("Filling USER for auth: (%s!%s) [%s]"), auth->nick, auth->host,
+      auth->user ? auth->user->handle : "*");
+  simple_snprintf(from, sizeof(from), "%s!%s", auth->nick, auth->host);
+  auth->user = get_user_by_host(from);
 }
 }
 
 
-void Auth::FillUsers()
+void Auth::FillUsers(const char *nick)
 {
 {
-  ht_host.each(auth_fill_users_block);
+  if (nick == NULL) {
+    ht_host.each(auth_fill_users_block);
+  } else {
+    if (ht_nick.contains(nick)) {
+      Auth *auth = ht_nick[nick];
+      auth_fill_users_block(nick, auth, NULL);
+    }
+  }
 }
 }
 
 
 
 
@@ -143,7 +146,7 @@ static void auth_expire_block(const bd::String key, Auth* auth, void* param)
 {
 {
   if (auth->Authed() && ((now - auth->atime) >= (60 * 60))) {
   if (auth->Authed() && ((now - auth->atime) >= (60 * 60))) {
     Auth::ht_host.remove(key);
     Auth::ht_host.remove(key);
-    Auth::ht_handle.remove(key);
+    Auth::ht_nick.remove(auth->nick);
     delete auth;
     delete auth;
   }
   }
 }
 }
@@ -158,7 +161,8 @@ void Auth::ExpireAuths()
 
 
 static void auth_delete_all_block(const bd::String, Auth* auth, void* param)
 static void auth_delete_all_block(const bd::String, Auth* auth, void* param)
 {
 {
-  putlog(LOG_DEBUG, "*", STR("Removing (%s!%s) [%s], from auth list."), auth->nick, auth->host, auth->handle);
+  putlog(LOG_DEBUG, "*", STR("Removing (%s!%s) [%s], from auth list."),
+      auth->nick, auth->host, auth->user ? auth->user->handle : "*");
   delete auth;
   delete auth;
 }
 }
 
 
@@ -168,7 +172,7 @@ void Auth::DeleteAll()
     putlog(LOG_DEBUG, "*", STR("Removing auth entries."));
     putlog(LOG_DEBUG, "*", STR("Removing auth entries."));
     ht_host.each(auth_delete_all_block);
     ht_host.each(auth_delete_all_block);
     ht_host.clear();
     ht_host.clear();
-    ht_handle.clear();
+    ht_nick.clear();
   }
   }
 }
 }
 
 
@@ -185,7 +189,7 @@ sdprintf(STR("GETIDX: auth: %s, idx: %d"), nick, idx);
       idx = -1;
       idx = -1;
     else if (!dcc[idx].irc || dcc[idx].simul == -1)
     else if (!dcc[idx].irc || dcc[idx].simul == -1)
       idx = -1;
       idx = -1;
-    else if (strcmp(dcc[idx].nick, handle))
+    else if (user && strcmp(dcc[idx].nick, user->handle))
       idx = -1;
       idx = -1;
     else {
     else {
       sdprintf(STR("FIRST FOUND: %d"), idx);
       sdprintf(STR("FIRST FOUND: %d"), idx);
@@ -199,7 +203,8 @@ sdprintf(STR("GETIDX: auth: %s, idx: %d"), nick, idx);
 
 
   for (i = 0; i < dcc_total; i++) {
   for (i = 0; i < dcc_total; i++) {
     if (dcc[i].type && dcc[i].irc &&
     if (dcc[i].type && dcc[i].irc &&
-       (((chname && chname[0]) && !strcmp(dcc[i].simulbot, chname) && !strcmp(dcc[i].nick, handle)) ||
+       (((chname && chname[0]) && !strcmp(dcc[i].simulbot, chname) &&
+         user && !strcmp(dcc[i].nick, user->handle)) ||
        (!(chname && chname[0]) && !strcmp(dcc[i].simulbot, nick)))) {
        (!(chname && chname[0]) && !strcmp(dcc[i].simulbot, nick)))) {
       putlog(LOG_DEBUG, "*", STR("Simul found old idx for %s/%s: (%s!%s)"), nick, chname, nick, host);
       putlog(LOG_DEBUG, "*", STR("Simul found old idx for %s/%s: (%s!%s)"), nick, chname, nick, host);
       dcc[i].simultime = now;
       dcc[i].simultime = now;
@@ -214,6 +219,8 @@ sdprintf(STR("GETIDX: auth: %s, idx: %d"), nick, idx);
   idx = new_dcc(&DCC_CHAT, sizeof(struct chat_info));
   idx = new_dcc(&DCC_CHAT, sizeof(struct chat_info));
 
 
   if (idx != -1) {
   if (idx != -1) {
+    char from[NICKLEN + UHOSTLEN];
+
     dcc[idx].sock = -1;
     dcc[idx].sock = -1;
     dcc[idx].timeval = now;
     dcc[idx].timeval = now;
     dcc[idx].irc = 1;
     dcc[idx].irc = 1;
@@ -224,10 +231,11 @@ sdprintf(STR("GETIDX: auth: %s, idx: %d"), nick, idx);
     strlcpy(dcc[idx].simulbot, nick, sizeof(dcc[idx].simulbot));
     strlcpy(dcc[idx].simulbot, nick, sizeof(dcc[idx].simulbot));
     strlcpy(dcc[idx].u.chat->con_chan, chname ? chname : "*", sizeof(dcc[idx].u.chat->con_chan));
     strlcpy(dcc[idx].u.chat->con_chan, chname ? chname : "*", sizeof(dcc[idx].u.chat->con_chan));
     dcc[idx].u.chat->strip_flags = STRIP_ALL;
     dcc[idx].u.chat->strip_flags = STRIP_ALL;
-    strlcpy(dcc[idx].nick, handle, sizeof(dcc[idx].nick));
+    strlcpy(dcc[idx].nick, user ? user->handle : "*", sizeof(dcc[idx].nick));
     strlcpy(dcc[idx].host, host, sizeof(dcc[idx].host));
     strlcpy(dcc[idx].host, host, sizeof(dcc[idx].host));
     dcc[idx].addr = 0L;
     dcc[idx].addr = 0L;
-    dcc[idx].user = user ? user : get_user_by_handle(userlist, handle);
+    simple_snprintf(from, sizeof(from), "%s!%s", nick, host);
+    dcc[idx].user = user ? user : get_user_by_host(from);
     return 1;
     return 1;
   }
   }
 
 
@@ -240,7 +248,8 @@ static void auth_tell_block(const bd::String key, Auth* auth, void* param)
   int idx = (int) lparam;
   int idx = (int) lparam;
 
 
   dprintf(idx, "(%s!%s) [%s] authtime: %li, atime: %li, Status: %d\n", auth->nick, 
   dprintf(idx, "(%s!%s) [%s] authtime: %li, atime: %li, Status: %d\n", auth->nick, 
-        auth->host, auth->handle, (long)auth->authtime, (long)auth->atime, auth->Status());
+        auth->host, auth->user ? auth->user->handle : "*",
+        (long)auth->authtime, (long)auth->atime, auth->Status());
 }
 }
 
 
 void Auth::TellAuthed(int idx)
 void Auth::TellAuthed(int idx)

+ 3 - 5
src/auth.h

@@ -25,9 +25,8 @@ class Auth {
   void NewNick(const char *nick);
   void NewNick(const char *nick);
 
 
   static Auth *Find(const char * host);
   static Auth *Find(const char * host);
-  static Auth *Find(const char * handle, bool _hand);
-  static void NullUsers();
-  static void FillUsers();
+  static void NullUsers(const char *nick = NULL);
+  static void FillUsers(const char *nick = NULL);
   static void ExpireAuths();
   static void ExpireAuths();
   static void InitTimer();
   static void InitTimer();
   static void DeleteAll();
   static void DeleteAll();
@@ -41,10 +40,9 @@ class Auth {
   char rand[51];
   char rand[51];
   char nick[NICKLEN];
   char nick[NICKLEN];
   char host[UHOSTLEN];
   char host[UHOSTLEN];
-  char handle[HANDLEN + 1];
 
 
-  static bd::HashTable<bd::String, Auth*> ht_handle;
   static bd::HashTable<bd::String, Auth*> ht_host;
   static bd::HashTable<bd::String, Auth*> ht_host;
+  static bd::HashTable<bd::String, Auth*> ht_nick;
 
 
   private:
   private:
   int status;
   int status;

+ 16 - 26
src/chanprog.cc

@@ -166,24 +166,6 @@ struct userrec *check_chanlist_hand(const char *hand)
   return NULL;
   return NULL;
 }
 }
 
 
-/* Clear the user pointers in the chanlists.
- *
- * Necessary when a hostmask is added/removed, a user is added or a new
- * userfile is loaded.
- */
-void clear_chanlist(void)
-{
-  memberlist		*m = NULL;
-  struct chanset_t	*chan = NULL;
-
-  for (chan = chanset; chan; chan = chan->next)
-    for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
-      m->user = NULL;
-      m->tried_getuser = 0;
-    }
-
-}
-
 /* Clear the user pointer of a specific nick in the chanlists.
 /* Clear the user pointer of a specific nick in the chanlists.
  *
  *
  * Necessary when a hostmask is added/removed, a nick changes, etc.
  * Necessary when a hostmask is added/removed, a nick changes, etc.
@@ -194,13 +176,19 @@ void clear_chanlist_member(const char *nick)
   memberlist		*m = NULL;
   memberlist		*m = NULL;
   struct chanset_t	*chan = NULL;
   struct chanset_t	*chan = NULL;
 
 
-  for (chan = chanset; chan; chan = chan->next)
-    for (m = chan->channel.member; m && m->nick[0]; m = m->next)
-      if (!rfc_casecmp(m->nick, nick)) {
+  for (chan = chanset; chan; chan = chan->next) {
+    for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
+      if (nick == NULL || !rfc_casecmp(m->nick, nick)) {
 	m->user = NULL;
 	m->user = NULL;
         m->tried_getuser = 0;
         m->tried_getuser = 0;
-	break;
+        if (nick != NULL) {
+          break;
+        }
       }
       }
+    }
+  }
+
+  Auth::NullUsers(nick);
 }
 }
 
 
 /* If this user@host is in a channel, set it (it was null)
 /* If this user@host is in a channel, set it (it was null)
@@ -218,6 +206,10 @@ void set_chanlist(const char *host, struct userrec *rec)
     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
       if (!rfc_casecmp(nick, m->nick) && !strcasecmp(uhost, m->userhost))
       if (!rfc_casecmp(nick, m->nick) && !strcasecmp(uhost, m->userhost))
 	m->user = rec;
 	m->user = rec;
+
+  if (!conf.bot->hub) {
+    Auth::FillUsers(nick);
+  }
 }
 }
 
 
 /* 0 marks all channels
 /* 0 marks all channels
@@ -668,15 +660,13 @@ void reload()
   else if (!conf.bot->hub)
   else if (!conf.bot->hub)
     add_localhub();
     add_localhub();
 
 
+  cache_users();
+
   /* Make sure no removed users/bots are still connected. */
   /* Make sure no removed users/bots are still connected. */
   check_stale_dcc_users();
   check_stale_dcc_users();
 
 
-  for (tand_t* bot = tandbot; bot; bot = bot->next)
-    bot->u = get_user_by_handle(userlist, bot->bot);
-
   /* I don't think these will ever be called anyway. */
   /* I don't think these will ever be called anyway. */
   if (!conf.bot->hub) {
   if (!conf.bot->hub) {
-    Auth::FillUsers();
     check_hostmask();
     check_hostmask();
   }
   }
 
 

+ 1 - 1
src/chanprog.h

@@ -21,8 +21,8 @@ void check_timers();
 void check_utimers();
 void check_utimers();
 void rmspace(char *s);
 void rmspace(char *s);
 void set_chanlist(const char *host, struct userrec *rec);
 void set_chanlist(const char *host, struct userrec *rec);
-void clear_chanlist(void);
 void clear_chanlist_member(const char *nick);
 void clear_chanlist_member(const char *nick);
+#define clear_chanlist() clear_chanlist_member(NULL)
 bool bot_shouldjoin(struct userrec* , struct flag_record *, const struct chanset_t *, bool = 0);
 bool bot_shouldjoin(struct userrec* , struct flag_record *, const struct chanset_t *, bool = 0);
 bool shouldjoin(const struct chanset_t *);
 bool shouldjoin(const struct chanset_t *);
 char *samechans(const char *, const char *);
 char *samechans(const char *, const char *);

+ 5 - 5
src/mod/irc.mod/chan.cc

@@ -455,7 +455,7 @@ static void priority_do(struct chanset_t * chan, bool opsonly, int action, bool
             if ((action == PRIO_DEOP) && !chan_sentdeop(m)) {
             if ((action == PRIO_DEOP) && !chan_sentdeop(m)) {
               ++actions;
               ++actions;
               ++sent;
               ++sent;
-              add_mode(chan, '-', 'o', m->nick);
+              add_mode(chan, '-', 'o', m);
               if (!floodless && (actions >= ct || (n == 1 && sent > 20))) {
               if (!floodless && (actions >= ct || (n == 1 && sent > 20))) {
                 if (flush)
                 if (flush)
                   flush_mode(chan, QUICK);
                   flush_mode(chan, QUICK);
@@ -901,7 +901,7 @@ static void refresh_ban_kick(struct chanset_t* chan, memberlist *m, const char *
     for (maskrec* b = cycle ? chan->bans : global_bans; b; b = b->next) {
     for (maskrec* b = cycle ? chan->bans : global_bans; b; b = b->next) {
       if (wild_match(b->mask, user) || match_cidr(b->mask, user)) {
       if (wild_match(b->mask, user) || match_cidr(b->mask, user)) {
         if ((chan->role & ROLE_DEOP) && chan_hasop(m))
         if ((chan->role & ROLE_DEOP) && chan_hasop(m))
-  	  add_mode(chan, '-', 'o', m->nick);	/* Guess it can't hurt.	*/
+          add_mode(chan, '-', 'o', m);	/* Guess it can't hurt.	*/
 	check_exemptlist(chan, user);
 	check_exemptlist(chan, user);
 	do_mask(chan, chan->channel.ban, b->mask, 'b');
 	do_mask(chan, chan->channel.ban, b->mask, 'b');
 	b->lastactive = now;
 	b->lastactive = now;
@@ -1229,7 +1229,7 @@ static void check_this_member(struct chanset_t *chan, char *nick, struct flag_re
       (chk_deop(*fr, chan) ||
       (chk_deop(*fr, chan) ||
        (!loading && userlist && chan_bitch(chan) && !chk_op(*fr, chan)) ) ) {
        (!loading && userlist && chan_bitch(chan) && !chk_op(*fr, chan)) ) ) {
     /* if (target_priority(chan, m, 1)) */
     /* if (target_priority(chan, m, 1)) */
-      add_mode(chan, '-', 'o', m->nick);
+      add_mode(chan, '-', 'o', m);
   } else if (!chan_hasop(m) && (chan->role & ROLE_OP) && chk_autoop(m->user, *fr, chan)) {
   } else if (!chan_hasop(m) && (chan->role & ROLE_OP) && chk_autoop(m->user, *fr, chan)) {
     do_op(m, chan, 1, 0);
     do_op(m, chan, 1, 0);
   }
   }
@@ -1237,11 +1237,11 @@ static void check_this_member(struct chanset_t *chan, char *nick, struct flag_re
     if (chan_hasvoice(m) && !chan_hasop(m)) {
     if (chan_hasvoice(m) && !chan_hasop(m)) {
       /* devoice +q users .. */
       /* devoice +q users .. */
       if (chk_devoice(*fr) || (channel_voicebitch(chan) && !chk_voice(*fr, chan)))
       if (chk_devoice(*fr) || (channel_voicebitch(chan) && !chk_voice(*fr, chan)))
-        add_mode(chan, '-', 'v', m->nick);
+        add_mode(chan, '-', 'v', m);
     } else if (!chan_hasvoice(m) && !chan_hasop(m)) {
     } else if (!chan_hasvoice(m) && !chan_hasop(m)) {
       /* voice +v users */
       /* voice +v users */
       if (chk_voice(*fr, chan)) {
       if (chk_voice(*fr, chan)) {
-        add_mode(chan, '+', 'v', m->nick);
+        add_mode(chan, '+', 'v', m);
         if (m->flags & EVOICE)
         if (m->flags & EVOICE)
           m->flags &= ~EVOICE;
           m->flags &= ~EVOICE;
       }
       }

+ 5 - 5
src/mod/irc.mod/cmdsirc.cc

@@ -305,8 +305,8 @@ static void cmd_kickban(int idx, char *par)
       dprintf(idx, "%s is permanently exempted!\n", nick);
       dprintf(idx, "%s is permanently exempted!\n", nick);
       return;
       return;
     }
     }
-    if (m->flags & CHANOP)
-      add_mode(chan, '-', 'o', m->nick);
+    if (chan_hasop(m))
+      add_mode(chan, '-', 'o', m);
     check_exemptlist(chan, s);
     check_exemptlist(chan, s);
     switch (bantype) {
     switch (bantype) {
       case '@':
       case '@':
@@ -396,7 +396,7 @@ static void cmd_voice(int idx, char *par)
       dprintf(idx, "%s is not on %s.\n", nick, chan->dname);
       dprintf(idx, "%s is not on %s.\n", nick, chan->dname);
       return;
       return;
     }
     }
-    add_mode(chan, '+', 'v', nick);
+    add_mode(chan, '+', 'v', m);
     dprintf(idx, "Gave voice to %s on %s\n", nick, chan->dname);
     dprintf(idx, "Gave voice to %s on %s\n", nick, chan->dname);
     next:;
     next:;
     if (!all)
     if (!all)
@@ -459,7 +459,7 @@ static void cmd_devoice(int idx, char *par)
     return;
     return;
   }
   }
 
 
-  add_mode(chan, '-', 'v', nick);
+  add_mode(chan, '-', 'v', m);
   dprintf(idx, "Devoiced %s on %s\n", nick, chan->dname);
   dprintf(idx, "Devoiced %s on %s\n", nick, chan->dname);
   next:;
   next:;
   if (!all)
   if (!all)
@@ -1041,7 +1041,7 @@ static void cmd_deop(int idx, char *par)
       if (all) goto next;  
       if (all) goto next;  
       return;
       return;
     }
     }
-    add_mode(chan, '-', 'o', nick);
+    add_mode(chan, '-', 'o', m);
     dprintf(idx, "Deopped %s on %s.\n", nick, chan->dname);
     dprintf(idx, "Deopped %s on %s.\n", nick, chan->dname);
     next:;
     next:;
     if (!all)
     if (!all)

+ 7 - 4
src/mod/irc.mod/irc.cc

@@ -212,7 +212,7 @@ void set_devoice(struct chanset_t *chan, memberlist* m) {
 const char* punish_flooder(struct chanset_t* chan, memberlist* m, const char *reason) {
 const char* punish_flooder(struct chanset_t* chan, memberlist* m, const char *reason) {
   if (channel_voice(chan) && chan->voice_moderate) {
   if (channel_voice(chan) && chan->voice_moderate) {
     if (!chan_sentdevoice(m)) {
     if (!chan_sentdevoice(m)) {
-      add_mode(chan, '-', 'v', m->nick);
+      add_mode(chan, '-', 'v', m);
       m->flags |= SENTDEVOICE;
       m->flags |= SENTDEVOICE;
       set_devoice(chan, m);
       set_devoice(chan, m);
       return "devoicing";
       return "devoicing";
@@ -1170,6 +1170,9 @@ killmember(struct chanset_t *chan, char *nick, bool cacheMember)
 
 
   if (cacheMember) {
   if (cacheMember) {
     x->last = now;
     x->last = now;
+    x->user = NULL;
+    x->next = NULL;
+    x->tried_getuser = 0;
     // Don't delete here, will delete when it expires from the cache.
     // Don't delete here, will delete when it expires from the cache.
     (*chan->channel.cached_members)[x->userhost] = x;
     (*chan->channel.cached_members)[x->userhost] = x;
   } else {
   } else {
@@ -1600,11 +1603,11 @@ check_expired_chanstuff(struct chanset_t *chan)
                      (!channel_voice(chan) && !privchan(fr, chan, PRIV_VOICE) && chk_voice(fr, chan))
                      (!channel_voice(chan) && !privchan(fr, chan, PRIV_VOICE) && chk_voice(fr, chan))
                     )
                     )
                    ) {
                    ) {
-                  add_mode(chan, '+', 'v', m->nick);
+                  add_mode(chan, '+', 'v', m);
                 }
                 }
               }
               }
             } else if (!m->user && channel_voice(chan) && !channel_voicebitch(chan) && voice_ok(m, chan)) {
             } else if (!m->user && channel_voice(chan) && !channel_voicebitch(chan) && voice_ok(m, chan)) {
-              add_mode(chan, '+', 'v', m->nick);
+              add_mode(chan, '+', 'v', m);
             }
             }
           }
           }
         }
         }
@@ -1699,7 +1702,7 @@ flush_modes()
         }
         }
         if (chan_sentvoice(m)) {
         if (chan_sentvoice(m)) {
           m->flags &= ~SENTVOICE;
           m->flags &= ~SENTVOICE;
-          add_mode(chan, '+', 'v', m->nick);
+          add_mode(chan, '+', 'v', m);
         }
         }
       }
       }
     }
     }

+ 12 - 3
src/mod/irc.mod/irc.h

@@ -120,9 +120,18 @@ void join_chan(struct chanset_t* chan, int idx = DP_MODE);
 
 
 int check_bind_authc(char *, Auth *, char *, char *);
 int check_bind_authc(char *, Auth *, char *, char *);
 void notice_invite(struct chanset_t *, char *, char *, char *, bool);
 void notice_invite(struct chanset_t *, char *, char *, char *, bool);
-void real_add_mode(struct chanset_t *, const char, const char, const char *, bool);
-#define add_mode(chan, pls, mode, nick) real_add_mode(chan, pls, mode, nick, 0)
-#define add_cookie(chan, nick) real_add_mode(chan, '+', 'o', nick, 1)
+void real_add_mode(struct chanset_t *, const char, const char, const char *, bool, memberlist *);
+inline void add_mode(struct chanset_t *chan, const char plus, const char mode,
+    const char *op)
+{
+  real_add_mode(chan, plus, mode, op, 0, NULL);
+}
+inline void add_mode(struct chanset_t *chan, const char plus, const char mode,
+    memberlist *m)
+{
+  real_add_mode(chan, plus, mode, m->nick, 0, m);
+}
+#define add_cookie(chan, member) real_add_mode(chan, '+', 'o', member->nick, 1, member)
 /* Check if I am a chanop. Returns boolean 1 or 0.
 /* Check if I am a chanop. Returns boolean 1 or 0.
  */
  */
 inline bool me_op(const struct chanset_t *chan)
 inline bool me_op(const struct chanset_t *chan)

+ 17 - 14
src/mod/irc.mod/mode.cc

@@ -101,12 +101,16 @@ do_op(memberlist *m, struct chanset_t *chan, bool delay, bool force)
   if (delay) {
   if (delay) {
     m->delay = now + chan->auto_delay;
     m->delay = now + chan->auto_delay;
     m->flags |= SENTOP;
     m->flags |= SENTOP;
+    return 1;
   }
   }
 
 
   if (channel_fastop(chan) || channel_take(chan) || cookies_disabled) {
   if (channel_fastop(chan) || channel_take(chan) || cookies_disabled) {
-    add_mode(chan, '+', 'o', m->nick);
+    add_mode(chan, '+', 'o', m);
   } else if (!connect_bursting) {
   } else if (!connect_bursting) {
-    add_cookie(chan, m->nick);
+    add_cookie(chan, m);
+  } else {
+    /* Failed to give the mode, so requeue it. */
+    do_op(m, chan, 1, 0);
   }
   }
   return 1;
   return 1;
 }
 }
@@ -332,15 +336,14 @@ flush_mode(struct chanset_t *chan, int pri)
 /* Queue a channel mode change
 /* Queue a channel mode change
  */
  */
 void
 void
-real_add_mode(struct chanset_t *chan, const char plus, const char mode, const char *op, bool cookie)
+real_add_mode(struct chanset_t *chan, const char plus, const char mode, const char *op, bool cookie, memberlist *mx)
 {
 {
   if (!me_op(chan))
   if (!me_op(chan))
     return;
     return;
 
 
-  memberlist *mx = NULL;
-
   if (mode == 'o' || mode == 'v') {
   if (mode == 'o' || mode == 'v') {
-    mx = ismember(chan, op);
+    if (!mx)
+      mx = ismember(chan, op);
     if (!mx)
     if (!mx)
       return;
       return;
     if (plus == '-' && mode == 'o') {
     if (plus == '-' && mode == 'o') {
@@ -599,7 +602,7 @@ got_op(struct chanset_t *chan, memberlist *m, memberlist *mv)
         m->flags |= SENTDEOP;
         m->flags |= SENTDEOP;
 #endif
 #endif
       if (num == 5) {
       if (num == 5) {
-        add_mode(chan, '-', 'o', m->nick);
+        add_mode(chan, '-', 'o', m);
       } else if (bitch && num == 6) {
       } else if (bitch && num == 6) {
         len = simple_snprintf(outbuf, sizeof(outbuf), "KICK %s %s :%s\r\n", chan->name, mv->nick, response(RES_BITCHOPPED));
         len = simple_snprintf(outbuf, sizeof(outbuf), "KICK %s %s :%s\r\n", chan->name, mv->nick, response(RES_BITCHOPPED));
         mv->flags |= SENTKICK;
         mv->flags |= SENTKICK;
@@ -607,7 +610,7 @@ got_op(struct chanset_t *chan, memberlist *m, memberlist *mv)
         len = simple_snprintf(outbuf, sizeof(outbuf), "KICK %s %s :%s\r\n", chan->name, m->nick, response(RES_BITCHOP));
         len = simple_snprintf(outbuf, sizeof(outbuf), "KICK %s %s :%s\r\n", chan->name, m->nick, response(RES_BITCHOP));
         m->flags |= SENTKICK;
         m->flags |= SENTKICK;
       } else
       } else
-        add_mode(chan, '-', 'o', mv->nick);
+        add_mode(chan, '-', 'o', mv);
 
 
       if (len)
       if (len)
         dprintf_real(DP_MODE_NEXT, outbuf, len, sizeof(outbuf));
         dprintf_real(DP_MODE_NEXT, outbuf, len, sizeof(outbuf));
@@ -615,13 +618,13 @@ got_op(struct chanset_t *chan, memberlist *m, memberlist *mv)
 
 
 
 
   } else if (reversing && !me_opped)
   } else if (reversing && !me_opped)
-    add_mode(chan, '-', 'o', mv->nick);
+    add_mode(chan, '-', 'o', mv);
 
 
   /* server op */
   /* server op */
   if (!m && meop && !me_opped) {
   if (!m && meop && !me_opped) {
     if (chk_deop(victim, chan) || (chan_bitch(chan) && !chk_op(victim, chan))) {
     if (chk_deop(victim, chan) || (chan_bitch(chan) && !chk_op(victim, chan))) {
       mv->flags |= FAKEOP;
       mv->flags |= FAKEOP;
-      add_mode(chan, '-', 'o', mv->nick);
+      add_mode(chan, '-', 'o', mv);
     } 
     } 
   }
   }
   mv->flags |= WASOP;
   mv->flags |= WASOP;
@@ -1470,9 +1473,9 @@ gotmode(char *from, char *msg)
                 mv->flags |= CHANVOICE;
                 mv->flags |= CHANVOICE;
                 if (channel_active(chan) && dovoice(chan)) {
                 if (channel_active(chan) && dovoice(chan)) {
                   if (dv || chk_devoice(victim) || (channel_voicebitch(chan) && !chk_voice(victim, chan))) {
                   if (dv || chk_devoice(victim) || (channel_voicebitch(chan) && !chk_voice(victim, chan))) {
-                    add_mode(chan, '-', 'v', mparam);
+                    add_mode(chan, '-', 'v', mv);
                   } else if (reversing) {
                   } else if (reversing) {
-                    add_mode(chan, '-', 'v', mparam);
+                    add_mode(chan, '-', 'v', mv);
                   }
                   }
                 }
                 }
               } else if (msign == '-') {
               } else if (msign == '-') {
@@ -1481,9 +1484,9 @@ gotmode(char *from, char *msg)
                 if (channel_active(chan) && dovoice(chan) && !chan_hasop(mv)) {
                 if (channel_active(chan) && dovoice(chan) && !chan_hasop(mv)) {
                   /* revoice +v users */
                   /* revoice +v users */
                   if (chk_voice(victim, chan)) {
                   if (chk_voice(victim, chan)) {
-                    add_mode(chan, '+', 'v', mparam);
+                    add_mode(chan, '+', 'v', mv);
                   } else if (reversing) {
                   } else if (reversing) {
-                    add_mode(chan, '+', 'v', mparam);
+                    add_mode(chan, '+', 'v', mv);
                     /* if they arent +v|v and VOICER is m+ then EVOICE them */
                     /* if they arent +v|v and VOICER is m+ then EVOICE them */
                   } else {
                   } else {
                     if (!match_my_nick(nick) && channel_voice(chan) &&
                     if (!match_my_nick(nick) && channel_voice(chan) &&

+ 5 - 3
src/mod/irc.mod/msgcmds.cc

@@ -294,9 +294,11 @@ static int msg_invite(char *nick, char *host, struct userrec *u, char *par)
 static void logc(const char *cmd, Auth *a, char *chname, char *par)
 static void logc(const char *cmd, Auth *a, char *chname, char *par)
 {
 {
   if (chname && chname[0])
   if (chname && chname[0])
-    putlog(LOG_CMDS, "*", "(%s!%s) !%s! %s %c%s %s", a->nick, a->host, a->handle, chname, auth_prefix[0], cmd, par ? par : "");
+    putlog(LOG_CMDS, "*", "(%s!%s) !%s! %s %c%s %s", a->nick, a->host,
+        a->user ? a->user->handle : "*", chname, auth_prefix[0], cmd, par ? par : "");
   else
   else
-    putlog(LOG_CMDS, "*", "(%s!%s) !%s! %c%s %s", a->nick, a->host, a->handle, auth_prefix[0], cmd, par ? par : "");
+    putlog(LOG_CMDS, "*", "(%s!%s) !%s! %c%s %s", a->nick, a->host,
+        a->user ? a->user->handle : "*", auth_prefix[0], cmd, par ? par : "");
 }
 }
 #define LOGC(cmd) logc(cmd, a, chname, par)
 #define LOGC(cmd) logc(cmd, a, chname, par)
   
   
@@ -338,7 +340,7 @@ static int msg_authstart(char *nick, char *host, struct userrec *u, char *par)
 static void
 static void
 AuthFinish(Auth *auth)
 AuthFinish(Auth *auth)
 {
 {
-  putlog(LOG_CMDS, "*", STR("(%s!%s) !%s! +AUTH"), auth->nick, auth->host, auth->handle);
+  putlog(LOG_CMDS, "*", STR("(%s!%s) !%s! +AUTH"), auth->nick, auth->host, auth->user ? auth->user->handle : "*");
   auth->Done();
   auth->Done();
   bd::String msg;
   bd::String msg;
   msg = bd::String::printf(STR("You are now authorized for cmds, see %chelp"), auth_prefix[0]);
   msg = bd::String::printf(STR("You are now authorized for cmds, see %chelp"), auth_prefix[0]);

+ 5 - 41
src/mod/share.mod/share.cc

@@ -1342,7 +1342,6 @@ finish_share(int idx)
 static void share_read_stream(int idx, bd::Stream& stream) {
 static void share_read_stream(int idx, bd::Stream& stream) {
   struct userrec *u = NULL, *ou = NULL;
   struct userrec *u = NULL, *ou = NULL;
   struct chanset_t *chan = NULL;
   struct chanset_t *chan = NULL;
-  int i;
 
 
   /*
   /*
    * This is where we remove all global and channel bans/exempts/invites and
    * This is where we remove all global and channel bans/exempts/invites and
@@ -1373,23 +1372,7 @@ static void share_read_stream(int idx, bd::Stream& stream) {
   //userlist = (struct userrec *) -1;       /* Do this to prevent .user messups     */
   //userlist = (struct userrec *) -1;       /* Do this to prevent .user messups     */
   userlist = NULL;
   userlist = NULL;
 
 
-  /* Bot user pointers are updated to point to the new list, all others
-   * are set to NULL. If our userfile will be overriden, just set _all_
-   * to NULL directly.
-   */
-  for (i = 0; i < dcc_total; i++)
-    if (dcc[i].type)
-      dcc[i].user = NULL;
-
-  for (tand_t* bot = tandbot; bot; bot = bot->next)
-    bot->u = NULL;
-
-  if (!conf.bot->hub) {
-    Auth::NullUsers();
-  }
-
-  if (conf.bot->u)
-    conf.bot->u = NULL;
+  clear_cached_users();
 
 
   struct cmd_pass *old_cmdpass = cmdpass;
   struct cmd_pass *old_cmdpass = cmdpass;
   cmdpass = NULL;
   cmdpass = NULL;
@@ -1406,22 +1389,11 @@ static void share_read_stream(int idx, bd::Stream& stream) {
 
 
     Context;
     Context;
     clear_userlist(u);          /* Clear new, obsolete, user list.      */
     clear_userlist(u);          /* Clear new, obsolete, user list.      */
-    clear_chanlist();           /* Remove all user references from the
-                                 * channel lists.                       */
-    for (i = 0; i < dcc_total; i++)
-      if (dcc[i].type)
-        dcc[i].user = get_user_by_handle(ou, dcc[i].nick);
-
-    for (tand_t* bot = tandbot; bot; bot = bot->next)
-      bot->u = get_user_by_handle(ou, bot->bot);
-
-    conf.bot->u = get_user_by_handle(ou, conf.bot->nick);
 
 
     userlist = ou;              /* Revert to old user list.             */
     userlist = ou;              /* Revert to old user list.             */
     lastuser = NULL;            /* Reset last accessed user ptr.        */
     lastuser = NULL;            /* Reset last accessed user ptr.        */
 
 
-    Auth::FillUsers();
-
+    cache_users();
     cmdpass = old_cmdpass;
     cmdpass = old_cmdpass;
 
 
     checkchans(2);              /* un-flag the channels, we are keeping them.. */
     checkchans(2);              /* un-flag the channels, we are keeping them.. */
@@ -1442,8 +1414,7 @@ static void share_read_stream(int idx, bd::Stream& stream) {
   /* SUCCESS! */
   /* SUCCESS! */
 
 
   loading = 0;
   loading = 0;
-  clear_chanlist();             /* Remove all user references from the
-                                 * channel lists.                       */
+
   userlist = u;                 /* Set new user list.                   */
   userlist = u;                 /* Set new user list.                   */
   lastuser = NULL;              /* Reset last accessed user ptr.        */
   lastuser = NULL;              /* Reset last accessed user ptr.        */
   putlog(LOG_BOTS, "*", "%s.", "Userlist transfer complete; switched over");
   putlog(LOG_BOTS, "*", "%s.", "Userlist transfer complete; switched over");
@@ -1461,18 +1432,11 @@ static void share_read_stream(int idx, bd::Stream& stream) {
   if (conf.bot->localhub)
   if (conf.bot->localhub)
     add_child_bots();
     add_child_bots();
 
 
+  cache_users();
+
   /* Make sure no removed users/bots are still connected. */
   /* Make sure no removed users/bots are still connected. */
   check_stale_dcc_users();
   check_stale_dcc_users();
 
 
-  /* Refill tand list with cached user entries */
-  for (tand_t* bot = tandbot; bot; bot = bot->next)
-    bot->u = get_user_by_handle(userlist, bot->bot);
-
-  if (!conf.bot->hub) {  
-    /* copy over any auth users */
-    Auth::FillUsers();
-  }
-
   write_userfile(-1);
   write_userfile(-1);
 
 
   cmdpass_free(old_cmdpass);
   cmdpass_free(old_cmdpass);

+ 52 - 7
src/userrec.cc

@@ -172,6 +172,57 @@ void clear_masks(maskrec *m)
 
 
 static void freeuser(struct userrec *);
 static void freeuser(struct userrec *);
 
 
+void clear_cached_users()
+{
+  for (int i = 0; i < dcc_total; i++) {
+    if (dcc[i].type) {
+      dcc[i].user = NULL;
+    }
+  }
+
+  conf.bot->u = NULL;
+
+  for (conf_bot *bot = conf.bots; bot; bot = bot->next) {
+    bot->u = NULL;
+  }
+
+  for (tand_t* bot = tandbot; bot; bot = bot->next) {
+    bot->u = NULL;
+  }
+
+  if (!conf.bot->hub) {
+    clear_chanlist();           /* Remove all user references from the
+                                 * channel lists.                       */
+  }
+}
+
+void cache_users()
+{
+  for (int i = 0; i < dcc_total; i++) {
+    if (dcc[i].type) {
+      dcc[i].user = get_user_by_handle(userlist, dcc[i].nick);
+    }
+  }
+
+  if (conf.bot->u == NULL) {
+    conf.bot->u = get_user_by_handle(userlist, conf.bot->nick);
+  }
+
+  for (conf_bot *bot = conf.bots; bot; bot = bot->next) {
+    if (bot->u == NULL) {
+      bot->u = get_user_by_handle(userlist, bot->nick);
+    }
+  }
+
+  for (tand_t* bot = tandbot; bot; bot = bot->next) {
+    bot->u = get_user_by_handle(userlist, bot->bot);
+  }
+
+  if (!conf.bot->hub) {
+    Auth::FillUsers();
+  }
+}
+
 void clear_userlist(struct userrec *bu)
 void clear_userlist(struct userrec *bu)
 {
 {
   struct userrec *v = NULL;
   struct userrec *v = NULL;
@@ -183,13 +234,7 @@ void clear_userlist(struct userrec *bu)
   if (userlist == bu) {
   if (userlist == bu) {
     struct chanset_t *cst = NULL;
     struct chanset_t *cst = NULL;
 
 
-    for (int i = 0; i < dcc_total; i++)
-      if (dcc[i].type)
-        dcc[i].user = NULL;
-
-    conf.bot->u = NULL;
-
-    clear_chanlist();
+    clear_cached_users();
     lastuser = NULL;
     lastuser = NULL;
 
 
     while (global_ign)
     while (global_ign)

+ 2 - 0
src/userrec.h

@@ -8,6 +8,8 @@ namespace bd {
 struct userrec *adduser(struct userrec *, const char *, char *, char *, flag_t, int);
 struct userrec *adduser(struct userrec *, const char *, char *, char *, flag_t, int);
 void addhost_by_handle(char *, char *);
 void addhost_by_handle(char *, char *);
 void clear_masks(struct maskrec *);
 void clear_masks(struct maskrec *);
+void clear_cached_users();
+void cache_users();
 void clear_userlist(struct userrec *);
 void clear_userlist(struct userrec *);
 int u_pass_match(struct userrec *, const char *);
 int u_pass_match(struct userrec *, const char *);
 int delhost_by_handle(char *, char *);
 int delhost_by_handle(char *, char *);