/* ** m_part ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = reason */ static void m_part(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *p = NULL, *name = NULL; char reason[KICKLEN + 1] = { '\0' }; if (IsServer(source_p)) return; if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "PART"); return; } if (parc > 2 && !EmptyString(parv[2])) strlcpy(reason, parv[2], sizeof(reason)); /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); for (name = strtoken(&p, parv[1], ","); name; name = strtoken(&p, NULL, ",")) part_one_client(source_p, name, reason); }
/* * inputs - flag privmsg or notice * - pointer to command "PRIVMSG" or "NOTICE" * - pointer to client_p * - pointer to source_p * - pointer to channel */ static void m_message(int p_or_n, char *command, struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { int i; if (parc < 2 || *parv[1] == '\0') { if (p_or_n != NOTICE) sendto_one(source_p, form_str(source_p,ERR_NORECIPIENT), me.name, source_p->name, command); return; } if (parc < 3 || *parv[2] == '\0') { if (p_or_n != NOTICE) sendto_one(source_p, form_str(source_p,ERR_NOTEXTTOSEND), me.name, source_p->name); return; } /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (build_target_list(p_or_n, command, client_p, source_p, parv[1], parv[2]) < 0) { /* Sigh. We need to relay this command to the hub */ if (!ServerInfo.hub && (uplink != NULL)) sendto_one(uplink, ":%s %s %s :%s", source_p->name, command, parv[1], parv[2]); return; } for (i = 0; i < ntargets; i++) { switch (targets[i].type) { case ENTITY_CHANNEL: msg_channel(p_or_n, command, client_p, source_p, (struct Channel *)targets[i].ptr, parv[2]); break; case ENTITY_CHANOPS_ON_CHANNEL: msg_channel_flags(p_or_n, command, client_p, source_p, (struct Channel *)targets[i].ptr, targets[i].flags, parv[2]); break; case ENTITY_CLIENT: msg_client(p_or_n, command, source_p, (struct Client *)targets[i].ptr, parv[2]); break; } } }
/* ** m_part ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = reason */ static int m_part(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char *p, *name; char reason[REASONLEN + 1]; char *s = LOCAL_COPY(parv[1]); reason[0] = '\0'; if(parc > 2) strlcpy(reason, parv[2], sizeof(reason)); name = strtoken(&p, s, ","); /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); while (name) { part_one_client(client_p, source_p, name, reason); name = strtoken(&p, NULL, ","); } return 0; }
/* ** m_away ** parv[1] = away message */ static int m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(MyClient(source_p) && source_p->localClient->next_away && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; if(parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if(source_p->user->away != NULL) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); free_away(source_p); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, NOCAPS, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_UNAWAY, form_str(RPL_UNAWAY)); return 0; } /* Rate limit this because it is sent to common channels. */ if (MyClient(source_p)) { if(!IsOper(source_p) && source_p->localClient->next_away > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "AWAY"); return 0; } if(source_p->localClient->next_away < rb_current_time() - ConfigFileEntry.away_interval) source_p->localClient->next_away = rb_current_time(); else source_p->localClient->next_away = rb_current_time() + ConfigFileEntry.away_interval; } if(source_p->user->away == NULL) allocate_away(source_p); if(strncmp(source_p->user->away, parv[1], AWAYLEN - 1)) { rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), source_p->user->away); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_NOWAWAY, form_str(RPL_NOWAWAY)); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, NOCAPS, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->user->away); return 0; }
static void do_join_0(struct Client *client_p, struct Client *source_p) { struct Channel *chptr=NULL; dlink_node *lp; /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s JOIN 0", source_p->name); if (source_p->user->channel.head && MyConnect(source_p) && !IsOper(source_p)) check_spambot_warning(source_p, NULL); while ((lp = source_p->user->channel.head)) { chptr = lp->data; sendto_channel_local(ALL_MEMBERS,chptr, ":%s!%s@%s PART %s", source_p->name, source_p->username, source_p->host, chptr->chname); remove_user_from_channel(chptr, source_p); } }
/* ** m_part ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = reason */ static void m_part(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *p, *name; char reason[TOPICLEN + 1]; if(EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PART"); return; } reason[0] = '\0'; if(parc > 2) strlcpy(reason, parv[2], sizeof(reason)); name = strtoken(&p, parv[1], ","); /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); while (name) { part_one_client(client_p, source_p, name, reason); name = strtoken(&p, (char *) NULL, ","); } return; }
static void mo_away(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *cur_away_msg = source_p->user->away; char *new_away_msg; size_t nbytes = 0; if (!IsFloodDone(source_p)) flood_endgrace(source_p); if (parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if (cur_away_msg) { /* we now send this only if they were away before --is */ sendto_server(client_p, source_p, NULL, CAP_TS6, NOCAPS, NOFLAGS, ":%s AWAY", ID(source_p)); sendto_server(client_p, source_p, NULL, NOCAPS, CAP_TS6, NOFLAGS, ":%s AWAY", source_p->name); MyFree(cur_away_msg); source_p->user->away = NULL; } sendto_one(source_p, form_str(RPL_UNAWAY), me.name, parv[0]); return; } source_p->user->last_away = CurrentTime; new_away_msg = parv[1]; nbytes = strlen(new_away_msg); if (nbytes > (size_t)TOPICLEN) { new_away_msg[TOPICLEN] = '\0'; nbytes = TOPICLEN; } /* we now send this only if they * weren't away already --is */ if (!cur_away_msg) { sendto_server(client_p, source_p, NULL, CAP_TS6, NOCAPS, NOFLAGS, ":%s AWAY :%s", ID(source_p), new_away_msg); sendto_server(client_p, source_p, NULL, NOCAPS, CAP_TS6, NOFLAGS, ":%s AWAY :%s", source_p->name, new_away_msg); } else MyFree(cur_away_msg); cur_away_msg = MyMalloc(nbytes + 1); strcpy(cur_away_msg, new_away_msg); source_p->user->away = cur_away_msg; sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, parv[0]); }
static int m_cycle(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char *p, *name; char *s = LOCAL_COPY(parv[1]); struct Channel *chptr; struct membership *msptr; name = rb_strtok_r(s, ",", &p); /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); while(name) { if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(MyConnect(source_p) && !IsOper(source_p) && !IsExemptSpambot(source_p)) check_spambot_warning(source_p, NULL); if((is_any_op(msptr) || !MyConnect(source_p) || ((can_send(chptr, source_p, msptr) > 0 && (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) < rb_current_time())))) { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s :Cycling", use_id(source_p), chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :Cycling", source_p->name, source_p->username, source_p->host, chptr->chname); } else { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s", use_id(source_p), chptr->chname); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s", source_p->name, source_p->username, source_p->host, chptr->chname); } remove_user_from_channel(msptr); chptr = NULL; msptr = NULL; name = rb_strtok_r(NULL, ",", &p); } user_join(client_p, source_p, parv[1], parc > 2 ? parv[2] : NULL); return 0; }
/*! \brief MODE 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] = channel or nick name * - parv[2] = modes to be added or removed */ static int m_mode(struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; if (EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "MODE"); return 0; } /* Now, try to find the channel in question */ if (!IsChanPrefix(*parv[1])) { /* If here, it has to be a non-channel name */ set_user_mode(source_p, parc, parv); return 0; } if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]); return 0; } /* Now known the channel exists */ if (parc < 3) { char modebuf[MODEBUFLEN] = ""; char parabuf[MODEBUFLEN] = ""; channel_modes(chptr, source_p, modebuf, parabuf); sendto_one_numeric(source_p, &me, RPL_CHANNELMODEIS, chptr->name, modebuf, parabuf); sendto_one_numeric(source_p, &me, RPL_CREATIONTIME, chptr->name, chptr->creationtime); return 0; } /* * bounce all modes from people we deop on sjoin * servers have always gotten away with murder, * including telnet servers *g* - Dianora */ if (IsServer(source_p) || HasFlag(source_p, FLAGS_SERVICE)) set_channel_mode(source_p, chptr, NULL, parc - 2, parv + 2); else { struct Membership *member = find_channel_link(source_p, chptr); /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0'))) flood_endgrace(source_p); set_channel_mode(source_p, chptr, member, parc - 2, parv + 2); } return 0; }
/* ** m_oper ** parv[0] = sender prefix ** parv[1] = oper name ** parv[2] = oper password */ static void m_oper(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct ConfItem *conf; struct AccessItem *aconf=NULL; const char *name = parv[1]; const char *password = parv[2]; if (EmptyString(password)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "OPER"); return; } /* end the grace period */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); if ((conf = find_password_conf(name,source_p)) == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); conf = find_exact_name_conf(OPER_TYPE, name, NULL, NULL); failed_oper_notice(source_p, name, (conf != NULL) ? "host mismatch" : "no oper {} block"); log_failed_oper(source_p, name); return; } aconf = (struct AccessItem *)map_to_conf(conf); if (match_oper_password(password, aconf)) { if (attach_conf(source_p, conf) != 0) { sendto_one(source_p, ":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); failed_oper_notice(source_p, name, "can't attach conf!"); log_failed_oper(source_p, name); return; } oper_up(source_p); ilog(L_TRACE, "OPER %s by %s!%s@%s", name, source_p->name, source_p->username, source_p->host); log_oper(source_p, name); } else { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, parv[0]); failed_oper_notice(source_p, name, "password mismatch"); log_failed_oper(source_p, name); } }
/* * m_time * parv[1] = servername */ static void m_time(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { /* this is not rate limited, so end the grace period */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(hunt_server(client_p, source_p, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME) sendto_one_numeric(source_p, RPL_TIME, form_str(RPL_TIME), me.name, date()); }
/* * 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); }
/* ** m_oper ** parv[0] = sender prefix ** parv[1] = oper name ** parv[2] = oper password */ static void m_oper(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct MaskItem *conf = NULL; const char *name = parv[1]; const char *password = parv[2]; if (EmptyString(password)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "OPER"); return; } /* end the grace period */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); if ((conf = find_exact_name_conf(CONF_OPER, source_p, name, NULL, NULL)) == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); conf = find_exact_name_conf(CONF_OPER, NULL, name, NULL, NULL); failed_oper_notice(source_p, name, (conf != NULL) ? "host mismatch" : "no oper {} block"); return; } if (match_conf_password(password, conf)) { if (attach_conf(source_p, conf) != 0) { sendto_one(source_p, ":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); failed_oper_notice(source_p, name, "can't attach conf!"); return; } ++conf->count; oper_up(source_p); ilog(LOG_TYPE_OPER, "OPER %s by %s!%s@%s", name, source_p->name, source_p->username, source_p->host); } else { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); failed_oper_notice(source_p, name, "password mismatch"); } }
/*! \brief TIME 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/servername */ static int m_time(struct Client *source_p, int parc, char *parv[]) { /* This is not rate limited, so end the grace period */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); /* This is safe enough to use during non hidden server mode */ if (!ConfigServerHide.disable_remote_commands) if (hunt_server(source_p, ":%s TIME :%s", 1, parc, parv) != HUNTED_ISME) return 0; sendto_one_numeric(source_p, &me, RPL_TIME, me.name, date(0)); return 0; }
/* * m_time * parv[0] = sender prefix * parv[1] = servername */ static int m_time(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { /* this is not rate limited, so end the grace period */ char buf[80]; if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (hunt_server(client_p, source_p, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME) { sendto_one_numeric(source_p, RPL_TIME, form_str(RPL_TIME), me.name, rb_date(rb_current_time(), buf, sizeof(buf))); } return 0; }
/*! \brief PART 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] = channel name * - parv[2] = part message */ static int m_part(struct Client *source_p, int parc, char *parv[]) { if (EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "PART"); return 0; } /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); channel_do_part(source_p, parv[1], parv[2]); return 0; }
/* * m_time * parv[0] = sender prefix * parv[1] = servername */ static void m_time(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { /* this is not rate limited, so end the grace period */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); /* This is safe enough to use during non hidden server mode */ if(!ConfigServerHide.disable_remote) { if (hunt_server(client_p,source_p,":%s TIME :%s",1,parc,parv) != HUNTED_ISME) return; } sendto_one(source_p, form_str(RPL_TIME), me.name, parv[0], me.name, date(0)); }
/* handle_command() * * inputs - pointer to message block * - pointer to client * - pointer to client message is from * - count of number of args * - pointer to argv[] array * output - -1 if error from server * side effects - */ static void parse_handle_command(struct Message *message, struct Client *source_p, unsigned int i, char *para[]) { if (IsServer(source_p->from)) ++message->rcount; ++message->count; if (MyClient(source_p) && (message->flags & MFLG_ENDGRACE)) flood_endgrace(source_p); /* Check right amount of parameters is passed... --is */ if (i < message->args_min) sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, message->cmd); else message->handlers[source_p->from->handler](source_p, i, para); }
/* ** m_away ** parv[0] = sender prefix ** parv[1] = away message */ static int m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; if(parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if(source_p->user->away != NULL) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s AWAY", source_p->name); free_away(source_p); } if(MyConnect(source_p)) sendto_one(source_p, form_str(RPL_UNAWAY), me.name, source_p->name); return 0; } if(source_p->user->away == NULL) { allocate_away(source_p); rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), source_p->user->away); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s AWAY :%s", source_p->name, source_p->user->away); } else { rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); } if(MyConnect(source_p)) sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, source_p->name); return 0; }
/* ** m_away ** parv[1] = away message */ static int m_away(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; if(parc < 2 || EmptyString(parv[1])) { /* Marking as not away */ if(source_p->user->away != NULL) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); free_away(source_p); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, NOCAPS, ":%s!%s@%s AWAY", source_p->name, source_p->username, source_p->host); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_UNAWAY, form_str(RPL_UNAWAY)); return 0; } if(source_p->user->away == NULL) allocate_away(source_p); if(strncmp(source_p->user->away, parv[1], AWAYLEN - 1)) { rb_strlcpy(source_p->user->away, parv[1], AWAYLEN); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), source_p->user->away); } if(MyConnect(source_p)) sendto_one_numeric(source_p, RPL_NOWAWAY, form_str(RPL_NOWAWAY)); sendto_common_channels_local_butone(source_p, CLICAP_AWAY_NOTIFY, NOCAPS, ":%s!%s@%s AWAY :%s", source_p->name, source_p->username, source_p->host, source_p->user->away); return 0; }
/* * inputs - flag privmsg or notice * - pointer to command "PRIVMSG" or "NOTICE" * - pointer to source_p * - pointer to channel */ static void m_message(int p_or_n, const char *command, struct Client *source_p, int parc, char *parv[]) { if (parc < 2 || EmptyString(parv[1])) { if (p_or_n != NOTICE) sendto_one_numeric(source_p, &me, ERR_NORECIPIENT, command); return; } if (parc < 3 || EmptyString(parv[2])) { if (p_or_n != NOTICE) sendto_one_numeric(source_p, &me, ERR_NOTEXTTOSEND); return; } /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (build_target_list(p_or_n, command, source_p, parv[1], parv[2]) < 0) return; for (unsigned int i = 0; i < ntargets; ++i) { switch (targets[i].type) { case ENTITY_CLIENT: msg_client(p_or_n, command, source_p, targets[i].ptr, parv[2]); break; case ENTITY_CHANNEL: msg_channel(p_or_n, command, source_p, targets[i].ptr, parv[2]); break; case ENTITY_CHANOPS_ON_CHANNEL: msg_channel_flags(p_or_n, command, source_p, targets[i].ptr, targets[i].flags, parv[2]); break; } } }
/* ** m_part ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = reason */ static int m_part(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { char *p, *name; char *reason = NULL; char *s = LOCAL_COPY(parv[1]); if(parc > 2) reason = LOCAL_COPY_N(parv[2], REASONLEN); name = rb_strtok_r(s, ",", &p); /* Finish the flood grace period... */ if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); while(name) { part_one_client(client_p, source_p, name, reason); name = rb_strtok_r(NULL, ",", &p); } return 0; }
/* * m_topic * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static int m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char *p = NULL; if((p = strchr(parv[1], ','))) *p = '\0'; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsChannelName(parv[1])) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } chptr = find_channel(parv[1]); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } /* setting topic */ if(parc > 2) { msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), parv[1]); return 0; } if((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chanop(msptr) || !MyClient(source_p)) { char topic_info[USERHOST_REPLYLEN]; ircsprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_server(client_p, chptr, NOCAPS, CAP_TS6, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, parv[1]); } else if(MyClient(source_p)) { if(!IsMember(source_p, chptr) && SecretChannel(chptr)) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), parv[1]); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, parv[1]); else { sendto_one(source_p, form_str(RPL_TOPIC), me.name, source_p->name, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time); } } return 0; }
static int m_remove(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct membership *msptr; struct Client *who; struct Channel *chptr; int chasing = 0; char *comment; const char *name; char *p = NULL; const char *user; static char buf[BUFSIZE]; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); *buf = '\0'; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if(!IsServer(source_p)) { msptr = find_channel_membership(chptr, source_p); if((msptr == NULL) && MyConnect(source_p)) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(get_channel_access(source_p, msptr, MODE_ADD) < CHFL_CHANOP) { if(MyConnect(source_p)) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, name); return 0; } /* If its a TS 0 channel, do it the old way */ if(chptr->channelts == 0) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); return 0; } } /* Its a user doing a kick, but is not showing as chanop locally * its also not a user ON -my- server, and the channel has a TS. * There are two cases we can get to this point then... * * 1) connect burst is happening, and for some reason a legit * op has sent a KICK, but the SJOIN hasn't happened yet or * been seen. (who knows.. due to lag...) * * 2) The channel is desynced. That can STILL happen with TS * * Now, the old code roger wrote, would allow the KICK to * go through. Thats quite legit, but lets weird things like * KICKS by users who appear not to be chanopped happen, * or even neater, they appear not to be on the channel. * This fits every definition of a desync, doesn't it? ;-) * So I will allow the KICK, otherwise, things are MUCH worse. * But I will warn it as a possible desync. * * -Dianora */ } if((p = strchr(parv[2], ','))) *p = '\0'; user = parv[2]; /* strtoken(&p2, parv[2], ","); */ if(!(who = find_chasing(source_p, user, &chasing))) { return 0; } msptr = find_channel_membership(chptr, who); if(msptr != NULL) { if(MyClient(source_p) && IsService(who)) { sendto_one(source_p, form_str(ERR_ISCHANSERVICE), me.name, source_p->name, who->name, chptr->chname); return 0; } if(MyClient(source_p)) { hook_data_channel_approval hookdata; hookdata.client = source_p; hookdata.chptr = chptr; hookdata.msptr = msptr; hookdata.target = who; hookdata.approved = 1; hookdata.dir = MODE_ADD; /* ensure modules like override speak up */ call_hook(h_can_kick, &hookdata); if (!hookdata.approved) return 0; } comment = LOCAL_COPY((EmptyString(parv[3])) ? who->name : parv[3]); if(strlen(comment) > (size_t) REASONLEN) comment[REASONLEN] = '\0'; /* jdc * - In the case of a server kicking a user (i.e. CLEARCHAN), * the kick should show up as coming from the server which did * the kick. * - Personally, flame and I believe that server kicks shouldn't * be sent anyways. Just waiting for some oper to abuse it... */ sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :requested by %s (%s)", who->name, who->username, who->host, name, source_p->name, comment); sendto_server(client_p, chptr, CAP_REMOVE, NOCAPS, ":%s REMOVE %s %s :%s", use_id(source_p), chptr->chname, use_id(who), comment); sendto_server(client_p, chptr, NOCAPS, CAP_REMOVE, ":%s KICK %s %s :%s", use_id(source_p), chptr->chname, use_id(who), comment); remove_user_from_channel(msptr); } else if (MyClient(source_p)) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), user, name); return 0; }
/* ** m_kick ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = client to kick ** parv[3] = kick comment */ static int m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct membership *msptr; struct Client *who; struct Channel *chptr; int chasing = 0; int halfop = 0; char *comment; const char *name; char *p = NULL; const char *user; static char buf[BUFSIZE]; if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); *buf = '\0'; if ((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; chptr = find_channel(name); if (chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if (!IsServer(source_p)) { msptr = find_channel_membership(chptr, source_p); if ((msptr == NULL) && MyConnect(source_p)) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if (!is_chanop(msptr) && !is_halfop(msptr)) { if (MyConnect(source_p)) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, name); return 0; } /* If its a TS 0 channel, do it the old way */ if (chptr->channelts == 0) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); return 0; } } halfop = !is_chanop(msptr) && is_halfop(msptr); /* Its a user doing a kick, but is not showing as chanop locally * its also not a user ON -my- server, and the channel has a TS. * There are two cases we can get to this point then... * * 1) connect burst is happening, and for some reason a legit * op has sent a KICK, but the SJOIN hasn't happened yet or * been seen. (who knows.. due to lag...) * * 2) The channel is desynced. That can STILL happen with TS * * Now, the old code roger wrote, would allow the KICK to * go through. Thats quite legit, but lets weird things like * KICKS by users who appear not to be chanopped happen, * or even neater, they appear not to be on the channel. * This fits every definition of a desync, doesn't it? ;-) * So I will allow the KICK, otherwise, things are MUCH worse. * But I will warn it as a possible desync. * * -Dianora */ } if ((p = strchr(parv[2], ','))) *p = '\0'; user = parv[2]; if (!(who = find_chasing(source_p, user, &chasing))) { return 0; } msptr = find_channel_membership(chptr, who); if (msptr != NULL) { if (MyClient(source_p) && IsService(who)) { sendto_one(source_p, form_str(ERR_ISCHANSERVICE), me.name, source_p->name, who->name, chptr->chname); return 0; } if (halfop && (is_chanop(msptr) || is_halfop(msptr))) { if (MyConnect(source_p)) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, name); return 0; } /* If its a TS 0 channel, do it the old way */ if (chptr->channelts == 0) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); return 0; } } comment = LOCAL_COPY_N((EmptyString(parv[3])) ? who->name : parv[3], REASONLEN); /* jdc * - In the case of a server kicking a user (i.e. CLEARCHAN), * the kick should show up as coming from the server which did * the kick. * - Personally, flame and I believe that server kicks shouldn't * be sent anyways. Just waiting for some oper to abuse it... */ if (IsServer(source_p)) sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s", source_p->name, name, who->name, comment); else sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s KICK %s %s :%s", source_p->name, source_p->username, IsCloaked(source_p) ? source_p->virthost : source_p->host, name, who->name, comment); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s KICK %s %s :%s", use_id(source_p), chptr->chname, use_id(who), comment); sendto_server(client_p, chptr, NOCAPS, CAP_TS6, ":%s KICK %s %s :%s", source_p->name, chptr->chname, who->name, comment); remove_user_from_channel(msptr); } else if (MyClient(source_p)) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), user, name); return 0; }
/*! \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); }
/* ** m_invite ** parv[0] - sender prefix ** parv[1] - user to invite ** parv[2] - channel name ** parv[3] - invite timestamp */ static void m_invite(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; struct Channel *chptr = NULL; struct Membership *ms = NULL; if (IsServer(source_p)) return; if (EmptyString(parv[2])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "INVITE"); return; } if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if ((target_p = find_person(client_p, parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return; } /* Do not send local channel invites to users if they are not on the * same server as the person sending the INVITE message. */ /* Possibly should be an error sent to source_p */ /* done .. there should be no problem because MyConnect(source_p) should * always be true if parse() and such is working correctly --is */ if (!MyConnect(target_p) && (*parv[2] == '&')) { if (ConfigServerHide.hide_servers == 0) sendto_one(source_p, form_str(ERR_USERNOTONSERV), me.name, source_p->name, target_p->name); return; } if ((chptr = hash_find_channel(parv[2])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, parv[2]); return; } if (MyConnect(source_p) && (ms = find_channel_link(source_p, chptr)) == NULL) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, chptr->chname); return; } if (MyConnect(source_p) && !has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP)) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, chptr->chname); return; } if ((chptr->mode.mode & MODE_OPERONLY)) { if (MyConnect(source_p) && !IsOper(source_p)) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, chptr->chname); return; } } if (IsMember(target_p, chptr)) { sendto_one(source_p, form_str(ERR_USERONCHANNEL), me.name, source_p->name, target_p->name, chptr->chname); return; } if (MyConnect(source_p)) { sendto_one(source_p, form_str(RPL_INVITING), me.name, source_p->name, target_p->name, chptr->chname); if (target_p->away) sendto_one(source_p, form_str(RPL_AWAY), me.name, source_p->name, target_p->name, target_p->away); } else if (parc > 3 && IsDigit(*parv[3])) if (atoi(parv[3]) > chptr->channelts) return; if (MyConnect(target_p)) { sendto_one(target_p, ":%s!%s@%s INVITE %s :%s", source_p->name, source_p->username, source_p->host, target_p->name, chptr->chname); if (chptr->mode.mode & MODE_INVITEONLY) { sendto_channel_local(CHFL_CHANOP|CHFL_HALFOP, 0, chptr, ":%s NOTICE %s :%s is inviting %s to %s.", me.name, chptr->chname, source_p->name, target_p->name, chptr->chname); sendto_channel_remote(source_p, client_p, CHFL_CHANOP|CHFL_HALFOP, NOCAPS, NOCAPS, chptr, ":%s NOTICE %s :%s is inviting %s to %s.", source_p->name, chptr->chname, source_p->name, target_p->name, chptr->chname); /* Add the invite if channel is +i */ add_invite(chptr, target_p); } } else if (target_p->from != client_p) sendto_one(target_p, ":%s INVITE %s %s %lu", ID_or_name(source_p, target_p->from), ID_or_name(target_p, target_p->from), chptr->chname, (unsigned long)chptr->channelts); }
/* ** m_oper ** parv[0] = sender prefix ** parv[1] = oper name ** parv[2] = oper password */ static void m_oper(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct ConfItem *aconf; struct ConfItem *oconf = NULL; char *name; char *password; dlink_node *ptr; name = parv[1]; password = parv[2]; if(EmptyString(password)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "OPER"); return; } /* end the grace period */ if(!IsFloodDone(source_p)) flood_endgrace(source_p); if((aconf = find_password_aconf(name, source_p)) == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); log_foper(source_p, name); if(ConfigFileEntry.failed_oper_notice) { sendto_realops_flags(UMODE_ALL, L_ALL, "Failed OPER attempt - host mismatch by %s (%s@%s)", source_p->name, source_p->username, source_p->host); } return; } if(match_oper_password(password, aconf)) { /* 20001216: detach old iline -einride */ ptr = source_p->localClient->confs.head; if(ptr) { oconf = ptr->data; detach_conf(source_p, oconf); } if(attach_conf(source_p, aconf) != 0) { sendto_one(source_p, ":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); sendto_realops_flags(UMODE_ALL, L_ALL, "Failed OPER attempt by %s (%s@%s) can't attach conf!", source_p->name, source_p->username, source_p->host); log_foper(source_p, name); /* 20001216: Reattach old iline -einride */ attach_conf(source_p, oconf); return; } oper_up(source_p, aconf); ilog(L_TRACE, "OPER %s by %s!%s@%s", name, source_p->name, source_p->username, source_p->host); log_oper(source_p, name); return; } else { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, parv[0]); log_foper(source_p, name); if(ConfigFileEntry.failed_oper_notice) { sendto_realops_flags(UMODE_ALL, L_ALL, "Failed OPER attempt by %s (%s@%s)", source_p->name, source_p->username, source_p->host); } } }
/* ** 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[]) { char *away, *awy2 = parv[1]; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return; away = source_p->user->away; if(parc < 2 || !*awy2) { /* Marking as not away */ if(away) { /* we now send this only if they were away before --is */ sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s AWAY", source_p->name); MyFree(away); source_p->user->away = NULL; } if(MyConnect(source_p)) sendto_one(source_p, form_str(RPL_UNAWAY), me.name, parv[0]); return; } /* Marking as away */ if(MyConnect(source_p) && !IsOper(source_p) && (CurrentTime - source_p->user->last_away) < ConfigFileEntry.pace_wait) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, parv[0], "AWAY"); return; } source_p->user->last_away = CurrentTime; if(strlen(awy2) > (size_t) TOPICLEN) awy2[TOPICLEN] = '\0'; /* we now send this only if they weren't away already --is */ if(!away) { sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s AWAY :%s", source_p->name, awy2); } else MyFree(away); away = (char *) MyMalloc(strlen(awy2) + 1); strcpy(away, awy2); source_p->user->away = away; if(MyConnect(source_p)) sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, parv[0]); }
/* * m_mode - MODE command handler * parv[0] - sender * parv[1] - channel */ static void m_mode(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; struct Membership *member; static char modebuf[MODEBUFLEN]; static char parabuf[MODEBUFLEN]; if (parv[1][0] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE"); return; } /* Now, try to find the channel in question */ if (!IsChanPrefix(parv[1][0])) { /* if here, it has to be a non-channel name */ set_user_mode(client_p, source_p, parc, parv); return; } if (!check_channel_name(parv[1])) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, parv[1]); return; } chptr = hash_find_channel(parv[1]); if (chptr == NULL) { /* if chptr isn't found locally, it =could= exist * on the uplink. So ask. */ /* LazyLinks */ /* only send a mode upstream if a local client sent this request * -davidt */ if (MyClient(source_p) && !ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL)) { sendto_one(uplink, ":%s MODE %s %s", ID_or_name(source_p, uplink), parv[1], (parv[2] ? parv[2] : "")); return; } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); return; } } /* Now known the channel exists */ if (parc < 3) { channel_modes(chptr, source_p, modebuf, parabuf); sendto_one(source_p, form_str(RPL_CHANNELMODEIS), me.name, parv[0], parv[1], modebuf, parabuf); sendto_one(source_p, form_str(RPL_CREATIONTIME), me.name, parv[0], parv[1], chptr->channelts); } /* bounce all modes from people we deop on sjoin * servers have always gotten away with murder, * including telnet servers *g* - Dianora * * XXX Is it worth the bother to make an ms_mode() ? - Dianora */ else if (IsServer(source_p)) { set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2, chptr->chname); } else { member = find_channel_link(source_p, chptr); if (!has_member_flags(member, CHFL_DEOPPED)) { /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) { if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0'))) flood_endgrace(source_p); } set_channel_mode(client_p, source_p, chptr, member, parc - 2, parv + 2, chptr->chname); } } }