commit - f38a9035e5439cb395b2de6b9bdfa36102bfe80c
commit + f37600ee01f6cfd86e8fa80f77ee26ebaf3012b2
blob - 0035855c90e6f21dee2a6fb55c9009c5d8873b22
blob + a7b6a22ca342633e30fe0be9b83ea9ad975f0476
--- doc/.gitignore
+++ doc/.gitignore
sample-ngircd.conf
+Add_Modes.txt
blob - c2c533f2a67e1784561869cfee1ac49c5bf0fd90
blob + dec80ce819756e3576ee6d70dfe39e21fe676379
--- doc/Modes.txt
+++ doc/Modes.txt
mode since description
+ q 20? User is channel owner can only be set by a service, other
+ owner and irc op. Can promote other users to q, a, o, h, v.
+ a 20? User is channel admin and can promote other users to v, h, o
o 0.2.0 User is channel operator and can op/kick/... other members.
+ h 20? User is half op and can set channel modes imntvIbek and kick
+ voiced and normal users.
v 0.2.0 User is "voiced" and can speak even if channel is moderated.
blob - f0a9525d348a5d992596f453fd9ba709cbd47c9a
blob + 8d001a825c013e8c77e339f5915a54eac792b6fa
--- src/ngircd/channel.c
+++ src/ngircd/channel.c
const char *Reason )
{
CHANNEL *chan;
+ char *ptr, *target_modes;
+ bool can_kick = false;
assert(Peer != NULL);
assert(Target != NULL);
/* Check that user is on the specified channel */
if (!Channel_IsMemberOf(chan, Origin)) {
IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG,
- Client_ID(Origin), Name);
+ Client_ID(Origin), Name);
return;
}
+ }
- /* Check if user has operator status */
- if (!strchr(Channel_UserModes(chan, Origin), 'o')) {
- IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG,
- Client_ID(Origin), Name);
+ if(Client_Type(Peer) == CLIENT_USER) {
+ /* Check if client has the rights to kick target */
+ ptr = Channel_UserModes(chan, Peer);
+ target_modes = Channel_UserModes(chan, Target);
+ while(*ptr) {
+ /* Owner can kick everyone */
+ if ( *ptr == 'q') {
+ can_kick = true;
+ break;
+ }
+ /* Admin can't kick owner */
+ if ( *ptr == 'a' ) {
+ if (!strchr(target_modes, 'q')) {
+ can_kick = true;
+ break;
+ }
+ }
+ /* Op can't kick owner | admin */
+ if ( *ptr == 'o' ) {
+ if (!strchr(target_modes, 'q') &&
+ !strchr(target_modes, 'a')) {
+ can_kick = true;
+ break;
+ }
+ }
+ /* Half Op can't kick owner | admin | op */
+ if ( *ptr == 'h' ) {
+ if (!strchr(target_modes, 'q') &&
+ !strchr(target_modes, 'a') &&
+ !strchr(target_modes, 'o')) {
+ can_kick = true;
+ break;
+ }
+ }
+ ptr++;
+ }
+
+ if(!can_kick) {
+ IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOLOW_MSG,
+ Client_ID(Origin), Name);
return;
}
}
static bool
Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
{
- bool is_member, has_voice, is_op;
+ bool is_member, has_voice, is_halfop, is_op, is_chanadmin, is_owner;
- is_member = has_voice = is_op = false;
+ is_member = has_voice = is_halfop = is_op = is_chanadmin = is_owner = false;
/* The server itself always can send messages :-) */
if (Client_ThisServer() == From)
is_member = true;
if (strchr(Channel_UserModes(Chan, From), 'v'))
has_voice = true;
+ if (strchr(Channel_UserModes(Chan, From), 'h'))
+ is_halfop = true;
if (strchr(Channel_UserModes(Chan, From), 'o'))
is_op = true;
+ if (strchr(Channel_UserModes(Chan, From), 'a'))
+ is_chanadmin = true;
+ if (strchr(Channel_UserModes(Chan, From), 'q'))
+ is_owner = true;
}
/*
&& !Client_HasMode(From, 'o'))
return false;
- if (is_op || has_voice)
+ if (has_voice || is_halfop || is_op || is_chanadmin || is_owner)
return true;
if (strchr(Channel_Modes(Chan), 'm'))
} /* Channel_CheckKey */
-/**
- * Check wether a client is allowed to administer a channel or not.
- *
- * @param Chan The channel to test.
- * @param Client The client from which the command has been received.
- * @param Origin The originator of the command (or NULL).
- * @param OnChannel Set to true if the originator is member of the channel.
- * @param AdminOk Set to true if the client is allowed to do
- * administrative tasks on this channel.
- * @param UseServerMode Set to true if ngIRCd should emulate "server mode",
- * that is send commands as if originating from a server
- * and not the originator of the command.
- */
-GLOBAL void
-Channel_CheckAdminRights(CHANNEL *Chan, CLIENT *Client, CLIENT *Origin,
- bool *OnChannel, bool *AdminOk, bool *UseServerMode)
-{
- assert (Chan != NULL);
- assert (Client != NULL);
- assert (OnChannel != NULL);
- assert (AdminOk != NULL);
- assert (UseServerMode != NULL);
-
- /* Use the client as origin, if no origin has been given (no prefix?) */
- if (!Origin)
- Origin = Client;
-
- *OnChannel = false;
- *AdminOk = false;
- *UseServerMode = false;
-
- if (Client_Type(Client) != CLIENT_USER
- && Client_Type(Client) != CLIENT_SERVER
- && Client_Type(Client) != CLIENT_SERVICE)
- return;
-
- /* Allow channel administration if the client is a server or service */
- if (Client_Type(Client) != CLIENT_USER) {
- *AdminOk = true;
- return;
- }
-
- *OnChannel = Channel_IsMemberOf(Chan, Origin);
-
- if (*OnChannel && strchr(Channel_UserModes(Chan, Origin), 'o')) {
- /* User is a channel operator */
- *AdminOk = true;
- } else if (Conf_OperCanMode) {
- /* IRC operators are allowed to administer channels as well */
- if (Client_OperByMe(Origin)) {
- *AdminOk = true;
- if (Conf_OperServerMode)
- *UseServerMode = true;
- }
- }
-} /* Channel_CheckAdminRights */
-
-
static CL2CHAN *
Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
{
blob - 82837599aadbb6485f0f044b447739d7b5f922fa
blob + ba7adf17adb204840418b7482b75fef975844138
--- src/ngircd/defines.h
+++ src/ngircd/defines.h
#define USERMODES "aBcCiorRswx"
/** Supported channel modes. */
-#define CHANMODES "beiIklmMnoOPrRstvz"
+#define CHANMODES "abehiIklmMnoOPqrRstvz"
/** Away message for users connected to linked servers. */
#define DEFAULT_AWAY_MSG "Away"
blob - d714b48fcb8e3d28aed8cb2101bc6e452295290b
blob + 9e88e1bd0031de480a33d3ddfb5b447fed81d013
--- src/ngircd/irc-channel.c
+++ src/ngircd/irc-channel.c
CHANNEL *chan;
CLIENT *from;
char *topic;
- bool onchannel, topicok, use_servermode, r;
+ bool r, is_oper;
assert( Client != NULL );
assert( Req != NULL );
return IRC_WriteStrClient(from, ERR_NOSUCHCHANNEL_MSG,
Client_ID(from), Req->argv[0]);
- Channel_CheckAdminRights(chan, Client, from,
- &onchannel, &topicok, &use_servermode);
-
- if (!onchannel && !topicok)
+ /* Only IRC opers and channel members allowed */
+ is_oper = Client_OperByMe(from);
+ if (!Channel_IsMemberOf(chan, from) && !is_oper)
return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
Client_ID(from), Req->argv[0]);
}
if (strchr(Channel_Modes(chan), 't')) {
- /* Topic Lock. Is the user a channel or IRC operator? */
- if (!topicok)
+ /* Topic Lock. Is the user a channel op or IRC operator? */
+ if(!strchr(Channel_UserModes(chan, from), 'h') &&
+ !strchr(Channel_UserModes(chan, from), 'o') &&
+ !strchr(Channel_UserModes(chan, from), 'a') &&
+ !strchr(Channel_UserModes(chan, from), 'q') &&
+ !is_oper)
return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
Client_ID(from),
Channel_Name(chan));
Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
Req->argv[1][0] ? Req->argv[1] : "<none>");
- if (use_servermode)
+ if (Conf_OperServerMode)
from = Client_ThisServer();
/* Update channel and forward new topic to other servers */
blob - 6eb8d9421922e8606e0e5cbd83729f1c90c7d4b5
blob + 7a122ef790a0c5ec0148c3224b83956a8de00020
--- src/ngircd/irc-info.c
+++ src/ngircd/irc-info.c
}
-static const char *
-who_flags_qualifier(CLIENT *Client, const char *chan_user_modes)
+static char *
+who_flags_qualifier(CLIENT *Client, const char *chan_user_modes, char *str, size_t len)
{
assert(Client != NULL);
-
- if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
- if (strchr(chan_user_modes, 'o') &&
- strchr(chan_user_modes, 'v'))
- return "@+";
+
+ if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
+ if (strchr(chan_user_modes, 'q'))
+ strlcat(str, "~", len);
+ if (strchr(chan_user_modes, 'a'))
+ strlcat(str, "&", len);
+ if (strchr(chan_user_modes, 'o'))
+ strlcat(str, "@", len);
+ if (strchr(chan_user_modes, 'h'))
+ strlcat(str, "&", len);
+ if (strchr(chan_user_modes, 'v'))
+ strlcat(str, "+", len);
+
+ return str;
}
-
- if (strchr(chan_user_modes, 'o'))
- return "@";
+
+ if (strchr(chan_user_modes, 'q'))
+ strlcat(str, "~", len);
+ else if (strchr(chan_user_modes, 'a'))
+ strlcat(str, "&", len);
+ else if (strchr(chan_user_modes, 'o'))
+ strlcat(str, "@", len);
+ else if (strchr(chan_user_modes, 'h'))
+ strlcat(str, "%", len);
else if (strchr(chan_user_modes, 'v'))
- return "+";
- return "";
+ strlcat(str, "+", len);
+
+ return str;
}
CL2CHAN *cl2chan;
const char *client_modes;
const char *chan_user_modes;
- char flags[8];
+ char flags[10];
CLIENT *c;
int count = 0;
strlcat(flags, "*", sizeof(flags));
chan_user_modes = Channel_UserModes(Chan, c);
- strlcat(flags, who_flags_qualifier(c, chan_user_modes),
- sizeof(flags));
-
+ who_flags_qualifier(c, chan_user_modes, flags, sizeof(flags));
+
if (!write_whoreply(Client, c, Channel_Name(Chan),
flags))
return DISCONNECTED;
if (str[strlen(str) - 1] != ':')
strlcat(str, " ", sizeof(str));
- strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)),
- sizeof(str));
+ who_flags_qualifier(c, Channel_UserModes(chan, c), str, sizeof(str));
strlcat(str, Channel_Name(chan), sizeof(str));
if (strlen(str) > (LINE_LEN - CHANNEL_NAME_LEN - 4)) {
if (is_member || is_visible) {
if (str[strlen(str) - 1] != ':')
strlcat(str, " ", sizeof(str));
- if (Client_Cap(cl) & CLIENT_CAP_MULTI_PREFIX) {
- if (strchr(Channel_UserModes(Chan, cl), 'o') &&
- strchr(Channel_UserModes(Chan, cl), 'v'))
- strlcat(str, "@+", sizeof(str));
- } else {
- if (strchr(Channel_UserModes(Chan, cl), 'o'))
- strlcat(str, "@", sizeof(str));
- else if (strchr(Channel_UserModes(Chan, cl), 'v'))
- strlcat(str, "+", sizeof(str));
- }
+
+ who_flags_qualifier(cl, Channel_UserModes(Chan, cl), str, sizeof(str));
strlcat(str, Client_ID(cl), sizeof(str));
if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {
blob - 71557201d8d938f4a5ff65416f50eb487f78333d
blob + f39463433ce5261b0d3736174845f92aadb21e76
--- src/ngircd/irc-mode.c
+++ src/ngircd/irc-mode.c
Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
{
char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
- argadd[CLIENT_PASS_LEN], *mode_ptr;
- bool connected, set, skiponce, retval, onchannel, modeok, use_servermode;
+ argadd[CLIENT_PASS_LEN], *mode_ptr, *o_mode_ptr;
+ bool connected, set, skiponce, retval, use_servermode,
+ is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
int mode_arg, arg_arg, mode_arg_count = 0;
CLIENT *client;
long l;
size_t len;
+ is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;
+
if (Channel_IsModeless(Channel))
return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG,
Client_ID(Client), Channel_Name(Channel));
if (Req->argc <= 1)
return Channel_Mode_Answer_Request(Origin, Channel);
- Channel_CheckAdminRights(Channel, Client, Origin,
- &onchannel, &modeok, &use_servermode);
+ /* Check if origin is oper and opers can use mode */
+ use_servermode = Conf_OperServerMode;
+ if(Client_OperByMe(Client) && Conf_OperCanMode) {
+ is_oper = true;
+ }
+
+ /* Check if client is a server/service */
+ if(Client_Type(Client) == CLIENT_SERVER ||
+ Client_Type(Client) == CLIENT_SERVICE) {
+ is_machine = true;
+ }
- if (!onchannel && !modeok)
+ /* Check if client is member of channel or an oper or an server/service */
+ if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
Client_ID(Origin),
Channel_Name(Channel));
/* Are there arguments left? */
if (arg_arg >= Req->argc)
arg_arg = -1;
+
+ if(!is_machine) {
+ o_mode_ptr = Channel_UserModes(Channel, Client);
+ while( *o_mode_ptr ) {
+ if ( *o_mode_ptr == 'q')
+ is_owner = true;
+ if ( *o_mode_ptr == 'a')
+ is_admin = true;
+ if ( *o_mode_ptr == 'o')
+ is_op = true;
+ if ( *o_mode_ptr == 'h')
+ is_halfop = true;
+ o_mode_ptr++;
+ }
+ }
/* Validate modes */
x[0] = '\0';
client = NULL;
switch (*mode_ptr) {
/* --- Channel modes --- */
+ case 'R': /* Registered users only */
+ case 's': /* Secret channel */
+ case 'z': /* Secure connections only */
+ if(!is_oper && !is_machine && !is_owner &&
+ !is_admin && !is_op) {
+ connected = IRC_WriteStrClient(Origin,
+ ERR_CHANOPRIVSNEEDED_MSG,
+ Client_ID(Origin), Channel_Name(Channel));
+ goto chan_exit;
+ }
case 'i': /* Invite only */
case 'M': /* Only identified nicks can write */
case 'm': /* Moderated */
case 'n': /* Only members can write */
- case 'R': /* Registered users only */
- case 's': /* Secret channel */
case 't': /* Topic locked */
- case 'z': /* Secure connections only */
- if (modeok)
+ if(is_oper || is_machine || is_owner ||
+ is_admin || is_op || is_halfop)
x[0] = *mode_ptr;
else
connected = IRC_WriteStrClient(Origin,
if (Mode_Limit_Reached(Client, mode_arg_count++))
goto chan_exit;
if (!set) {
- if (modeok)
+ if (is_oper || is_machine || is_owner ||
+ is_admin || is_op || is_halfop)
x[0] = *mode_ptr;
else
connected = IRC_WriteStrClient(Origin,
break;
}
if (arg_arg > mode_arg) {
- if (modeok) {
+ if (is_oper || is_machine || is_owner ||
+ is_admin || is_op || is_halfop) {
Channel_ModeDel(Channel, 'k');
Channel_SetKey(Channel,
Req->argv[arg_arg]);
if (Mode_Limit_Reached(Client, mode_arg_count++))
goto chan_exit;
if (!set) {
- if (modeok)
+ if (is_oper || is_machine || is_owner ||
+ is_admin || is_op || is_halfop)
x[0] = *mode_ptr;
else
connected = IRC_WriteStrClient(Origin,
break;
}
if (arg_arg > mode_arg) {
- if (modeok) {
+ if (is_oper || is_machine || is_owner ||
+ is_admin || is_op || is_halfop) {
l = atol(Req->argv[arg_arg]);
if (l > 0 && l < 0xFFFF) {
Channel_ModeDel(Channel, 'l');
}
break;
case 'O': /* IRC operators only */
- if (modeok) {
+ if (set) {
/* Only IRC operators are allowed to
* set the 'O' channel mode! */
- if (set && !(Client_OperByMe(Client)
- || Client_Type(Client) == CLIENT_SERVER))
+ if(is_oper || is_machine)
+ x[0] = 'O';
+ else
connected = IRC_WriteStrClient(Origin,
ERR_NOPRIVILEGES_MSG,
Client_ID(Origin));
- else
- x[0] = 'O';
- } else
+ } else if(is_oper || is_machine || is_owner ||
+ is_admin || is_op)
+ x[0] = 'O';
+ else
connected = IRC_WriteStrClient(Origin,
- ERR_CHANOPRIVSNEEDED_MSG,
- Client_ID(Origin),
- Channel_Name(Channel));
- break;
+ ERR_CHANOPRIVSNEEDED_MSG,
+ Client_ID(Origin),
+ Channel_Name(Channel));
+ break;
case 'P': /* Persistent channel */
- if (modeok) {
+ if (set) {
/* Only IRC operators are allowed to
* set the 'P' channel mode! */
- if (set && !(Client_OperByMe(Client)
- || Client_Type(Client) == CLIENT_SERVER))
+ if(is_oper || is_machine)
+ x[0] = 'P';
+ else
connected = IRC_WriteStrClient(Origin,
ERR_NOPRIVILEGES_MSG,
Client_ID(Origin));
- else
- x[0] = 'P';
- } else
+ } else if(is_oper || is_machine || is_owner ||
+ is_admin || is_op)
+ x[0] = 'P';
+ else
connected = IRC_WriteStrClient(Origin,
ERR_CHANOPRIVSNEEDED_MSG,
Client_ID(Origin),
Channel_Name(Channel));
break;
/* --- Channel user modes --- */
- case 'a':
- case 'h':
- case 'q':
- if (Client_Type(Client) != CLIENT_SERVER) {
+ case 'q': /* Owner */
+ case 'a': /* Channel admin */
+ if(!is_oper && !is_machine && !is_owner) {
connected = IRC_WriteStrClient(Origin,
ERR_CHANOPRIVSNEEDED_MSG,
Client_ID(Origin),
goto chan_exit;
}
case 'o': /* Channel operator */
+ if(!is_oper && !is_machine && !is_owner &&
+ !is_admin && !is_op) {
+ connected = IRC_WriteStrClient(Origin,
+ ERR_CHANOPRIVSNEEDED_MSG,
+ Client_ID(Origin),
+ Channel_Name(Channel));
+ goto chan_exit;
+ }
+ case 'h': /* Half Op */
+ if(!is_oper && !is_machine && !is_owner &&
+ !is_admin && !is_op) {
+ connected = IRC_WriteStrClient(Origin,
+ ERR_CHANOPRIVSNEEDED_MSG,
+ Client_ID(Origin),
+ Channel_Name(Channel));
+ goto chan_exit;
+ }
case 'v': /* Voice */
if (arg_arg > mode_arg) {
- if (modeok) {
+ if (is_oper || is_machine || is_owner ||
+ is_admin || is_op || is_halfop) {
client = Client_Search(Req->argv[arg_arg]);
if (client)
x[0] = *mode_ptr;
else
- connected = IRC_WriteStrClient(Client,
+ connected = IRC_WriteStrClient(Origin,
ERR_NOSUCHNICK_MSG,
- Client_ID(Client),
+ Client_ID(Origin),
Req->argv[arg_arg]);
} else {
connected = IRC_WriteStrClient(Origin,
goto chan_exit;
if (arg_arg > mode_arg) {
/* modify list */
- if (modeok) {
+ if (is_oper || is_machine || is_owner ||
+ is_admin || is_op || is_halfop) {
connected = set
? Add_To_List(*mode_ptr, Origin,
Client, Channel,
blob - 5e36b02bef478ce9ac2a0d96e411deaf2e11c4cc
blob + 08495475f60520c7dd899d7cef9e10b4f4852550
--- src/ngircd/irc-op.c
+++ src/ngircd/irc-op.c
/* Is the channel "invite-only"? */
if (strchr(Channel_Modes(chan), 'i')) {
- /* Yes. The user must be channel operator! */
- if (!strchr(Channel_UserModes(chan, from), 'o'))
+ /* Yes. The user must be channel owner/admin/operator/halfop! */
+ if (!strchr(Channel_UserModes(chan, from), 'q') &&
+ !strchr(Channel_UserModes(chan, from), 'a') &&
+ !strchr(Channel_UserModes(chan, from), 'o') &&
+ !strchr(Channel_UserModes(chan, from), 'h'))
return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
Client_ID(from), Channel_Name(chan));
remember = true;
blob - 8526a573ec361b0851222314343e079b447114f6
blob + f9182d984ca9c2c6f1f743b419a198d89b31ada7
--- src/ngircd/irc-server.c
+++ src/ngircd/irc-server.c
IRC_NJOIN( CLIENT *Client, REQUEST *Req )
{
char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8];
- bool is_op, is_voiced;
+ bool is_owner, is_chanadmin, is_op, is_halfop, is_voiced;
CHANNEL *chan;
CLIENT *c;
is_op = is_voiced = false;
/* cut off prefixes */
- while(( *ptr == '@' ) || ( *ptr == '+' ))
- {
+ while(( *ptr == '~') || ( *ptr == '&' ) || ( *ptr == '@' ) ||
+ ( *ptr == '%') || ( *ptr == '+' ))
+ {
+ if( *ptr == '~' ) is_owner = true;
+ if( *ptr == '&' ) is_chanadmin = true;
if( *ptr == '@' ) is_op = true;
+ if( *ptr == 'h' ) is_halfop = true;
if( *ptr == '+' ) is_voiced = true;
ptr++;
}
chan = Channel_Search( channame );
assert( chan != NULL );
+ if( is_owner ) Channel_UserModeAdd( chan, c, 'q' );
+ if( is_chanadmin ) Channel_UserModeAdd( chan, c, 'a' );
if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
+ if( is_halfop ) Channel_UserModeAdd( chan, c, 'h' );
if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
/* announce to channel... */
}
if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out ));
+ if( is_owner ) strlcat( nick_out, "~", sizeof( nick_out ));
+ if( is_chanadmin ) strlcat( nick_out, "&", sizeof( nick_out ));
if( is_op ) strlcat( nick_out, "@", sizeof( nick_out ));
+ if( is_halfop ) strlcat( nick_out, "%", sizeof( nick_out ));
if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out ));
strlcat( nick_out, ptr, sizeof( nick_out ));
}
blob - 4f3a397b2647eabc6fd6ed21f9aa31d776df69e9
blob + d99930faa5d079995932ba3140d207c08e20e5c9
--- src/ngircd/messages.h
+++ src/ngircd/messages.h
#define RPL_YOURHOST_MSG "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)"
#define RPL_CREATED_MSG "003 %s :This server has been started %s"
#define RPL_MYINFO_MSG "004 %s %s ngircd-%s %s %s"
-#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
+#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(qaohv)~&@%%+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
#define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d EXCEPTS=e INVEX=I PENALTY :are supported on this server"
#define RPL_TRACELINK_MSG "200 %s Link %s-%s %s %s V%s %ld %d %d"
#define ERR_LISTFULL_MSG "478 %s %s %s: Channel list is full (%d)"
#define ERR_NOPRIVILEGES_MSG "481 %s :Permission denied"
#define ERR_CHANOPRIVSNEEDED_MSG "482 %s %s :You are not channel operator"
+#define ERR_CHANOPPRIVTOLOW_MSG "482 %s %s :Your privileges are to low"
#define ERR_CANTKILLSERVER_MSG "483 %s :You can't kill a server!"
#define ERR_RESTRICTED_MSG "484 %s :Your connection is restricted"
#define ERR_NICKREGISTER_MSG "484 %s :Cannot modify user mode (+R) -- Use IRC services"
blob - d59a1dc3a9be6895de5f2565337fe8e29a3fbb40
blob + 4bce60fb12a947908f14118b7aa200439f4284df
--- src/ngircd/numeric.c
+++ src/ngircd/numeric.c
* (if user is channel operator or has voice) */
if (str[strlen(str) - 1] != ':')
strlcat(str, ",", sizeof(str));
- if (strchr(Channel_UserModes(Chan, cl), 'v'))
- strlcat(str, "+", sizeof(str));
+ if (strchr(Channel_UserModes(Chan, cl), 'q'))
+ strlcat(str, "~", sizeof(str));
+ if (strchr(Channel_UserModes(Chan, cl), 'a'))
+ strlcat(str, "&", sizeof(str));
if (strchr(Channel_UserModes(Chan, cl), 'o'))
strlcat(str, "@", sizeof(str));
+ if (strchr(Channel_UserModes(Chan, cl), 'h'))
+ strlcat(str, "%", sizeof(str));
+ if (strchr(Channel_UserModes(Chan, cl), 'v'))
+ strlcat(str, "+", sizeof(str));
+
strlcat(str, Client_ID(cl), sizeof(str));
/* Send the data if the buffer is "full" */
blob - 260cd03c12898ae46c5e9d58b1f5f4fb4bcf74ff
blob + 44b6e5dfe5a3bb3cb05dddba1e08498e1cb58bdd
--- src/testsuite/mode-test.e
+++ src/testsuite/mode-test.e
"@* MODE nick :-i"
}
+send "join #usermode\r"
+expect {
+ timeout { exit 1 }
+ "@* JOIN :#usermode"
+}
+expect {
+ timeout { exit 1 }
+ "366"
+}
+
+send "mode #usermode +v nick\r"
+expect {
+ timeout { exit 1 }
+ "@* MODE #usermode +v nick\r"
+}
+
+send "mode #usermode +h nick\r"
+expect {
+ timeout { exit 1 }
+ "@* MODE #usermode +h nick\r"
+}
+
+send "mode #usermode +a nick\r"
+expect {
+ timeout { exit 1 }
+ "482 nick"
+}
+
+send "mode #usermode +q nick\r"
+expect {
+ timeout { exit 1 }
+ "482 nick"
+}
+
+send "mode #usermode -vho nick nick nick\r"
+expect {
+ timeout { exit 1 }
+ "@* MODE #usermode -vho nick nick nick"
+}
+
send "oper TestOp 123\r"
expect {
timeout { exit 1 }
"221 nick +o"
}
+send "mode #usermode +a nick\r"
+expect {
+ timeout { exit 1 }
+ "@* MODE #usermode +a nick"
+}
+
+send "mode #usermode +q nick\r"
+expect {
+ timeout { exit 1 }
+ "@* MODE #usermode +q nick"
+}
+
+send "names #usermode\r"
+expect {
+ timeout { exit 1 }
+ "353 nick = #usermode :~nick"
+}
+expect {
+ timeout { exit 1 }
+ "366 nick #usermode"
+}
+
+send "part #usermode\r"
+expect {
+ timeout { exit 1 }
+ "@* PART #usermode"
+}
+
send "join #channel\r"
expect {
timeout { exit 1 }