]> arthur.barton.de Git - ngircd-alex.git/commitdiff
Implement new IRC+ "CHARCONV" command
authorAlexander Barton <alex@barton.de>
Sun, 16 Sep 2012 22:36:10 +0000 (00:36 +0200)
committerAlexander Barton <alex@barton.de>
Sun, 16 Sep 2012 22:56:36 +0000 (00:56 +0200)
See bug 109 and doc/Protocol.txt for details and documentation.

13 files changed:
contrib/MacOSX/config.h
contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
doc/Protocol.txt
src/ngircd/Makefile.am
src/ngircd/conn-encoding.c [new file with mode: 0644]
src/ngircd/conn-encoding.h [new file with mode: 0644]
src/ngircd/conn.c
src/ngircd/conn.h
src/ngircd/irc-encoding.c [new file with mode: 0644]
src/ngircd/irc-encoding.h [new file with mode: 0644]
src/ngircd/irc.c
src/ngircd/messages.h
src/ngircd/parse.c

index 5b47e9da7ac277b4baf8411013dff10bc2611f76..a25d88617705646a25d38b56ebde1c62d5cea9ed 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2012 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
  *
  * 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
@@ -51,6 +51,9 @@
 /* Define if PAM should be used */
 #define PAM 1
 
 /* Define if PAM should be used */
 #define PAM 1
 
+/* Define if libiconv can be used, e.g. for CHARCONV */
+#define ICONV 1
+
 /* -- Supported features -- */
 
 /* Define if SSP C support is enabled. */
 /* -- Supported features -- */
 
 /* Define if SSP C support is enabled. */
@@ -76,6 +79,8 @@
 
 /* Define to 1 if you have the `gai_strerror' function. */
 #define HAVE_GAI_STRERROR 1
 
 /* Define to 1 if you have the `gai_strerror' function. */
 #define HAVE_GAI_STRERROR 1
+/* Define to 1 if you have the `iconv_open' function. */
+#define HAVE_ICONV_OPEN 1
 /* Define to 1 if you have the `kqueue' function. */
 #define HAVE_KQUEUE 1
 /* Define to 1 if you have the `inet_ntoa' function. */
 /* Define to 1 if you have the `kqueue' function. */
 #define HAVE_KQUEUE 1
 /* Define to 1 if you have the `inet_ntoa' function. */
index ac3f6235381cea4879e4b0c09a1fee324ee93777..b904c763003be5868cc3ff934c4135374ddb54f6 100644 (file)
@@ -36,6 +36,9 @@
                FA322DBE0CEF7766001761B3 /* tool.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D330CEF74B1001761B3 /* tool.c */; };
                FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA322DC00CEF77CB001761B3 /* libz.dylib */; };
                FA407F2E0DB159F400271AF1 /* ng_ipaddr.c in Sources */ = {isa = PBXBuildFile; fileRef = FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */; };
                FA322DBE0CEF7766001761B3 /* tool.c in Sources */ = {isa = PBXBuildFile; fileRef = FA322D330CEF74B1001761B3 /* tool.c */; };
                FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA322DC00CEF77CB001761B3 /* libz.dylib */; };
                FA407F2E0DB159F400271AF1 /* ng_ipaddr.c in Sources */ = {isa = PBXBuildFile; fileRef = FA407F2C0DB159F400271AF1 /* ng_ipaddr.c */; };
+               FA6BBC631605F0AC0004247A /* conn-encoding.c in Sources */ = {isa = PBXBuildFile; fileRef = FA6BBC5F1605F0AB0004247A /* conn-encoding.c */; };
+               FA6BBC641605F0AC0004247A /* irc-encoding.c in Sources */ = {isa = PBXBuildFile; fileRef = FA6BBC611605F0AC0004247A /* irc-encoding.c */; };
+               FA6BBC661605F6D60004247A /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA6BBC651605F6D60004247A /* libiconv.dylib */; };
                FA85178C0FA061EC006A1F5A /* op.c in Sources */ = {isa = PBXBuildFile; fileRef = FA85178B0FA061EC006A1F5A /* op.c */; };
                FA99428C10E82A27007F27ED /* proc.c in Sources */ = {isa = PBXBuildFile; fileRef = FA99428B10E82A27007F27ED /* proc.c */; };
                FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; };
                FA85178C0FA061EC006A1F5A /* op.c in Sources */ = {isa = PBXBuildFile; fileRef = FA85178B0FA061EC006A1F5A /* op.c */; };
                FA99428C10E82A27007F27ED /* proc.c in Sources */ = {isa = PBXBuildFile; fileRef = FA99428B10E82A27007F27ED /* proc.c */; };
                FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; };
                FA4B08E613E7F91700765BA3 /* ngIRCd-Logo.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "ngIRCd-Logo.gif"; sourceTree = "<group>"; };
                FA4B08E713E7F91700765BA3 /* ngircd-redhat.init */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "ngircd-redhat.init"; sourceTree = "<group>"; };
                FA4B08E813E7F91C00765BA3 /* platformtest.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = platformtest.sh; sourceTree = "<group>"; };
                FA4B08E613E7F91700765BA3 /* ngIRCd-Logo.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "ngIRCd-Logo.gif"; sourceTree = "<group>"; };
                FA4B08E713E7F91700765BA3 /* ngircd-redhat.init */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "ngircd-redhat.init"; sourceTree = "<group>"; };
                FA4B08E813E7F91C00765BA3 /* platformtest.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = platformtest.sh; sourceTree = "<group>"; };
+               FA6BBC5F1605F0AB0004247A /* conn-encoding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "conn-encoding.c"; sourceTree = "<group>"; };
+               FA6BBC601605F0AC0004247A /* conn-encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "conn-encoding.h"; sourceTree = "<group>"; };
+               FA6BBC611605F0AC0004247A /* irc-encoding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "irc-encoding.c"; sourceTree = "<group>"; };
+               FA6BBC621605F0AC0004247A /* irc-encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "irc-encoding.h"; sourceTree = "<group>"; };
+               FA6BBC651605F6D60004247A /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = ../../../../../../../usr/lib/libiconv.dylib; sourceTree = "<group>"; };
                FA77849A133FB9FF00740057 /* sample-ngircd.conf.tmpl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "sample-ngircd.conf.tmpl"; sourceTree = "<group>"; };
                FA85178A0FA061EC006A1F5A /* op.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = op.h; sourceTree = "<group>"; };
                FA85178B0FA061EC006A1F5A /* op.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = op.c; sourceTree = "<group>"; };
                FA77849A133FB9FF00740057 /* sample-ngircd.conf.tmpl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "sample-ngircd.conf.tmpl"; sourceTree = "<group>"; };
                FA85178A0FA061EC006A1F5A /* op.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = op.h; sourceTree = "<group>"; };
                FA85178B0FA061EC006A1F5A /* op.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = op.c; sourceTree = "<group>"; };
                        files = (
                                FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */,
                                FA2D567B11EA1AB300D37A35 /* libpam.dylib in Frameworks */,
                        files = (
                                FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */,
                                FA2D567B11EA1AB300D37A35 /* libpam.dylib in Frameworks */,
+                               FA6BBC661605F6D60004247A /* libiconv.dylib in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                FA322D600CEF750F001761B3 /* configure.in */,
                                FA322D630CEF750F001761B3 /* Makefile.am */,
                                1AB674ADFE9D54B511CA2CBB /* Products */,
                                FA322D600CEF750F001761B3 /* configure.in */,
                                FA322D630CEF750F001761B3 /* Makefile.am */,
                                1AB674ADFE9D54B511CA2CBB /* Products */,
-                               FA322DC00CEF77CB001761B3 /* libz.dylib */,
+                               FA6BBC651605F6D60004247A /* libiconv.dylib */,
                                FA2D567A11EA1AB300D37A35 /* libpam.dylib */,
                                FA2D567A11EA1AB300D37A35 /* libpam.dylib */,
+                               FA322DC00CEF77CB001761B3 /* libz.dylib */,
                        );
                        name = ngIRCd;
                        sourceTree = "<group>";
                        );
                        name = ngIRCd;
                        sourceTree = "<group>";
                                FA322CDF0CEF74B1001761B3 /* conf.c */,
                                FA322CE00CEF74B1001761B3 /* conf.h */,
                                FAA3D2780F139CDC00B2447E /* conf-ssl.h */,
                                FA322CDF0CEF74B1001761B3 /* conf.c */,
                                FA322CE00CEF74B1001761B3 /* conf.h */,
                                FAA3D2780F139CDC00B2447E /* conf-ssl.h */,
+                               FA322CE50CEF74B1001761B3 /* conn.c */,
+                               FA322CE60CEF74B1001761B3 /* conn.h */,
+                               FA6BBC5F1605F0AB0004247A /* conn-encoding.c */,
+                               FA6BBC601605F0AC0004247A /* conn-encoding.h */,
                                FA322CE10CEF74B1001761B3 /* conn-func.c */,
                                FA322CE20CEF74B1001761B3 /* conn-func.h */,
                                FA322CE30CEF74B1001761B3 /* conn-zip.c */,
                                FA322CE40CEF74B1001761B3 /* conn-zip.h */,
                                FA322CE10CEF74B1001761B3 /* conn-func.c */,
                                FA322CE20CEF74B1001761B3 /* conn-func.h */,
                                FA322CE30CEF74B1001761B3 /* conn-zip.c */,
                                FA322CE40CEF74B1001761B3 /* conn-zip.h */,
-                               FA322CE50CEF74B1001761B3 /* conn.c */,
-                               FA322CE60CEF74B1001761B3 /* conn.h */,
                                FAA3D2790F139CDC00B2447E /* conn-ssl.c */,
                                FAA3D27A0F139CDC00B2447E /* conn-ssl.h */,
                                FA322CE70CEF74B1001761B3 /* defines.h */,
                                FAA3D2790F139CDC00B2447E /* conn-ssl.c */,
                                FAA3D27A0F139CDC00B2447E /* conn-ssl.h */,
                                FA322CE70CEF74B1001761B3 /* defines.h */,
                                FA322CE90CEF74B1001761B3 /* hash.h */,
                                FA322CEA0CEF74B1001761B3 /* io.c */,
                                FA322CEB0CEF74B1001761B3 /* io.h */,
                                FA322CE90CEF74B1001761B3 /* hash.h */,
                                FA322CEA0CEF74B1001761B3 /* io.c */,
                                FA322CEB0CEF74B1001761B3 /* io.h */,
+                               FA322CFC0CEF74B1001761B3 /* irc.c */,
+                               FA322CFD0CEF74B1001761B3 /* irc.h */,
                                FAD5853315271AB800328741 /* irc-cap.c */,
                                FAD5853415271AB800328741 /* irc-cap.h */,
                                FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
                                FA322CED0CEF74B1001761B3 /* irc-channel.h */,
                                FAD5853315271AB800328741 /* irc-cap.c */,
                                FAD5853415271AB800328741 /* irc-cap.h */,
                                FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
                                FA322CED0CEF74B1001761B3 /* irc-channel.h */,
+                               FA6BBC611605F0AC0004247A /* irc-encoding.c */,
+                               FA6BBC621605F0AC0004247A /* irc-encoding.h */,
                                FA322CEE0CEF74B1001761B3 /* irc-info.c */,
                                FA322CEF0CEF74B1001761B3 /* irc-info.h */,
                                FA322CF00CEF74B1001761B3 /* irc-login.c */,
                                FA322CEE0CEF74B1001761B3 /* irc-info.c */,
                                FA322CEF0CEF74B1001761B3 /* irc-info.h */,
                                FA322CF00CEF74B1001761B3 /* irc-login.c */,
                                FA322CF90CEF74B1001761B3 /* irc-server.h */,
                                FA322CFA0CEF74B1001761B3 /* irc-write.c */,
                                FA322CFB0CEF74B1001761B3 /* irc-write.h */,
                                FA322CF90CEF74B1001761B3 /* irc-server.h */,
                                FA322CFA0CEF74B1001761B3 /* irc-write.c */,
                                FA322CFB0CEF74B1001761B3 /* irc-write.h */,
-                               FA322CFC0CEF74B1001761B3 /* irc.c */,
-                               FA322CFD0CEF74B1001761B3 /* irc.h */,
                                FA322CFE0CEF74B1001761B3 /* lists.c */,
                                FA322CFF0CEF74B1001761B3 /* lists.h */,
                                FA322D000CEF74B1001761B3 /* log.c */,
                                FA322CFE0CEF74B1001761B3 /* lists.c */,
                                FA322CFF0CEF74B1001761B3 /* lists.h */,
                                FA322D000CEF74B1001761B3 /* log.c */,
                                FAD5853215271AAB00328741 /* client-cap.c in Sources */,
                                FAD5853515271AB800328741 /* irc-cap.c in Sources */,
                                FAD5853815272C2600328741 /* login.c in Sources */,
                                FAD5853215271AAB00328741 /* client-cap.c in Sources */,
                                FAD5853515271AB800328741 /* irc-cap.c in Sources */,
                                FAD5853815272C2600328741 /* login.c in Sources */,
+                               FA6BBC631605F0AC0004247A /* conn-encoding.c in Sources */,
+                               FA6BBC641605F0AC0004247A /* irc-encoding.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 5093eea9f3ace44b40b5c6388f0395dcc66f4693..3d2cda6cb23f8bdd33dee20bc643dbfd59dec19c 100644 (file)
@@ -1,9 +1,8 @@
 
                      ngIRCd - Next Generation IRC Server
 
                      ngIRCd - Next Generation IRC Server
+                           http://ngircd.barton.de/
 
 
-                        (c)2001-2008 Alexander Barton,
-                    alex@barton.de, http://www.barton.de/
-
+               (c)2001-2012 Alexander Barton and Contributors.
                ngIRCd is free software and published under the
                    terms of the GNU General Public License.
 
                ngIRCd is free software and published under the
                    terms of the GNU General Public License.
 
@@ -181,3 +180,34 @@ first command sent to the server, even before USER and NICK commands!
 The <password> must be set in the server configuration file to prevent
 unauthorized clients to fake their identity; it is an arbitrary string.
 
 The <password> must be set in the server configuration file to prevent
 unauthorized clients to fake their identity; it is an arbitrary string.
 
+
+II.5 Client character encoding conversion
+
+     Command: CHARCONV
+  Parameters: <client-charset>
+     Used by: registered clients
+     Replies: RPL_IP_CHARCONV_MSG, ERR_IP_CHARCONV_MSG
+
+
+III. Numerics used by IRC+ Protocol
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The IRC+ protocol uses numerics in the range 800-899 which aren't used by
+RFC 2812 and hopefully don't clash with other implementations ...
+
+Numerics 800-849 are used for status and success messages, and numerics
+850-899 are failure and error messages.
+
+
+III.1 IRC+ status and success numerics
+
+800 - RPL_IP_CHARCONV_MSG
+       %1 :Client encoding set"
+
+               %1      client character set
+
+
+III.2 IRC+ failure and error numerics
+
+850 - ERR_IP_CHARCONV_MSG
+       :Can't initialize client encoding
index 3a411a964b266a2ab9874342ee618018c953ba86..c1fd42409dbb1b24b57492e6dc9e9d161ca8c481 100644 (file)
@@ -27,6 +27,7 @@ ngircd_SOURCES = \
        client-cap.c \
        conf.c \
        conn.c \
        client-cap.c \
        conf.c \
        conn.c \
+       conn-encoding.c \
        conn-func.c \
        conn-ssl.c \
        conn-zip.c \
        conn-func.c \
        conn-ssl.c \
        conn-zip.c \
@@ -35,6 +36,7 @@ ngircd_SOURCES = \
        irc.c \
        irc-cap.c \
        irc-channel.c \
        irc.c \
        irc-cap.c \
        irc-channel.c \
+       irc-encoding.c \
        irc-info.c \
        irc-login.c \
        irc-mode.c \
        irc-info.c \
        irc-login.c \
        irc-mode.c \
@@ -68,6 +70,7 @@ noinst_HEADERS = \
        conf.h \
        conf-ssl.h \
        conn.h \
        conf.h \
        conf-ssl.h \
        conn.h \
+       conn-encoding.h \
        conn-func.h \
        conn-ssl.h \
        conn-zip.h \
        conn-func.h \
        conn-ssl.h \
        conn-zip.h \
@@ -77,6 +80,7 @@ noinst_HEADERS = \
        irc.h \
        irc-cap.h \
        irc-channel.h \
        irc.h \
        irc-cap.h \
        irc-channel.h \
+       irc-encoding.h \
        irc-info.h \
        irc-login.h \
        irc-mode.h \
        irc-info.h \
        irc-login.h \
        irc-mode.h \
diff --git a/src/ngircd/conn-encoding.c b/src/ngircd/conn-encoding.c
new file mode 100644 (file)
index 0000000..71ab588
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 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
+ * 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.
+ */
+
+#define __conn_encoding_c__
+
+#define CONN_MODULE
+
+#include "portab.h"
+
+/**
+ * @file
+ * Functions to deal with character encodings and conversions
+ */
+
+#include "imp.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "defines.h"
+#include "conn.h"
+#include "log.h"
+
+#include "exp.h"
+#include "conn-encoding.h"
+
+#ifdef ICONV
+
+char Encoding_Buffer[COMMAND_LEN];
+
+char *Convert_Message PARAMS((iconv_t Handle, char *Message));
+
+
+/**
+ * Set client character encoding on a connection.
+ *
+ * @param Conn Connection identifier.
+ * @param ClientEnc Client encoding (for example "ASCII", "MacRoman", ...).
+ * @return true on success, false otherwise.
+ */
+GLOBAL bool
+Conn_SetEncoding(CONN_ID Conn, const char *ClientEnc)
+{
+       char client_enc[25], server_enc[25];
+
+       assert(Conn > NONE);
+       assert(ClientEnc != NULL);
+
+       Conn_UnsetEncoding(Conn);
+
+       /* Is the client character set identical to server character set? */
+       if (strcasecmp(ClientEnc, "UTF-8") == 0)
+               return true;
+
+       snprintf(client_enc, sizeof(client_enc), "%s//TRANSLIT", ClientEnc);
+       snprintf(server_enc, sizeof(server_enc), "%s//TRANSLIT", "UTF-8");
+
+       My_Connections[Conn].iconv_from = iconv_open(server_enc, client_enc);
+       if (My_Connections[Conn].iconv_from == (iconv_t)(-1)) {
+               Conn_UnsetEncoding(Conn);
+               return false;
+       }
+       My_Connections[Conn].iconv_to = iconv_open(client_enc, server_enc);
+       if (My_Connections[Conn].iconv_to == (iconv_t)(-1)) {
+               Conn_UnsetEncoding(Conn);
+               return false;
+       }
+
+       LogDebug("Set client character set of connection \"%d\" to \"%s\".",
+                Conn, client_enc);
+       return true;
+}
+
+/**
+ * Remove client character encoding conversion on a connection.
+ *
+ * @param Conn Connection identifier.
+ */
+GLOBAL void
+Conn_UnsetEncoding(CONN_ID Conn)
+{
+       assert(Conn > NONE);
+
+       if (My_Connections[Conn].iconv_from != (iconv_t)(-1))
+               iconv_close(My_Connections[Conn].iconv_from);
+       if (My_Connections[Conn].iconv_to != (iconv_t)(-1))
+               iconv_close(My_Connections[Conn].iconv_to);
+
+       My_Connections[Conn].iconv_from = (iconv_t)(-1);
+       My_Connections[Conn].iconv_to = (iconv_t)(-1);
+
+       LogDebug("Unset character conversion of connection %d.", Conn);
+}
+
+/**
+ * Convert the encoding of a given message.
+ *
+ * This function uses a static buffer for the result of the encoding
+ * conversion which is overwritten by subsequent calls to this function!
+ *
+ * @param Handle libiconv handle.
+ * @param Message The message to convert.
+ * @return Pointer to the result.
+ */
+char *
+Convert_Message(iconv_t Handle, char *Message)
+{
+       size_t in_left, out_left;
+       char *out = Encoding_Buffer;
+
+       assert (Handle != (iconv_t)(-1));
+       assert (Message != NULL);
+
+       in_left = strlen(Message);
+       out_left = sizeof(Encoding_Buffer) - 1;
+
+       if (iconv(Handle, &Message, &in_left, &out, &out_left) == (size_t)(-1)) {
+               /* An error occured! */
+               LogDebug("Error converting message encoding!");
+               strlcpy(Encoding_Buffer, Message, sizeof(Encoding_Buffer));
+               iconv(Handle, NULL, NULL, NULL, NULL);
+       } else
+               *out = '\0';
+
+       return Encoding_Buffer;
+}
+
+#endif
+
+/**
+ * Convert encoding of a message received from a connection.
+ *
+ * Note 1: If no conversion is required, this function returns the original
+ * pointer to the message.
+ *
+ * Note 2: This function uses Convert_Message(), so subsequent calls to this
+ * function will overwrite the earlier results.
+ *
+ * @param Conn Connection identifier.
+ * @param Message The message to convert.
+ * @return Pointer to the result.
+ * @see Convert_Message
+ */
+GLOBAL char *
+Conn_EncodingFrom(UNUSED CONN_ID Conn, char *Message)
+{
+       assert(Conn > NONE);
+       assert (Message != NULL);
+
+#ifdef ICONV
+       if (My_Connections[Conn].iconv_from != (iconv_t)(-1))
+               return Convert_Message(My_Connections[Conn].iconv_from, Message);
+#endif
+       return Message;
+}
+
+/**
+ * Convert encoding of a message for sending on a connection.
+ *
+ * Note 1: If no conversion is required, this function returns the original
+ * pointer to the message.
+ *
+ * Note 2: This function uses Convert_Message(), so subsequent calls to this
+ * function will overwrite the earlier results.
+ *
+ * @param Conn Connection identifier.
+ * @param Message The message to convert.
+ * @return Pointer to the result.
+ * @see Convert_Message
+ */
+GLOBAL char *
+Conn_EncodingTo(UNUSED CONN_ID Conn, char *Message)
+{
+       assert(Conn > NONE);
+       assert (Message != NULL);
+
+#ifdef ICONV
+       if (My_Connections[Conn].iconv_to != (iconv_t)(-1))
+               return Convert_Message(My_Connections[Conn].iconv_to, Message);
+#endif
+       return Message;
+}
+
+/* -eof- */
diff --git a/src/ngircd/conn-encoding.h b/src/ngircd/conn-encoding.h
new file mode 100644 (file)
index 0000000..7b50ed6
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 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
+ * 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.
+ */
+
+#ifndef __conn_encoding_h__
+#define __conn_encoding_h__
+
+/**
+ * @file
+ * Functions to deal with character encodings and conversions (header)
+ */
+
+#ifdef ICONV
+
+GLOBAL bool Conn_SetEncoding PARAMS((CONN_ID Idx, const char *ClientEnc));
+GLOBAL void Conn_UnsetEncoding PARAMS((CONN_ID Idx));
+
+#endif /* ICONV */
+
+GLOBAL char* Conn_EncodingFrom PARAMS((CONN_ID Idx, char *Message));
+GLOBAL char* Conn_EncodingTo PARAMS((CONN_ID Idx, char *Message));
+
+#endif
index f4511642c7c7b309c0e302de58cd7e184c172166..5d086857dcd2f634ab4ec5b506d57ddf3f9d3ce2 100644 (file)
@@ -63,6 +63,7 @@
 #include "client.h"
 #include "class.h"
 #include "conf.h"
 #include "client.h"
 #include "class.h"
 #include "conf.h"
+#include "conn-encoding.h"
 #include "conn-ssl.h"
 #include "conn-zip.h"
 #include "conn-func.h"
 #include "conn-ssl.h"
 #include "conn-zip.h"
 #include "conn-func.h"
@@ -861,6 +862,9 @@ va_dcl
 #endif
 {
        char buffer[COMMAND_LEN];
 #endif
 {
        char buffer[COMMAND_LEN];
+#ifdef ICONV
+       char *ptr, *message;
+#endif
        size_t len;
        bool ok;
        va_list ap;
        size_t len;
        bool ok;
        va_list ap;
@@ -901,6 +905,16 @@ va_dcl
                        CUT_TXTSUFFIX);
        }
 
                        CUT_TXTSUFFIX);
        }
 
+#ifdef ICONV
+       ptr = strchr(buffer + 1, ':');
+       if (ptr) {
+               ptr++;
+               message = Conn_EncodingTo(Idx, ptr);
+               if (message != ptr)
+                       strlcpy(ptr, message, sizeof(buffer) - (ptr - buffer));
+       }
+#endif
+
 #ifdef SNIFFER
        if (NGIRCd_Sniffer)
                Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer);
 #ifdef SNIFFER
        if (NGIRCd_Sniffer)
                Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer);
@@ -2105,6 +2119,11 @@ Init_Conn_Struct(CONN_ID Idx)
        My_Connections[Idx].lastdata = now;
        My_Connections[Idx].lastprivmsg = now;
        Proc_InitStruct(&My_Connections[Idx].proc_stat);
        My_Connections[Idx].lastdata = now;
        My_Connections[Idx].lastprivmsg = now;
        Proc_InitStruct(&My_Connections[Idx].proc_stat);
+
+#ifdef ICONV
+       My_Connections[Idx].iconv_from = (iconv_t)(-1);
+       My_Connections[Idx].iconv_to = (iconv_t)(-1);
+#endif
 } /* Init_Conn_Struct */
 
 
 } /* Init_Conn_Struct */
 
 
index e42a2ae6a7ac1c1466ade3a8124650a489e61715..9236c58ba7767a7be858a6a331abeedc78e02221 100644 (file)
@@ -54,6 +54,10 @@ typedef int CONN_ID;
 #include "tool.h"
 #include "ng_ipaddr.h"
 
 #include "tool.h"
 #include "ng_ipaddr.h"
 
+#ifdef ICONV
+# include <iconv.h>
+#endif
+
 #ifdef ZLIB
 #include <zlib.h>
 typedef struct _ZipData
 #ifdef ZLIB
 #include <zlib.h>
 typedef struct _ZipData
@@ -95,6 +99,10 @@ typedef struct _Connection
 #ifndef STRICT_RFC
        long auth_ping;                 /** PING response expected on login */
 #endif
 #ifndef STRICT_RFC
        long auth_ping;                 /** PING response expected on login */
 #endif
+#ifdef ICONV
+       iconv_t iconv_from;             /** iconv: convert from client to server */
+       iconv_t iconv_to;               /** iconv: convert from server to client */
+#endif
 } CONNECTION;
 
 GLOBAL CONNECTION *My_Connections;
 } CONNECTION;
 
 GLOBAL CONNECTION *My_Connections;
diff --git a/src/ngircd/irc-encoding.c b/src/ngircd/irc-encoding.c
new file mode 100644 (file)
index 0000000..b1d3a69
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 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
+ * 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.
+ */
+
+#include "portab.h"
+
+/**
+ * @file
+ * IRC encoding commands
+ */
+
+#include "imp.h"
+#include <assert.h>
+#include <string.h>
+
+#include "conn-func.h"
+#include "channel.h"
+#include "conn-encoding.h"
+#include "irc-write.h"
+#include "messages.h"
+#include "parse.h"
+#include "tool.h"
+
+#include "exp.h"
+#include "irc-encoding.h"
+
+#ifdef ICONV
+
+/**
+ * Handler for the IRC+ "CHARCONV" command.
+ *
+ * @param Client The client from which this command has been received.
+ * @param Req Request structure with prefix and all parameters.
+ * @returns CONNECTED or DISCONNECTED.
+ */
+GLOBAL bool
+IRC_CHARCONV(CLIENT *Client, REQUEST *Req)
+{
+       char encoding[20];
+
+       assert (Client != NULL);
+       assert (Req != NULL);
+
+       if (Req->argc != 1)
+               return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+                                         Client_ID(Client), Req->command);
+
+       strlcpy(encoding, Req->argv[0], sizeof(encoding));
+       ngt_UpperStr(encoding);
+
+       if (!Conn_SetEncoding(Client_Conn(Client), encoding))
+               return IRC_WriteStrClient(Client, ERR_IP_CHARCONV_MSG,
+                                         Client_ID(Client), encoding);
+
+       return IRC_WriteStrClient(Client, RPL_IP_CHARCONV_MSG,
+                                 Client_ID(Client), encoding);
+} /* IRC_CHARCONV */
+
+#endif
+
+/* -eof- */
diff --git a/src/ngircd/irc-encoding.h b/src/ngircd/irc-encoding.h
new file mode 100644 (file)
index 0000000..4349c91
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ * Copyright (c)2001-2012 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
+ * 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.
+ */
+
+#ifndef __irc_encoding_h__
+#define __irc_encoding_h__
+
+/**
+ * @file
+ * IRC encoding commands (header)
+ */
+
+GLOBAL bool IRC_CHARCONV PARAMS((CLIENT *Client, REQUEST *Req));
+
+#endif
+
+/* -eof- */
index efc34d4b2e087f8e3742c1d44ea6a820e2073f92..ceb649ecf350159d1db1bc969d0a5bb496372a2a 100644 (file)
@@ -25,6 +25,7 @@
 #include "conn-func.h"
 #include "conf.h"
 #include "channel.h"
 #include "conn-func.h"
 #include "conf.h"
 #include "channel.h"
+#include "conn-encoding.h"
 #include "defines.h"
 #include "irc-write.h"
 #include "log.h"
 #include "defines.h"
 #include "irc-write.h"
 #include "log.h"
@@ -359,6 +360,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
        CHANNEL *chan;
        char *currentTarget = Req->argv[0];
        char *lastCurrentTarget = NULL;
        CHANNEL *chan;
        char *currentTarget = Req->argv[0];
        char *lastCurrentTarget = NULL;
+       char *message = NULL;
 
        assert(Client != NULL);
        assert(Req != NULL);
 
        assert(Client != NULL);
        assert(Req != NULL);
@@ -390,6 +392,13 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
                                          Client_ID(Client), Req->prefix);
 
                return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
                                          Client_ID(Client), Req->prefix);
 
+#ifdef ICONV
+       if (Client_Conn(Client) > NONE)
+               message = Conn_EncodingFrom(Client_Conn(Client), Req->argv[1]);
+       else
+#endif
+               message = Req->argv[1];
+
        /* handle msgtarget = msgto *("," msgto) */
        currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget);
        ngt_UpperStr(Req->command);
        /* handle msgtarget = msgto *("," msgto) */
        currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget);
        ngt_UpperStr(Req->command);
@@ -523,12 +532,12 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                        }
                        if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
                                                      Req->command, Client_ID(cl),
                        }
                        if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
                                                      Req->command, Client_ID(cl),
-                                                     Req->argv[1]))
+                                                     message))
                                return DISCONNECTED;
                } else if (ForceType != CLIENT_SERVICE
                           && (chan = Channel_Search(currentTarget))) {
                        if (!Channel_Write(chan, from, Client, Req->command,
                                return DISCONNECTED;
                } else if (ForceType != CLIENT_SERVICE
                           && (chan = Channel_Search(currentTarget))) {
                        if (!Channel_Write(chan, from, Client, Req->command,
-                                          SendErrors, Req->argv[1]))
+                                          SendErrors, message))
                                        return DISCONNECTED;
                } else if (ForceType != CLIENT_SERVICE
                        /* $#: server/target mask, RFC 2812, sec. 3.3.1 */
                                        return DISCONNECTED;
                } else if (ForceType != CLIENT_SERVICE
                        /* $#: server/target mask, RFC 2812, sec. 3.3.1 */
@@ -536,7 +545,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
                           && strchr(currentTarget, '.')) {
                        /* targetmask */
                        if (!Send_Message_Mask(from, Req->command, currentTarget,
                           && strchr(currentTarget, '.')) {
                        /* targetmask */
                        if (!Send_Message_Mask(from, Req->command, currentTarget,
-                                              Req->argv[1], SendErrors))
+                                              message, SendErrors))
                                return DISCONNECTED;
                } else {
                        if (!SendErrors)
                                return DISCONNECTED;
                } else {
                        if (!SendErrors)
index 4f3a397b2647eabc6fd6ed21f9aa31d776df69e9..99d258284eb4624e173b0e8576959f1ff368e2ee 100644 (file)
@@ -21,7 +21,7 @@
 #define RPL_YOURHOST_MSG               "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)"
 #define RPL_CREATED_MSG                        "003 %s :This server has been started %s"
 #define RPL_MYINFO_MSG                 "004 %s %s ngircd-%s %s %s"
 #define RPL_YOURHOST_MSG               "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)"
 #define RPL_CREATED_MSG                        "003 %s :This server has been started %s"
 #define RPL_MYINFO_MSG                 "004 %s %s ngircd-%s %s %s"
-#define RPL_ISUPPORT1_MSG              "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
+#define RPL_ISUPPORT1_MSG              "005 %s RFC2812 IRCD=ngIRCd CHARSET=UTF-8 CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
 #define RPL_ISUPPORT2_MSG              "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d EXCEPTS=e INVEX=I PENALTY :are supported on this server"
 
 #define RPL_TRACELINK_MSG              "200 %s Link %s-%s %s %s V%s %ld %d %d"
 #define RPL_ISUPPORT2_MSG              "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d EXCEPTS=e INVEX=I PENALTY :are supported on this server"
 
 #define RPL_TRACELINK_MSG              "200 %s Link %s-%s %s %s V%s %ld %d %d"
@@ -34,7 +34,6 @@
 #define RPL_UMODEIS_MSG                        "221 %s +%s"
 #define RPL_SERVLIST_MSG               "234 %s %s %s %s %d %d :%s"
 #define RPL_SERVLISTEND_MSG            "235 %s %s %s :End of service listing"
 #define RPL_UMODEIS_MSG                        "221 %s +%s"
 #define RPL_SERVLIST_MSG               "234 %s %s %s %s %d %d :%s"
 #define RPL_SERVLISTEND_MSG            "235 %s %s %s :End of service listing"
-
 #define RPL_STATSUPTIME                        "242 %s :Server Up %u days %u:%02u:%02u"
 #define RPL_LUSERCLIENT_MSG            "251 %s :There are %ld users and %ld services on %ld servers"
 #define RPL_LUSEROP_MSG                        "252 %s %lu :operator(s) online"
 #define RPL_STATSUPTIME                        "242 %s :Server Up %u days %u:%02u:%02u"
 #define RPL_LUSERCLIENT_MSG            "251 %s :There are %ld users and %ld services on %ld servers"
 #define RPL_LUSEROP_MSG                        "252 %s %lu :operator(s) online"
 #define ERR_USERSDONTMATCH_MSG         "502 %s :Can't set/get mode for other users"
 
 #ifdef ZLIB
 #define ERR_USERSDONTMATCH_MSG         "502 %s :Can't set/get mode for other users"
 
 #ifdef ZLIB
-#define RPL_STATSLINKINFOZIP_MSG       "211 %s %s %d %ld %ld/%ld %ld %ld/%ld :%ld"
+# define RPL_STATSLINKINFOZIP_MSG      "211 %s %s %d %ld %ld/%ld %ld %ld/%ld :%ld"
 #endif
 
 #endif
 
+#ifdef IRCPLUS
+
+# define RPL_IP_CHARCONV_MSG           "801 %s %s :Client encoding set"
+
+# define ERR_IP_CHARCONV_MSG           "851 %s :Can't initialize client encoding"
+
+#endif /* IRCPLUS */
+
 #endif
 
 /* -eof- */
 #endif
 
 /* -eof- */
index e9c5d53a3f584bc2fda3a13cc5625e63ca37e3c7..f3b04d0c2ee8617ceb21d32ce919859e640b55f4 100644 (file)
@@ -38,6 +38,7 @@
 #include "irc.h"
 #include "irc-cap.h"
 #include "irc-channel.h"
 #include "irc.h"
 #include "irc-cap.h"
 #include "irc-channel.h"
+#include "irc-encoding.h"
 #include "irc-info.h"
 #include "irc-login.h"
 #include "irc-mode.h"
 #include "irc-info.h"
 #include "irc-login.h"
 #include "irc-mode.h"
@@ -114,6 +115,9 @@ static COMMAND My_Commands[] =
 
 #ifdef IRCPLUS
        { "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
 
 #ifdef IRCPLUS
        { "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
+# ifdef ICONV
+       { "CHARCONV", IRC_CHARCONV, CLIENT_USER, 0, 0, 0 },
+# endif
 #endif
 
 #ifndef STRICT_RFC
 #endif
 
 #ifndef STRICT_RFC