/*! \brief NICK command handler (called by unregistered, * locally connected clients) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \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] = sender prefix * - parv[1] = nickname */ static void mr_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; char nick[NICKLEN]; char *s = NULL; if (parc < 2 || EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, EmptyString(parv[0]) ? "*" : parv[0]); return; } /* Terminate the nick at the first ~ */ if ((s = strchr(parv[1], '~')) != NULL) *s = '\0'; /* copy the nick and terminate it */ strlcpy(nick, parv[1], sizeof(nick)); /* check the nickname is ok */ if (!clean_nick_name(nick, 1)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, EmptyString(parv[0]) ? "*" : parv[0], parv[1]); return; } /* check if the nick is resv'd */ if (find_matching_name_conf(NRESV_TYPE, nick, NULL, NULL, 0) && !IsExemptResv(source_p)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, EmptyString(parv[0]) ? "*" : parv[0], nick); return; } if ((target_p = find_client(nick)) == NULL) set_initial_nick(source_p, nick); else if (source_p == target_p) strlcpy(source_p->name, nick, sizeof(source_p->name)); else sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick); }
/*! \brief NICK command handler (called by already registered, * locally connected clients) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \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] = sender prefix * - parv[1] = nickname */ static void m_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char nick[NICKLEN + 1] = { '\0' }; struct Client *target_p = NULL; struct MaskItem *conf = NULL; assert(source_p == client_p); if (parc < 2 || EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name); return; } /* mark end of grace period, to prevent nickflooding */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); /* terminate nick to NICKLEN */ strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ServerInfo.max_nick_length + 1)); /* check the nickname is ok */ if (!valid_nickname(nick, 1)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick, "Erroneous Nickname"); return; } if (!IsExemptResv(source_p) && !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv) && (conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0))) { ++conf->count; sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick, conf->reason); sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE, "Forbidding reserved nick [%s] from user %s", nick, get_client_name(client_p, HIDE_IP)); return; } if ((target_p = hash_find_client(nick)) == NULL) change_local_nick(source_p, nick); else if (target_p == source_p) { /* * If (target_p == source_p) the client is changing nicks between * equivalent nicknames ie: [nick] -> {nick} */ /* Check the nick isn't exactly the same */ if (strcmp(target_p->name, nick)) change_local_nick(source_p, nick); } else if (IsUnknown(target_p)) { /* * If the client that has the nick isn't registered yet (nick but no * user) then drop the unregged client */ exit_client(target_p, &me, "Overridden"); change_local_nick(source_p, nick); } else sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, source_p->name, nick); }
/*! \brief NICK command handler (called by already registered, * locally connected clients) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \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] = sender prefix * - parv[1] = nickname */ static void m_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char nick[NICKLEN]; struct Client *target_p = NULL; if (parc < 2 || EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name); return; } /* mark end of grace period, to prevent nickflooding */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); /* terminate nick to NICKLEN */ strlcpy(nick, parv[1], sizeof(nick)); /* check the nickname is ok */ if (!clean_nick_name(nick, 1)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick); return; } if (find_matching_name_conf(NRESV_TYPE, nick, NULL, NULL, 0) && !IsExemptResv(source_p) && !(IsOper(source_p) && ConfigFileEntry.oper_pass_resv)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick); return; } if ((target_p = find_client(nick)) == NULL) change_local_nick(client_p, source_p, nick); else if (target_p == source_p) { /* * If (target_p == source_p) the client is changing nicks between * equivalent nicknames ie: [nick] -> {nick} */ /* check the nick isnt exactly the same */ if (strcmp(target_p->name, nick)) change_local_nick(client_p, source_p, nick); } else if (IsUnknown(target_p)) { /* * if the client that has the nick isn't registered yet (nick but no * user) then drop the unregged client */ exit_client(target_p, &me, "Overridden"); change_local_nick(client_p, source_p, nick); } else sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, source_p->name, nick); }
/* Join a channel, ignoring forwards, +ib, etc. It notifes source_p of any errors joining * NB: this assumes a local user. */ void user_join_override(struct Client * client_p, struct Client * source_p, struct Client * target_p, const char * channels) { static char jbuf[BUFSIZE]; struct ConfItem *aconf; struct Channel *chptr = NULL; char *name; const char *modes; char *p = NULL; int flags; char *chanlist; jbuf[0] = '\0'; if(channels == NULL) return; /* rebuild the list of channels theyre supposed to be joining. */ chanlist = LOCAL_COPY(channels); for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p)) { /* check the length and name of channel is ok */ if(!check_channel_name_loc(target_p, name) || (strlen(name) > LOC_CHANNELLEN)) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), (unsigned char *) name); continue; } /* join 0 parts all channels */ if(*name == '0' && (name[1] == ',' || name[1] == '\0') && name == chanlist) { (void) strcpy(jbuf, "0"); continue; } /* check it begins with # or & */ else if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); continue; } /* see if its resv'd */ if(!IsExemptResv(target_p) && (aconf = hash_find_resv(name))) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), name); /* dont update tracking for jupe exempt users, these * are likely to be spamtrap leaves */ if(IsExemptJupe(source_p)) aconf->port--; continue; } if(splitmode && !IsOper(target_p) && (*name != '&') && ConfigChannel.no_join_on_split) { sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE), me.name, source_p->name, name); continue; } if(*jbuf) (void) strcat(jbuf, ","); (void) rb_strlcat(jbuf, name, sizeof(jbuf)); } for(name = rb_strtok_r(jbuf, ",", &p); name; name = rb_strtok_r(NULL, ",", &p)) { /* JOIN 0 simply parts all channels the user is in */ if(*name == '0' && !atoi(name)) { if(target_p->user->channel.head == NULL) continue; do_join_0(&me, target_p); continue; } if((chptr = find_channel(name)) != NULL) { if(IsMember(target_p, chptr)) { /* debugging is fun... */ sendto_one_notice(source_p, ":*** Notice -- %s is already in %s", target_p->name, chptr->chname); return; } add_user_to_channel(chptr, target_p, CHFL_PEON); if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time) { chptr->join_count = 0; chptr->join_delta = rb_current_time(); } chptr->join_count++; sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); sendto_server(target_p, chptr, CAP_TS6, NOCAPS, ":%s JOIN %ld %s +", get_id(target_p, client_p), (long) chptr->channelts, chptr->chname); del_invite(chptr, target_p); if(chptr->topic != NULL) { sendto_one(target_p, form_str(RPL_TOPIC), me.name, target_p->name, chptr->chname, chptr->topic); sendto_one(target_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } channel_member_names(chptr, target_p, 1); } else { hook_data_channel_activity hook_info; char statusmodes[5] = ""; if(!check_channel_name(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) name); return; } /* channel name must begin with & or # */ if(!IsChannelName(name)) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, (unsigned char *) name); return; } /* name can't be longer than CHANNELLEN */ if(strlen(name) > CHANNELLEN) { sendto_one_notice(source_p, ":Channel name is too long"); return; } chptr = get_or_create_channel(target_p, name, NULL); flags = CHFL_CHANOP; add_user_to_channel(chptr, target_p, flags); if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time) { chptr->join_count = 0; chptr->join_delta = rb_current_time(); } chptr->join_count++; sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; modes = channel_modes(chptr, &me); sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s", me.name, chptr->chname, modes); strcat(statusmodes, "@"); sendto_server(target_p, chptr, CAP_TS6, NOCAPS, ":%s SJOIN %ld %s %s :%s%s", me.id, (long) chptr->channelts, chptr->chname, modes, statusmodes, get_id(target_p, client_p)); target_p->localClient->last_join_time = rb_current_time(); channel_member_names(chptr, target_p, 1); /* Call channel join hooks */ hook_info.client = source_p; hook_info.chptr = chptr; hook_info.key = chptr->mode.key; call_hook(h_channel_join, &hook_info); /* we do this to let the oper know that a channel was created, this will be * seen from the server handling the command instead of the server that * the oper is on. */ sendto_one_notice(source_p, ":*** Notice -- Creating channel %s", chptr->chname); } } return; }