bool ChannelManager::UpdateUser(int channel_id_, const IM::User& user_) { auto it = m_mapChannels.find(channel_id_); if (it != m_mapChannels.end()) { int64_t user_id = user_.id(); auto user_it = find_if (it->second.m_users.begin(), it->second.m_users.end(), [&] (IM::User& v_user_) { return v_user_.id() == user_id; }); if (user_it != it->second.m_users.end()) { user_it->set_id(user_.id()); user_it->set_name(user_.name()); user_it->set_nick_name(user_.nick_name()); user_it->set_sex(user_.sex()); return true; } else { // not find user id return false; } } else { // not find ch_id return false; } }
/* * ms_nick - server message handler for nicks * parv[0] = sender prefix * parv[1] = nickname * * If from server, source is client: * parv[2] = timestamp * * Source is server: * parv[2] = hopcount * parv[3] = timestamp * parv[4] = username * parv[5] = hostname * parv[6] = umode (optional) * parv[parc-3] = IP# <- Only Protocol >= 10 * parv[parc-2] = YXX, numeric nick <- Only Protocol >= 10 * parv[parc-1] = info * parv[0] = server */ int ms_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; char nick[NICKLEN + 2]; time_t lastnick = 0; int differ = 1; const char *type; assert(0 != cptr); assert(0 != sptr); assert(IsServer(cptr)); if ((IsServer(sptr) && parc < 8) || parc < 3) { sendto_opmask_butone(0, SNO_OLDSNO, "bad NICK param count for %s from %C", parv[1], cptr); return need_more_params(sptr, "NICK"); } ircd_strncpy(nick, parv[1], NICKLEN); nick[NICKLEN] = '\0'; if (IsServer(sptr)) { lastnick = atoi(parv[3]); if (lastnick > OLDEST_TS && !IsBurstOrBurstAck(sptr)) cli_serv(sptr)->lag = TStime() - lastnick; } else { lastnick = atoi(parv[2]); if (lastnick > OLDEST_TS && !IsBurstOrBurstAck(sptr)) cli_serv(cli_user(sptr)->server)->lag = TStime() - lastnick; } /* * If do_nick_name() returns a null name OR if the server sent a nick * name and do_nick_name() changed it in some way (due to rules of nick * creation) then reject it. If from a server and we reject it, * and KILL it. -avalon 4/4/92 */ if (!do_nick_name(nick) || strcmp(nick, parv[1])) { send_reply(sptr, ERR_ERRONEUSNICKNAME, parv[1]); ++ServerStats->is_kill; sendto_opmask_butone(0, SNO_OLDSNO, "Bad Nick: %s From: %s %C", parv[1], parv[0], cptr); sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (%s <- %s[%s])", IsServer(sptr) ? parv[parc - 2] : parv[0], cli_name(&me), parv[1], nick, cli_name(cptr)); if (!IsServer(sptr)) { /* * bad nick _change_ */ sendcmdto_serv_butone(&me, CMD_KILL, 0, "%s :%s (%s <- %s!%s@%s)", parv[0], cli_name(&me), cli_name(cptr), parv[0], cli_user(sptr) ? cli_username(sptr) : "", cli_user(sptr) ? cli_name(cli_user(sptr)->server) : cli_name(cptr)); } return 0; } /* Check against nick name collisions. */ if ((acptr = FindClient(nick)) == NULL) /* No collisions, all clear... */ return set_nick_name(cptr, sptr, nick, parc, parv); /* * If acptr == sptr, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch) */ if (acptr == sptr) { if (strcmp(cli_name(acptr), nick) != 0) /* Allows change of case in his/her nick */ return set_nick_name(cptr, sptr, nick, parc, parv); else /* Setting their nick to what it already is? Ignore it. */ return 0; } /* now we know we have a real collision. */ /* * Note: From this point forward it can be assumed that * acptr != sptr (point to different client structures). */ assert(acptr != sptr); /* * If the older one is "non-person", the new entry is just * allowed to overwrite it. Just silently drop non-person, * and proceed with the nick. This should take care of the * "dormant nick" way of generating collisions... */ if (IsUnknown(acptr) && MyConnect(acptr)) { ServerStats->is_ref++; IPcheck_connect_fail(acptr); exit_client(cptr, acptr, &me, "Overridden by other sign on"); return set_nick_name(cptr, sptr, nick, parc, parv); } /* * Decide, we really have a nick collision and deal with it */ /* * NICK was coming from a server connection. * This means we have a race condition (two users signing on * at the same time), or two net fragments reconnecting with the same nick. * The latter can happen because two different users connected * or because one and the same user switched server during a net break. * If the TimeStamps are equal, we kill both (or only 'new' * if it was a ":server NICK new ..."). * Otherwise we kill the youngest when user@host differ, * or the oldest when they are the same. * We treat user and ~user as different, because if it wasn't * a faked ~user the AUTH wouldn't have added the '~'. * --Run * */ if (IsServer(sptr)) { struct irc_in_addr ip; /* * A new NICK being introduced by a neighbouring * server (e.g. message type ":server NICK new ..." received) * * compare IP address and username */ base64toip(parv[parc - 3], &ip); differ = (0 != memcmp(&cli_ip(acptr), &ip, sizeof(cli_ip(acptr)))) || (0 != ircd_strcmp(cli_user(acptr)->username, parv[4])); sendto_opmask_butone(0, SNO_OLDSNO, "Nick collision on %C (%C %Tu <- " "%C %Tu (%s user@host))", acptr, cli_from(acptr), cli_lastnick(acptr), cptr, lastnick, differ ? "Different" : "Same"); } else { /* * A NICK change has collided (e.g. message type ":old NICK new"). * * compare IP address and username */ differ = (0 != memcmp(&cli_ip(acptr), &cli_ip(sptr), sizeof(cli_ip(acptr)))) || (0 != ircd_strcmp(cli_user(acptr)->username, cli_user(sptr)->username)); sendto_opmask_butone(0, SNO_OLDSNO, "Nick change collision from %C to " "%C (%C %Tu <- %C %Tu)", sptr, acptr, cli_from(acptr), cli_lastnick(acptr), cptr, lastnick); } type = differ ? "overruled by older nick" : "nick collision from same user@host"; /* * Now remove (kill) the nick on our side if it is the youngest. * If no timestamp was received, we ignore the incoming nick * (and expect a KILL for our legit nick soon ): * When the timestamps are equal we kill both nicks. --Run * acptr->from != cptr should *always* be true (?). * * This exits the client sending the NICK message */ if ((differ && lastnick >= cli_lastnick(acptr)) || (!differ && lastnick <= cli_lastnick(acptr))) { ServerStats->is_kill++; if (!IsServer(sptr)) { /* If this was a nick change and not a nick introduction, we * need to ensure that we remove our record of the client, and * send a KILL to the whole network. */ assert(!MyConnect(sptr)); /* Inform the rest of the net... */ sendcmdto_serv_butone(&me, CMD_KILL, 0, "%C :%s (%s)", sptr, cli_name(&me), type); /* Don't go sending off a QUIT message... */ SetFlag(sptr, FLAG_KILLED); /* Remove them locally. */ exit_client_msg(cptr, sptr, &me, "Killed (%s (%s))", feature_str(FEAT_HIS_SERVERNAME), type); } else { /* If the origin is a server, this was a new client, so we only * send the KILL in the direction it came from. We have no * client record that we would have to clean up. */ sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (%s)", parv[parc - 2], cli_name(&me), type); } /* If the timestamps differ and we just killed sptr, we don't need to kill * acptr as well. */ if (lastnick != cli_lastnick(acptr)) return 0; } /* Tell acptr why we are killing it. */ send_reply(acptr, ERR_NICKCOLLISION, nick); ServerStats->is_kill++; SetFlag(acptr, FLAG_KILLED); /* * This exits the client we had before getting the NICK message */ sendcmdto_serv_butone(&me, CMD_KILL, NULL, "%C :%s (%s)", acptr, feature_str(FEAT_HIS_SERVERNAME), type); exit_client_msg(cptr, acptr, &me, "Killed (%s (%s))", feature_str(FEAT_HIS_SERVERNAME), type); if (lastnick == cli_lastnick(acptr)) return 0; if (sptr == NULL) return 0; return set_nick_name(cptr, sptr, nick, parc, parv); }
/* * m_nick - message handler for local clients * parv[0] = sender prefix * parv[1] = nickname */ int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr; char nick[NICKLEN + 2]; char* arg; char* s; const char* client_name; assert(0 != cptr); assert(cptr == sptr); if (IsServerPort(cptr)) return exit_client(cptr, cptr, &me, "Use a different port"); /* * parv[0] will be empty for clients connecting for the first time */ client_name = (*(cli_name(sptr))) ? cli_name(sptr) : "*"; if (parc < 2) { send_reply(sptr, ERR_NONICKNAMEGIVEN); return 0; } /* * Don't let them send make us send back a really long string of * garbage */ arg = parv[1]; if (strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0'; if ((s = strchr(arg, '~'))) *s = '\0'; strcpy(nick, arg); /* * If do_nick_name() returns a null name then reject it. */ if (0 == do_nick_name(nick)) { send_reply(sptr, ERR_ERRONEUSNICKNAME, arg); return 0; } /* * Check if this is a LOCAL user trying to use a reserved (Juped) * nick, if so tell him that it's a nick in use... */ if (isNickJuped(nick)) { send_reply(sptr, ERR_NICKNAMEINUSE, nick); return 0; /* NICK message ignored */ } if (!(acptr = FindClient(nick))) { /* * No collisions, all clear... */ return set_nick_name(cptr, sptr, nick, parc, parv); } if (IsServer(acptr)) { send_reply(sptr, ERR_NICKNAMEINUSE, nick); return 0; /* NICK message ignored */ } /* * If acptr == sptr, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch) */ if (acptr == sptr) { /* * If acptr == sptr, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch) */ if (0 != strcmp(cli_name(acptr), nick)) { /* * Allows change of case in his/her nick */ return set_nick_name(cptr, sptr, nick, parc, parv); } /* * This is just ':old NICK old' type thing. * Just forget the whole thing here. There is * no point forwarding it to anywhere, * especially since servers prior to this * version would treat it as nick collision. */ return 0; } /* * Note: From this point forward it can be assumed that * acptr != sptr (point to different client structures). */ assert(acptr != sptr); /* * If the older one is "non-person", the new entry is just * allowed to overwrite it. Just silently drop non-person, * and proceed with the nick. This should take care of the * "dormant nick" way of generating collisions... * * XXX - hmmm can this happen after one is registered? * * Yes, client 1 connects to IRC and registers, client 2 connects and * sends "NICK foo" but doesn't send anything more. client 1 now does * /nick foo, they should succeed and client 2 gets disconnected with * the message below. */ if (IsUnknown(acptr) && MyConnect(acptr)) { ServerStats->is_ref++; IPcheck_connect_fail(acptr); exit_client(cptr, acptr, &me, "Overridden by other sign on"); return set_nick_name(cptr, sptr, nick, parc, parv); } /* * NICK is coming from local client connection. Just * send error reply and ignore the command. */ send_reply(sptr, ERR_NICKNAMEINUSE, nick); return 0; /* NICK message ignored */ }
/* * ms_nick - server message handler for nicks * parv[0] = sender prefix * parv[1] = nickname * * If from server, source is client: * parv[2] = timestamp * * Source is server: * parv[2] = hopcount * parv[3] = timestamp * parv[4] = username * parv[5] = hostname * parv[6] = umode (optional) * parv[parc-3] = IP# <- Only Protocol >= 10 * parv[parc-2] = YXX, numeric nick <- Only Protocol >= 10 * parv[parc-1] = info * parv[0] = server */ int ms_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr; char nick[NICKLEN + 2]; time_t lastnick = 0; int differ = 1; int samelastnick = 0; assert(0 != cptr); assert(0 != sptr); assert(IsServer(cptr)); if ((IsServer(sptr) && parc < 8) || parc < 3) { sendto_opmask_butone(0, SNO_OLDSNO, "bad NICK param count for %s from %C", parv[1], cptr); return need_more_params(sptr, "NICK"); } ircd_strncpy(nick, parv[1], NICKLEN); nick[NICKLEN] = '\0'; if (IsServer(sptr)) { lastnick = atoi(parv[3]); if (lastnick > OLDEST_TS && !IsBurstOrBurstAck(sptr)) cli_serv(sptr)->lag = TStime() - lastnick; } else { lastnick = atoi(parv[2]); if (lastnick > OLDEST_TS && !IsBurstOrBurstAck(sptr)) cli_serv(cli_user(sptr)->server)->lag = TStime() - lastnick; } /* * If do_nick_name() returns a null name OR if the server sent a nick * name and do_nick_name() changed it in some way (due to rules of nick * creation) then reject it. If from a server and we reject it, * and KILL it. -avalon 4/4/92 */ if (0 == do_nick_name(nick) || 0 != strcmp(nick, parv[1])) { send_reply(sptr, ERR_ERRONEUSNICKNAME, parv[1]); ++ServerStats->is_kill; sendto_opmask_butone(0, SNO_OLDSNO, "Bad Nick: %s From: %s %C", parv[1], parv[0], cptr); sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (%s <- %s[%s])", IsServer(sptr) ? parv[parc - 2] : parv[0], cli_name(&me), parv[1], nick, cli_name(cptr)); if (!IsServer(sptr)) { /* * bad nick _change_ */ sendcmdto_serv_butone(&me, CMD_KILL, 0, "%s :%s (%s <- %s!%s@%s)", parv[0], cli_name(&me), cli_name(cptr), parv[0], cli_user(sptr) ? cli_username(sptr) : "", cli_user(sptr) ? cli_name(cli_user(sptr)->server) : cli_name(cptr)); } return 0; } /* * Check against nick name collisions. * * Put this 'if' here so that the nesting goes nicely on the screen :) * We check against server name list before determining if the nickname * is present in the nicklist (due to the way the below for loop is * constructed). -avalon */ assert(NULL == strchr(nick,'.')); acptr = FindClient(nick); if (!acptr) { /* * No collisions, all clear... */ return set_nick_name(cptr, sptr, nick, parc, parv); } assert(0 != acptr); /* * If acptr == sptr, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch) */ if (acptr == sptr) { if (strcmp(cli_name(acptr), nick) == 0) /* * This is just ':old NICK old' type thing. * Just forget the whole thing here. There is * no point forwarding it to anywhere, * especially since servers prior to this * version would treat it as nick collision. */ return 0; /* NICK Message ignored */ else /* * Allows change of case in his/her nick */ return set_nick_name(cptr, sptr, nick, parc, parv); } /* * Note: From this point forward it can be assumed that * acptr != sptr (point to different client structures). */ assert(acptr != sptr); /* * If the older one is "non-person", the new entry is just * allowed to overwrite it. Just silently drop non-person, * and proceed with the nick. This should take care of the * "dormant nick" way of generating collisions... */ if (IsUnknown(acptr) && MyConnect(acptr)) { ++ServerStats->is_ref; IPcheck_connect_fail(cli_ip(acptr)); exit_client(cptr, acptr, &me, "Overridden by other sign on"); return set_nick_name(cptr, sptr, nick, parc, parv); } /* * Decide, we really have a nick collision and deal with it */ /* * NICK was coming from a server connection. * This means we have a race condition (two users signing on * at the same time), or two net fragments reconnecting with the same nick. * The latter can happen because two different users connected * or because one and the same user switched server during a net break. * If the TimeStamps are equal, we kill both (or only 'new' * if it was a ":server NICK new ..."). * Otherwise we kill the youngest when user@host differ, * or the oldest when they are the same. * We treat user and ~user as different, because if it wasn't * a faked ~user the AUTH wouldn't have added the '~'. * --Run * */ if (IsServer(sptr)) { /* * A new NICK being introduced by a neighbouring * server (e.g. message type ":server NICK new ..." received) * * compare IP address and username */ differ = (cli_ip(acptr).s_addr != htonl(base64toint(parv[parc - 3]))) || (0 != ircd_strcmp(cli_user(acptr)->username, parv[4])); sendto_opmask_butone(0, SNO_OLDSNO, "Nick collision on %C (%C %Tu <- " "%C %Tu (%s user@host))", acptr, cli_from(acptr), cli_lastnick(acptr), cptr, lastnick, differ ? "Different" : "Same"); } else { /* * A NICK change has collided (e.g. message type ":old NICK new"). * * compare IP address and username */ differ = (cli_ip(acptr).s_addr != cli_ip(sptr).s_addr) || (0 != ircd_strcmp(cli_user(acptr)->username, cli_user(sptr)->username)); sendto_opmask_butone(0, SNO_OLDSNO, "Nick change collision from %C to " "%C (%C %Tu <- %C %Tu)", sptr, acptr, cli_from(acptr), cli_lastnick(acptr), cptr, lastnick); } /* * Now remove (kill) the nick on our side if it is the youngest. * If no timestamp was received, we ignore the incoming nick * (and expect a KILL for our legit nick soon ): * When the timestamps are equal we kill both nicks. --Run * acptr->from != cptr should *always* be true (?). * * This exits the client sending the NICK message */ if (cli_from(acptr) != cptr) { if ((differ && lastnick >= cli_lastnick(acptr)) || (!differ && lastnick <= cli_lastnick(acptr))) { if (!IsServer(sptr)) { ++ServerStats->is_kill; sendcmdto_serv_butone(&me, CMD_KILL, NULL, "%C :%s (Nick collision)", sptr, cli_name(&me)); assert(!MyConnect(sptr)); SetFlag(sptr, FLAG_KILLED); exit_client_msg(cptr, sptr, &me, "Killed (%s (Nick collision))", feature_str(FEAT_HIS_SERVERNAME)); sptr = 0; /* Make sure we don't use the dead client */ } else { /* We need to kill this incoming client, which hasn't been properly registered yet. * Send a KILL message upstream to the server it came from */ sendcmdto_one(&me, CMD_KILL, sptr, "%s :%s (Nick collision)", parv[parc-2], cli_name(&me)); } /* If the two have the same TS then we want to kill both sides, so * don't leave yet! */ if (lastnick != cli_lastnick(acptr)) return 0; /* Ignore the NICK */ } send_reply(acptr, ERR_NICKCOLLISION, nick); } ++ServerStats->is_kill; SetFlag(acptr, FLAG_KILLED); if (lastnick == cli_lastnick(acptr)) samelastnick = 1; /* * This exits the client we had before getting the NICK message */ if (differ) { sendcmdto_serv_butone(&me, CMD_KILL, NULL, "%C :%s (older nick " "overruled)", acptr, cli_name(&me)); if (MyConnect(acptr)) { sendcmdto_one(acptr, CMD_QUIT, cptr, ":Killed (%s (older " "nick overruled))", feature_str(FEAT_HIS_SERVERNAME)); sendcmdto_one(&me, CMD_KILL, acptr, "%C :%s (older nick " "overruled)", acptr, feature_str(FEAT_HIS_SERVERNAME)); } exit_client_msg(cptr, acptr, &me, "Killed (%s (older nick " "overruled))", feature_str(FEAT_HIS_SERVERNAME)); } else { sendcmdto_serv_butone(&me, CMD_KILL, NULL, "%C :%s (nick collision from " "same user@host)", acptr, cli_name(&me)); if (MyConnect(acptr)) { sendcmdto_one(acptr, CMD_QUIT, cptr, ":Killed (%s (nick " "collision from same user@host))", feature_str(FEAT_HIS_SERVERNAME)); sendcmdto_one(&me, CMD_KILL, acptr, "%C :%s (older nick " "overruled)", acptr, feature_str(FEAT_HIS_SERVERNAME)); } exit_client_msg(cptr, acptr, &me, "Killed (%s (nick collision from " "same user@host))", feature_str(FEAT_HIS_SERVERNAME)); } if (samelastnick) return 0; assert(0 != sptr); return set_nick_name(cptr, sptr, nick, parc, parv); }
/* * ms_svsnick - server message handler * parv[0] = sender prefix * parv[1] = Target numeric * parv[2] = New nickname */ int ms_svsnick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr = NULL; struct Client* acptr2 = NULL; char nick[NICKLEN + 2]; char* arg; if (parc < 3) return need_more_params(sptr, "SVSNICK"); if (!(acptr = findNUser(parv[1]))) return 0; /* Ignore SVSNICK for a user that has quit */ if (ircd_strcmp(cli_name(acptr), parv[2]) == 0) return 0; /* Nick already set to what SVSNICK wants, ignoring... */ /* * Basic sanity checks */ /* * Don't let them make us send back a really long string of * garbage */ arg = parv[2]; if (strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0'; strcpy(nick, arg); /* * If do_nick_name() returns a null name then reject it. */ if (0 == do_nick_name(nick)) return 0; /* * Check if this is a LOCAL user trying to use a reserved (Juped) * nick, if so tell him that it's a nick in use... */ if (isNickJuped(nick)) return 0; /* NICK message ignored */ if (feature_bool(FEAT_OPER_SINGLELETTERNICK) && !IsAnOper(acptr) && nick[1] == '\0') return 0; /* * Set acptr2 to the client pointer of any user with nick's name. * If the user is the same as the person being svsnick'ed, let it * through as it is probably a change in the nickname's case. */ if ((acptr2 = FindClient(nick))) { /* * If acptr == acptr2, then we have a client doing a nick * change between *equivalent* nicknames as far as server * is concerned (user is changing the case of his/her * nickname or somesuch), so we let it through :) */ if (acptr != acptr2) { /* Nick collision occured, kill user with specific reason */ ++ServerStats->is_kill; /* ??? - Why do we use cptr here? */ SetFlag(cptr, FLAG_KILLED); exit_client(cptr, acptr2, &me, "Killed (Nickname Enforcement)"); } } set_nick_name(acptr, acptr, nick, parc, parv, 1); sendcmdto_serv_butone(sptr, CMD_SVSNICK, cptr, "%s %s", parv[1], nick); return 0; }