/* * set_topic * * inputs - source_p pointer * - channel pointer * - topicts to set * - who to set as who doing the topic * - topic * output - none * Side effects - simply propagates topic as needed * little helper function, could be removed */ static void set_topic(struct Client *source_p, struct Channel *chptr, time_t topicts, const char *topicwho, const char *topic) { int new_topic = strcmp(chptr->topic ? chptr->topic : "", topic); set_channel_topic(chptr, topic, topicwho, topicts); /* Only send TOPIC to channel if it's different */ if (new_topic) sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s TOPIC %s :%s", ConfigServerHide.hide_servers ? me.name : source_p->name, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_server(source_p, chptr, CAP_TBURST, NOCAPS, ":%s TBURST %lu %s %lu %s :%s", me.name, (unsigned long)chptr->channelts, chptr->chname, (unsigned long)chptr->topic_time, chptr->topic_info == NULL ? "" : chptr->topic_info, chptr->topic == NULL ? "" : chptr->topic); sendto_server(source_p, chptr, CAP_TB, CAP_TBURST, ":%s TB %s %lu %s :%s", me.name, chptr->chname, (unsigned long)chptr->topic_time, chptr->topic_info == NULL ? "" : chptr->topic_info, chptr->topic == NULL ? "" : chptr->topic); }
static void ms_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; const char *from, *to; char topic_info[USERHOST_REPLYLEN]; if (IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) { from = me.id; to = source_p->id; } else { from = me.name; to = source_p->name; } if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), from, to, "TOPIC"); return; } if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, parv[1]); return; } if (!IsClient(source_p)) strlcpy(topic_info, source_p->name, sizeof(topic_info)); else snprintf(topic_info, sizeof(topic_info), "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime, 0); sendto_server(client_p, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", ID(source_p), chptr->chname, chptr->topic); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic); if (!IsClient(source_p)) sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic); else sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic); }
/* 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_topic * parv[1] = channel name * parv[2] = topic_info * parv[3] = topic_info time * parv[4] = new channel topic * * Let servers always set a topic */ static int ms_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr = NULL; if((chptr = find_channel(parv[1])) == NULL) return 0; set_channel_topic(chptr, parv[4], parv[2], atoi(parv[3])); sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s", source_p->name, parv[1], chptr->topic == NULL ? "" : chptr->topic); return 0; }
static void set_topic(struct Client *source_p, struct Channel *chptr, time_t newtopicts, char *topicwho, char *topic) { set_channel_topic(chptr, topic, topicwho, newtopicts); sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); #ifdef TBURST_PROPAGATE sendto_server(source_p, NULL, chptr, CAP_TBURST, NOCAPS, NOFLAGS, ":%s TBURST %ld %s %ld %s :%s", me.name, (unsigned long)chptr->channelts, chptr->chname, (unsigned long)chptr->topic_time, chptr->topic_info == NULL ? "" : chptr->topic_info, chptr->topic == NULL ? "" : chptr->topic); #endif }
/* * ms_topic * parv[0] = sender prefix * parv[1] = channel name * parv[2] = topic_info * parv[3] = topic_info time * parv[4] = new channel topic * * Let servers always set a topic */ static void ms_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; if (!IsServer(source_p)) { m_topic(client_p, source_p, parc, parv); return; } if( parc < 5 ) return; if (parv[1] && IsChannelName(parv[1])) { if ((chptr = hash_find_channel(parv[1])) == NULL) return; set_channel_topic(chptr, parv[4], parv[2], atoi(parv[3])); if(ConfigServerHide.hide_servers) { sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s", me.name, parv[1], chptr->topic == NULL ? "" : chptr->topic); } else { sendto_channel_local(ALL_MEMBERS, chptr, ":%s TOPIC %s :%s", source_p->name, parv[1], chptr->topic == NULL ? "" : chptr->topic); } } }
/* * 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(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_topic() * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static void m_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; char *p; struct Membership *ms; const char *from, *to; if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) { from = me.id; to = source_p->id; } else { from = me.name; to = source_p->name; } if ((p = strchr(parv[1], ',')) != NULL) *p = '\0'; if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), from, to, "TOPIC"); return; } if (MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (IsChanPrefix(*parv[1])) { if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, parv[1]); return; } /* setting topic */ if (parc > 2) { if ((ms = find_channel_link(source_p, chptr)) == NULL && !IsService(source_p)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, parv[1]); return; } if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) || IsGod(source_p) || IsService(source_p)) { char topic_info[USERHOST_REPLYLEN]; if(!has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) && IsGod(source_p) && MyClient(source_p) && (chptr->mode.mode & MODE_TOPICLIMIT) != 0) { char tmp[IRCD_BUFSIZE]; ircsprintf(tmp, "%s is using God mode: TOPIC %s %s", source_p->name, chptr->chname, parv[2]); sendto_gnotice_flags(UMODE_SERVNOTICE, L_ALL, me.name, &me, NULL, tmp); oftc_log(tmp); } 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", 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, NO, 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), from, to, chptr->chname); } else /* only asking for topic */ { if (!SecretChannel(chptr) || IsMember(source_p, chptr)) { if (chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), from, to, chptr->chname); else { sendto_one(source_p, form_str(RPL_TOPIC), from, to, chptr->chname, chptr->topic); sendto_one(source_p, form_str(RPL_TOPICWHOTIME), from, to, chptr->chname, chptr->topic_info, chptr->topic_time); } } else { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), from, to, chptr->chname); return; } } } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), from, to, parv[1]); } }
/* * 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; }
/* 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; }
/* ms_tburst() * * parv[0] = sender prefix * parv[1] = channel timestamp * parv[2] = channel * parv[3] = topic timestamp * parv[4] = topic setter * parv[5] = topic */ static void ms_tburst(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; int accept_remote = 0; time_t remote_channel_ts = atol(parv[1]); time_t remote_topic_ts = atol(parv[3]); const char *topic = ""; const char *setby = ""; /* * Do NOT test parv[5] for an empty string and return if true! * parv[5] CAN be an empty string, i.e. if the other side wants * to unset our topic. Don't forget: an empty topic is also a * valid topic. */ if ((chptr = hash_find_channel(parv[2])) == NULL) return; if (parc == 6) { topic = parv[5]; setby = parv[4]; } /* * The logic for accepting and rejecting channel topics was * always a bit hairy, so now we got exactly 2 cases where * we would accept a bursted topic * * Case 1: * The TS of the remote channel is older than ours * Case 2: * The TS of the remote channel is equal to ours AND * the TS of the remote topic is newer than ours */ if (remote_channel_ts < chptr->channelts) accept_remote = 1; else if (remote_channel_ts == chptr->channelts) if (remote_topic_ts > chptr->topic_time) accept_remote = 1; if (accept_remote) { int topic_differs = strcmp(chptr->topic ? chptr->topic : "", topic); set_channel_topic(chptr, topic, setby, remote_topic_ts); if (topic_differs) sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s TOPIC %s :%s", ConfigServerHide.hide_servers ? me.name : source_p->name, chptr->chname, chptr->topic == NULL ? "" : chptr->topic); } /* * Always propagate what we have received, not only if we accept the topic. * This will keep other servers in sync. */ sendto_server(source_p, chptr, CAP_TBURST, NOCAPS, ":%s TBURST %s %s %s %s :%s", source_p->name, parv[1], parv[2], parv[3], setby, topic); if (parc > 5 && *topic != '\0') /* unsetting a topic is not supported by TB */ sendto_server(source_p, chptr, CAP_TB, CAP_TBURST, ":%s TB %s %s %s :%s", source_p->name, parv[1], parv[2], setby, topic); }
/* * m_topic * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static void m_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; struct Channel *root_chan; char *p = NULL; #ifdef VCHANS struct Channel *vchan; #endif if ((p = strchr(parv[1],','))) *p = '\0'; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); if (parv[1] && IsChannelName(parv[1])) { chptr = hash_find_channel(parv[1]); if(chptr == NULL) { /* if chptr isn't found locally, it =could= exist * on the uplink. so forward reqeuest */ if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL)) { sendto_one(uplink, ":%s TOPIC %s %s", source_p->name, parv[1], ((parc > 2) ? parv[2] : "")); return; } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); return; } } root_chan = chptr; #ifdef VCHANS if (HasVchans(chptr)) { vchan = map_vchan(chptr,source_p); if(vchan != NULL) chptr = vchan; } else if (IsVchan(chptr)) root_chan = RootChan(chptr); #endif /* setting topic */ if (parc > 2) { if (!IsMember(source_p, chptr)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[1]); return; } if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_any_op(chptr,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, NULL, chptr, NOCAPS, NOCAPS, NOFLAGS, ":%s TOPIC %s :%s", parv[0], chptr->chname, chptr->topic == NULL ? "" : chptr->topic); if(chptr->mode.mode & MODE_HIDEOPS) { sendto_channel_local(ONLY_CHANOPS_HALFOPS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, root_chan->chname, chptr->topic == NULL ? "" : chptr->topic); sendto_channel_local(NON_CHANOPS, chptr, ":%s TOPIC %s :%s", me.name, root_chan->chname, chptr->topic == NULL ? "" : chptr->topic); } else { sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, root_chan->chname, chptr->topic == NULL ? "" : chptr->topic); } } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0], parv[1]); } else /* only asking for topic */ { if (!IsMember(source_p, chptr) && SecretChannel(chptr)) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[1]); return; } if (chptr->topic == NULL) sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, parv[0], parv[1]); else { sendto_one(source_p, form_str(RPL_TOPIC), me.name, parv[0], root_chan->chname, chptr->topic); if(!(chptr->mode.mode & MODE_HIDEOPS) || is_any_op(chptr,source_p)) { sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], root_chan->chname, chptr->topic_info, chptr->topic_time); } /* client on LL needing the topic - if we have serverhide, say * its the actual LL server that set the topic, not us the * uplink -- fl_ */ else if(ConfigServerHide.hide_servers && !MyClient(source_p) && IsCapable(client_p, CAP_LL) && ServerInfo.hub) { sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], root_chan->chname, client_p->name, chptr->topic_time); } /* just normal topic hiding.. */ else { sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name, parv[0], root_chan->chname, me.name, chptr->topic_time); } } } } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); } }
/* m_topic() * parv[0] = sender prefix * parv[1] = channel name * parv[2] = new topic, if setting topic */ static void m_topic(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "TOPIC"); return; } if (!IsFloodDone(source_p)) flood_endgrace(source_p); if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, source_p->name, parv[1]); return; } /* setting topic */ if (parc > 2) { struct Membership *ms; if ((ms = find_channel_link(source_p, chptr)) == NULL) { sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, parv[1]); return; } if (!(chptr->mode.mode & MODE_TOPICLIMIT) || has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP)) { char topic_info[USERHOST_REPLYLEN]; snprintf(topic_info, sizeof(topic_info), "%s!%s@%s", source_p->name, source_p->username, source_p->host); set_channel_topic(chptr, parv[2], topic_info, CurrentTime, 1); sendto_server(client_p, CAP_TS6, NOCAPS, ":%s TOPIC %s :%s", ID(source_p), chptr->chname, chptr->topic); sendto_server(client_p, NOCAPS, CAP_TS6, ":%s TOPIC %s :%s", source_p->name, chptr->chname, chptr->topic); sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->chname, chptr->topic); } else sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, chptr->chname); } else /* only asking for topic */ { if (!SecretChannel(chptr) || IsMember(source_p, chptr)) { if (chptr->topic[0] == '\0') sendto_one(source_p, form_str(RPL_NOTOPIC), me.name, source_p->name, chptr->chname); 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); } } else sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name, source_p->name, chptr->chname); } }
/* ms_tburst() * * parv[0] = sender prefix * parv[1] = channel timestamp * parv[2] = channel * parv[3] = topic timestamp * parv[4] = topic setter * parv[5] = topic */ static void ms_tburst(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; int accept_remote = 0; time_t remote_channel_ts = atol(parv[1]); time_t remote_topic_ts = atol(parv[3]); const char *topic = parv[5]; const char *setby = parv[4]; /* * Do NOT test parv[5] for an empty string and return if true! * parv[5] CAN be an empty string, i.e. if the other side wants * to unset our topic. Don't forget: an empty topic is also a * valid topic. */ if ((chptr = hash_find_channel(parv[2])) == NULL) return; /* * The logic for accepting and rejecting channel topics was * always a bit hairy, so now we got exactly 2 cases where * we would accept a bursted topic * * Case 1: * The TS of the remote channel is older than ours * Case 2: * The TS of the remote channel is equal to ours AND * the TS of the remote topic is newer than ours */ if (HasFlag(source_p, FLAGS_SERVICE)) accept_remote = 1; else if (remote_channel_ts < chptr->channelts) accept_remote = 1; else if (remote_channel_ts == chptr->channelts) if (remote_topic_ts > chptr->topic_time) accept_remote = 1; if (accept_remote) { int topic_differs = strncmp(chptr->topic, topic, sizeof(chptr->topic) - 1); int hidden_server = (ConfigServerHide.hide_servers || IsHidden(source_p)); set_channel_topic(chptr, topic, setby, remote_topic_ts, !!MyClient(source_p)); sendto_server(source_p, CAP_TBURST|CAP_TS6, NOCAPS, ":%s TBURST %s %s %s %s :%s", ID(source_p), parv[1], parv[2], parv[3], setby, topic); sendto_server(source_p, CAP_TBURST, CAP_TS6, ":%s TBURST %s %s %s %s :%s", source_p->name, parv[1], parv[2], parv[3], setby, topic); if (topic_differs) sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :%s", hidden_server ? me.name : source_p->name, chptr->chname, chptr->topic); } }