#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);
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);
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);
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);
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)
{