autogen.sh produces the Makefile.in's, which are necessary for the configure
script itself, and some more files for make. To run autogen.sh you'll need
-GNU autoconf and GNU automake (use recent versions! autoconf 2.53 and
-automake 1.6.1 are known to work).
-
-Again: "end users" do not need this step!
+GNU autoconf and GNU automake: at least autoconf 2.61 and automake 1.10 are
+requird, newer is better. But don't use automake 1.12 or newer for creating
+distribution archives: it will work but lack "de-ANSI-fucation" support in the
+generated Makefile's! Stick with automake 1.11.x for this purpose ...
+So automake 1.11.x and autoconf 2.67+ is recommended.
+
+Again: "end users" do not need this step and neither need GNU autoconf nor GNU
+automake at all!
2): "./configure"
( [ -n "$V" ] && echo "$V" || echo "??" ) | tr -d '\n';
]))
+m4_ifdef([AM_SILENT_RULES],
+ [m4_define([ng_color_tests], [color-tests])],
+ [m4_define([ng_color_tests], [])])
+
# -- Initialisation --
-AC_PREREQ([2.67])
+AC_PREREQ([2.61])
AC_INIT([ngIRCd], VERSION_ID,
[ngircd-ml@ngircd.barton.de], [ngircd], [http://ngircd.barton.de/])
AC_CONFIG_HEADER([src/config.h])
AC_CANONICAL_HOST
-AM_INIT_AUTOMAKE([1.11])
+AM_INIT_AUTOMAKE([-Wall 1.10 ]ng_color_tests)
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
static_docs = \
Bopm.txt \
Capabilities.txt \
+ Contributing.txt \
FAQ.txt \
GIT.txt \
HowToRelease.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.
EXTRA_DIST = Makefile.ng
-INCLUDES = -I$(srcdir)/../portab
+AM_CPPFLAGS = -I$(srcdir)/../portab
noinst_LIBRARIES = libngipaddr.a
EXTRA_DIST = Makefile.ng
-INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr
+AM_CPPFLAGS = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr
LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \
-varuse -retvalother -emptyret -unrecog
for f in *.c; do \
echo "checking $$f ..."; \
splint $$f $(LINTARGS) -I$(srcdir) -I$(srcdir)/.. \
- $(INCLUDES) $(AM_CFLAGS) >lint.out 2>&1; \
+ $(AM_CPPFLAGS) $(AM_CFLAGS) >lint.out 2>&1; \
grep "no warnings" lint.out > /dev/null 2>&1; \
if [ $$? -ne 0 ]; then \
waswarning=1; \
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;
}
+ }
+
+ 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++;
+ }
- /* Check if user has operator status */
- if (!strchr(Channel_UserModes(chan, Origin), 'o')) {
- IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG,
- Client_ID(Origin), Name);
+ 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 )
{
free(Conf_SSLOptions.DHFile);
Conf_SSLOptions.DHFile = NULL;
array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
+
+ array_free(&Conf_SSLOptions.ListenPorts);
}
/**
PACKAGE_NAME, PACKAGE_VERSION);
free(Conf_ListenAddress);
Conf_ListenAddress = NULL;
+ array_free(&Conf_ListenPorts);
array_free(&Conf_Motd);
strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile));
strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile));
bool
ConnSSL_InitLibrary( void )
{
+ if (!array_bytes(&Conf_SSLOptions.ListenPorts))
+ return true;
+
#ifdef HAVE_LIBSSL
SSL_CTX *newctx;
* According to OpenSSL RAND_egd(3): "The automatic query of /var/run/egd-pool et al was added in OpenSSL 0.9.7";
* so it makes little sense to deal with PRNGD seeding ourselves.
*/
+ array_free(&Conf_SSLOptions.ListenPorts);
return false;
}
newctx = SSL_CTX_new(SSLv23_method());
if (!newctx) {
LogOpenSSLError("SSL_CTX_new()", NULL);
+ array_free(&Conf_SSLOptions.ListenPorts);
return false;
}
return true;
out:
SSL_CTX_free(newctx);
+ array_free(&Conf_SSLOptions.ListenPorts);
return false;
#endif
#ifdef HAVE_LIBGNUTLS
err = gnutls_global_init();
if (err) {
Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err));
+ array_free(&Conf_SSLOptions.ListenPorts);
return false;
}
- if (!ConnSSL_LoadServerKey_gnutls())
+ if (!ConnSSL_LoadServerKey_gnutls()) {
+ array_free(&Conf_SSLOptions.ListenPorts);
return false;
+ }
Log(LOG_INFO, "gnutls %s initialized.", gnutls_check_version(NULL));
initialized = true;
return true;
cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
if (!cert_file) {
- Log(LOG_NOTICE, "No SSL server key configured, SSL disabled.");
+ Log(LOG_ERR, "No SSL server key configured!");
return false;
}
assert(ctx);
if (!Conf_SSLOptions.KeyFile) {
- Log(LOG_NOTICE, "No SSL server key configured, SSL disabled.");
+ Log(LOG_ERR, "No SSL server key configured!");
return false;
}
#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"
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 */
target = Client_Search(Req->argv[0]);
else
target = Client_ThisServer();
-
+
/* Make sure that the target is a server */
if (target && Client_Type(target) != CLIENT_SERVER)
target = Client_Introducer(target);
}
-static const char *
-who_flags_qualifier(CLIENT *Client, const char *chan_user_modes)
+/**
+ * Return channel user mode prefix(es).
+ *
+ * @param Client The client requesting the mode prefixes.
+ * @param chan_user_modes String with channel user modes.
+ * @param str String buffer to which the prefix(es) will be appended.
+ * @param len Size of "str" buffer.
+ * @return Pointer to "str".
+ */
+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 (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;
}
bool is_visible, is_member, is_ircop;
CL2CHAN *cl2chan;
const char *client_modes;
- const char *chan_user_modes;
- char flags[8];
+ char flags[10];
CLIENT *c;
int count = 0;
if (is_ircop)
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(Client, Channel_UserModes(Chan, c),
+ flags, sizeof(flags));
if (!write_whoreply(Client, c, Channel_Name(Chan),
flags))
if (str[strlen(str) - 1] != ':')
strlcat(str, " ", sizeof(str));
- strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)),
- sizeof(str));
+ who_flags_qualifier(Client, Channel_UserModes(chan, c),
+ str, sizeof(str));
strlcat(str, Channel_Name(chan), sizeof(str));
if (strlen(str) > (LINE_LEN - CHANNEL_NAME_LEN - 4)) {
Conn_CountMax(), Conn_CountAccepted()))
return DISCONNECTED;
#endif
-
+
return CONNECTED;
} /* IRC_Send_LUSERS */
if (is_member || is_visible) {
if (str[strlen(str) - 1] != ':')
strlcat(str, " ", sizeof(str));
- if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX &&
- 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(Client, Channel_UserModes(Chan, cl),
+ str, sizeof(str));
strlcat(str, Client_ID(cl), sizeof(str));
if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {
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));
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';
argadd[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,
/* 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;
CLIENT *from, *c;
int i;
CONN_ID con;
-
+
assert( Client != NULL );
assert( Req != NULL );
Conn_Close( Client_Conn( Client ), NULL, "Bad password", true);
return DISCONNECTED;
}
-
+
/* Is there a registered server with this ID? */
if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
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;
-
+
assert( Client != NULL );
assert( Req != NULL );
while( ptr )
{
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++;
}
Channel_Join( c, channame );
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 ));
}
else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
-
+
/* search for next Nick */
ptr = strtok( NULL, "," );
}
#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"
/* SSL initialization */
if (!ConnSSL_InitLibrary())
Log(LOG_WARNING,
- "Warning: Error during SSL initialization, continuing ...");
+ "Error during SSL initialization, continuing without SSL ...");
/* Change root */
if (Conf_Chroot[0]) {
* (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" */
__ng_Makefile_am_template__
-INCLUDES = -I$(srcdir)/../portab
+AM_CPPFLAGS = -I$(srcdir)/../portab
EXTRA_DIST = \
Makefile.ng README functions.inc getpid.sh \
"@* 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 }
EXTRA_DIST = Makefile.ng
-INCLUDES = -I$(srcdir)/../portab
+AM_CPPFLAGS = -I$(srcdir)/../portab
noinst_LIBRARIES = libngtool.a