mirror of
https://github.com/osmarks/ngircd.git
synced 2025-01-05 21:30:29 +00:00
Cumulative Message Patch
This commit is contained in:
parent
b92a7627f3
commit
2546a13ad2
251
src/ngircd/irc.c
251
src/ngircd/irc.c
@ -30,6 +30,7 @@ static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $";
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "irc-write.h"
|
#include "irc-write.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "match.h"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
|
||||||
@ -38,7 +39,9 @@ static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $";
|
|||||||
|
|
||||||
|
|
||||||
static char *Option_String PARAMS((CONN_ID Idx));
|
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
|
||||||
@ -170,35 +173,7 @@ IRC_KILL( CLIENT *Client, REQUEST *Req )
|
|||||||
GLOBAL bool
|
GLOBAL bool
|
||||||
IRC_NOTICE( CLIENT *Client, REQUEST *Req )
|
IRC_NOTICE( CLIENT *Client, REQUEST *Req )
|
||||||
{
|
{
|
||||||
CLIENT *to, *from;
|
return Send_Message(Client, Req, CLIENT_USER, false);
|
||||||
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;
|
|
||||||
} /* IRC_NOTICE */
|
} /* IRC_NOTICE */
|
||||||
|
|
||||||
|
|
||||||
@ -208,7 +183,7 @@ IRC_NOTICE( CLIENT *Client, REQUEST *Req )
|
|||||||
GLOBAL bool
|
GLOBAL bool
|
||||||
IRC_PRIVMSG(CLIENT *Client, REQUEST *Req)
|
IRC_PRIVMSG(CLIENT *Client, REQUEST *Req)
|
||||||
{
|
{
|
||||||
return Send_Message(Client, Req, CLIENT_USER);
|
return Send_Message(Client, Req, CLIENT_USER, true);
|
||||||
} /* IRC_PRIVMSG */
|
} /* IRC_PRIVMSG */
|
||||||
|
|
||||||
|
|
||||||
@ -218,7 +193,7 @@ IRC_PRIVMSG(CLIENT *Client, REQUEST *Req)
|
|||||||
GLOBAL bool
|
GLOBAL bool
|
||||||
IRC_SQUERY(CLIENT *Client, REQUEST *Req)
|
IRC_SQUERY(CLIENT *Client, REQUEST *Req)
|
||||||
{
|
{
|
||||||
return Send_Message(Client, Req, CLIENT_SERVICE);
|
return Send_Message(Client, Req, CLIENT_SERVICE, true);
|
||||||
} /* IRC_SQUERY */
|
} /* IRC_SQUERY */
|
||||||
|
|
||||||
|
|
||||||
@ -330,62 +305,206 @@ Option_String( CONN_ID Idx )
|
|||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
Send_Message(CLIENT * Client, REQUEST * Req, int ForceType)
|
Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
|
||||||
{
|
{
|
||||||
CLIENT *cl, *from;
|
CLIENT *cl, *from;
|
||||||
CHANNEL *chan;
|
CHANNEL *chan;
|
||||||
|
char *targetList = Req->argv[0];
|
||||||
|
char *currentTarget = Req->argv[0];
|
||||||
|
unsigned int targetCount = 1;
|
||||||
|
|
||||||
assert(Client != NULL);
|
assert( Client != NULL );
|
||||||
assert(Req != NULL);
|
assert( Req != NULL );
|
||||||
|
|
||||||
if (Req->argc == 0)
|
if (Req->argc == 0) {
|
||||||
|
if (!SendErrors)
|
||||||
|
return true;
|
||||||
return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG,
|
return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG,
|
||||||
Client_ID(Client), Req->command);
|
Client_ID(Client), Req->command);
|
||||||
if (Req->argc == 1)
|
}
|
||||||
|
if (Req->argc == 1) {
|
||||||
|
if (!SendErrors)
|
||||||
|
return true;
|
||||||
return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG,
|
return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG,
|
||||||
Client_ID(Client));
|
Client_ID(Client));
|
||||||
if (Req->argc > 2)
|
}
|
||||||
|
if (Req->argc > 2) {
|
||||||
|
if (!SendErrors)
|
||||||
|
return true;
|
||||||
return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
|
return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
|
||||||
Client_ID(Client), Req->command);
|
Client_ID(Client), Req->command);
|
||||||
|
}
|
||||||
|
|
||||||
if (Client_Type(Client) == CLIENT_SERVER)
|
if (Client_Type(Client) == CLIENT_SERVER)
|
||||||
from = Client_Search(Req->prefix);
|
from = Client_Search(Req->prefix);
|
||||||
else
|
else
|
||||||
from = Client;
|
from = Client;
|
||||||
if (!from)
|
if (!from) {
|
||||||
return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
|
return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
|
||||||
Client_ID(Client), Req->prefix);
|
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]);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Client_Conn(from) > NONE)
|
|
||||||
Conn_UpdateIdle(Client_Conn(from));
|
|
||||||
return IRC_WriteStrClientPrefix(cl, from, "PRIVMSG %s :%s",
|
|
||||||
Client_ID(cl), Req->argv[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chan = Channel_Search(Req->argv[0]);
|
while (*targetList) {
|
||||||
if (chan)
|
if (*targetList == ',') {
|
||||||
return Channel_Write(chan, from, Client, Req->argv[1]);
|
*targetList = '\0';
|
||||||
|
targetCount++;
|
||||||
|
}
|
||||||
|
targetList++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (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--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CONNECTED;
|
||||||
|
|
||||||
return IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
|
|
||||||
Client_ID(from), Req->argv[0]);
|
|
||||||
} /* Send_Message */
|
} /* 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- */
|
/* -eof- */
|
||||||
|
112
src/testsuite/message-test.e
Normal file
112
src/testsuite/message-test.e
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# $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-
|
Loading…
Reference in New Issue
Block a user