#define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag))
/** String containing valid user modes, in no particular order. */
-#define infousermodes "dioswkgxR"
+#define infousermodes "dioswkgxRXIn"
/** Operator privileges. */
enum Priv
FLAG_ACCOUNTONLY, /**< ASUKA_R: hide privmsgs/notices if
user is not authed or opered */
FLAG_HIDDENHOST, /**< user's host is hidden */
+ FLAG_NOCHAN, /**< user's channels are hidden */
+ FLAG_NOIDLE, /**< user's idletime is hidden */
+ FLAG_XTRAOP, /**< oper has special powers */
+
FLAG_LAST_FLAG, /**< number of flags */
FLAG_LOCAL_UMODES = FLAG_LOCOP, /**< First local mode flag */
FLAG_GLOBAL_UMODES = FLAG_OPER /**< First global mode flag */
#define IsAccount(x) HasFlag(x, FLAG_ACCOUNT)
/** Return non-zero if the client has set mode +x (hidden host). */
#define IsHiddenHost(x) HasFlag(x, FLAG_HIDDENHOST)
+/** Return non-zero if the client has set mode +X (xtraop) */
+#define IsXtraOp(x) HasFlag(x, FLAG_XTRAOP)
+/** Return non-zero if the client has set mode +n (hide channels) */
+#define IsNoChan(x) HasFlag(x, FLAG_NOCHAN)
+/** Return non-zero if the client has set mode +I (hide idletime) */
+#define IsNoIdle(x) HasFlag(x, FLAG_NOIDLE)
/** Return non-zero if the client has an active PING request. */
#define IsPingSent(x) HasFlag(x, FLAG_PINGSENT)
/** Return non-zero if the client should not receive privmsgs/notices
#define SetAccount(x) SetFlag(x, FLAG_ACCOUNT)
/** Mark a client as having mode +x (hidden host). */
#define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST)
+/** Mark a client as having mode +X (xtraop). */
+#define SetXtraOp(x) SetFlag(x, FLAG_XTRAOP)
+/** Mark a client as having mode +n (hide channels). */
+#define SetNoChan(x) SetFlag(x, FLAG_NOCHAN)
+/** Mark a client as having mode +I (hide idletime). */
+#define SetNoIdle(x) SetFlag(x, FLAG_NOIDLE)
/** Mark a client as having a pending PING. */
#define SetPingSent(x) SetFlag(x, FLAG_PINGSENT)
/** Mark a client as having mode +R (account only). */
#define ClearServNotice(x) ClrFlag(x, FLAG_SERVNOTICE)
/** Remove mode +x (hidden host) from the client. */
#define ClearHiddenHost(x) ClrFlag(x, FLAG_HIDDENHOST)
+/** Remove mode +X (xtraop) from a client. */
+#define ClearXtraOp(x) ClrFlag(x, FLAG_XTRAOP)
+/** Remove mode +n (hide channels) from a client. */
+#define ClearNoChan(x) ClrFlag(x, FLAG_NOCHAN)
+/** Remove mode +I (hide idletime) from a client. */
+#define ClearNoIdle(x) ClrFlag(x, FLAG_NOIDLE)
/** Clear the client's pending PING flag. */
#define ClearPingSent(x) ClrFlag(x, FLAG_PINGSENT)
/** Remove mode +R (account only) from a client */
FEAT_HIDDEN_IP,
FEAT_AUTOINVISIBLE,
FEAT_CONNEXIT_NOTICES,
+ FEAT_USER_HIDECHANS,
FEAT_OPLEVELS,
FEAT_LOCAL_CHANNELS,
FEAT_TOPIC_BURST,
/* ERR_DESYNC 484 Dalnet,PTlink */
/* ERR_ATTACKDENY 484 unreal */
/* ERR_RESTRICTED 484 IRCnet extension */
+#define ERR_ISREALSERVICE 485 /* QuakeNet/ASUKA extension */
/* ERR_UNIQOPRIVSNEEDED 485 IRCnet extension */
/* ERR_KILLDENY 485 unreal */
/* ERR_CANTKICKADMIN 485 PTlink */
/*
* Servers can always speak on channels.
*/
- if (IsServer(cptr))
+ if (IsServer(cptr) || IsXtraOp(cptr))
return 1;
member = find_channel_member(cptr, chptr);
if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
(MODE_DEL | MODE_CHANOP)) {
/* prevent +k users from being deopped */
- if (IsChannelService(state->cli_change[i].client)) {
+ /*
+ * ASUKA_X:
+ * Allow +X'ed users to mess with +k'ed.
+ * --Bigfoot
+ */
+ if ((IsChannelService(state->cli_change[i].client) && IsService(cli_user(state->cli_change[i].client)->server)) || (IsChannelService(state->cli_change[i].client) && !IsXtraOp(state->sptr))) {
if (state->flags & MODE_PARSE_FORCE) /* it was forced */
sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
state->chptr,
(IsServer(state->sptr) ? cli_name(state->sptr) :
cli_name((cli_user(state->sptr))->server)));
- else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
- send_reply(state->sptr, ERR_ISCHANSERVICE,
- cli_name(state->cli_change[i].client),
- state->chptr->chname);
+ else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET && (state->sptr != state->cli_change[i].client)) {
+ if(IsService(cli_user(state->cli_change[i].client)->server) && IsChannelService(state->cli_change[i].client)){
+ send_reply(state->sptr, ERR_ISREALSERVICE,
+ cli_name(state->cli_change[i].client),
+ state->chptr->chname);
+ }else{
+ send_reply(state->sptr, ERR_ISCHANSERVICE,
+ cli_name(state->cli_change[i].client),
+ state->chptr->chname);
+ }
+
continue;
}
}
F_S(HIDDEN_IP, 0, "127.0.0.1", 0),
F_B(AUTOINVISIBLE, 0, 1, 0),
F_B(CONNEXIT_NOTICES, 0, 0, 0),
+ F_B(USER_HIDECHANS, 0, 0, 0),
F_B(OPLEVELS, 0, 1, 0),
F_B(LOCAL_CHANNELS, 0, 1, 0),
F_B(TOPIC_BURST, 0, 0, 0),
else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
err = ERR_BADCHANNELKEY;
+ /*
+ * ASUKA_X:
+ * Allow XtraOpers to join all channels.
+ * --Bigfoot
+ */
+ if (IsXtraOp(sptr))
+ err = 0;
+
/* An oper with WALK_LCHAN privilege can join a local channel
* he otherwise could not join by using "OVERRIDE" as the key.
* This will generate a HACK(4) notice, but fails if the oper
return 0; /* find_chasing sends the reply for us */
/* Don't allow the channel service to be kicked */
- if (IsChannelService(who))
+ /*
+ * ASUKA_X:
+ * Allow +X'ed users to kick +k'ed, but not U-lined services.
+ * --Bigfoot
+ */
+ if (IsChannelService(who) && IsService(cli_user(who)->server))
+ return send_reply(sptr, ERR_ISREALSERVICE, cli_name(who), chptr->chname);
+
+ if (IsChannelService(who) && !IsXtraOp(sptr) && (who!=sptr))
return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname);
/* Prevent kicking opers from local channels -DM- */
/*
* if the user is +k, prevent a kill from local user
*/
- if (IsChannelService(victim))
+ /*
+ * ASUKA_X:
+ * Allow +X'ed users to kill +k'ed, but not U-lined services.
+ * --Bigfoot
+ */
+ if (IsChannelService(victim) && IsService(cli_user(victim)->server))
+ return send_reply(sptr, ERR_ISREALSERVICE, "KILL", cli_name(victim));
+
+ if (IsChannelService(victim) && !IsXtraOp(sptr) && !(victim==sptr))
return send_reply(sptr, ERR_ISCHANSERVICE, "KILL", cli_name(victim));
cli_info(acptr));
/* Display the channels this user is on. */
- if (!IsChannelService(acptr))
+ if ((!IsChannelService(acptr) && !IsNoChan(acptr)) || (acptr==sptr))
{
struct Membership* chan;
mlen = strlen(cli_name(&me)) + strlen(cli_name(sptr)) + 12 + strlen(name);
* probably a good place to add them :)
*/
- if (MyConnect(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) ||
- (sptr == acptr || IsAnOper(sptr) || parc >= 3)))
+ if (MyConnect(acptr) &&
+ (IsAnOper(sptr) ||
+ (!IsNoIdle(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) ||
+ sptr == acptr || parc >= 3))))
send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last,
cli_firsttime(acptr));
}
/* 483 */
{ ERR_CANTKILLSERVER, ":You cant kill a server!", "483" },
/* 484 */
- { ERR_ISCHANSERVICE, "%s %s :Cannot kill, kick or deop a network service", "484" },
+ { ERR_ISCHANSERVICE, "%s %s :Cannot kill, kick or deop an IRC operator", "484" },
/* 485 */
- { 0 },
+ { ERR_ISREALSERVICE, "%s %s :Cannot kill, kick or deop a network service", "485" },
/* 486 */
{ ERR_ACCOUNTONLY, "%s :You must be authed in order to message this user", "486" },
/* 487 */
{ FLAG_DEBUG, 'g' },
{ FLAG_ACCOUNT, 'r' },
{ FLAG_HIDDENHOST, 'x' },
- { FLAG_ACCOUNTONLY, 'R' }
+ { FLAG_ACCOUNTONLY, 'R' },
+ { FLAG_XTRAOP, 'X' },
+ { FLAG_NOCHAN, 'n' },
+ { FLAG_NOIDLE, 'I' }
};
/** Length of #userModeList. */
if (MyUser(sptr)) {
const char* channel_name;
struct Membership *member;
- if ((channel_name = find_no_nickchange_channel(sptr))) {
+ if ((channel_name = find_no_nickchange_channel(sptr)) && !IsXtraOp(sptr)) {
return send_reply(cptr, ERR_BANNICKCHANGE, channel_name);
}
/*
else
ClearChannelService(sptr);
break;
+ case 'X':
+ if (what == MODE_ADD)
+ SetXtraOp(sptr);
+ else
+ ClearXtraOp(sptr);
+ break;
+ case 'n':
+ if (what == MODE_ADD)
+ SetNoChan(sptr);
+ else
+ ClearNoChan(sptr);
+ break;
+ case 'I':
+ if (what == MODE_ADD)
+ SetNoIdle(sptr);
+ else
+ ClearNoIdle(sptr);
+ break;
case 'g':
if (what == MODE_ADD)
SetDebug(sptr);
* new umode; servers can set it, local users cannot;
* prevents users from /kick'ing or /mode -o'ing
*/
- if (!FlagHas(&setflags, FLAG_CHSERV))
+ if (!FlagHas(&setflags, FLAG_CHSERV) && !IsOper(sptr))
ClearChannelService(sptr);
+ if (!FlagHas(&setflags, FLAG_XTRAOP) && !IsOper(sptr))
+ ClearXtraOp(sptr);
+ if (!FlagHas(&setflags, FLAG_NOCHAN) && !(IsOper(sptr) || feature_bool(FEAT_USER_HIDECHANS)))
+ ClearNoChan(sptr);
+ if (!FlagHas(&setflags, FLAG_NOIDLE) && !IsOper(sptr))
+ ClearNoIdle(sptr);
+
/*
* only send wallops to opers
*/
if (repchan)
chan = find_channel_member(acptr, repchan);
else if ((!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA)))
- && !IsChannelService(acptr))
+ && !IsChannelService(acptr) && !IsNoChan(acptr))
{
for (chan = cli_user(acptr)->channel; chan; chan = chan->next_channel)
if (PubChannel(chan->channel) &&