/* ** 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; }
/* Disable this because of the abuse potential -- jilles * No, make it toggleable via ./configure. --nenolod */ static int mo_chghost(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } if (!(target_p = find_named_person(parv[1]))) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]); return 0; } if (!clean_host(parv[2])) { sendto_one_notice(source_p, ":Hostname %s is invalid", parv[2]); return 0; } do_chghost(source_p, target_p, parv[2], 0); sendto_server(NULL, NULL, CAP_EUID | CAP_TS6, NOCAPS, ":%s CHGHOST %s %s", use_id(source_p), use_id(target_p), parv[2]); sendto_server(NULL, NULL, CAP_TS6, CAP_EUID, ":%s ENCAP * CHGHOST %s :%s", use_id(source_p), use_id(target_p), parv[2]); return 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; }
/* * part_one_client * * inputs - pointer to server * - pointer to source client to remove * - char pointer of name of channel to remove from * output - none * side effects - remove ONE client given the channel name */ static void part_one_client(struct Client *client_p, struct Client *source_p, char *name, char *reason) { struct Channel *chptr; struct membership *msptr; if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return; } msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return; } if(MyConnect(source_p) && !IsOper(source_p) && !IsExemptSpambot(source_p)) check_spambot_warning(source_p, NULL); /* * Remove user from the old channel (if any) * only allow /part reasons in -m chans */ if(reason[0] && (is_chanop(msptr) || !MyConnect(source_p) || ((can_send(chptr, source_p, msptr) > 0 && (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) < CurrentTime)))) { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s :%s", use_id(source_p), chptr->chname, reason); sendto_server(client_p, chptr, NOCAPS, CAP_TS6, ":%s PART %s :%s", source_p->name, chptr->chname, reason); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, reason); } else { sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s", use_id(source_p), chptr->chname); sendto_server(client_p, chptr, NOCAPS, CAP_TS6, ":%s PART %s", source_p->name, 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); }
/* * part_one_client * * inputs - pointer to server * - pointer to source client to remove * - char pointer of name of channel to remove from * output - none * side effects - remove ONE client given the channel name */ static void part_one_client(struct Client *client_p, struct Client *source_p, char *name, char *reason) { struct Channel *chptr; struct membership *msptr; char reason2[BUFSIZE]; if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return; } msptr = find_channel_membership(chptr, source_p); if(msptr == NULL) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return; } if(MyConnect(source_p) && !IsOper(source_p) && !IsExemptSpambot(source_p)) check_spambot_warning(source_p, NULL); /* * Remove user from the old channel (if any) * only allow /part reasons in -m chans */ if(reason[0] && (is_any_op(msptr) || !MyConnect(source_p) || ((can_send(chptr, source_p, msptr) > 0 && ConfigFileEntry.use_part_messages && (source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) < rb_current_time())))) { if(chptr->mode.mode & MODE_NOCOLOR && (!ConfigChannel.exempt_cmode_c || !is_any_op(msptr))) { rb_strlcpy(reason2, reason, BUFSIZE); strip_colour(reason2); reason = reason2; } sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s PART %s :%s", use_id(source_p), chptr->chname, reason); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :\"%s\"", source_p->name, source_p->username, source_p->host, chptr->chname, reason); } 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); }
static int mo_privs(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; if (parc < 2 || EmptyString(parv[1])) target_p = source_p; else { target_p = find_named_person(parv[1]); if (target_p == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]); return 0; } } if (MyClient(target_p)) show_privs(source_p, target_p); else sendto_one(target_p, ":%s ENCAP %s PRIVS %s", get_id(source_p, target_p), target_p->servptr->name, use_id(target_p)); return 0; }
/* * ms_wallops (write to *all* opers currently online) * parv[1] = message text */ static int ms_wallops(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { const char *prefix = ""; if (MyClient(source_p) && !IsOperMassNotice(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "mass_notice"); return 0; } if (IsPerson(source_p)) { if (!strncmp(parv[1], "OPERWALL - ", 11) || !strncmp(parv[1], "LOCOPS - ", 9) || !strncmp(parv[1], "SLOCOPS - ", 10) || !strncmp(parv[1], "ADMINWALL - ", 12)) prefix = "WALLOPS - "; } sendto_wallops_flags(UMODE_WALLOP, source_p, "%s%s", prefix, parv[1]); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s WALLOPS :%s", use_id(source_p), parv[1]); return 0; }
/* ** 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; }
/* * ms_operwall - OPERWALL message handler * (write to *all* local opers currently online) * parv[1] = message text */ static int ms_operwall(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s OPERWALL :%s", use_id(source_p), parv[1]); sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", parv[1]); return 0; }
inline Uint32 use_typeless_id(const Uint32 typeless_id) { Uint32 id; id = get_id(typeless_id); use_id(id); return id; }
/* m_tb() * * parv[1] - channel * parv[2] - topic ts * parv[3] - optional topicwho/topic * parv[4] - topic */ static int ms_tb(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; const char *newtopic; const char *newtopicwho; time_t newtopicts; chptr = find_channel(parv[1]); if(chptr == NULL) return 0; newtopicts = atol(parv[2]); if(parc == 5) { newtopic = parv[4]; newtopicwho = parv[3]; } else { newtopic = parv[3]; newtopicwho = source_p->name; } if(EmptyString(newtopic)) return 0; if(chptr->topic == NULL || (chptr->topic != NULL && chptr->topic->topic_time > newtopicts)) { /* its possible the topicts is a few seconds out on some * servers, due to lag when propagating it, so if theyre the * same topic just drop the message --fl */ if(chptr->topic != NULL && strcmp(chptr->topic->topic, newtopic) == 0) return 0; set_channel_topic(chptr, newtopic, newtopicwho, newtopicts); sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s", source_p->name, chptr->chname, newtopic); sendto_server(client_p, chptr, CAP_TB | CAP_TS6, NOCAPS, ":%s TB %s %ld %s%s:%s", use_id(source_p), chptr->chname, (long)chptr->topic->topic_time, ConfigChannel.burst_topicwho ? chptr->topic->topic_info : "", ConfigChannel.burst_topicwho ? " " : "", chptr->topic->topic); sendto_server(client_p, chptr, CAP_TB, CAP_TS6, ":%s TB %s %ld %s%s:%s", source_p->name, chptr->chname, (long)chptr->topic->topic_time, ConfigChannel.burst_topicwho ? chptr->topic->topic_info : "", ConfigChannel.burst_topicwho ? " " : "", chptr->topic->topic); } return 0; }
/* * ms_chghost * parv[1] = target * parv[2] = host */ static int ms_chghost(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; if (!(target_p = find_person(parv[1]))) return -1; if (do_chghost(source_p, target_p, parv[2], 0)) { sendto_server(client_p, NULL, CAP_EUID | CAP_TS6, NOCAPS, ":%s CHGHOST %s %s", use_id(source_p), use_id(target_p), parv[2]); sendto_server(client_p, NULL, CAP_TS6, CAP_EUID, ":%s ENCAP * CHGHOST %s :%s", use_id(source_p), use_id(target_p), parv[2]); } return 0; }
static void send_signon(struct Client *client_p, struct Client *target_p, const char *nick, const char *user, const char *host, unsigned int newts, const char *login) { sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s SIGNON %s %s %s %ld %s", use_id(target_p), nick, user, host, (long) target_p->tsinfo, *login ? login : "******"); strcpy(target_p->user->suser, login); change_nick_user_host(target_p, nick, user, host, newts, "Signing %s (%s)", *login ? "in" : "out", nick); }
/* * ms_wallops (write to *all* opers currently online) * parv[1] = message text */ static int ms_wallops(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if (IsClient(source_p)) sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", parv[1]); else sendto_wallops_flags(UMODE_WALLOP, source_p, "%s", parv[1]); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s WALLOPS :%s", use_id(source_p), parv[1]); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s WALLOPS :%s", source_p->name, parv[1]); return 0; }
static void distribute_hostchange(struct Client *client) { if (irccmp(client->host, client->orighost)) sendto_one_numeric(client, RPL_HOSTHIDDEN, "%s :is now your hidden host", client->host); else sendto_one_numeric(client, RPL_HOSTHIDDEN, "%s :hostname reset", client->host); sendto_server(NULL, NULL, CAP_EUID | CAP_TS6, NOCAPS, ":%s CHGHOST %s :%s", use_id(&me), use_id(client), client->host); sendto_server(NULL, NULL, CAP_TS6, CAP_EUID, ":%s ENCAP * CHGHOST %s :%s", use_id(&me), use_id(client), client->host); sendto_server(NULL, NULL, NOCAPS, CAP_TS6, ":%s ENCAP * CHGHOST %s :%s", me.name, client->name, client->host); if (irccmp(client->host, client->orighost)) SetDynSpoof(client); else ClearDynSpoof(client); }
static int mo_dehelper(struct Client *client_p, struct Client *source_p, int parc, const char **parv) { struct Client *target_p; if (!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } if(!(target_p = find_named_person(parv[1]))) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), me.name, parv[1]); return 0; } if(MyClient(target_p)) do_dehelper(source_p, target_p); else sendto_one(target_p, ":%s ENCAP %s DEHELPER %s", use_id(source_p), target_p->servptr->name, use_id(target_p)); return 0; }
/* * mo_operwall (write to *all* opers currently online) * parv[1] = message text */ static int mo_operwall(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { if(!IsOperOperwall(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "operwall"); return 0; } sendto_wallops_flags(UMODE_OPERWALL, source_p, "OPERWALL - %s", parv[1]); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s OPERWALL :%s", use_id(source_p), parv[1]); return 0; }
static void forcepart_channels(struct Client *client_p, struct Client *source_p, struct Client *target_p, const char *channels, const char *reason) { struct Channel *chptr = NULL; struct membership *msptr = NULL; char *name; char *p = NULL; char *chanlist; chanlist = LOCAL_COPY(channels); for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p)) { if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); continue; } if((msptr = find_channel_membership(chptr, target_p)) == NULL) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), target_p->name, name); continue; } sendto_server(target_p, chptr, NOCAPS, NOCAPS, ":%s PART %s :%s", use_id(target_p), chptr->chname, reason); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s", target_p->name, target_p->username, target_p->host, chptr->chname, reason); remove_user_from_channel(msptr); } return; }
/* * ms_wallops (write to *all* opers currently online) * parv[1] = message text */ static int ms_wallops(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { const char *prefix = ""; if (IsPerson(source_p)) { if (!strncmp(parv[1], "OPERWALL - ", 11) || !strncmp(parv[1], "LOCOPS - ", 9) || !strncmp(parv[1], "SLOCOPS - ", 10)) prefix = "WALLOPS - "; } sendto_wallops_flags(UMODE_WALLOP, source_p, "%s%s", prefix, parv[1]); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s WALLOPS :%s", use_id(source_p), parv[1]); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s WALLOPS :%s", source_p->name, parv[1]); return 0; }
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; }
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_knock * parv[1] = channel * * The KNOCK command has the following syntax: * :<sender> KNOCK <channel> * * If a user is not banned from the channel they can use the KNOCK * command to have the server NOTICE the channel operators notifying * they would like to join. Helpful if the channel is invite-only, the * key is forgotten, or the channel is full (INVITE can bypass each one * of these conditions. Concept by Dianora <*****@*****.**> and written by * <anonymous> */ static int m_knock(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; char *p, *name; if(MyClient(source_p) && ConfigChannel.use_knock == 0) { sendto_one(source_p, form_str(ERR_KNOCKDISABLED), me.name, source_p->name); return 0; } name = LOCAL_COPY(parv[1]); /* dont allow one knock to multiple chans */ if((p = strchr(name, ','))) *p = '\0'; if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if((chptr = find_channel(name)) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if(IsMember(source_p, chptr)) { if(MyClient(source_p)) sendto_one(source_p, form_str(ERR_KNOCKONCHAN), me.name, source_p->name, name); return 0; } if(!((chptr->mode.mode & MODE_INVITEONLY) || (*chptr->mode.key) || (chptr->mode.limit && rb_dlink_list_length(&chptr->members) >= (unsigned long)chptr->mode.limit))) { sendto_one_numeric(source_p, ERR_CHANOPEN, form_str(ERR_CHANOPEN), name); return 0; } /* cant knock to a +p channel */ if(HiddenChannel(chptr)) { sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name, "channel does not accept knocks"); return 0; } if(MyClient(source_p)) { /* don't allow a knock if the user is banned */ if(is_banned(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN || is_quieted(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN) { sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), name, "you are banned from this channel"); return 0; } /* local flood protection: * allow one knock per user per knock_delay * allow one knock per channel per knock_delay_channel */ if(!IsOper(source_p) && (source_p->localClient->last_knock + ConfigChannel.knock_delay) > rb_current_time()) { sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name, source_p->name, name, "user"); return 0; } else if((chptr->last_knock + ConfigChannel.knock_delay_channel) > rb_current_time()) { sendto_one(source_p, form_str(ERR_TOOMANYKNOCK), me.name, source_p->name, name, "channel"); return 0; } /* ok, we actually can send the knock, tell client */ source_p->localClient->last_knock = rb_current_time(); sendto_one(source_p, form_str(RPL_KNOCKDLVR), me.name, source_p->name, name); } chptr->last_knock = rb_current_time(); if(ConfigChannel.use_knock) sendto_channel_local(chptr->mode.mode & MODE_FREEINVITE ? ALL_MEMBERS : ONLY_CHANOPS, chptr, form_str(RPL_KNOCK), me.name, name, name, source_p->name, source_p->username, source_p->host); sendto_server(client_p, chptr, CAP_KNOCK|CAP_TS6, NOCAPS, ":%s KNOCK %s", use_id(source_p), name); sendto_server(client_p, chptr, CAP_KNOCK, CAP_TS6, ":%s KNOCK %s", source_p->name, name); return 0; }
/* ** 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[]) { char *away; char *awy2 = LOCAL_COPY(parv[1]); if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsClient(source_p)) return 0; 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, CAP_TS6, NOCAPS, ":%s AWAY", use_id(source_p)); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%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, source_p->name); return 0; } /* 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, source_p->name, "AWAY"); return 0; } 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, CAP_TS6, NOCAPS, ":%s AWAY :%s", use_id(source_p), awy2); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s AWAY :%s", source_p->name, awy2); } else MyFree(away); DupString(away, awy2); source_p->user->away = away; if(MyConnect(source_p)) sendto_one(source_p, form_str(RPL_NOWAWAY), me.name, source_p->name); return 0; }
/* * m_topic * 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; const char *name; int operspy = 0; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; if(IsOperSpy(source_p) && parv[1][0] == '!') { name++; operspy = 1; if(EmptyString(name)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return 0; } } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); 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), name); return 0; } if(MyClient(source_p) && !is_chanop_voiced(msptr) && !IsOper(source_p) && !add_channel_target(source_p, chptr)) { sendto_one(source_p, form_str(ERR_TARGCHANGE), me.name, source_p->name, chptr->chname); return 0; } if(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || get_channel_access(source_p, chptr, msptr, MODE_ADD, NULL) >= CHFL_CHANOP) && (!MyClient(source_p) || can_send(chptr, source_p, msptr))) { char topic[TOPICLEN + 1]; char topic_info[USERHOST_REPLYLEN]; rb_strlcpy(topic, parv[2], sizeof(topic)); rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); if (ConfigChannel.strip_topic_colors) strip_colour(topic); set_channel_topic(chptr, topic, topic_info, rb_current_time()); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), 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), get_id(&me, source_p), get_id(source_p, source_p), name); } else if(MyClient(source_p)) { if(operspy) report_operspy(source_p, "TOPIC", chptr->chname); if(!IsMember(source_p, chptr) && SecretChannel(chptr) && !operspy) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, name); 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, (unsigned long)chptr->topic_time); } } return 0; }
/* ms_etb() * * parv[1] - channel ts * parv[2] - channel * parv[3] - topic ts * parv[4] - topicwho * parv[5] - topic */ static int ms_etb(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; const char *newtopic; const char *newtopicwho; time_t channelts, newtopicts; struct Client *fakesource_p, *source_server_p; int textchange, can_use_tb, member; channelts = atol(parv[1]); chptr = find_channel(parv[2]); if(chptr == NULL) return 0; newtopicts = atol(parv[3]); /* Hide connecting server on netburst -- jilles */ if (IsServer(source_p) && ConfigServerHide.flatten_links && !HasSentEob(source_p)) fakesource_p = &me; else fakesource_p = source_p; newtopicwho = parv[4]; newtopic = parv[parc - 1]; if(chptr->topic == NULL || chptr->channelts > channelts || (chptr->channelts == channelts && chptr->topic_time < newtopicts)) { textchange = chptr->topic == NULL || strcmp(chptr->topic, newtopic); can_use_tb = textchange && !EmptyString(newtopic) && (chptr->topic == NULL || chptr->topic_time > newtopicts); set_channel_topic(chptr, newtopic, newtopicwho, newtopicts); newtopic = chptr->topic ? chptr->topic : ""; if (chptr->topic_info) newtopicwho = chptr->topic_info; /* Do not send a textually identical topic to clients, * but do propagate the new topicts/topicwho to servers. */ if(textchange) { if (IsPerson(fakesource_p)) sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", fakesource_p->name, fakesource_p->username, fakesource_p->host, chptr->chname, newtopic); else sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s", fakesource_p->name, chptr->chname, newtopic); } /* Propagate channelts as given, because an older channelts * forces any change. */ sendto_server(client_p, chptr, CAP_EOPMOD|CAP_TS6, NOCAPS, ":%s ETB %ld %s %ld %s :%s", use_id(source_p), (long)channelts, chptr->chname, (long)newtopicts, newtopicwho, newtopic); source_server_p = IsServer(source_p) ? source_p : source_p->servptr; if (can_use_tb) sendto_server(client_p, chptr, CAP_TB|CAP_TS6, CAP_EOPMOD, ":%s TB %s %ld %s :%s", use_id(source_server_p), chptr->chname, (long)newtopicts, newtopicwho, newtopic); else if (IsPerson(source_p) && textchange) { member = IsMember(source_p, chptr); if (!member) sendto_server(client_p, chptr, CAP_TS6, CAP_EOPMOD, ":%s SJOIN %ld %s + :@%s", use_id(source_server_p), (long)chptr->channelts, chptr->chname, use_id(source_p)); if (EmptyString(newtopic) || newtopicts >= rb_current_time() - 60) sendto_server(client_p, chptr, CAP_TS6, CAP_EOPMOD, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, newtopic); else { sendto_server(client_p, chptr, CAP_TS6, CAP_EOPMOD, ":%s TOPIC %s :%s", use_id(source_p), chptr->chname, ""); sendto_server(client_p, chptr, CAP_TB|CAP_TS6, CAP_EOPMOD, ":%s TB %s %ld %s :%s", use_id(source_server_p), chptr->chname, (long)newtopicts, newtopicwho, newtopic); } if (!member) sendto_server(client_p, chptr, CAP_TS6, CAP_EOPMOD, ":%s PART %s :Topic set for %s", use_id(source_p), chptr->chname, newtopicwho); } else if (textchange) { /* Should not send :server ETB if not all servers * support EOPMOD. */ sendto_server(client_p, chptr, CAP_TS6, CAP_EOPMOD, ":%s NOTICE %s :*** Notice -- Dropping topic change for %s", me.id, chptr->chname, chptr->chname); } } return 0; }
/* ** m_kick ** 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; char *comment; const char *name; char *p = NULL; char text[10]; const char *user; static char buf[BUFSIZE]; int is_override = 0; 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; } user = parv[2]; /* strtoken(&p2, parv[2], ","); */ if(!(who = find_chasing(source_p, user, &chasing))) { 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(!can_kick_deop(msptr, find_channel_membership(chptr, who))) { if(MyConnect(source_p)) { if(IsOverride(source_p)) is_override = 1; else { sendto_one(source_p, ":%s 482 %s %s :You do not have the proper privileges to kick this user", me.name, source_p->name, name); return 0; } } /* If its a TS 0 channel, do it the old way */ else 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'; 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) && chptr->mode.mode & MODE_NOKICK) { sendto_one_numeric(source_p, ERR_NOKICK, form_str(ERR_NOKICK), chptr->chname); return 0; } if (MyClient(source_p) && chptr->mode.mode & MODE_NOOPERKICK && IsOper(who)) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Overriding KICK from %s on %s in %s (channel is +M)", source_p->name, who->name, chptr->chname); sendto_one_numeric(source_p, ERR_ISCHANSERVICE, "%s %s :Cannot kick IRC operators from that channel.", who->name, chptr->chname); return 0; } if(MyClient(source_p)) { hook_data_channel_approval hookdata; hookdata.client = source_p; hookdata.chptr = chptr; hookdata.target = who; hookdata.approved = 1; 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'; if(is_override) { sendto_wallops_flags(UMODE_WALLOP, &me, "%s is overriding KICK [%s] on [%s] [%s]", get_oper_name(source_p), who->name, chptr->chname, comment); sendto_server(NULL, chptr, NOCAPS, NOCAPS, ":%s WALLOPS :%s is overriding KICK [%s] on [%s] [%s]", me.name, get_oper_name(source_p), who->name, chptr->chname, comment); } /* 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, 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); remove_user_from_channel(msptr); rb_snprintf(text, sizeof(text), "K%s", who->id); /* we don't need to track NOREJOIN stuff unless it's our client being kicked */ if(MyClient(who) && chptr->mode.mode & MODE_NOREJOIN) channel_metadata_time_add(chptr, text, rb_current_time(), "KICKNOREJOIN"); } 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; }
/* * 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; }
/* * m_topic * 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; const char *name; int operspy = 0; if((p = strchr(parv[1], ','))) *p = '\0'; name = parv[1]; if(IsOperAuspex(source_p) && parv[1][0] == '!') { name++; operspy = 1; if(EmptyString(name)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return 0; } } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if(!IsChannelName(name)) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } chptr = find_channel(name); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } /* setting topic */ if(parc > 2) { char topic_info[USERHOST_REPLYLEN]; char topic[BUFSIZE]; 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(MyClient(source_p) && !is_chanop_voiced(msptr) && !IsOper(source_p) && !add_channel_target(source_p, chptr)) { sendto_one(source_p, form_str(ERR_TARGCHANGE), me.name, source_p->name, chptr->chname); return 0; } if(MyClient(source_p) && !(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chanop(msptr)) && can_send(chptr, source_p, msptr))) { if(IsOverride(source_p)) sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is overriding TOPIC on [%s]", get_oper_name(source_p), chptr->chname); else { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), get_id(&me, source_p), get_id(source_p, source_p), name); return 0; } } rb_strlcpy(topic, parv[2], BUFSIZE); strip_colour(topic); rb_sprintf(topic_info, "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, topic, topic_info, rb_current_time()); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", use_id(source_p), 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 if(MyClient(source_p)) { if(operspy) report_operspy(source_p, "TOPIC", chptr->chname); if(!IsMember(source_p, chptr) && SecretChannel(chptr) && !operspy) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), name); return 0; } if(chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, name); 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; }