X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc.c;h=47f86528004d24a009504076108ded7fc7b2f8c6;hp=98dda7af2ad6dc198ff61ad368c1e471b4b95d5d;hb=0e4e22a7a671d1e8efbc44bffd80062191f75c38;hpb=b15d906dff84b35ebd05df44aa13e67c9c938fd2 diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 98dda7af..47f86528 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc.c,v 1.128 2005/08/02 23:19:22 alex Exp $"; +static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $"; #include "imp.h" #include @@ -22,23 +22,29 @@ static char UNUSED id[] = "$Id: irc.c,v 1.128 2005/08/02 23:19:22 alex Exp $"; #include #include "ngircd.h" -#include "conn.h" #include "resolve.h" -#include "conf.h" #include "conn-func.h" +#include "conf.h" #include "client.h" #include "channel.h" #include "defines.h" #include "irc-write.h" #include "log.h" +#include "match.h" #include "messages.h" #include "parse.h" +#include "tool.h" #include "exp.h" #include "irc.h" -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, + bool SendErrors)); +static bool Send_Message_Mask PARAMS((CLIENT *from, char *command, + char *targetMask, char *message, + bool SendErrors)); GLOBAL bool @@ -160,81 +166,41 @@ IRC_KILL( CLIENT *Client, REQUEST *Req ) Log( LOG_NOTICE, "Client with nick \"%s\" is unknown here.", Req->argv[0] ); /* Are we still connected or were we killed, too? */ - if(( my_conn > NONE ) && ( Client_GetFromConn( my_conn ))) + if(( my_conn > NONE ) && ( Conn_GetClient( my_conn ))) return CONNECTED; else return DISCONNECTED; } /* IRC_KILL */ +/** + * Handler for the IRC command NOTICE. + */ GLOBAL bool -IRC_NOTICE( CLIENT *Client, REQUEST *Req ) +IRC_NOTICE(CLIENT *Client, REQUEST *Req) { - CLIENT *to, *from; - - 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 return CONNECTED; + return Send_Message(Client, Req, CLIENT_USER, false); } /* IRC_NOTICE */ +/** + * Handler for the IRC command PRIVMSG. + */ GLOBAL bool -IRC_PRIVMSG( CLIENT *Client, REQUEST *Req ) +IRC_PRIVMSG(CLIENT *Client, REQUEST *Req) { - CLIENT *cl, *from; - CHANNEL *chan; - - assert( Client != NULL ); - assert( Req != NULL ); - - /* Falsche Anzahl Parameter? */ - if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command ); - if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client )); - if( Req->argc > 2 ) 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 ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix ); - - cl = Client_Search( Req->argv[0] ); - if( cl ) - { - /* Okay, Ziel ist ein Client. Aber ist es auch ein User? */ - if( Client_Type( cl ) != CLIENT_USER ) return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] ); - - /* Okay, Ziel ist ein User */ - if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' ))) - { - /* Ziel-User ist AWAY: Meldung verschicken */ - if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( cl ), Client_Away( cl ))) return DISCONNECTED; - } - - /* Text senden */ - if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from )); - return IRC_WriteStrClientPrefix( cl, from, "PRIVMSG %s :%s", Client_ID( cl ), Req->argv[1] ); - } + return Send_Message(Client, Req, CLIENT_USER, true); +} /* IRC_PRIVMSG */ - chan = Channel_Search( Req->argv[0] ); - if( chan ) return Channel_Write( chan, from, Client, Req->argv[1] ); - return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] ); -} /* IRC_PRIVMSG */ +/** + * Handler for the IRC command SQUERY. + */ +GLOBAL bool +IRC_SQUERY(CLIENT *Client, REQUEST *Req) +{ + return Send_Message(Client, Req, CLIENT_SERVICE, true); +} /* IRC_SQUERY */ GLOBAL bool @@ -329,17 +295,246 @@ static char * Option_String( CONN_ID Idx ) { static char option_txt[8]; - int options; + UINT16 options; - options = Conn_Options( Idx ); + options = Conn_Options(Idx); - strcpy( option_txt, "F" ); /* No idea what this means but the original ircd sends it ... */ + strcpy(option_txt, "F"); /* No idea what this means, but the + * original ircd sends it ... */ #ifdef ZLIB - if( options & CONN_ZIP ) strcat( option_txt, "z" ); + if(options & CONN_ZIP) /* zlib compression supported. */ + strcat(option_txt, "z"); #endif return option_txt; } /* Option_String */ +static bool +Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) +{ + CLIENT *cl, *from; + CHANNEL *chan; + char *currentTarget = Req->argv[0]; + char *lastCurrentTarget = NULL; + + assert(Client != NULL); + assert(Req != NULL); + + if (Req->argc == 0) { + if (!SendErrors) + return CONNECTED; + return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG, + Client_ID(Client), Req->command); + } + if (Req->argc == 1) { + if (!SendErrors) + return CONNECTED; + return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG, + Client_ID(Client)); + } + if (Req->argc > 2) { + if (!SendErrors) + return CONNECTED; + 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) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->prefix); + + /* handle msgtarget = msgto *("," msgto) */ + currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget); + ngt_UpperStr(Req->command); + + while (currentTarget) { + /* Check for and handle valid of form: + * RFC 2812 2.3.1: + * msgto = channel / ( user [ "%" host ] "@" servername ) + * msgto =/ ( user "%" host ) / targetmask + * msgto =/ nickname / ( nickname "!" user "@" host ) + */ + if (strchr(currentTarget, '!') == NULL) + /* nickname */ + cl = Client_Search(currentTarget); + else + cl = NULL; + + if (cl == NULL) { + /* If currentTarget isn't a nickname check for: + * user ["%" host] "@" servername + * user "%" host + * nickname "!" user "@" host + */ + char target[COMMAND_LEN]; + char * nick = NULL; + char * user = NULL; + char * host = NULL; + char * server = NULL; + + strlcpy(target, currentTarget, COMMAND_LEN); + server = strchr(target, '@'); + if (server) { + *server = '\0'; + server++; + } + host = strchr(target, '%'); + if (host) { + *host = '\0'; + host++; + } + user = strchr(target, '!'); + if (user) { + /* msgto form: nick!user@host */ + *user = '\0'; + user++; + nick = target; + host = server; /* not "@server" but "@host" */ + } else { + user = target; + } + + for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { + if (Client_Type(cl) != CLIENT_USER && + Client_Type(cl) != CLIENT_SERVICE) + continue; + if (nick != NULL && host != 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 */ +#ifndef STRICT_RFC + if (Client_Type(cl) != ForceType && + !(ForceType == CLIENT_USER && + (Client_Type(cl) == CLIENT_USER || + Client_Type(cl) == CLIENT_SERVICE))) { +#else + if (Client_Type(cl) != ForceType) { +#endif + if (!SendErrors) + return CONNECTED; + return IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG, + Client_ID(from), + currentTarget); + } + +#ifndef STRICT_RFC + if (ForceType == CLIENT_SERVICE && + (Conn_Options(Client_Conn(Client_NextHop(cl))) + & CONN_RFC1459)) { + /* SQUERY command but RFC 1459 link: convert + * request to PRIVMSG command */ + Req->command = "PRIVMSG"; + } +#endif + + if (SendErrors && (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)); + } + if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", + Req->command, Client_ID(cl), + Req->argv[1])) + return DISCONNECTED; + } else if (ForceType != CLIENT_SERVICE + && strchr("$#", currentTarget[0]) + && strchr(currentTarget, '.')) { + /* targetmask */ + if (!Send_Message_Mask(from, Req->command, currentTarget, + Req->argv[1], SendErrors)) + return DISCONNECTED; + } else if (ForceType != CLIENT_SERVICE + && (chan = Channel_Search(currentTarget))) { + /* channel */ + if (!Channel_Write(chan, from, Client, Req->command, + SendErrors, Req->argv[1])) + return DISCONNECTED; + } else { + if (!SendErrors) + return CONNECTED; + if (!IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG, + Client_ID(from), currentTarget)) + return DISCONNECTED; + } + + currentTarget = strtok_r(NULL, ",", &lastCurrentTarget); + } + + return CONNECTED; +} /* Send_Message */ + + +static bool +Send_Message_Mask(CLIENT * from, char * command, 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, "%s %s :%s", + command, 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, "%s %s :%s", + command, Client_ID(cl), message)) + return false; + } + } + return CONNECTED; +} /* Send_Message_Mask */ + + /* -eof- */