/*! \brief AWAY command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = away message */ static int ms_away(struct Client *source_p, int parc, char *parv[]) { const char *const message = parv[1]; if (EmptyString(message)) { /* Marking as not away */ if (source_p->away[0]) { source_p->away[0] = '\0'; /* We now send this only if they were away before --is */ sendto_server(source_p, 0, 0, ":%s AWAY", source_p->id); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } return 0; } strlcpy(source_p->away, message, sizeof(source_p->away)); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->away); sendto_server(source_p, 0, 0, ":%s AWAY :%s", source_p->id, source_p->away); return 0; }
/* * m_away * parv[0] = sender prefix * parv[1] = away message */ static void m_away(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { if (!IsFloodDone(source_p)) flood_endgrace(source_p); if (parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if (source_p->away[0]) { source_p->away[0] = '\0'; /* we now send this only if they were away before --is */ sendto_server(client_p, CAP_TS6, NOCAPS, ":%s AWAY", ID(source_p)); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s AWAY", source_p->name); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } sendto_one(source_p, form_str(RPL_UNAWAY), me.name, source_p->name); return; } if ((CurrentTime - source_p->localClient->last_away) < ConfigFileEntry.pace_wait) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name); return; } source_p->localClient->last_away = CurrentTime; sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, source_p->name); if (!strncmp(source_p->away, parv[1], sizeof(source_p->away) - 1)) return; strlcpy(source_p->away, parv[1], sizeof(source_p->away)); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->away); sendto_server(client_p, CAP_TS6, NOCAPS, ":%s AWAY :%s", ID(source_p), source_p->away); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s AWAY :%s", source_p->name, source_p->away); }
/*! * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * * - parv[0] = command * - parv[1] = nickname * - parv[2] = timestamp */ static void change_remote_nick(struct Client *source_p, char *parv[]) { int samenick = !irccmp(source_p->name, parv[1]); assert(!EmptyString(parv[1])); assert(IsClient(source_p)); assert(source_p->name[0]); /* Client changing their nick */ if (!samenick) { DelUMode(source_p, UMODE_REGISTERED); watch_check_hash(source_p, RPL_LOGOFF); source_p->tsinfo = atol(parv[2]); assert(source_p->tsinfo > 0); } sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, parv[1]); whowas_add_history(source_p, 1); sendto_server(source_p, 0, 0, ":%s NICK %s :%lu", source_p->id, parv[1], (unsigned long)source_p->tsinfo); /* Set the new nick name */ hash_del_client(source_p); strlcpy(source_p->name, parv[1], sizeof(source_p->name)); hash_add_client(source_p); if (!samenick) watch_check_hash(source_p, RPL_LOGON); }
/*! \brief AWAY command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = away message */ static int m_away(struct Client *source_p, int parc, char *parv[]) { const char *const message = parv[1]; if (EmptyString(message)) { /* Marking as not away */ if (source_p->away[0]) { source_p->away[0] = '\0'; /* We now send this only if they were away before --is */ sendto_server(source_p, 0, 0, ":%s AWAY", source_p->id); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } sendto_one_numeric(source_p, &me, RPL_UNAWAY); return 0; } if ((source_p->connection->away.last_attempt + ConfigGeneral.away_time) < CurrentTime) source_p->connection->away.count = 0; if (source_p->connection->away.count > ConfigGeneral.away_count) { sendto_one_numeric(source_p, &me, ERR_TOOMANYAWAY); return 0; } source_p->connection->away.last_attempt = CurrentTime; source_p->connection->away.count++; strlcpy(source_p->away, message, sizeof(source_p->away)); sendto_one_numeric(source_p, &me, RPL_NOWAWAY); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->away); sendto_server(source_p, 0, 0, ":%s AWAY :%s", source_p->id, source_p->away); return 0; }
static void ms_away(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { if (parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if (source_p->away[0]) { source_p->away[0] = '\0'; /* we now send this only if they were away before --is */ sendto_server(client_p, CAP_TS6, NOCAPS, ":%s AWAY", ID(source_p)); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s AWAY", source_p->name); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } return; } if (!strncmp(source_p->away, parv[1], sizeof(source_p->away) - 1)) return; strlcpy(source_p->away, parv[1], sizeof(source_p->away)); sendto_common_channels_local(source_p, 1, CAP_AWAY_NOTIFY, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->away); sendto_server(client_p, CAP_TS6, NOCAPS, ":%s AWAY :%s", ID(source_p), source_p->away); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s AWAY :%s", source_p->name, source_p->away); }
static int change_nick(struct Client *client_p, const char *newnick) { char note[NICKLEN + 10]; client_p->tsinfo = rb_current_time(); monitor_signoff(client_p); invalidate_bancache_user(client_p); sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Forced nick change: From %s to %s [%s@%s]", client_p->name, newnick, client_p->username, client_p->host); sendto_common_channels_local(client_p, NOCAPS, ":%s!%s@%s NICK :%s", client_p->name, client_p->username, client_p->host, newnick); add_history(client_p, 1); sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld", use_id(client_p), newnick, (long) client_p->tsinfo); del_from_client_hash(client_p->name, client_p); strcpy(client_p->name, newnick); add_to_client_hash(client_p->name, client_p); monitor_signon(client_p); del_all_accepts(client_p); rb_snprintf(note, NICKLEN + 10, "Nick: %s", client_p->name); rb_note(client_p->localClient->F, note); return 0; }
/* * nick_from_server() */ static void nick_from_server(struct Client *client_p, struct Client *source_p, int parc, char *parv[], time_t newts, const char *svsid, char *nick, char *ngecos) { int samenick = 0; if (IsServer(source_p)) { /* A server introducing a new client, change source */ source_p = make_client(client_p); dlinkAdd(source_p, &source_p->node, &global_client_list); if (parc > 2) source_p->hopcount = atoi(parv[2]); if (newts) source_p->tsinfo = newts; else { newts = source_p->tsinfo = CurrentTime; ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]); } strlcpy(source_p->svid, svsid, sizeof(source_p->svid)); strlcpy(source_p->info, ngecos, sizeof(source_p->info)); /* copy the nick in place */ strlcpy(source_p->name, nick, sizeof(source_p->name)); hash_add_client(source_p); if (parc > 8) { const char *m; /* parse usermodes */ for (m = &parv[4][1]; *m; ++m) { unsigned int flag = user_modes[(unsigned char)*m]; if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE)) ++Count.invisi; if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER)) ++Count.oper; source_p->umodes |= flag & SEND_UMODES; } register_remote_user(source_p, parv[5], parv[6], parv[7], ngecos); return; } } else if (source_p->name[0]) { samenick = !irccmp(source_p->name, nick); /* Client changing their nick */ if (!samenick) { DelUMode(source_p, UMODE_REGISTERED); watch_check_hash(source_p, RPL_LOGOFF); source_p->tsinfo = newts ? newts : CurrentTime; } sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s", source_p->name,source_p->username, source_p->host, nick); add_history(source_p, 1); sendto_server(client_p, CAP_TS6, NOCAPS, ":%s NICK %s :%lu", ID(source_p), nick, (unsigned long)source_p->tsinfo); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s NICK %s :%lu", source_p->name, nick, (unsigned long)source_p->tsinfo); } /* set the new nick name */ if (source_p->name[0]) hash_del_client(source_p); strlcpy(source_p->name, nick, sizeof(source_p->name)); hash_add_client(source_p); if (!samenick) watch_check_hash(source_p, RPL_LOGON); }
/* change_local_nick() * * inputs - pointer to server * - pointer to client * - nick * output - * side effects - changes nick of a LOCAL user */ static void change_local_nick(struct Client *source_p, const char *nick) { assert(source_p->name[0] && !EmptyString(nick)); assert(MyConnect(source_p)); /* * Client just changing his/her nick. If he/she is * on a channel, send note of change to all clients * on that channel. Propagate notice to other servers. */ if ((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < CurrentTime) source_p->localClient->number_of_nick_changes = 0; source_p->localClient->last_nick_change = CurrentTime; source_p->localClient->number_of_nick_changes++; if ((ConfigFileEntry.anti_nick_flood && (source_p->localClient->number_of_nick_changes <= ConfigFileEntry.max_nick_changes)) || !ConfigFileEntry.anti_nick_flood || (HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.no_oper_flood)) { int samenick = !irccmp(source_p->name, nick); if (!samenick) { source_p->tsinfo = CurrentTime; clear_ban_cache_client(source_p); watch_check_hash(source_p, RPL_LOGOFF); if (HasUMode(source_p, UMODE_REGISTERED)) { unsigned int oldmodes = source_p->umodes; char modebuf[IRCD_BUFSIZE] = { '\0' }; DelUMode(source_p, UMODE_REGISTERED); send_umode(source_p, source_p, oldmodes, 0xffffffff, modebuf); } } sendto_realops_flags(UMODE_NCHANGE, L_ALL, SEND_NOTICE, "Nick change: From %s to %s [%s@%s]", source_p->name, nick, source_p->username, source_p->host); sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); add_history(source_p, 1); sendto_server(source_p, CAP_TS6, NOCAPS, ":%s NICK %s :%lu", ID(source_p), nick, (unsigned long)source_p->tsinfo); sendto_server(source_p, NOCAPS, CAP_TS6, ":%s NICK %s :%lu", source_p->name, nick, (unsigned long)source_p->tsinfo); hash_del_client(source_p); strlcpy(source_p->name, nick, sizeof(source_p->name)); hash_add_client(source_p); if (!samenick) watch_check_hash(source_p, RPL_LOGON); /* fd_desc is long enough */ fd_note(&source_p->localClient->fd, "Nick: %s", nick); } else sendto_one(source_p, form_str(ERR_NICKTOOFAST), me.name, source_p->name, source_p->name, nick, ConfigFileEntry.max_nick_time); }
/* change_local_nick() * * inputs - pointer to server * - pointer to client * - nick * output - * side effects - changes nick of a LOCAL user */ static void change_local_nick(struct Client *source_p, const char *nick) { int samenick = 0; assert(source_p->name[0] && !EmptyString(nick)); assert(MyClient(source_p)); /* * Client just changing his/her nick. If he/she is * on a channel, send note of change to all clients * on that channel. Propagate notice to other servers. */ if ((source_p->connection->nick.last_attempt + ConfigGeneral.max_nick_time) < CurrentTime) source_p->connection->nick.count = 0; if (ConfigGeneral.anti_nick_flood && !HasUMode(source_p, UMODE_OPER) && source_p->connection->nick.count > ConfigGeneral.max_nick_changes) { sendto_one_numeric(source_p, &me, ERR_NICKTOOFAST, nick, ConfigGeneral.max_nick_time); return; } source_p->connection->nick.last_attempt = CurrentTime; source_p->connection->nick.count++; samenick = !irccmp(source_p->name, nick); if (!samenick) { source_p->tsinfo = CurrentTime; clear_ban_cache_client(source_p); watch_check_hash(source_p, RPL_LOGOFF); if (HasUMode(source_p, UMODE_REGISTERED)) { unsigned int oldmodes = source_p->umodes; char modebuf[IRCD_BUFSIZE] = ""; DelUMode(source_p, UMODE_REGISTERED); send_umode(source_p, source_p, oldmodes, modebuf); } } sendto_realops_flags(UMODE_NCHANGE, L_ALL, SEND_NOTICE, "Nick change: From %s to %s [%s@%s]", source_p->name, nick, source_p->username, source_p->host); sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); whowas_add_history(source_p, 1); sendto_server(source_p, 0, 0, ":%s NICK %s :%lu", source_p->id, nick, (unsigned long)source_p->tsinfo); hash_del_client(source_p); strlcpy(source_p->name, nick, sizeof(source_p->name)); hash_add_client(source_p); if (!samenick) watch_check_hash(source_p, RPL_LOGON); /* fd_desc is long enough */ fd_note(&source_p->connection->fd, "Nick: %s", source_p->name); }
/*! \brief SVSMODE command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = nickname * - parv[2] = TS * - parv[3] = mode * - parv[4] = optional argument (services account, vhost) */ static int ms_svsmode(struct Client *source_p, int parc, char *parv[]) { const struct user_modes *tab = NULL; struct Client *target_p = NULL; int what = MODE_ADD; unsigned int setmodes = 0; const char *modes = NULL, *extarg = NULL; time_t ts = 0; if (!HasFlag(source_p, FLAGS_SERVICE)) return 0; modes = parv[3]; extarg = (parc > 4) ? parv[4] : NULL; if ((target_p = find_person(source_p, parv[1])) == NULL) return 0; ts = atol(parv[2]); if (ts && (ts != target_p->tsinfo)) return 0; setmodes = target_p->umodes; for (const char *m = modes; *m; ++m) { switch (*m) { case '+': what = MODE_ADD; break; case '-': what = MODE_DEL; break; case 'd': if (!EmptyString(extarg)) { strlcpy(target_p->account, extarg, sizeof(target_p->account)); sendto_common_channels_local(target_p, 1, CAP_ACCOUNT_NOTIFY, ":%s!%s@%s ACCOUNT %s", target_p->name, target_p->username, target_p->host, target_p->account); } break; case 'x': if (!EmptyString(extarg) && valid_hostname(extarg)) user_set_hostmask(target_p, extarg, what); break; case 'o': if (what == MODE_DEL && HasUMode(target_p, UMODE_OPER)) { ClearOper(target_p); --Count.oper; if (MyConnect(target_p)) { dlink_node *node = NULL; detach_conf(target_p, CONF_OPER); ClrOFlag(target_p); DelUMode(target_p, ConfigGeneral.oper_only_umodes); if ((node = dlinkFindDelete(&oper_list, target_p))) free_dlink_node(node); } } break; case 'i': if (what == MODE_ADD && !HasUMode(target_p, UMODE_INVISIBLE)) { AddUMode(target_p, UMODE_INVISIBLE); ++Count.invisi; } if (what == MODE_DEL && HasUMode(target_p, UMODE_INVISIBLE)) { DelUMode(target_p, UMODE_INVISIBLE); --Count.invisi; } break; case 'S': /* Only servers may set +S in a burst */ case 'W': /* Only servers may set +W in a burst */ break; default: if ((tab = umode_map[(unsigned char)*m])) { if (what == MODE_ADD) AddUMode(target_p, tab->flag); else DelUMode(target_p, tab->flag); } break; } } if (extarg) sendto_server(source_p, 0, 0, ":%s SVSMODE %s %lu %s %s", source_p->id, target_p->id, (unsigned long)target_p->tsinfo, modes, extarg); else sendto_server(source_p, 0, 0, ":%s SVSMODE %s %lu %s", source_p->id, target_p->id, (unsigned long)target_p->tsinfo, modes); if (MyConnect(target_p) && (setmodes != target_p->umodes)) { char modebuf[IRCD_BUFSIZE] = ""; send_umode(target_p, target_p, setmodes, modebuf); } return 0; }
/* ** Exit one client, local or remote. Assuming all dependents have ** been already removed, and socket closed for local client. */ static void exit_one_client(struct Client *client_p, struct Client *source_p, struct Client *from, const char *comment) { struct Client* target_p; dlink_node *lp; dlink_node *next_lp; if (IsServer(source_p)) { if (source_p->servptr && source_p->servptr->serv) del_client_from_llist(&(source_p->servptr->serv->servers), source_p); else ts_warn("server %s without servptr!", source_p->name); if(!IsMe(source_p)) remove_server_from_list(source_p); } else if (source_p->servptr && source_p->servptr->serv) { del_client_from_llist(&(source_p->servptr->serv->users), source_p); } /* there are clients w/o a servptr: unregistered ones */ /* ** For a server or user quitting, propogate the information to ** other servers (except to the one where is came from (client_p)) */ if (IsMe(source_p)) { sendto_realops_flags(FLAGS_ALL, L_ALL, "ERROR: tried to exit me! : %s", comment); return; /* ...must *never* exit self!! */ } else if (IsServer(source_p)) { /* ** Old sendto_serv_but_one() call removed because we now ** need to send different names to different servers ** (domain name matching) */ /* ** The bulk of this is done in remove_dependents now, all ** we have left to do is send the SQUIT upstream. -orabidoo */ if (source_p->localClient) { if(source_p->localClient->ctrlfd > -1) { fd_close(source_p->localClient->ctrlfd); source_p->localClient->ctrlfd = -1; #ifndef HAVE_SOCKETPAIR fd_close(source_p->localClient->ctrlfd_r); fd_close(source_p->localClient->fd_r); source_p->localClient->ctrlfd_r = -1; source_p->localClient->fd_r = -1; #endif } } target_p = source_p->from; if (target_p && IsServer(target_p) && target_p != client_p && !IsMe(target_p) && (source_p->flags & FLAGS_KILLED) == 0) sendto_one(target_p, ":%s SQUIT %s :%s", from->name, source_p->name, comment); } else if (source_p->name[0]) /* ...just clean all others with QUIT... */ { /* ** If this exit is generated from "m_kill", then there ** is no sense in sending the QUIT--KILL's have been ** sent instead. */ if ((source_p->flags & FLAGS_KILLED) == 0) { sendto_server(client_p, source_p, NULL, NOCAPS, NOCAPS, NOFLAGS, ":%s QUIT :%s", source_p->name, comment); } /* ** If a person is on a channel, send a QUIT notice ** to every client (person) on the same channel (so ** that the client can show the "**signoff" message). ** (Note: The notice is to the local clients *only*) */ if (source_p->user) { sendto_common_channels_local(source_p, ":%s!%s@%s QUIT :%s", source_p->name, source_p->username, source_p->host, comment); for (lp = source_p->user->channel.head; lp; lp = next_lp) { next_lp = lp->next; remove_user_from_channel(lp->data, source_p); } /* Should not be in any channels now */ assert(source_p->user->channel.head == NULL); /* Clean up invitefield */ for (lp = source_p->user->invited.head; lp; lp = next_lp) { next_lp = lp->next; del_invite(lp->data, source_p); } /* Clean up allow lists */ del_all_accepts(source_p); add_history(source_p, 0); off_history(source_p); if (HasID(source_p)) del_from_id_hash_table(source_p->user->id, source_p); /* again, this is all that is needed */ } } /* * Remove source_p from the client lists */ del_from_client_hash_table(source_p->name, source_p); /* remove from global client list */ remove_client_from_list(source_p); /* Check to see if the client isn't already on the dead list */ assert(dlinkFind(&dead_list, source_p) == NULL); /* add to dead client dlist */ lp = make_dlink_node(); SetDead(source_p); dlinkAdd(source_p, lp, &dead_list); }
/* * change_local_nick * inputs - pointer to server * - pointer to client * output - * side effects - changes nick of a LOCAL user * */ int change_local_nick(struct Client *client_p, struct Client *source_p, char *nick) { /* ** Client just changing his/her nick. If he/she is ** on a channel, send note of change to all clients ** on that channel. Propagate notice to other servers. */ source_p->tsinfo = CurrentTime; if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < CurrentTime) source_p->localClient->number_of_nick_changes = 0; source_p->localClient->last_nick_change = CurrentTime; source_p->localClient->number_of_nick_changes++; if((ConfigFileEntry.anti_nick_flood && (source_p->localClient->number_of_nick_changes <= ConfigFileEntry.max_nick_changes)) || !ConfigFileEntry.anti_nick_flood || (IsOper(source_p) && ConfigFileEntry.no_oper_flood)) { sendto_realops_flags(FLAGS_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]", source_p->name, nick, source_p->username, source_p->host); sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); if (source_p->user) { add_history(source_p, 1); /* Only hubs care about lazy link nicks not being sent on yet * lazylink leafs/leafs always send their nicks up to hub, * hence must always propogate nick changes. * hubs might not propogate a nick change, if the leaf * does not know about that client yet. */ sendto_server(client_p, source_p, NULL, NOCAPS, NOCAPS, NOFLAGS, ":%s NICK %s :%lu", source_p->name, nick, (unsigned long) source_p->tsinfo); } } else { sendto_one(source_p, form_str(ERR_NICKTOOFAST),me.name, source_p->name, source_p->name, nick, ConfigFileEntry.max_nick_time); return 0; } /* Finally, add to hash */ del_from_client_hash_table(source_p->name, source_p); strcpy(source_p->name, nick); add_to_client_hash_table(nick, source_p); /* Make sure everyone that has this client on its accept list * loses that reference. */ del_all_accepts(source_p); /* fd_desc is long enough */ fd_note(client_p->localClient->fd, "Nick: %s", nick); return 1; }
/*! \brief SVSNICK command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = old nickname * - parv[2] = new nickname * - parv[3] = timestamp */ static int ms_svsnick(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL, *exists_p = NULL; if (!HasFlag(source_p, FLAGS_SERVICE) || !valid_nickname(parv[2], 1)) return 0; if ((target_p = find_person(source_p, parv[1])) == NULL) return 0; if (!MyConnect(target_p)) { if (target_p->from == source_p->from) { sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE, "Received wrong-direction SVSNICK " "for %s (behind %s) from %s", target_p->name, source_p->from->name, get_client_name(source_p, HIDE_IP)); return 0; } sendto_one(target_p, ":%s SVSNICK %s %s %s", source_p->id, target_p->id, parv[2], parv[3]); return 0; } if ((exists_p = hash_find_client(parv[2]))) { if (target_p == exists_p) { if (!strcmp(target_p->name, parv[2])) return 0; } else if (IsUnknown(exists_p)) exit_client(exists_p, "SVSNICK Override"); else { exit_client(target_p, "SVSNICK Collide"); return 0; } } target_p->tsinfo = strtoimax(parv[3], NULL, 10); clear_ban_cache_client(target_p); watch_check_hash(target_p, RPL_LOGOFF); if (HasUMode(target_p, UMODE_REGISTERED)) { const unsigned int oldmodes = target_p->umodes; char modebuf[IRCD_BUFSIZE] = ""; DelUMode(target_p, UMODE_REGISTERED); send_umode(target_p, target_p, oldmodes, modebuf); } sendto_common_channels_local(target_p, 1, 0, 0, ":%s!%s@%s NICK :%s", target_p->name, target_p->username, target_p->host, parv[2]); whowas_add_history(target_p, 1); sendto_server(NULL, 0, 0, ":%s NICK %s :%ju", target_p->id, parv[2], target_p->tsinfo); hash_del_client(target_p); strlcpy(target_p->name, parv[2], sizeof(target_p->name)); hash_add_client(target_p); watch_check_hash(target_p, RPL_LOGON); fd_note(&target_p->connection->fd, "Nick: %s", target_p->name); return 0; }
/* * nick_from_server() */ static int nick_from_server(struct Client *client_p, struct Client *source_p, int parc, char *parv[], time_t newts, char *nick) { if(IsServer(source_p)) { /* A server introducing a new client, change source */ source_p = make_client(client_p); add_client_to_list(source_p); if(parc > 2) source_p->hopcount = atoi(parv[2]); if(newts) source_p->tsinfo = newts; else { newts = source_p->tsinfo = CurrentTime; ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]); } /* copy the nick in place */ (void) strcpy(source_p->name, nick); (void) add_to_client_hash_table(nick, source_p); if(parc > 8) { int flag; char *m; /* parse usermodes */ m = &parv[4][1]; while (*m) { flag = user_modes_from_c_to_bitmask[(unsigned char) *m]; if(!(source_p->umodes & UMODE_INVISIBLE) && (flag & UMODE_INVISIBLE)) Count.invisi++; if(!(source_p->umodes & UMODE_OPER) && (flag & UMODE_OPER)) Count.oper++; source_p->umodes |= flag & SEND_UMODES; m++; } return do_remote_user(nick, client_p, source_p, parv[5], parv[6], parv[7], (parc > 9)? parv[8] : NULL, parv[(parc > 9)? 9 : 8]); } } else if(source_p->name[0]) { /* client changing their nick */ if(irccmp(parv[0], nick)) source_p->tsinfo = newts ? newts : CurrentTime; sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); if(source_p->user) { add_history(source_p, 1); sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s NICK %s :%lu", parv[0], nick, (unsigned long) source_p->tsinfo); } } /* set the new nick name */ if(source_p->name[0]) del_from_client_hash_table(source_p->name, source_p); strcpy(source_p->name, nick); add_to_client_hash_table(nick, source_p); /* remove all accepts pointing to the client */ del_all_accepts(source_p); return 0; }