/** Send a bot command to all local users on a channel. * @param[in] botname Bot sending the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command (ignored). * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_DEAF, SKIP_NONOPS, SKIP_NONVOICES indicating which clients to skip. * @param[in] pattern Format string for command arguments. */ void sendcmdbotto_channel(const char *botname, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, const char *pattern, ...) { struct VarData vd; struct MsgBuf *mb; struct Membership *member; vd.vd_format = pattern; /* set up the struct VarData for %v */ va_start(vd.vd_args, pattern); /* build the buffer */ mb = msgq_make(0, ":%s %s %v", botname, cmd, &vd); va_end(vd.vd_args); /* send the buffer to each local channel member */ for (member = to->members; member; member = member->next_member) { if (!MyConnect(member->user) || member->user == one || IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) #if defined(DDB) || defined(SERVICES) || (skip & SKIP_NONOPS && !IsChanOwner(member) && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOwner(member) && !IsChanOp(member) && !HasVoice(member))) #else || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member))) #endif continue; send_buffer(member->user, mb, 0); } msgq_clean(mb); }
/** Send a (prefixed) command to all users on this channel, except for * \a one and those matching \a skip. * @warning \a pattern must not contain %v. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST, SKIP_SERVERS. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, const char *pattern, ...) { struct Membership *member; struct VarData vd; struct MsgBuf *user_mb; struct MsgBuf *serv_mb; vd.vd_format = pattern; /* Build buffer to send to users */ va_start(vd.vd_args, pattern); user_mb = msgq_make(0, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? "%:#C %s @%v" : "%:#C %s %v", from, cmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ if ((skip & SKIP_SERVERS) || IsLocalChannel(to->chname)) serv_mb = NULL; else { va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, skip & SKIP_NONOPS ? "%C %s @%v" : "%C %s %v", from, tok, &vd); va_end(vd.vd_args); } /* send buffer along! */ bump_sentalong(one); for (member = to->members; member; member = member->next_member) { /* skip duplicates, zombies, and flagged users... */ if (cli_sentalong(member->user) == sentalong_marker || IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || #if defined(DDB) || defined(SERVICES) (skip & SKIP_NONOPS && !IsChanOwner(member) && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOwner(member) && !IsChanOp(member) && !HasVoice(member)) || #else (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)) || #endif (skip & SKIP_COLOUR && !IsStripColour(member->user)) || (skip & SKIP_NOCOLOUR && IsStripColour(member->user)) || (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || !(serv_mb || MyUser(member->user)) || cli_fd(cli_from(member->user)) < 0) continue; cli_sentalong(member->user) = sentalong_marker; /* pick right buffer to send */ send_buffer(member->user, MyConnect(member->user) ? user_mb : serv_mb, 0); } msgq_clean(user_mb); if (serv_mb) msgq_clean(serv_mb); }
/** Send a (prefixed) command to all local users on a channel with or without * a client capability specified. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command (ignored). * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_DEAF, SKIP_NONOPS, SKIP_NONVOICES indicating which clients to skip. * @param[in] withcap CAP_* that the user must have active to receive the message. * @param[in] skipcap CAP_* that the user must not have active to receive the message. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_capab_butserv_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, int withcap, int skipcap, const char *pattern, ...) { struct VarData vd; struct MsgBuf *mb; struct Membership *member; vd.vd_format = pattern; /* set up the struct VarData for %v */ va_start(vd.vd_args, pattern); /* build the buffer */ mb = msgq_make(0, "%:#C %s %v", from, cmd, &vd); va_end(vd.vd_args); /* send the buffer to each local channel member */ for (member = to->members; member; member = member->next_member) { if (!MyConnect(member->user) || member->user == one || IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONHOPS && !IsChanOp(member) && !IsHalfOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !IsHalfOp(member)&& !HasVoice(member)) || ((withcap != CAP_NONE) && !CapActive(member->user, withcap)) || ((skipcap != CAP_NONE) && CapActive(member->user, skipcap))) continue; send_buffer(member->user, mb, 0); } msgq_clean(mb); }
void CChatChannel::PrivateMessage(CChatMember *pFrom, LPCTSTR pszTo, LPCTSTR pszMsg, CLanguageID lang) { ADDTOCALLSTACK("CChatChannel::PrivateMessage"); CChatMember *pTo = FindMember(pszTo); if ( !pTo ) { pFrom->SendChatMsg(CHATMSG_NoPlayer, pszTo); return; } if ( !pTo->m_bReceiving ) { pFrom->SendChatMsg(CHATMSG_PlayerNotReceivingPrivateMessages, pszTo); return; } // Members without voice can't send private messages on channel, but they still allowed to send private messages to moderators if ( !HasVoice(pFrom->GetChatName()) && !IsModerator(pszTo) ) { pFrom->SendChatMsg(CHATMSG_RevokedSpeaking); return; } if ( pTo->IsIgnoring(pFrom->GetChatName()) ) { pFrom->SendChatMsg(CHATMSG_PlayerIsIgnoring, pszTo); return; } CGString sName; g_Serv.m_Chats.FormatName(sName, pFrom); pFrom->SendChatMsg(CHATMSG_PlayerPrivateMessage, sName, pszMsg, lang); if ( pTo != pFrom ) pTo->SendChatMsg(CHATMSG_PlayerPrivateMessage, sName, pszMsg, lang); }
/** Send a (prefixed) command to all servers with users on \a to. * Skip \a from and \a one plus those indicated in \a skip. * @param[in] from Client originating the command. * @param[in] cmd Long name of command (ignored). * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS and SKIP_NONVOICES indicating which clients to skip. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_servers_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, const char *pattern, ...) { struct VarData vd; struct MsgBuf *serv_mb; struct Membership *member; /* build the buffer */ vd.vd_format = pattern; va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, "%:#C %s %v", from, tok, &vd); va_end(vd.vd_args); /* send the buffer to each server */ bump_sentalong(one); cli_sentalong(from) = sentalong_marker; for (member = to->members; member; member = member->next_member) { if (MyConnect(member->user) || IsZombie(member) || cli_fd(cli_from(member->user)) < 0 || cli_sentalong(member->user) == sentalong_marker || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONHOPS && !IsChanOp(member) && !IsHalfOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !IsHalfOp(member)&& !HasVoice(member))) continue; cli_sentalong(member->user) = sentalong_marker; send_buffer(member->user, serv_mb, 0); } msgq_clean(serv_mb); }
void CChatChannel::RemoveVoice(CChatMember *pByMember, LPCTSTR pszName) { ADDTOCALLSTACK("CChatChannel::RemoveVoice"); LPCTSTR pszByName = pByMember->GetChatName(); if ( !IsModerator(pszByName) ) { pByMember->SendChatMsg(CHATMSG_MustHaveOps); return; } CChatMember *pMember = FindMember(pszName); if ( !pMember ) { pByMember->SendChatMsg(CHATMSG_NoPlayer, pszName); return; } pszName = pMember->GetChatName(); // fix case-sensitive mismatch if ( !HasVoice(pszName) ) return; SetVoice(pszName, true); SendMember(pMember); // update name color pMember->SendChatMsg(CHATMSG_ModeratorHasRemovedSpeakPriv, pszByName); Broadcast(CHATMSG_PlayerNoSpeaking, pszName); }
void CChatChannel::ToggleVoice(CChatMember *pByMember, LPCTSTR pszName) { ADDTOCALLSTACK("CChatChannel::ToggleVoice"); if ( !HasVoice(pszName) ) // this also returns true if this person is not in the channel AddVoice(pByMember, pszName); else RemoveVoice(pByMember, pszName); }
void CChatChannel::ToggleVoice(CChatChanMember * pByMember, LPCTSTR pszName) { ADDTOCALLSTACK("CChatChannel::ToggleVoice"); if (!HasVoice(pszName)) // (This also returns true if this person is not in the channel) GrantVoice(pByMember, pszName); // this checks and reports on membership else RevokeVoice(pByMember, pszName); // this checks and reports on membership }
void CChatChannel::Emote(LPCTSTR pszBy, LPCTSTR pszMsg, CLanguageID lang ) { ADDTOCALLSTACK("CChatChannel::Emote"); if (HasVoice(pszBy)) Broadcast(CHATMSG_PlayerEmote, pszBy, pszMsg, lang ); else FindMember(pszBy)->SendChatMsg(CHATMSG_RevokedSpeaking); }
void ChatChannel::AddVoice(std::string inVoiced) { if(!HasVoice(inVoiced)) { Voiced.push_back(inVoiced); _log(UCS__TRACE, "Added %s as voiced to channel %s", inVoiced.c_str(), Name.c_str()); } }
void CChatChannel::MemberTalk(CChatChanMember * pByMember, LPCTSTR pszText, CLanguageID lang ) { ADDTOCALLSTACK("CChatChannel::MemberTalk"); // Do I have a voice? if (!HasVoice(pByMember->GetChatName())) { pByMember->SendChatMsg(CHATMSG_RevokedSpeaking); return; } Broadcast(CHATMSG_PlayerTalk, pByMember->GetChatName(), pszText, lang ); }
void CChatChannel::MemberTalk(CChatMember *pByMember, LPCTSTR pszText, CLanguageID lang) { ADDTOCALLSTACK("CChatChannel::MemberTalk"); LPCTSTR pszName = pByMember->GetChatName(); if ( !HasVoice(pszName) ) { pByMember->SendChatMsg(CHATMSG_RevokedSpeaking); return; } Broadcast(CHATMSG_PlayerMessage, pszName, pszText, lang); }
/** Send a (prefixed) command to all users on this channel, except for * \a one and those matching \a skip. * @warning \a pattern must not contain %v. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, const char *pattern, ...) { struct Membership *member; struct VarData vd; struct MsgBuf *user_mb; struct MsgBuf *serv_mb; vd.vd_format = pattern; /* Build buffer to send to users */ va_start(vd.vd_args, pattern); user_mb = msgq_make(0, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? "%:#C %s @%v" : "%:#C %s %v", from, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? MSG_NOTICE : cmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, "%C %s %v", from, tok, &vd); va_end(vd.vd_args); /* send buffer along! */ bump_sentalong(one); for (member = to->members; member; member = member->next_member) { /* skip one, zombies, and deaf users... */ if (IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)) || (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || cli_fd(cli_from(member->user)) < 0 || cli_sentalong(member->user) == sentalong_marker) continue; cli_sentalong(member->user) = sentalong_marker; if (MyConnect(member->user)) /* pick right buffer to send */ send_buffer(member->user, user_mb, 0); else send_buffer(member->user, serv_mb, 0); } msgq_clean(user_mb); msgq_clean(serv_mb); }
void CChatChannel::RevokeVoice(CChatChanMember * pByMember, LPCTSTR pszName) { ADDTOCALLSTACK("CChatChannel::RevokeVoice"); if (!IsModerator(pByMember->GetChatName())) { pByMember->SendChatMsg(CHATMSG_MustHaveOps); return; } CChatChanMember * pMember = FindMember(pszName); if (!pMember) { pByMember->SendChatMsg(CHATMSG_NoPlayer, pszName); return; } if (!HasVoice(pszName)) return; SetVoice(pszName, false); SendThisMember(pMember); // Update the color pMember->SendChatMsg(CHATMSG_ModeratorRemovedSpeaking, pByMember->GetChatName()); Broadcast(CHATMSG_PlayerNoSpeaking, pszName, "", ""); }
void CChatChannel::SendThisMember(CChatChanMember * pMember, CChatChanMember * pToMember) { ADDTOCALLSTACK("CChatChannel::SendThisMember"); TCHAR buffer[2048]; sprintf(buffer, "%s%s", (IsModerator(pMember->GetChatName()) == true) ? "1" : (HasVoice(pMember->GetChatName()) == true) ? "0" : "2", pMember->GetChatName()); // If no particular member is specified in pToMember, then send it out to all members if (pToMember == NULL) { for (size_t i = 0; i < m_Members.GetCount(); i++) { // Don't send out members if they are ignored by someone if (!m_Members[i]->IsIgnoring(pMember->GetChatName())) m_Members[i]->SendChatMsg(CHATMSG_SendPlayerName, buffer); } } else { // Don't send out members if they are ignored by someone if (!pToMember->IsIgnoring(pMember->GetChatName())) pToMember->SendChatMsg(CHATMSG_SendPlayerName, buffer); } }
void CChatChannel::SendPrivateMessage(CChatChanMember * pFrom, LPCTSTR pszTo, LPCTSTR pszMsg) { ADDTOCALLSTACK("CChatChannel::SendPrivateMessage"); CChatChanMember * pTo = FindMember(pszTo); if (!pTo) { pFrom->SendChatMsg(CHATMSG_NoPlayer, pszTo); return; } if (!pTo->IsReceivingAllowed()) { pFrom->SendChatMsg(CHATMSG_PlayerNotReceivingPrivate, pszTo); return; } // Can always send private messages to moderators (but only if they are receiving) bool fHasVoice = HasVoice(pFrom->GetChatName()); if ( !fHasVoice && !IsModerator(pszTo)) { pFrom->SendChatMsg(CHATMSG_RevokedSpeaking); return; } if (pTo->IsIgnoring(pFrom->GetChatName())) // See if ignoring you { pFrom->SendChatMsg(CHATMSG_PlayerIsIgnoring, pszTo); return; } CGString sName; g_Serv.m_Chats.DecorateName(sName, pFrom); // Echo to the sending client so they know the message went out pFrom->SendChatMsg(CHATMSG_PlayerPrivate, sName, pszMsg); // If the sending and receiving are different send it out to the receiver if (pTo != pFrom) pTo->SendChatMsg(CHATMSG_PlayerPrivate, sName, pszMsg); }
/** Handle a JOIN message from a server connection. * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Membership *member; struct Channel *chptr; struct JoinBuf join; unsigned int flags; time_t creation = 0; char *p = 0; char *chanlist; char *name; if (IsServer(sptr)) { return protocol_violation(cptr, "%s tried to JOIN %s, duh!", cli_name(sptr), (parc < 2 || *parv[1] == '\0') ? "a channel" : parv[1] ); } if (parc < 2 || *parv[1] == '\0') return need_more_params(sptr, "JOIN"); if (parc > 2 && parv[2]) creation = atoi(parv[2]); joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0); chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */ for (name = ircd_strtok(&p, chanlist, ","); name; name = ircd_strtok(&p, 0, ",")) { flags = CHFL_DEOPPED; if (IsLocalChannel(name) || !IsChannelName(name)) { protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name); continue; } if (!(chptr = FindChannel(name))) { /* No channel exists, so create one */ if (!(chptr = get_channel(sptr, name, CGT_CREATE))) { protocol_violation(sptr,"couldn't get channel %s for %s", name,cli_name(sptr)); continue; } flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0; chptr->creationtime = creation; } else { /* We have a valid channel? */ if ((member = find_member_link(chptr, sptr))) { /* It is impossible to get here --Run */ if (!IsZombie(member)) /* already on channel */ continue; flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK); remove_user_from_channel(sptr, chptr); chptr = FindChannel(name); } else flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0; /* Always copy the timestamp when it is older, that is the only way to ensure network-wide synchronization of creation times. We now also copy a creation time that only 1 second younger... this is needed because the timestamp must be incremented by one when someone joins an existing, but empty, channel. However, this is only necessary when the channel is still empty (also here) and when this channel doesn't have +A set. To prevent this from allowing net-rides on the channel, we clear all modes from the channel. (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only user in the channel; c1 parts and rejoins, gaining ops. Before s2 sees c1's part, c2 joins the channel and parts immediately. s1 sees c1 part, c1 create, c2 join, c2 part; c2's join resets the timestamp. s2 sees c2 join, c2 part, c1 part, c1 create; but since s2 sees the channel as a zannel or non-existent, it does not bounce the create with the newer timestamp.) */ if (creation && (creation < chptr->creationtime || (!chptr->mode.apass[0] && chptr->users == 0))) { struct Membership *member; struct ModeBuf mbuf; chptr->creationtime = creation; /* Wipe out the current modes on the channel. */ modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3); modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode); chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS; if (chptr->mode.limit) { modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); chptr->mode.limit = 0; } if (chptr->mode.key[0]) { modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); chptr->mode.key[0] = '\0'; } if (chptr->mode.upass[0]) { modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0); chptr->mode.upass[0] = '\0'; } if (chptr->mode.apass[0]) { modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0); chptr->mode.apass[0] = '\0'; } for (member = chptr->members; member; member = member->next_member) { if (IsChanOp(member)) { modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member)); member->status &= ~CHFL_CHANOP; } if (HasVoice(member)) { modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member)); member->status &= ~CHFL_VOICE; } } modebuf_flush(&mbuf); } } joinbuf_join(&join, chptr, flags); } joinbuf_flush(&join); /* flush joins... */ return 0; }
/** Send a (prefixed) command to all users on this channel, except for * \a one and those matching \a skip. * @warning \a pattern must not contain %v. * @param[in] from Client originating the command. * @param[in] cmd Long name of command. * @param[in] tok Short name of command. * @param[in] to Destination channel. * @param[in] one Client direction to skip (or NULL). * @param[in] skip Bitmask of SKIP_NONOPS, SKIP_NONVOICES, SKIP_DEAF, SKIP_BURST. * @param[in] pattern Format string for command arguments. */ void sendcmdto_channel_butone(struct Client *from, const char *cmd, const char *tok, struct Channel *to, struct Client *one, unsigned int skip, unsigned char prefix, const char *pattern, ...) { struct Membership *member; struct VarData vd; struct MsgBuf *user_mb; struct MsgBuf *serv_mb; struct Client *service; const char *userfmt; const char *usercmd; vd.vd_format = pattern; /* Build buffer to send to users */ usercmd = cmd; userfmt = "%:#C %s %v"; if (skip & (SKIP_NONOPS | SKIP_NONHOPS | SKIP_NONVOICES)) { usercmd = MSG_NOTICE; if (skip & SKIP_NONVOICES) userfmt = "%:#C %s +%v"; else if (skip & SKIP_NONHOPS) userfmt = "%:#C %s %%%v"; else userfmt = "%:#C %s @%v"; } va_start(vd.vd_args, pattern); user_mb = msgq_make(0, userfmt, from, usercmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ va_start(vd.vd_args, pattern); serv_mb = msgq_make(&me, "%C %s %v", from, tok, &vd); va_end(vd.vd_args); /* send buffer along! */ bump_sentalong(one); for (member = to->members; member; member = member->next_member) { /* skip one, zombies, and deaf users... */ if (IsZombie(member) || (skip & SKIP_DEAF && IsDeaf(member->user)) || (skip & SKIP_NONOPS && !IsChanOp(member)) || (skip & SKIP_NONHOPS && !IsChanOp(member) && !IsHalfOp(member)) || (skip & SKIP_NONVOICES && !IsChanOp(member) && !IsHalfOp(member) && !HasVoice(member)) || (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || (is_silenced(from, member->user, 1)) || cli_fd(cli_from(member->user)) < 0 || cli_sentalong(member->user) == sentalong_marker) continue; cli_sentalong(member->user) = sentalong_marker; if (MyConnect(member->user)) /* pick right buffer to send */ send_buffer(member->user, user_mb, 0); else send_buffer(member->user, serv_mb, 0); } /* Consult service forwarding table. */ if(GlobalForwards[prefix] && (service = FindServer(GlobalForwards[prefix])) && cli_sentalong(service) != sentalong_marker) { cli_sentalong(service) = sentalong_marker; send_buffer(service, serv_mb, 0); } msgq_clean(user_mb); msgq_clean(serv_mb); }
/* * Send whois information for acptr to sptr */ static void do_whois(struct Client* sptr, struct Client *acptr, int parc) { struct Client *a2cptr=0; struct Channel *chptr=0; int mlen; int len; static char buf[512]; const struct User* user = cli_user(acptr); const char* name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr); a2cptr = feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsAnOper(sptr) && sptr != acptr ? &his : user->server; assert(user); send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host, cli_info(acptr)); /* Display the channels this user is on. */ if (!IsChannelService(acptr)) { struct Membership* chan; mlen = strlen(cli_name(&me)) + strlen(cli_name(sptr)) + 12 + strlen(name); len = 0; *buf = '\0'; for (chan = user->channel; chan; chan = chan->next_channel) { chptr = chan->channel; if (!ShowChannel(sptr, chptr) && !(IsOper(sptr) && IsLocalChannel(chptr->chname))) continue; if (acptr != sptr && IsZombie(chan)) continue; /* Don't show local channels when HIS is defined, unless it's a * remote WHOIS --ULtimaTe_ */ if (IsLocalChannel(chptr->chname) && (acptr != sptr) && (parc == 2) && feature_bool(FEAT_HIS_WHOIS_LOCALCHAN) && !IsAnOper(sptr)) continue; if (len+strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS, "%s :%s", name, buf); *buf = '\0'; len = 0; } if (IsDeaf(acptr)) *(buf + len++) = '-'; if (!ShowChannel(sptr, chptr)) *(buf + len++) = '*'; if (IsDelayedJoin(chan) && (sptr != acptr)) *(buf + len++) = '<'; else if (IsChanOp(chan)) *(buf + len++) = '@'; else if (HasVoice(chan)) *(buf + len++) = '+'; else if (IsZombie(chan)) *(buf + len++) = '!'; if (len) *(buf + len) = '\0'; strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); strcat(buf + len, " "); len++; } if (buf[0] != '\0') send_reply(sptr, RPL_WHOISCHANNELS, name, buf); } send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr), cli_info(a2cptr)); if (user) { if (user->away) send_reply(sptr, RPL_AWAY, name, user->away); if (SeeOper(sptr,acptr)) send_reply(sptr, RPL_WHOISOPERATOR, name); if (IsAccount(acptr)) send_reply(sptr, RPL_WHOISACCOUNT, name, user->account); if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr)) send_reply(sptr, RPL_WHOISACTUALLY, name, user->username, user->realhost, ircd_ntoa(&cli_ip(acptr))); /* Hint: if your looking to add more flags to a user, eg +h, here's * probably a good place to add them :) */ if (MyConnect(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) || (sptr == acptr || IsAnOper(sptr) || parc >= 3))) send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last, cli_firsttime(acptr)); } }
/* * ms_kick - server message handler * * parv[0] = sender prefix * parv[1] = channel * parv[2] = client to kick * parv[parc-1] = kick comment */ int ms_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *who; struct Channel *chptr; struct Membership *member = 0, *sptr_link = 0; char *name, *comment; ClrFlag(sptr, FLAG_TS8); if (parc < 3 || *parv[1] == '\0') return need_more_params(sptr, "KICK"); name = parv[1]; comment = parv[parc - 1]; /* figure out who gets kicked from what */ if (IsLocalChannel(name) || !(chptr = get_channel(sptr, name, CGT_NO_CREATE)) || !(who = findNUser(parv[2]))) return 0; /* We go ahead and pass on the KICK for users not on the channel */ member = find_member_link(chptr, who); if (member && IsZombie(member)) { /* We might get a KICK from a zombie's own server because the user * net-rode during a burst (which always generates a KICK) *and* * was kicked via another server. In that case, we must remove * the user from the channel. */ if (sptr == cli_user(who)->server) { remove_user_from_channel(who, chptr); } /* Otherwise, we treat zombies like they are not channel members. */ member = 0; } /* Send HACK notice, but not for servers in BURST */ /* 2002-10-17: Don't send HACK if the users local server is kicking them */ if (IsServer(sptr) && !IsBurstOrBurstAck(sptr) && sptr!=cli_user(who)->server) sendto_opmask_butone(0, SNO_HACK4, "HACK: %C KICK %H %C %s", sptr, chptr, who, comment); /* Unless someone accepted it downstream (or the user isn't on the channel * here), if kicker is not on channel, or if kicker is not a channel * operator, bounce the kick */ if (!IsServer(sptr) && member && cli_from(who) != cptr && (!(sptr_link = find_member_link(chptr, sptr)) || !IsChanOp(sptr_link))) { sendto_opmask_butone(0, SNO_HACK2, "HACK: %C KICK %H %C %s", sptr, chptr, who, comment); sendcmdto_one(who, CMD_JOIN, cptr, "%H", chptr); /* Reop/revoice member */ if (IsChanOp(member) || HasVoice(member)) { struct ModeBuf mbuf; modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_SERVER | /* Send mode to a server */ MODEBUF_DEST_DEOP | /* Deop the source */ MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */ if (IsChanOp(member)) modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, who, OpLevel(member)); if (HasVoice(member)) modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, who, MAXOPLEVEL + 1); modebuf_flush(&mbuf); } } else { /* Propagate kick... */ sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, comment); if (member) { /* and tell the channel about it */ if (IsDelayedJoin(member)) { if (MyUser(who)) sendcmdto_one(IsServer(sptr) ? &his : sptr, CMD_KICK, who, "%H %C :%s", chptr, who, comment); } else { sendcmdto_channel_butserv_butone(IsServer(sptr) ? &his : sptr, CMD_KICK, chptr, NULL, 0, "%H %C :%s", chptr, who, comment); } make_zombie(member, who, cptr, sptr, chptr); } } return 0; }
void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) { struct Membership *lp; struct SLink *slp; struct Client *acptr; char outbuf[BUFSIZE], ustat[64]; int cntr = 0, opcntr = 0, hopcntr = 0, vcntr = 0, clones = 0, bans = 0, excepts = 0, c = 0, authed = 0; if (flags & CHECK_SHOWUSERS) { if (feature_bool(FEAT_HALFOPS)) send_reply(sptr, RPL_DATASTR, "Users (@ = op, % = halfop, + = voice, * = clone)"); else send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice, * = clone)"); } for (lp = chptr->members; lp; lp = lp->next_member) { int opped = 0; acptr = lp->user; if ((c = checkClones(chptr, acptr->cli_name, acptr->cli_user->realhost)) != 0) { ircd_snprintf(0, ustat, sizeof(ustat), "%2d ", c); clones++; } else { strcpy(ustat, " "); } if (chptr && IsChanOp(lp)) { strcat(ustat, "@"); opcntr++; opped = 1; } else if (chptr && IsHalfOp(lp)) { strcat(ustat, "%"); hopcntr++; } else if (chptr && HasVoice(lp)) { strcat(ustat, "+"); vcntr++; } else strcat(ustat, " "); if ((c = IsAccount(acptr)) != 0) ++authed; if ((flags & CHECK_SHOWUSERS) || ((flags & CHECK_OPSONLY) && opped)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF); send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, acptr->cli_user->realusername, (flags & CHECK_SHOWIPS) ? ircd_ntoa((const char*)&(cli_ip(acptr))) : acptr->cli_user->realhost, outbuf, (c ? acptr->cli_user->account : "")); } cntr++; } send_reply(sptr, RPL_DATASTR, " "); if (feature_bool(FEAT_HALFOPS)) ircd_snprintf(0, outbuf, sizeof(outbuf), "Total users:: %d (%d ops, %d half ops, %d voiced, %d clones, %d authed)", cntr, opcntr, hopcntr, vcntr, clones, authed); else ircd_snprintf(0, outbuf, sizeof(outbuf), "Total users:: %d (%d ops, %d voiced, %d clones, %d authed)", cntr, opcntr, vcntr, clones, authed); send_reply(sptr, RPL_DATASTR, outbuf); send_reply(sptr, RPL_DATASTR, " "); /* Do not display bans if ! flags & CHECK_SHOWUSERS */ if (!(flags & CHECK_SHOWUSERS)) { send_reply(sptr, RPL_ENDOFCHECK, " "); return; } /* Bans */ send_reply(sptr, RPL_DATASTR, "Bans on channel::"); for (slp = chptr->banlist; slp; slp = slp->next) { ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s - Set by %s, on %s", ++bans, slp->value.ban.banstr, slp->value.ban.who, myctime(slp->value.ban.when)); send_reply(sptr, RPL_DATASTR, outbuf); } if (bans == 0) send_reply(sptr, RPL_DATASTR, "<none>"); /* Excepts */ if (feature_bool(FEAT_EXCEPTS)) { send_reply(sptr, RPL_DATASTR, "Excepts on channel::"); for (slp = chptr->exceptlist; slp; slp = slp->next) { ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s - Set by %s, on %s", ++excepts, slp->value.except.exceptstr, slp->value.except.who, myctime(slp->value.except.when)); send_reply(sptr, RPL_DATASTR, outbuf); } if (excepts == 0) send_reply(sptr, RPL_DATASTR, "<none>"); } send_reply(sptr, RPL_ENDOFCHECK, " "); }
void do_names(struct Client* sptr, struct Channel* chptr, int filter) { int mlen; int idx; int flag; int needs_space; int len; char buf[BUFSIZE]; struct Client *c2ptr; struct Membership* member; assert(chptr); assert(sptr); assert((filter&NAMES_ALL) != (filter&NAMES_VIS)); /* Tag Pub/Secret channels accordingly. */ strcpy(buf, "* "); if (PubChannel(chptr)) *buf = '='; else if (SecretChannel(chptr)) *buf = '@'; len = strlen(chptr->chname); strcpy(buf + 2, chptr->chname); strcpy(buf + 2 + len, " :"); idx = len + 4; flag = 1; needs_space = 0; if (!ShowChannel(sptr, chptr)) /* Don't list private channels unless we are on them. */ return; /* Iterate over all channel members, and build up the list. */ mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr)); for (member = chptr->members; member; member = member->next_member) { c2ptr = member->user; if (((filter&NAMES_VIS)!=0) && IsInvisible(c2ptr)) continue; if (IsZombie(member) && member->user != sptr) continue; if (IsDelayedJoin(member) && (member->user != sptr) && !(filter & NAMES_DEL)) continue; if ((!IsDelayedJoin(member) || (member->user == sptr)) && (filter & NAMES_DEL)) continue; if (needs_space) buf[idx++] = ' '; needs_space=1; if (IsZombie(member)) buf[idx++] = '!'; else if (IsChanOp(member)) buf[idx++] = '@'; else if (HasVoice(member)) buf[idx++] = '+'; strcpy(buf + idx, cli_name(c2ptr)); idx += strlen(cli_name(c2ptr)); flag = 1; if (mlen + idx + NICKLEN + 5 > BUFSIZE) /* space, modifier, nick, \r \n \0 */ { send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); idx = len + 4; flag = 0; needs_space=0; } } if (flag) send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); if (filter&NAMES_EON) send_reply(sptr, RPL_ENDOFNAMES, chptr->chname); }
/* * do_clearmode(struct Client *cptr, struct Client *sptr, * struct Channel *chptr, char *control) * * This is the function that actually clears the channel modes. */ static int do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr, char *control) { static int flags[] = { MODE_CHANOP, 'o', MODE_VOICE, 'v', MODE_PRIVATE, 'p', MODE_SECRET, 's', MODE_MODERATED, 'm', MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i', MODE_NOPRIVMSGS, 'n', MODE_KEY, 'k', MODE_BAN, 'b', MODE_LIMIT, 'l', MODE_REGONLY, 'r', MODE_DELJOINS, 'D', 0x0, 0x0 }; int *flag_p; unsigned int del_mode = 0; char control_buf[20]; int control_buf_i = 0; struct ModeBuf mbuf; struct Ban *link, *next; struct Membership *member; /* Ok, so what are we supposed to get rid of? */ for (; *control; control++) { for (flag_p = flags; flag_p[0]; flag_p += 2) if (*control == flag_p[1]) { del_mode |= flag_p[0]; break; } } if (!del_mode) return 0; /* nothing to remove; ho hum. */ modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */ MODEBUF_DEST_OPMODE | /* Treat it like an OPMODE */ MODEBUF_DEST_HACK4)); /* Generate a HACK(4) notice */ modebuf_mode(&mbuf, MODE_DEL | (del_mode & chptr->mode.mode)); chptr->mode.mode &= ~del_mode; /* and of course actually delete them */ /* If we're removing invite, remove all the invites */ if (del_mode & MODE_INVITEONLY) mode_invite_clear(chptr); /* * If we're removing the key, note that; note that we can't clear * the key until after modebuf_* are done with it */ if (del_mode & MODE_KEY && *chptr->mode.key) modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); /* If we're removing the limit, note that and clear the limit */ if (del_mode & MODE_LIMIT && chptr->mode.limit) { modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); chptr->mode.limit = 0; /* not referenced, so safe */ } /* * Go through and mark the bans for deletion; note that we can't * free them until after modebuf_* are done with them */ if (del_mode & MODE_BAN) { for (link = chptr->banlist; link; link = next) { char *bandup; next = link->next; DupString(bandup, link->banstr); modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, /* delete ban */ bandup, 1); free_ban(link); } chptr->banlist = 0; } /* Deal with users on the channel */ if (del_mode & (MODE_BAN | MODE_CHANOP | MODE_VOICE)) for (member = chptr->members; member; member = member->next_member) { if (IsZombie(member)) /* we ignore zombies */ continue; if (del_mode & MODE_BAN) /* If we cleared bans, clear the valid flags */ ClearBanValid(member); /* Drop channel operator status */ if (IsChanOp(member) && del_mode & MODE_CHANOP) { modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, MAXOPLEVEL + 1); member->status &= ~CHFL_CHANOP; } /* Drop voice */ if (HasVoice(member) && del_mode & MODE_VOICE) { modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1); member->status &= ~CHFL_VOICE; } } /* And flush the modes to the channel */ modebuf_flush(&mbuf); /* Finally, we can clear the key... */ if (del_mode & MODE_KEY) chptr->mode.key[0] = '\0'; /* Ok, build control string again */ for (flag_p = flags; flag_p[0]; flag_p += 2) if (del_mode & flag_p[0]) control_buf[control_buf_i++] = flag_p[1]; control_buf[control_buf_i] = '\0'; /* Log it... */ log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE, "%#C CLEARMODE %H %s", sptr, chptr, control_buf); /* Then send it */ if (!IsLocalChannel(chptr->chname)) sendcmdto_serv_butone(sptr, CMD_CLEARMODE, cptr, "%H %s", chptr, control_buf); return 0; }