commit - b92a7627f3dc6b85310964d4b602bea2509dade6
commit + 2546a13ad2949192eb70bf21e114ec60af287ee4
blob - 0418e7b4cb31cb82f4be6006c021c1af37c5f41a
blob + 2e3af757584b0d9630640da16029a6fe9e18b03f
--- src/ngircd/irc.c
+++ src/ngircd/irc.c
#include "defines.h"
#include "irc-write.h"
#include "log.h"
+#include "match.h"
#include "messages.h"
#include "parse.h"
static char *Option_String PARAMS((CONN_ID Idx));
-static bool Send_Message PARAMS((CLIENT *Client, REQUEST *Req, int ForceType));
+static bool Send_Message PARAMS((CLIENT *Client, REQUEST *Req, int ForceType, bool SendErrors));
+static bool Send_Message_Mask PARAMS((CLIENT *from, char *targetMask, char *message, bool SendErrors));
+static bool MatchCaseInsensitive PARAMS((const char *pattern, const char *searchme));
GLOBAL bool
GLOBAL bool
IRC_NOTICE( CLIENT *Client, REQUEST *Req )
{
- CLIENT *to, *from;
- CHANNEL *chan;
-
- assert( Client != NULL );
- assert( Req != NULL );
-
- if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return CONNECTED;
-
- /* Falsche Anzahl Parameter? */
- if( Req->argc != 2 ) return CONNECTED;
-
- if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
- else from = Client;
- if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
-
- to = Client_Search( Req->argv[0] );
- if(( to ) && ( Client_Type( to ) == CLIENT_USER ))
- {
- /* Okay, Ziel ist ein User */
- return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
- }
- else
- {
- chan = Channel_Search(Req->argv[0]);
- if (chan)
- return Channel_Notice(chan, from, Client, Req->argv[1]);
- }
-
- return CONNECTED;
+ return Send_Message(Client, Req, CLIENT_USER, false);
} /* IRC_NOTICE */
GLOBAL bool
IRC_PRIVMSG(CLIENT *Client, REQUEST *Req)
{
- return Send_Message(Client, Req, CLIENT_USER);
+ return Send_Message(Client, Req, CLIENT_USER, true);
} /* IRC_PRIVMSG */
GLOBAL bool
IRC_SQUERY(CLIENT *Client, REQUEST *Req)
{
- return Send_Message(Client, Req, CLIENT_SERVICE);
+ return Send_Message(Client, Req, CLIENT_SERVICE, true);
} /* IRC_SQUERY */
static bool
-Send_Message(CLIENT * Client, REQUEST * Req, int ForceType)
+Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
{
CLIENT *cl, *from;
CHANNEL *chan;
+ char *targetList = Req->argv[0];
+ char *currentTarget = Req->argv[0];
+ unsigned int targetCount = 1;
- assert(Client != NULL);
- assert(Req != NULL);
+ assert( Client != NULL );
+ assert( Req != NULL );
- if (Req->argc == 0)
+ if (Req->argc == 0) {
+ if (!SendErrors)
+ return true;
return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG,
Client_ID(Client), Req->command);
- if (Req->argc == 1)
+ }
+ if (Req->argc == 1) {
+ if (!SendErrors)
+ return true;
return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG,
Client_ID(Client));
- if (Req->argc > 2)
+ }
+ if (Req->argc > 2) {
+ if (!SendErrors)
+ return true;
return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
Client_ID(Client), Req->command);
+ }
if (Client_Type(Client) == CLIENT_SERVER)
from = Client_Search(Req->prefix);
else
from = Client;
- if (!from)
+ if (!from) {
return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
Client_ID(Client), Req->prefix);
+ }
- cl = Client_Search(Req->argv[0]);
- if (cl) {
- /* Target is a user, enforce type */
- if (Client_Type(cl) != ForceType)
- return IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
- Client_ID(from),
- Req->argv[0]);
+ while (*targetList) {
+ if (*targetList == ',') {
+ *targetList = '\0';
+ targetCount++;
+ }
+ targetList++;
+ }
- if ((Client_Type(Client) != CLIENT_SERVER)
- && (strchr(Client_Modes(cl), 'a'))) {
- /* Target is away */
- if (!IRC_WriteStrClient
- (from, RPL_AWAY_MSG, Client_ID(from), Client_ID(cl),
- Client_Away(cl)))
- return DISCONNECTED;
+ while (targetCount > 0) {
+ if (strchr(currentTarget, '!') == NULL)
+ cl = Client_Search(currentTarget);
+ else
+ cl = NULL;
+ if (cl == NULL) {
+ char target[513]; // max mesage length plus null terminator
+ char * nick = NULL;
+ char * user = NULL;
+ char * host = NULL;
+ char * server = NULL;
+
+ strncpy(target, currentTarget, 512);
+ target[512] = '\0';
+ server = strchr(target, '@');
+ if (server) {
+ *server = '\0';
+ server++;
+ }
+ host = strchr(target, '%');
+ if (host) {
+ *host = '\0';
+ host++;
+ }
+ user = strchr(target, '!');
+ if (user) {
+ *user = '\0';
+ user++;
+ nick = target;
+ host = server; // <msgto> form: nick!user@host
+ } else {
+ user = target;
+ }
+
+ if (user != NULL) {
+ for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
+ if (Client_Type(cl) != CLIENT_USER)
+ continue;
+ if (nick != NULL) {
+ if (strcmp(nick, Client_ID(cl)) == 0 && strcmp(user, Client_User(cl)) == 0 && strcasecmp(host, Client_Hostname(cl)) == 0)
+ break;
+ else
+ continue;
+ }
+ if (strcasecmp(user, Client_User(cl)) != 0)
+ continue;
+ if (host != NULL && strcasecmp(host, Client_Hostname(cl)) != 0)
+ continue;
+ if (server != NULL && strcasecmp(server, Client_ID(Client_Introducer(cl))) != 0)
+ continue;
+ break;
+ }
+ }
}
- if (Client_Conn(from) > NONE)
- Conn_UpdateIdle(Client_Conn(from));
- return IRC_WriteStrClientPrefix(cl, from, "PRIVMSG %s :%s",
- Client_ID(cl), Req->argv[1]);
+ if (cl) {
+ /* Target is a user, enforce type */
+ if (Client_Type(cl) != ForceType) {
+ if (!SendErrors)
+ return true;
+ if (!IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
+ Client_ID(from),
+ currentTarget))
+ return false;
+ } else if ((Client_Type(Client) != CLIENT_SERVER
+ && (strchr(Client_Modes(cl), 'a')))) {
+ /* Target is away */
+ if (!SendErrors)
+ return true;
+ if (!IRC_WriteStrClient
+ (from, RPL_AWAY_MSG, Client_ID(from), Client_ID(cl),
+ Client_Away(cl)))
+ return DISCONNECTED;
+ } if (Client_Conn(from) > NONE) {
+ Conn_UpdateIdle(Client_Conn(from));
+ }
+ if (!IRC_WriteStrClientPrefix(cl, from, "PRIVMSG %s :%s",
+ Client_ID(cl), Req->argv[1]))
+ return false;
+ } else if (strchr("$#", currentTarget[0]) && strchr(currentTarget, '.')) {
+ if (!Send_Message_Mask(from, currentTarget, Req->argv[1], SendErrors))
+ return false;
+ } else if ((chan = Channel_Search(currentTarget))) {
+ if (!Channel_Write(chan, from, Client, Req->argv[1]))
+ return false;
+ } else {
+ if (!SendErrors)
+ return true;
+ if (!IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
+ Client_ID(from), currentTarget))
+ return false;
+ }
+
+ while (*currentTarget)
+ currentTarget++;
+
+ currentTarget++;
+ targetCount--;
}
- chan = Channel_Search(Req->argv[0]);
- if (chan)
- return Channel_Write(chan, from, Client, Req->argv[1]);
+ return CONNECTED;
- return IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
- Client_ID(from), Req->argv[0]);
} /* Send_Message */
+static bool
+Send_Message_Mask(CLIENT * from, char * targetMask, char * message, bool SendErrors)
+{
+ CLIENT *cl;
+ bool client_match;
+ char *mask = targetMask + 1;
+
+ cl = NULL;
+
+ if (strchr(Client_Modes(from), 'o') == NULL) {
+ if (!SendErrors)
+ return true;
+ return IRC_WriteStrClient(from, ERR_NOPRIVILEGES_MSG, Client_ID(from));
+ }
+
+ if (targetMask[0] == '#') {
+ for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
+ if (Client_Type(cl) != CLIENT_USER)
+ continue;
+ client_match = MatchCaseInsensitive(mask, Client_Hostname(cl));
+ if (client_match)
+ if (!IRC_WriteStrClientPrefix(cl, from, "PRIVMSG %s :%s", Client_ID(cl), message))
+ return false;
+ }
+ } else {
+ for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
+ if (Client_Type(cl) != CLIENT_USER)
+ continue;
+ client_match = MatchCaseInsensitive(mask, Client_ID(Client_Introducer(cl)));
+ if (client_match)
+ if (!IRC_WriteStrClientPrefix(cl, from, "PRIVMSG %s :%s", Client_ID(cl), message))
+ return false;
+ }
+ }
+ return CONNECTED;
+} /* Send_Message_Mask */
+
+
+static bool
+MatchCaseInsensitive(const char *pattern, const char *searchme)
+{
+ char haystack[COMMAND_LEN];
+
+ strlcpy(haystack, searchme, sizeof(haystack));
+
+ ngt_LowerStr(haystack);
+
+ return Match(pattern, haystack);
+}
+
/* -eof- */
blob - /dev/null
blob + 000334649d53e07230e36cff0c7be7c0a2abdb3c (mode 644)
--- /dev/null
+++ src/testsuite/message-test.e
+# $Id: mode-test.e,v 1.7 2008/02/16 11:27:49 fw Exp $
+
+spawn telnet localhost 6789
+expect {
+ timeout { exit 1 }
+ "Connected"
+}
+
+send "nick nick\r"
+send "user user . . :User\r"
+expect {
+ timeout { exit 1 }
+ "376"
+}
+
+send "privmsg nick :test\r"
+expect {
+ timeout { exit 1 }
+ "@* PRIVMSG nick :test"
+}
+
+send "privmsg nick\r"
+expect {
+ timeout { exit 1 }
+ "412"
+}
+
+send "privmsg\r"
+expect {
+ timeout { exit 1 }
+ "411"
+}
+
+send "privmsg nick,nick :test\r"
+expect {
+ timeout { exit 1 }
+ "@* PRIVMSG nick :test\r*@* PRIVMSG nick :test"
+}
+
+send "privmsg nick,#testChannel,nick :test\r"
+expect {
+ timeout { exit 1 }
+ "@* PRIVMSG nick :test\r*401*@* PRIVMSG nick :test"
+}
+
+send "JOIN #testChannel\r"
+
+send "privmsg doesnotexist :test\r"
+expect {
+ timeout { exit 1 }
+ "401"
+}
+
+send "away :away\r"
+expect {
+ timeout { exit 1 }
+ "306"
+}
+
+send "privmsg nick :test\r"
+expect {
+ timeout { exit 1 }
+ "301"
+}
+
+send "away\r"
+expect {
+ timeout { exit 1 }
+ "305"
+}
+
+send "privmsg \$ngircd.test.server :test\r"
+expect {
+ timeout { exit 1 }
+ "481"
+}
+
+send "privmsg #*.de :test\r"
+expect {
+ timeout { exit 1 }
+ "481"
+}
+
+send "oper TestOp 123\r"
+
+send "privmsg \$ngircd.test.server :test\r"
+expect {
+ timeout { exit 1 }
+ "@* PRIVMSG nick :test"
+}
+
+send "privmsg \$*.test*.server :test\r"
+expect {
+ timeout { exit 1 }
+ "@* PRIVMSG nick :test"
+}
+
+send "privmsg \$noDotServer :test\r"
+expect {
+ timeout { exit 1 }
+ "401"
+}
+
+#cannot test host mask since localhost has no '.' as RFC requires
+
+send "quit\r"
+expect {
+ timeout { exit 1 }
+ "Connection closed"
+}
+
+# -eof-