]> PatchyGit - patchyircd.git/commitdiff
run all username updates through chghost
authorEgor <egor@patchysicp.xyz>
Thu, 25 Jan 2024 03:50:16 +0000 (05:50 +0200)
committerEgor <egor@patchysicp.xyz>
Thu, 25 Jan 2024 03:50:16 +0000 (05:50 +0200)
src/irc.c

index ffb611e..acf46a2 100644 (file)
--- a/src/irc.c
+++ b/src/irc.c
@@ -373,14 +373,8 @@ int processPacket(struct client_data *client, char *source, char *command, int a
 #endif
                                }
                                if (res != -1) {
-                                       client->umode |= UMODE_REGISTERED;
-                                       free(client->username);
-                                       client->username = mystrdup(username);
-                                       if (!client->username)
-                                               abort();
                                        copy_strf(&databuf, ":%s 903 * :SASL authentication successful\r\n", hostname), sendbuf(client);
-                                       copy_strf(&databuf, ":%s 900 * *!%s@%s %s :You are now logged in as %s\r\n",
-                                                       hostname, client->username, client->hostname, client->username, client->username), sendbuf(client);
+                                       client_chghost(client, username, 0);
                                } else {
 saslerr:
                                        copy_strf(&databuf, ":%s 904 * :SASL authentication failed\r\n", hostname), sendbuf(client);
@@ -413,14 +407,8 @@ saslcleanup:
                        return err_alreadyregistered(client), sendbuf(client), 0;
                // set username, but only if we didn't auth yet
                if (!client->username || client->username[0] == '~') {
-                       free(client->username);
-                       size_t ulen = strlen(args[0]);
-                       client->username = malloc(ulen+2);
-                       if (!client->username)
-                               abort();
-                       client->umode &= ~UMODE_REGISTERED;
-                       client->username[0] = '~';
-                       memcpy(client->username + 1, args[0], ulen+1);
+                       args[0][-1] = '~'; // ugly hack
+                       client_chghost(client, args[0]-1, 0);
                }
                // set realname
                free(client->realname);
@@ -1182,6 +1170,7 @@ saslcleanup:
                                if (cl->cctx && tls_peer_cert_provided(cl->cctx))
                                        rpl_whoiscertfp(client, cl, tls_peer_cert_hash(cl->cctx)), sendbuf(client);
 #endif
+                       // TODO: this needs to do a nicks.txt lookup
                        if (cl->umode & UMODE_REGISTERED && !strcmp(cl->key, cl->username))
                                rpl_whoisregnick(client, cl), sendbuf(client);
                        rpl_whoisuser(client, cl), sendbuf(client);
@@ -1346,8 +1335,7 @@ void newUser(struct client_data *client) {
                if (!(client->umode & UMODE_SECURE) || res == -1) {
                        return err_passwdmismatch(client), sendbuf(client);
                } else {
-                       client->umode |= UMODE_REGISTERED;
-                       memmove(client->username, client->username+1, strlen(client->username));
+                       client_chghost(client, client->username+1, 0);
                }
        }
        setNick(client, client->nick_reg);
@@ -1499,64 +1487,103 @@ void setNick(struct client_data *client, char* nickname) {
        rpl_mononline(0, client), sendbuf_monitor(client->key, 0, 0, 0);
        return;
 }
+/* changes username, hostname or both
+ * NULL means no change. additionally username can be client->username+1
+ * this has to work during registration, so there are no assumptions about nick/username already existing
+ */
 void client_chghost(struct client_data *client, const char *newusername, const char *newhostname)
 {
-       if (!strcmp(client->username, newusername) && !strcmp(client->hostname, newhostname))
+       if (client->username && newusername && !strcmp(client->username, newusername))
+               newusername = 0;
+       if (newhostname && !strcmp(client->hostname, newhostname))
+               newhostname = 0;
+       if (!newusername && !newhostname)
                return;
-       msg_quit(client, "Changing hostname", "");
-       sendbuf_visible_caps(client, 0, CAP_CHGHOST);
-       msg_chghost(client, newusername, newhostname);
-       int cookie = sendbuf_visible_caps(client, CAP_CHGHOST, 0);
-       sendbuf_monitor(client->key, cookie, CAP_CHGHOST|CAP_EXTENDEDMONITOR, 0);
-       if (client->cookie != cookie)
-               sendbuf(client);
-       rpl_visiblehost(client), sendbuf(client);
-       int changedacc = client->username[0] != '~' || newusername[0] != '~';
-       int loggedout = client->username[0] != '~' && newusername[0] == '~';
+       int wasloggedin = client->username && client->username[0] != '~';
+       int willbeloggedin = newusername ? newusername[0] != '~' : wasloggedin;
+       int changedacc = newusername && (wasloggedin || willbeloggedin);
 
-       free(client->username);
-       client->username = mystrdup(newusername);
-       free(client->hostname);
-       client->hostname = mystrdup(newhostname);
-       free(client->nuh);
-       client->nuh = malloc(strlen(client->nick) + strlen(client->username) + strlen(client->hostname) + 3);
-       if (!client->nuh)
-               abort();
-       sprintf(client->nuh, "%s!%s@%s", client->nick, client->username, client->hostname);
-       stringlower(client->nuh);
+       // notify clients that the user is changing their hostname
+       if (is_registered(client)) {
+               msg_quit(client, "Changing hostname", "");
+               sendbuf_visible_caps(client, 0, CAP_CHGHOST);
+               msg_chghost(client, newusername ? newusername : client->username, newhostname ? newhostname : client->hostname);
+               int cookie = sendbuf_visible_caps(client, CAP_CHGHOST, 0);
+               sendbuf_monitor(client->key, cookie, CAP_CHGHOST|CAP_EXTENDEDMONITOR, 0);
+               if (client->cookie != cookie)
+                       sendbuf(client);
+               rpl_visiblehost(client), sendbuf(client);
+       }
 
-       struct channel *chan;
-       map_foreach(&client->channels, 0, &chan) {
-               msg_join(client, chan);
-               sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_EXTENDEDJOIN|CAP_CHGHOST);
-               msg_join_extended(client, chan);
-               sendbuf_list_sans_self_caps(client, &chan->members, 0, CAP_EXTENDEDJOIN, CAP_CHGHOST);
-               if (map_get(&chan->v, client->key)) {
-                       copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +v %s\r\n", chan->name, client->nick);
-                       sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST);
+       // update username
+       if (newusername == client->username+1) {
+               memmove(client->username, client->username+1, strlen(client->username));
+       } else if (newusername) {
+               free(client->username);
+               client->username = mystrdup(newusername);
+               if (!client->username)
+                       abort();
+       }
+       // update hostname
+       if (newhostname) {
+               free(client->hostname);
+               client->hostname = mystrdup(newhostname);
+               if (!client->hostname)
+                       abort();
+       }
+       // update nuh
+       {
+               char *n = client->nick ? client->nick : "*";
+               char *u = client->username ? client->username : "*";
+               char *h = client->hostname;
+               free(client->nuh);
+               client->nuh = malloc(strlen(n) + strlen(u) + strlen(h) + 3);
+               if (!client->nuh)
+                       abort();
+               sprintf(client->nuh, "%s!%s@%s", n, u, h);
+               stringlower(client->nuh);
+       }
+
+       // now we have to simulate rejoins for clients without chghost support
+       if (is_registered(client)) {
+               struct channel *chan;
+               map_foreach(&client->channels, 0, &chan) {
+                       msg_join(client, chan);
+                       sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_EXTENDEDJOIN|CAP_CHGHOST);
+                       msg_join_extended(client, chan);
+                       sendbuf_list_sans_self_caps(client, &chan->members, 0, CAP_EXTENDEDJOIN, CAP_CHGHOST);
+                       if (map_get(&chan->v, client->key)) {
+                               copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +v %s\r\n", chan->name, client->nick);
+                               sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST);
+                       }
+                       if (map_get(&chan->o, client->key)) {
+                               copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick);
+                               sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST);
+                       }
                }
-               if (map_get(&chan->o, client->key)) {
-                       copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick);
-                       sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST);
+               if (changedacc) {
+                       msg_account(client);
+                       int cookie = sendbuf_visible_caps(client, CAP_ACCOUNTNOTIFY, 0);
+                       sendbuf_monitor(client->key, cookie, CAP_ACCOUNTNOTIFY|CAP_EXTENDEDMONITOR, 0);
+                       if (client->cookie != cookie)
+                               sendbuf(client);
                }
        }
-       if (changedacc) {
-               msg_account(client);
-               int cookie = sendbuf_visible_caps(client, CAP_ACCOUNTNOTIFY, 0);
-               sendbuf_monitor(client->key, cookie, CAP_ACCOUNTNOTIFY|CAP_EXTENDEDMONITOR, 0);
-               if (client->cookie != cookie)
-                       sendbuf(client);
-       }
-       if (newusername[0] != '~') {
-               copy_strf(&databuf, ":%s 900 %s %s %s :You are now logged in as %s\r\n",
-                               hostname, client->nick, client->nuh, client->username, client->username), sendbuf(client);
+       
+       // notify the user of their new account name, and update the +r mode
+       if (willbeloggedin) {
+               if (newusername)
+                       copy_strf(&databuf, ":%s 900 %s %s %s :You are now logged in as %s\r\n",
+                                       hostname, client->nick ? client->nick : "*", client->nuh, client->username, client->username), sendbuf(client);
                client->umode |= UMODE_REGISTERED;
        } else {
-               if (loggedout)
+               if (wasloggedin)
                        copy_strf(&databuf, ":%s 901 %s %s :You are now logged out\r\n",
-                                       hostname, client->nick, client->nuh), sendbuf(client);
+                                       hostname, client->nick ? client->nick : "*", client->nuh), sendbuf(client);
                client->umode &= ~UMODE_REGISTERED;
        }
+       if (is_registered(client) && wasloggedin != willbeloggedin)
+               copy_strf(&databuf, ":cia!cia@cia.gov MODE %s %cr\r\n", client->nick, willbeloggedin ? '+' : '-'), sendbuf(client);
 }
 void channel_sendtopic(struct client_data *client, struct channel *chan, int joining)
 {