]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/irc.c
Add Doxygen @file documentation to each source and header file
[ngircd-alex.git] / src / ngircd / irc.c
index 0741aefa9622f02dc06439c63cba0142365d1f46..9e2aaeaf64fec42d746851f5b6f9d5e63d5b9a88 100644 (file)
@@ -7,14 +7,15 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
- *
- * IRC commands
  */
 
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $";
+/**
+ * @file
+ * IRC commands
+ */
 
 #include "imp.h"
 #include <assert.h>
@@ -22,10 +23,8 @@ static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $";
 #include <string.h>
 
 #include "ngircd.h"
-#include "resolve.h"
 #include "conn-func.h"
 #include "conf.h"
-#include "client.h"
 #include "channel.h"
 #include "defines.h"
 #include "irc-write.h"
@@ -33,14 +32,18 @@ static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $";
 #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 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 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
@@ -49,8 +52,12 @@ IRC_ERROR( CLIENT *Client, REQUEST *Req )
        assert( Client != NULL );
        assert( Req != NULL );
 
-       if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
-       else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
+       if (Req->argc < 1)
+               Log(LOG_NOTICE, "Got ERROR from \"%s\"!",
+                   Client_Mask(Client));
+       else
+               Log(LOG_NOTICE, "Got ERROR from \"%s\": \"%s\"!",
+                   Client_Mask(Client), Req->argv[0]);
 
        return CONNECTED;
 } /* IRC_ERROR */
@@ -62,7 +69,7 @@ IRC_ERROR( CLIENT *Client, REQUEST *Req )
  * disconnect clients. It can be used by IRC operators and servers, for example
  * to "solve" nick collisions after netsplits.
  * Please note that this function is also called internally, without a real
- * KILL command beeing received over the network! Client is Client_ThisServer()
+ * KILL command being received over the network! Client is Client_ThisServer()
  * in this case. */
 GLOBAL bool
 IRC_KILL( CLIENT *Client, REQUEST *Req )
@@ -152,11 +159,15 @@ IRC_KILL( CLIENT *Client, REQUEST *Req )
                             Client_Type( c ), Req->argv[0] );
                }
 
-               /* Kill client NOW! */
+               /* Kill the client NOW:
+                *  - Close the local connection (if there is one),
+                *  - Destroy the CLIENT structure for remote clients.
+                * Note: Conn_Close() removes the CLIENT structure as well. */
                conn = Client_Conn( c );
-               Client_Destroy( c, NULL, reason, false );
-               if( conn > NONE )
-                       Conn_Close( conn, NULL, reason, true );
+               if(conn > NONE)
+                       Conn_Close(conn, NULL, reason, true);
+               else
+                       Client_Destroy(c, NULL, reason, false);
        }
        else
                Log( LOG_NOTICE, "Client with nick \"%s\" is unknown here.", Req->argv[0] );
@@ -346,6 +357,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
 
        /* handle msgtarget = msgto *("," msgto) */
        currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget);
+       ngt_UpperStr(Req->command);
 
        while (currentTarget) {
                /* Check for and handle valid <msgto> of form:
@@ -395,12 +407,13 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                        }
 
                        for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
-                               if (Client_Type(cl) != CLIENT_USER)
+                               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)
+                                           strcasecmp(host, Client_HostnameCloaked(cl)) == 0)
                                                break;
                                        else
                                                continue;
@@ -408,7 +421,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                                if (strcasecmp(user, Client_User(cl)) != 0)
                                        continue;
                                if (host != NULL && strcasecmp(host,
-                                               Client_Hostname(cl)) != 0)
+                                               Client_HostnameCloaked(cl)) != 0)
                                        continue;
                                if (server != NULL && strcasecmp(server,
                                                Client_ID(Client_Introducer(cl))) != 0)
@@ -433,6 +446,17 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                                                          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 */
@@ -445,19 +469,23 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                        if (Client_Conn(from) > NONE) {
                                Conn_UpdateIdle(Client_Conn(from));
                        }
-                       if (!IRC_WriteStrClientPrefix(cl, from, "PRIVMSG %s :%s",
-                                               Client_ID(cl), Req->argv[1]))
+                       if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
+                                                     Req->command, Client_ID(cl),
+                                                     Req->argv[1]))
                                return DISCONNECTED;
-               } else if (strchr("$#", currentTarget[0])
+               } else if (ForceType != CLIENT_SERVICE
+                          && (chan = Channel_Search(currentTarget))) {
+                       if (!Channel_Write(chan, from, Client, Req->command,
+                                          SendErrors, Req->argv[1]))
+                                       return DISCONNECTED;
+               } else if (ForceType != CLIENT_SERVICE
+                       /* $#: server/target mask, RFC 2812, sec. 3.3.1 */
+                          && strchr("$#", currentTarget[0])
                           && strchr(currentTarget, '.')) {
                        /* targetmask */
-                       if (!Send_Message_Mask(from, currentTarget,
+                       if (!Send_Message_Mask(from, Req->command, currentTarget,
                                               Req->argv[1], SendErrors))
                                return DISCONNECTED;
-               } else if ((chan = Channel_Search(currentTarget))) {
-                       /* channel */
-                       if (!Channel_Write(chan, from, Client, Req->argv[1]))
-                               return DISCONNECTED;
                } else {
                        if (!SendErrors)
                                return CONNECTED;
@@ -474,11 +502,13 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
 
 
 static bool
-Send_Message_Mask(CLIENT * from, char * targetMask, char * message, bool SendErrors)
+Send_Message_Mask(CLIENT * from, char * command, char * targetMask,
+                 char * message, bool SendErrors)
 {
        CLIENT *cl;
        bool client_match;
        char *mask = targetMask + 1;
+       const char *check_wildcards;
 
        cl = NULL;
 
@@ -489,25 +519,41 @@ Send_Message_Mask(CLIENT * from, char * targetMask, char * message, bool SendErr
                                          Client_ID(from));
        }
 
+       /*
+        * RFC 2812, sec. 3.3.1 requires that targetMask have at least one
+        * dot (".") and no wildcards ("*", "?") following the last one.
+        */
+       check_wildcards = strrchr(targetMask, '.');
+       assert(check_wildcards != NULL);
+       if (check_wildcards &&
+               check_wildcards[strcspn(check_wildcards, "*?")])
+       {
+               if (!SendErrors)
+                       return true;
+               return IRC_WriteStrClient(from, ERR_WILDTOPLEVEL, targetMask);
+       }
+
+       /* #: hostmask, see RFC 2812, sec. 3.3.1 */
        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))
+                               if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
+                                               command, Client_ID(cl), message))
                                        return false;
                }
        } else {
+               assert(targetMask[0] == '$'); /* $: server mask, see RFC 2812, sec. 3.3.1 */
                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))
+                               if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
+                                               command, Client_ID(cl), message))
                                        return false;
                }
        }