Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion include/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ typedef unsigned long flagpage_t;
#define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag))

/** String containing valid user modes, in no particular order. */
#define infousermodes "diOoswkgx"
#define infousermodes "diOoswkgxc"

/** Operator privileges. */
enum Priv
Expand Down Expand Up @@ -166,6 +166,7 @@ enum Flag
FLAG_DEBUG, /**< send global debug/anti-hack info */
FLAG_ACCOUNT, /**< account name has been set */
FLAG_HIDDENHOST, /**< user's host is hidden */
FLAG_COMMONCHANS, /**< only accepts messages from users in common channels */
FLAG_LAST_FLAG, /**< number of flags */
FLAG_LOCAL_UMODES = FLAG_LOCOP, /**< First local mode flag */
FLAG_GLOBAL_UMODES = FLAG_OPER /**< First global mode flag */
Expand Down Expand Up @@ -599,6 +600,8 @@ struct Client {
#define IsHiddenHost(x) HasFlag(x, FLAG_HIDDENHOST)
/** Return non-zero if the client has an active PING request. */
#define IsPingSent(x) HasFlag(x, FLAG_PINGSENT)
/** Return non-zero if the client has mode +c (only messages from common channels). */
#define IsCommonChans(x) HasFlag(x, FLAG_COMMONCHANS)

/** Return non-zero if the client has operator or server privileges. */
#define IsPrivileged(x) (IsAnOper(x) || IsServer(x))
Expand Down Expand Up @@ -645,6 +648,8 @@ struct Client {
#define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST)
/** Mark a client as having a pending PING. */
#define SetPingSent(x) SetFlag(x, FLAG_PINGSENT)
/** Mark a client as having mode +c (only messages from those in common channels). */
#define SetCommonChans(x) SetFlag(x, FLAG_COMMONCHANS)

/** Return non-zero if \a sptr sees \a acptr as an operator. */
#define SeeOper(sptr,acptr) (IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) \
Expand Down Expand Up @@ -680,6 +685,8 @@ struct Client {
#define ClearPingSent(x) ClrFlag(x, FLAG_PINGSENT)
/** Clear the client's HUB flag. */
#define ClearHub(x) ClrFlag(x, FLAG_HUB)
/** Remove mode +c (only accepts messages from common channels) from the client. */
#define ClearCommonChans(x) ClrFlag(x, FLAG_COMMONCHANS)

/* free flags */
#define FREEFLAG_SOCKET 0x0001 /**< socket needs to be freed */
Expand Down
35 changes: 35 additions & 0 deletions ircd/ircd_relay.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,28 @@ void relay_directed_notice(struct Client* sptr, char* name, char* server, const
}
}

/** Check if two users share a common channel.
* @param[in] sptr Source client.
* @param[in] acptr Target client.
* @return Non-zero if users share a channel, zero otherwise.
*/
static int has_common_channel(struct Client *sptr, struct Client *acptr)
{
struct Membership *schan, *achan;

for (schan = cli_user(sptr)->channel; schan; schan = schan->next_channel) {
if (IsZombie(schan) || IsDelayedJoin(schan))
continue;
for (achan = cli_user(acptr)->channel; achan; achan = achan->next_channel) {
if (IsZombie(achan) || IsDelayedJoin(achan))
continue;
if (schan->channel == achan->channel)
return 1; /* Found common channel */
}
}
return 0; /* No common channels */
}

/** Relay a private message from a local user.
* Returns an error if the user does not exist or sending to him would
* exceed the source's free targets. Sends an AWAY status message if
Expand All @@ -426,6 +448,12 @@ void relay_private_message(struct Client* sptr, const char* name, const char* te
is_silenced(sptr, acptr))
return;

/* Check +c mode: block private messages from users not in common channels */
if (IsCommonChans(acptr) && !IsChannelService(sptr) && !IsOper(sptr)) {
if (!has_common_channel(sptr, acptr))
return;
}

/*
* send away message if user away
*/
Expand Down Expand Up @@ -464,6 +492,13 @@ void relay_private_notice(struct Client* sptr, const char* name, const char* tex
check_target_limit(sptr, acptr, NULL)) ||
is_silenced(sptr, acptr))
return;

/* Check +c mode: block notices from users not in common channels */
if (IsCommonChans(acptr) && !IsChannelService(sptr) && !IsOper(sptr)) {
if (!has_common_channel(sptr, acptr))
return;
}

/*
* deliver the message
*/
Expand Down
10 changes: 9 additions & 1 deletion ircd/s_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,8 @@ static const struct UserMode {
{ FLAG_CHSERV, 'k' },
{ FLAG_DEBUG, 'g' },
{ FLAG_ACCOUNT, 'r' },
{ FLAG_HIDDENHOST, 'x' }
{ FLAG_HIDDENHOST, 'x' },
{ FLAG_COMMONCHANS, 'c' }
};

/** Length of #userModeList. */
Expand Down Expand Up @@ -1081,12 +1082,19 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc,
}
/* There is no -r */
break;
case 'c':
if (what == MODE_ADD)
SetCommonChans(sptr);
else
ClearCommonChans(sptr);
break;
default:
send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m);
break;
}
}
}

/*
* Evaluate rules for new user mode
* Stop users making themselves operators too easily:
Expand Down