/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2015 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2018 Alexander Barton (alex@barton.de) and Contributors.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
GLOBAL bool
IRC_ERROR(CLIENT *Client, REQUEST *Req)
{
+ char *msg;
+
assert( Client != NULL );
assert( Req != NULL );
return CONNECTED;
}
- if (Req->argc < 1)
+ if (Req->argc < 1) {
+ msg = "Got ERROR command";
Log(LOG_NOTICE, "Got ERROR from \"%s\"!",
Client_Mask(Client));
- else
+ } else {
+ msg = Req->argv[0];
Log(LOG_NOTICE, "Got ERROR from \"%s\": \"%s\"!",
- Client_Mask(Client), Req->argv[0]);
+ Client_Mask(Client), msg);
+ }
+
+ if (Client_Conn(Client) != NONE) {
+ Conn_Close(Client_Conn(Client), NULL, msg, false);
+ return DISCONNECTED;
+ }
return CONNECTED;
} /* IRC_ERROR */
* in this case, and the prefix in Req is NULL.
*
* @param Client The client from which this command has been received or
- * Client_ThisServer() when generated interanlly.
+ * Client_ThisServer() when generated internally.
* @param Req Request structure with prefix and all parameters.
* @return CONNECTED or DISCONNECTED.
*/
/* Do we know such a client in the network? */
c = Client_Search(Nick);
if (!c) {
- LogDebug("Client with nick \"%s\" is unknown, not forwaring.", Nick);
+ LogDebug("Client with nick \"%s\" is unknown, not forwarding.", Nick);
return CONNECTED;
}
- /* Inform other servers */
- IRC_WriteStrServersPrefix(From ? Client : NULL,
- From ? From : Client_ThisServer(),
- "KILL %s :%s", Nick, Reason);
-
- if (Client_Type(c) != CLIENT_USER && Client_Type(c) != CLIENT_GOTNICK) {
+ if (Client_Type(c) != CLIENT_USER && Client_Type(c) != CLIENT_GOTNICK
+ && Client_Type(c) != CLIENT_SERVICE) {
/* Target of this KILL is not a regular user, this is
* invalid! So we ignore this case if we received a
* regular KILL from the network and try to kill the
Client_Type(c), Nick);
}
+ /* Inform other servers */
+ IRC_WriteStrServersPrefix(From ? Client : NULL,
+ From ? From : Client_ThisServer(),
+ "KILL %s :%s", Nick, Reason);
+
+
/* Save ID of this connection */
if (Client)
my_conn = Client_Conn(Client);
* Send help for a given topic to the client.
*
* @param Client The client requesting help.
- * @param Topoc The help topic requested.
+ * @param Topic The help topic requested.
* @return CONNECTED or DISCONNECTED.
*/
static bool
* @return Pointer to static (global) string buffer.
*/
static char *
-#ifdef ZLIB
+#if defined(SSL_SUPPORT) || defined(ZLIB)
Option_String(CONN_ID Idx)
-#else
-Option_String(UNUSED CONN_ID Idx)
-#endif
{
static char option_txt[8];
UINT16 options;
if(options & CONN_ZIP) /* zlib compression enabled */
strlcat(option_txt, "z", sizeof(option_txt));
#endif
- LogDebug(" *** %d: %d = %s", Idx, options, option_txt);
return option_txt;
+#else
+Option_String(UNUSED CONN_ID Idx)
+{
+ return "";
+#endif
} /* Option_String */
+/**
+ * Send a message to target(s).
+ *
+ * This function is used by IRC_{PRIVMSG|NOTICE|SQUERY} to actually
+ * send the message(s).
+ *
+ * @param Client The client from which this command has been received.
+ * @param Req Request structure with prefix and all parameters.
+ * @param ForceType Required type of the destination of the message(s).
+ * @param SendErrors Whether to report errors back to the client or not.
+ * @return CONNECTED or DISCONNECTED.
+ */
static bool
Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
{
CL2CHAN *cl2chan;
CHANNEL *chan;
char *currentTarget = Req->argv[0];
- char *lastCurrentTarget = NULL;
+ char *strtok_last = NULL;
char *message = NULL;
+ char *targets[MAX_HNDL_TARGETS];
+ int i, target_nr = 0;
assert(Client != NULL);
assert(Req != NULL);
#endif
message = Req->argv[1];
+ if (message[0] == '\0') {
+ if (!SendErrors)
+ return CONNECTED;
+ return IRC_WriteErrClient(Client, ERR_NOTEXTTOSEND_MSG,
+ Client_ID(Client));
+ }
+
/* handle msgtarget = msgto *("," msgto) */
- currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget);
+ currentTarget = strtok_r(currentTarget, ",", &strtok_last);
ngt_UpperStr(Req->command);
+ /* Please note that "currentTarget" is NULL when the target contains
+ * the separator character only, e. g. "," or ",,,," etc.! */
while (currentTarget) {
+ /* Make sure that there hasn't been such a target already: */
+ targets[target_nr++] = currentTarget;
+ for(i = 0; i < target_nr - 1; i++) {
+ if (strcasecmp(currentTarget, targets[i]) == 0)
+ goto send_next_target;
+ }
+
/* Check for and handle valid <msgto> of form:
* RFC 2812 2.3.1:
* msgto = channel / ( user [ "%" host ] "@" servername )
goto send_next_target;
}
- if (Client_HasMode(cl, 'C')) {
+ if (Client_HasMode(cl, 'C') &&
+ !Client_HasMode(from, 'o') &&
+ !(Client_Type(from) == CLIENT_SERVER) &&
+ !(Client_Type(from) == CLIENT_SERVICE)) {
cl2chan = Channel_FirstChannelOf(cl);
while (cl2chan) {
chan = Channel_GetChannel(cl2chan);
return DISCONNECTED;
} else if (ForceType != CLIENT_SERVICE
&& (chan = Channel_Search(currentTarget))) {
+ /* Target is a channel */
if (!Channel_Write(chan, from, Client, Req->command,
SendErrors, message))
return DISCONNECTED;
} else if (ForceType != CLIENT_SERVICE
- /* $#: server/target mask, RFC 2812, sec. 3.3.1 */
&& strchr("$#", currentTarget[0])
&& strchr(currentTarget, '.')) {
- /* targetmask */
+ /* $#: server/host mask, RFC 2812, sec. 3.3.1 */
if (!Send_Message_Mask(from, Req->command, currentTarget,
message, SendErrors))
return DISCONNECTED;
}
send_next_target:
- currentTarget = strtok_r(NULL, ",", &lastCurrentTarget);
- if (currentTarget)
- Conn_SetPenalty(Client_Conn(Client), 1);
+ currentTarget = strtok_r(NULL, ",", &strtok_last);
+ if (!currentTarget)
+ break;
+
+ Conn_SetPenalty(Client_Conn(Client), 1);
+
+ if (target_nr >= MAX_HNDL_TARGETS) {
+ /* Too many targets given! */
+ return IRC_WriteErrClient(Client,
+ ERR_TOOMANYTARGETS_MSG,
+ currentTarget);
+ }
}
return CONNECTED;
} /* Send_Message */
+/**
+ * Send a message to "target mask" target(s).
+ *
+ * See RFC 2812, sec. 3.3.1 for details.
+ *
+ * @param from The client from which this command has been received.
+ * @param command The command to use (PRIVMSG, NOTICE, ...).
+ * @param targetMask The "target mask" (will be verified by this function).
+ * @param message The message to send.
+ * @param SendErrors Whether to report errors back to the client or not.
+ * @return CONNECTED or DISCONNECTED.
+ */
static bool
Send_Message_Mask(CLIENT * from, char * command, char * targetMask,
char * message, bool SendErrors)
if (!check_wildcards || check_wildcards[strcspn(check_wildcards, "*?")]) {
if (!SendErrors)
return true;
- return IRC_WriteErrClient(from, ERR_WILDTOPLEVEL, targetMask);
+ return IRC_WriteErrClient(from, ERR_WILDTOPLEVEL_MSG,
+ targetMask);
}
- /* #: hostmask, see RFC 2812, sec. 3.3.1 */
if (targetMask[0] == '#') {
+ /* #: hostmask, see RFC 2812, sec. 3.3.1 */
for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
if (Client_Type(cl) != CLIENT_USER)
continue;
return false;
}
} else {
- assert(targetMask[0] == '$'); /* $: server mask, see RFC 2812, sec. 3.3.1 */
+ /* $: server mask, see RFC 2812, sec. 3.3.1 */
+ assert(targetMask[0] == '$');
for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
if (Client_Type(cl) != CLIENT_USER)
continue;