/*! \brief TOPIC command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = channel name * - parv[2] = topic text */ static int ms_topic(struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; char topic_info[USERHOST_REPLYLEN]; if (EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "TOPIC"); return 0; } if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]); return 0; } 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); channel_set_topic(chptr, parv[2], topic_info, CurrentTime, 0); sendto_server(source_p, 0, 0, ":%s TOPIC %s :%s", source_p->id, chptr->name, chptr->topic); if (!IsClient(source_p)) sendto_channel_local(0, chptr, ":%s TOPIC %s :%s", (IsHidden(source_p) || ConfigServerHide.hide_servers) ? me.name : source_p->name, chptr->name, chptr->topic); else sendto_channel_local(0, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->name, chptr->topic); return 0; }
/*! \brief TOPIC command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = channel name * - parv[2] = topic text, if setting topic */ static int m_topic(struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; if (EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "TOPIC"); return 0; } if (!IsFloodDone(source_p)) flood_endgrace(source_p); if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]); return 0; } /* setting topic */ if (parc > 2) { const struct Membership *member = NULL; if ((member = find_channel_link(source_p, chptr)) == NULL) { sendto_one_numeric(source_p, &me, ERR_NOTONCHANNEL, chptr->name); return 0; } if (!(chptr->mode.mode & MODE_TOPICLIMIT) || has_member_flags(member, 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); channel_set_topic(chptr, parv[2], topic_info, CurrentTime, 1); sendto_server(source_p, 0, 0, ":%s TOPIC %s :%s", source_p->id, chptr->name, chptr->topic); sendto_channel_local(0, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->name, chptr->topic); } else sendto_one_numeric(source_p, &me, ERR_CHANOPRIVSNEEDED, chptr->name); } else /* only asking for topic */ { if (!SecretChannel(chptr) || IsMember(source_p, chptr)) { if (chptr->topic[0] == '\0') sendto_one_numeric(source_p, &me, RPL_NOTOPIC, chptr->name); else { sendto_one_numeric(source_p, &me, RPL_TOPIC, chptr->name, chptr->topic); sendto_one_numeric(source_p, &me, RPL_TOPICWHOTIME, chptr->name, chptr->topic_info, chptr->topic_time); } } else sendto_one_numeric(source_p, &me, ERR_NOTONCHANNEL, chptr->name); } return 0; }
/*! \brief TBURST command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = channel timestamp * - parv[2] = channel name * - parv[3] = topic timestamp * - parv[4] = topic setter * - parv[5] = topic */ static int ms_tburst(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 0; /* * The logic for accepting and rejecting channel topics was * always a bit hairy, so now we got exactly 3 cases where * we would accept a topic * * Case 1: * A services client/server wants to set a topic * Case 2: * The TS of the remote channel is older than ours * Case 3: * 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->creationtime) accept_remote = 1; else if (remote_channel_ts == chptr->creationtime) 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)); channel_set_topic(chptr, topic, setby, remote_topic_ts, 0); sendto_server(source_p, CAPAB_TBURST, 0, ":%s TBURST %s %s %s %s :%s", source_p->id, parv[1], parv[2], parv[3], setby, topic); if (topic_differs) { if (!IsClient(source_p)) sendto_channel_local(0, chptr, ":%s TOPIC %s :%s", hidden_server ? me.name : source_p->name, chptr->name, chptr->topic); else sendto_channel_local(0, chptr, ":%s!%s@%s TOPIC %s :%s", source_p->name, source_p->username, source_p->host, chptr->name, chptr->topic); } } return 0; }