static int ms_tmode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; /* Now, try to find the channel in question */ if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2])) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[2]); return 0; } chptr = find_channel(parv[2]); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[2]); return 0; } /* TS is higher, drop it. */ if(atol(parv[1]) > chptr->channelts) return 0; if(IsServer(source_p)) { set_channel_mode(client_p, source_p, chptr, NULL, parc - 3, parv + 3); } else { msptr = find_channel_membership(chptr, source_p); set_channel_mode(client_p, source_p, chptr, msptr, parc - 3, parv + 3); } 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); }
static int mo_forcepart(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; struct Channel *chptr; struct membership *msptr; if(!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "forcepart"); return 0; } if((hunt_server(client_p, source_p, ":%s FORCEPART %s %s", 1, parc, parv)) != HUNTED_ISME) return 0; /* if target_p == NULL then let the oper know */ if((target_p = find_client(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return 0; } if(!IsClient(target_p)) return 0; if((chptr = find_channel(parv[2])) == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } if((msptr = find_channel_membership(chptr, target_p)) == NULL) { sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), me.name, source_p->name, parv[1], parv[2]); return 0; } sendto_server(target_p, chptr, NOCAPS, NOCAPS, ":%s PART %s :%s", target_p->name, chptr->chname, target_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s", target_p->name, target_p->username, target_p->host, chptr->chname, target_p->name); remove_user_from_channel(msptr); return 0; }
static void h_scc_channel_join(void *vdata) { hook_data_channel_activity *data = (hook_data_channel_activity *)vdata; struct Channel *chptr = data->chptr; struct Client *source_p = data->client; /* If they just joined a channel, and it only has one member, then they just created it. */ if(rb_dlink_list_length(&chptr->members) == 1 && is_chanop(find_channel_membership(chptr, source_p))) { sendto_realops_snomask(snomask_modes['l'], L_NETWIDE, "%s is creating new channel %s", source_p->name, chptr->chname); } }
/* * 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 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; }
/* * m_omode - MODE command handler * parv[0] - sender * parv[1] - channel */ static void m_omode(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; static char modebuf[MODEBUFLEN]; static char parabuf[MODEBUFLEN]; int n = 2; if(EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "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 */ 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, parv[0], (unsigned char *) parv[1]); return; } chptr = hash_find_channel(parv[1]); if(chptr == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); return; } sendto_wallops_flags(UMODE_WALLOP, &me, "OMODE called for [%s] by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); ilog(L_NOTICE, "OMODE called for [%s] by %s!%s@%s", parv[1], source_p->name, source_p->username, source_p->host); if(*chptr->chname != '&') sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s WALLOPS :OMODE called for [%s] by %s!%s@%s", me.name, parv[1], source_p->name, source_p->username, source_p->host); /* Now know the channel exists */ if(parc < n + 1) { 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); } else if(IsServer(source_p)) { set_channel_mode(client_p, source_p, chptr, NULL, parc - n, parv + n, chptr->chname); } else { msptr = find_channel_membership(chptr, source_p); set_channel_mode(client_p, source_p->servptr, chptr, msptr, parc - n, parv + n, chptr->chname); } }
static int m_displaymsg(struct Client *source_p, const char *channel, int underline, int action, const char *nick, const char *text) { struct Channel *chptr; struct membership *msptr; char nick2[NICKLEN+1]; char nick3[NICKLEN+1]; char text2[BUFSIZE]; if((chptr = find_channel(channel)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), channel); return 0; } if(!(msptr = find_channel_membership(chptr, source_p))) { sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), chptr->chname); return 0; } if(!(chptr->mode.mode & chmode_flags['N'])) { sendto_one_numeric(source_p, 573, "%s :Roleplay commands are not enabled on this channel.", chptr->chname); return 0; } if(!can_send(chptr, source_p, msptr)) { sendto_one_numeric(source_p, 573, "%s :Cannot send to channel.", chptr->chname); return 0; } /* enforce flood stuff on roleplay commands */ if(flood_attack_channel(0, source_p, chptr, chptr->chname)) return 0; /* enforce target change on roleplay commands */ if(!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; } rb_strlcpy(nick3, nick, sizeof(nick3)); if(underline) snprintf(nick2, sizeof(nick2), "\x1F%s\x1F", strip_unprintable(nick3)); else snprintf(nick2, sizeof(nick2), "%s", strip_unprintable(nick3)); /* don't allow nicks to be empty after stripping * this prevents nastiness like fake factions, etc. */ if(EmptyString(nick3)) { sendto_one_numeric(source_p, 573, "%s :No visible non-stripped characters in nick.", chptr->chname); return 0; } if(action) snprintf(text2, sizeof(text2), "\1ACTION %s\1", text); else snprintf(text2, sizeof(text2), "%s", text); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%[email protected] PRIVMSG %s :%s (%s)", nick2, source_p->name, channel, text2, source_p->name); sendto_match_servs(source_p, "*", CAP_ENCAP, NOCAPS, "ENCAP * ROLEPLAY %s %s :%s", channel, nick2, text2); 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; }
/* ** 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; }
static int m_cmessage(int p_or_n, const char *command, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; struct Channel *chptr; struct membership *msptr; if(!IsFloodDone(source_p)) flood_endgrace(source_p); if((target_p = find_named_person(parv[1])) == NULL) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]); return 0; } if((chptr = find_channel(parv[2])) == NULL) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[2]); return 0; } if((msptr = find_channel_membership(chptr, source_p)) == NULL) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NOTONCHANNEL, form_str(ERR_NOTONCHANNEL), chptr->chname); return 0; } if(!is_chanop_voiced(msptr)) { if(p_or_n != NOTICE) sendto_one(source_p, form_str(ERR_VOICENEEDED), me.name, source_p->name, chptr->chname); return 0; } if(!IsMember(target_p, chptr)) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), target_p->name, chptr->chname); return 0; } if(MyClient(target_p) && (IsSetCallerId(target_p) || (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])) && !accept_message(source_p, target_p) && !IsOper(source_p)) { if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0]) { if (p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_NONONREG, form_str(ERR_NONONREG), target_p->name); return 0; } if(p_or_n != NOTICE) sendto_one_numeric(source_p, ERR_TARGUMODEG, form_str(ERR_TARGUMODEG), target_p->name); if((target_p->localClient->last_caller_id_time + ConfigFileEntry.caller_id_wait) < rb_current_time()) { if(p_or_n != NOTICE) sendto_one_numeric(source_p, RPL_TARGNOTIFY, form_str(RPL_TARGNOTIFY), target_p->name); sendto_one(target_p, form_str(RPL_UMODEGMSG), me.name, target_p->name, source_p->name, source_p->username, source_p->host); target_p->localClient->last_caller_id_time = rb_current_time(); } return 0; } if(p_or_n != NOTICE) source_p->localClient->last = rb_current_time(); sendto_anywhere(target_p, source_p, command, ":%s", parv[3]); return 0; }
/* * m_mode - MODE command handler * parv[1] - channel */ static int m_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; int n = 2; const char *dest; int operspy = 0; dest = parv[1]; if(IsOperSpy(source_p) && *dest == '!') { dest++; operspy = 1; if(EmptyString(dest)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE"); return 0; } } /* Now, try to find the channel in question */ if(!IsChanPrefix(*dest)) { /* if here, it has to be a non-channel name */ user_mode(client_p, source_p, parc, parv); return 0; } if(!check_channel_name(dest)) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]); return 0; } chptr = find_channel(dest); if(chptr == NULL) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; } /* Now know the channel exists */ if(parc < n + 1) { if(operspy) report_operspy(source_p, "MODE", chptr->chname); sendto_one(source_p, form_str(RPL_CHANNELMODEIS), me.name, source_p->name, parv[1], operspy ? channel_modes(chptr, &me) : channel_modes(chptr, source_p)); sendto_one(source_p, form_str(RPL_CREATIONTIME), me.name, source_p->name, parv[1], chptr->channelts); } else { msptr = find_channel_membership(chptr, source_p); /* 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, msptr, parc - n, parv + n); } 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_okick ** parv[1] = channel ** parv[2] = client to kick ** parv[3] = kick comment */ static int mo_okick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *who; struct Client *target_p; struct Channel *chptr; struct membership *msptr; int chasing = 0; char *comment; char *name; char *p = NULL; char *user; char text[10]; static char buf[BUFSIZE]; if(*parv[2] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "KICK"); return 0; } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); comment = (EmptyString(LOCAL_COPY(parv[3]))) ? LOCAL_COPY(parv[2]) : LOCAL_COPY(parv[3]); if(strlen(comment) > (size_t) TOPICLEN) comment[TOPICLEN] = '\0'; *buf = '\0'; if((p = strchr(parv[1], ','))) *p = '\0'; name = LOCAL_COPY(parv[1]); chptr = find_channel(name); if(!chptr) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if((p = strchr(parv[2], ','))) *p = '\0'; user = LOCAL_COPY(parv[2]); // strtoken(&p2, parv[2], ","); if(!(who = find_chasing(source_p, user, &chasing))) { return 0; } if((target_p = find_client(user)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, user); return 0; } if((msptr = find_channel_membership(chptr, target_p)) == NULL) { sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), me.name, source_p->name, parv[1], parv[2]); return 0; } sendto_realops_snomask(SNO_GENERAL, L_ALL, "OKICK called for %s %s by %s!%s@%s", chptr->chname, target_p->name, source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OKICK called for %s %s by %s", chptr->chname, target_p->name, get_oper_name(source_p)); sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment); sendto_server(&me, chptr, CAP_TS6, NOCAPS, ":%s KICK %s %s :%s", me.id, chptr->chname, who->id, 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"); return 0; }
/* ** m_okick ** parv[0] = sender prefix ** parv[1] = channel ** parv[2] = client to kick ** parv[3] = kick comment */ static int mo_okick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *who; struct Client *target_p; struct Channel *chptr; struct membership *msptr; int chasing = 0; char *comment; char *name; char *p = NULL; char *user; static char buf[BUFSIZE]; if(*parv[2] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KICK"); return 0; } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); comment = (EmptyString(LOCAL_COPY(parv[3]))) ? LOCAL_COPY(parv[2]) : LOCAL_COPY(parv[3]); if(strlen(comment) > (size_t)REASONLEN) comment[REASONLEN] = '\0'; *buf = '\0'; if((p = strchr(parv[1], ','))) *p = '\0'; name = LOCAL_COPY(parv[1]); chptr = find_channel(name); if(!chptr) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return 0; } if((p = strchr(parv[2], ','))) *p = '\0'; user = LOCAL_COPY(parv[2]); // strtoken(&p2, parv[2], ","); if(!(who = find_chasing(source_p, user, &chasing))) { return 0; } if((target_p = find_client(user)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, parv[0], user); return 0; } if((msptr = find_channel_membership(chptr, target_p)) == NULL) { sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), me.name, parv[0], parv[1], parv[2]); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment); sendto_server(&me, chptr, NOCAPS, NOCAPS, ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment); remove_user_from_channel(msptr); 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_okick ** parv[1] = channel ** parv[2] = client to kick ** parv[3] = kick comment */ static void mo_okick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *who; struct Client *target_p; struct Channel *chptr; struct membership *msptr; int chasing = 0; char *comment; char *name; char *p = NULL; char *user; static char buf[BUFSIZE]; if(*parv[2] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "KICK"); return; } if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); comment = (EmptyString(LOCAL_COPY(parv[3]))) ? LOCAL_COPY(parv[2]) : LOCAL_COPY(parv[3]); if(strlen(comment) > (size_t) TOPICLEN) comment[TOPICLEN] = '\0'; *buf = '\0'; if((p = strchr(parv[1], ','))) *p = '\0'; name = LOCAL_COPY(parv[1]); chptr = find_channel(name); if(!chptr) { sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name); return; } if((p = strchr(parv[2], ','))) *p = '\0'; user = LOCAL_COPY(parv[2]); // strtoken(&p2, parv[2], ","); if(!(who = find_chasing(source_p, user, &chasing))) { return; } if((target_p = find_client(user)) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), user); return; } if((msptr = find_channel_membership(chptr, target_p)) == NULL) { sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), parv[1], parv[2]); return; } sendto_wallops_flags(UMODE_WALLOP, &me, "OKICK called for %s %s by %s!%s@%s", chptr->chname, target_p->name, source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OKICK called for %s %s by %s", chptr->chname, target_p->name, get_oper_name(source_p)); /* only sends stuff for #channels remotely */ sendto_server(NULL, chptr, NOCAPS, NOCAPS, ":%s WALLOPS :OKICK called for %s %s by %s!%s@%s", me.name, chptr->chname, target_p->name, source_p->name, source_p->username, source_p->host); sendto_channel_local(&me, ALL_MEMBERS, chptr, ":%s KICK %s %s :%s", me.name, chptr->chname, who->name, comment); sendto_server(&me, chptr, CAP_TS6, NOCAPS, ":%s KICK %s %s :%s", me.id, chptr->chname, who->id, comment); remove_user_from_channel(msptr); }
/* * mo_omode - MODE command handler * parv[1] - channel */ static int mo_omode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; struct membership *msptr; char params[512]; int i; int wasonchannel; /* admins only */ if (!IsOperAdmin(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin"); return 0; } /* Now, try to find the channel in question */ if (!IsChanPrefix(parv[1][0]) || !check_channel_name(parv[1])) { sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), 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; } /* Now know the channel exists */ msptr = find_channel_membership(chptr, source_p); wasonchannel = msptr != NULL; if (is_any_op(msptr)) { sendto_one_notice(source_p, ":Use a normal MODE you idiot"); return 0; } params[0] = '\0'; for (i = 2; i < parc; i++) { if (i != 2) rb_strlcat(params, " ", sizeof params); rb_strlcat(params, parv[i], sizeof params); } sendto_wallops_flags(UMODE_WALLOP, &me, "OMODE called for [%s] [%s] by %s!%s@%s", parv[1], params, source_p->name, source_p->username, source_p->host); ilog(L_MAIN, "OMODE called for [%s] [%s] by %s", parv[1], params, get_oper_name(source_p)); if (*chptr->chname != '&') sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s WALLOPS :OMODE called for [%s] [%s] by %s!%s@%s", me.name, parv[1], params, source_p->name, source_p->username, source_p->host); #if 0 set_channel_mode(client_p, source_p->servptr, chptr, msptr, parc - 2, parv + 2); #else if (parc == 4 && !strcmp(parv[2], "+y") && !irccmp(parv[3], source_p->name)) { /* Ownering themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +y %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +y %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_OWNER; } else if (parc == 4 && !strcmp(parv[2], "+a") && !irccmp(parv[3], source_p->name)) { /* Admining themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +a %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +a %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_ADMIN; } else if (parc == 4 && !strcmp(parv[2], "+o") && !irccmp(parv[3], source_p->name)) { /* Opping themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +o %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_CHANOP; } else if (parc == 4 && !strcmp(parv[2], "+h") && !irccmp(parv[3], source_p->name)) { /* Halfopping themselves */ if (!wasonchannel) { sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL, form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname); return 0; } sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +h %s", me.name, parv[1], source_p->name); sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s TMODE %ld %s +h %s", me.id, (long) chptr->channelts, parv[1], source_p->id); msptr->flags |= CHFL_HALFOP; } else if (ConfigChannel.use_owner) { /* I hope this is correct. * -- Kabaka */ /* Hack it so set_channel_mode() will accept */ if (wasonchannel) msptr->flags |= CHFL_OWNER; else { add_user_to_channel(chptr, source_p, CHFL_CHANOP); msptr = find_channel_membership(chptr, source_p); } set_channel_mode(client_p, source_p, chptr, msptr, parc - 2, parv + 2); if (wasonchannel) msptr->flags &= ~CHFL_OWNER; else remove_user_from_channel(msptr); } else if (ConfigChannel.use_admin) { /* Hack it so set_channel_mode() will accept */ if (wasonchannel) msptr->flags |= CHFL_ADMIN; else { add_user_to_channel(chptr, source_p, CHFL_CHANOP); msptr = find_channel_membership(chptr, source_p); } set_channel_mode(client_p, source_p, chptr, msptr, parc - 2, parv + 2); /* We know they were not opped before and they can't have opped * themselves as set_channel_mode() does not allow that * -- jilles */ if (wasonchannel) msptr->flags &= ~CHFL_ADMIN; else remove_user_from_channel(msptr); } else { /* CHFL_ADMIN is only useful if admin is enabled * so hack it with op if it is not. */ if (wasonchannel) msptr->flags |= CHFL_CHANOP; else { add_user_to_channel(chptr, source_p, CHFL_CHANOP); msptr = find_channel_membership(chptr, source_p); } set_channel_mode(client_p, source_p, chptr, msptr, parc - 2, parv + 2); /* We know they were not opped before and they can't have opped * themselves as set_channel_mode() does not allow that * -- jilles */ if (wasonchannel) msptr->flags &= ~CHFL_CHANOP; else remove_user_from_channel(msptr); } #endif 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; }