commit 46b0eef721b9b3eec37d29aff65b6a7fc488a887 from: Alexander Barton date: Sat Oct 06 16:26:25 2012 UTC Merge branch 'bug109-CHARCONV' This closes bug #109. * bug109-CHARCONV: Debian: require "telnet" or "telnet-ssl" for building Debian ngircd-full[-dbg]: enable CHARCONV Add "CHARCONV" to "feature string" when enabled Implement new IRC+ "CHARCONV" command Added new configure option "--with-iconv" Conflicts: src/ngircd/messages.h commit - 4790d78c980c79abfd71c064be1eb085717210f8 commit + 46b0eef721b9b3eec37d29aff65b6a7fc488a887 blob - 8b47ad15dfdded9638be714f46df4b150c099522 blob + a3cab6aee2a77b31cc901aa92ca5795ea5b5e415 --- configure.ng +++ configure.ng @@ -39,6 +39,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AH_TEMPLATE([DEBUG], [Define if debug-mode should be enabled]) AH_TEMPLATE([HAVE_sockaddr_in_len], [Define if sockaddr_in.sin_len exists]) AH_TEMPLATE([HAVE_socklen_t], [Define if socklen_t exists]) +AH_TEMPLATE([ICONV], [Define if libiconv can be used, e.g. for CHARCONV]) AH_TEMPLATE([IDENTAUTH], [Define if the server should do IDENT requests]) AH_TEMPLATE([IRCPLUS], [Define if IRC+ protocol should be used]) AH_TEMPLATE([PAM], [Define if PAM should be used]) @@ -511,6 +512,29 @@ AC_ARG_ENABLE(ircplus, ) if test "$x_ircplus_on" = "yes"; then AC_DEFINE(IRCPLUS, 1) + + # Compile in iconv support? + # We only check for it when IRC+ is enabled, because the IRC+ command + # CHARCONV is the only function depending on it. + x_iconv_on=no + AC_ARG_WITH(iconv, + [ --with-iconv enable character conversation using libiconv], + [ if test "$withval" != "no"; then + if test "$withval" != "yes"; then + CFLAGS="-I$withval/include $CFLAGS" + CPPFLAGS="-I$withval/include $CPPFLAGS" + LDFLAGS="-L$withval/lib $LDFLAGS" + fi + AC_CHECK_LIB(iconv, iconv_open) + AC_CHECK_FUNCS(iconv_open, x_iconv_on=yes, + AC_MSG_ERROR([Can't enable libiconv support!]) + ) + fi + ] + ) + if test "$x_iconv_on" = "yes"; then + AC_DEFINE(ICONV, 1) + fi fi # enable support for IPv6? @@ -683,6 +707,9 @@ test "$x_pam_on" = "yes" \ echo $ECHO_N " SSL support: $ECHO_C" echo "$x_ssl_lib" +echo $ECHO_N " libiconv support: $ECHO_C" + echo "$x_iconv_on" + echo if ! grep "^AUTOMAKE_OPTIONS = ../portab/ansi2knr" src/ngircd/Makefile.am >/dev/null 2>&1; then blob - d6cf418c15202f1227eb337fe6df94237ae49758 blob + 59a74ab5b4af7c18b505bf66d40576ce3d236866 --- contrib/Debian/control +++ contrib/Debian/control @@ -10,7 +10,7 @@ Build-Depends: debhelper (>> 4.0.0), libident-dev, libgnutls-dev, libpam0g-dev, - telnet, + telnet | telnet-ssl, Standards-Version: 3.9.1 Package: ngircd blob - 868a04250a09d70d37a952c24d5cff545b268a3a blob + 0aecde56e00ee6640b5155eab2c2a3974a908fb2 --- contrib/Debian/rules +++ contrib/Debian/rules @@ -1,7 +1,7 @@ #!/usr/bin/make -f # # ngIRCd -- The Next Generation IRC Daemon -# Copyright (c)2001-2009 Alexander Barton +# 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 @@ -53,7 +53,8 @@ configure-ngircd-full: configure --sysconfdir=/etc/ngircd \ --mandir=\$${prefix}/share/man \ --with-syslog --with-zlib \ - --with-gnutls --with-ident --with-tcp-wrappers --with-pam \ + --with-gnutls --with-iconv --with-ident --with-tcp-wrappers \ + --with-pam \ --enable-ipv6 configure-ngircd-full-dbg: configure @@ -66,7 +67,8 @@ configure-ngircd-full-dbg: configure --mandir=\$${prefix}/share/man \ --enable-debug --enable-sniffer \ --with-syslog --with-zlib \ - --with-gnutls --with-ident --with-tcp-wrappers --with-pam \ + --with-gnutls --with-iconv --with-ident --with-tcp-wrappers \ + --with-pam \ --enable-ipv6 build: blob - 5a71278486231654103dfd208f1184a3dab5c455 blob + bf94d327fb337e024eeb8c44501c8821e827863d --- contrib/MacOSX/config.h +++ contrib/MacOSX/config.h @@ -1,6 +1,6 @@ /* * 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 @@ -51,6 +51,9 @@ /* 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. */ @@ -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 `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. */ blob - ac3f6235381cea4879e4b0c09a1fee324ee93777 blob + b904c763003be5868cc3ff934c4135374ddb54f6 --- contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj +++ contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj @@ -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 */; }; + 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 */; }; @@ -203,6 +206,11 @@ FA4B08E613E7F91700765BA3 /* ngIRCd-Logo.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "ngIRCd-Logo.gif"; sourceTree = ""; }; FA4B08E713E7F91700765BA3 /* ngircd-redhat.init */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "ngircd-redhat.init"; sourceTree = ""; }; FA4B08E813E7F91C00765BA3 /* platformtest.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = platformtest.sh; sourceTree = ""; }; + FA6BBC5F1605F0AB0004247A /* conn-encoding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "conn-encoding.c"; sourceTree = ""; }; + FA6BBC601605F0AC0004247A /* conn-encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "conn-encoding.h"; sourceTree = ""; }; + FA6BBC611605F0AC0004247A /* irc-encoding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "irc-encoding.c"; sourceTree = ""; }; + FA6BBC621605F0AC0004247A /* irc-encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "irc-encoding.h"; sourceTree = ""; }; + FA6BBC651605F6D60004247A /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = ../../../../../../../usr/lib/libiconv.dylib; sourceTree = ""; }; FA77849A133FB9FF00740057 /* sample-ngircd.conf.tmpl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "sample-ngircd.conf.tmpl"; sourceTree = ""; }; FA85178A0FA061EC006A1F5A /* op.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = op.h; sourceTree = ""; }; FA85178B0FA061EC006A1F5A /* op.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = op.c; sourceTree = ""; }; @@ -258,6 +266,7 @@ files = ( FA322DC10CEF77CB001761B3 /* libz.dylib in Frameworks */, FA2D567B11EA1AB300D37A35 /* libpam.dylib in Frameworks */, + FA6BBC661605F6D60004247A /* libiconv.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -283,8 +292,9 @@ FA322D600CEF750F001761B3 /* configure.in */, FA322D630CEF750F001761B3 /* Makefile.am */, 1AB674ADFE9D54B511CA2CBB /* Products */, - FA322DC00CEF77CB001761B3 /* libz.dylib */, + FA6BBC651605F6D60004247A /* libiconv.dylib */, FA2D567A11EA1AB300D37A35 /* libpam.dylib */, + FA322DC00CEF77CB001761B3 /* libz.dylib */, ); name = ngIRCd; sourceTree = ""; @@ -328,12 +338,14 @@ 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 */, - FA322CE50CEF74B1001761B3 /* conn.c */, - FA322CE60CEF74B1001761B3 /* conn.h */, FAA3D2790F139CDC00B2447E /* conn-ssl.c */, FAA3D27A0F139CDC00B2447E /* conn-ssl.h */, FA322CE70CEF74B1001761B3 /* defines.h */, @@ -341,10 +353,14 @@ 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 */, + FA6BBC611605F0AC0004247A /* irc-encoding.c */, + FA6BBC621605F0AC0004247A /* irc-encoding.h */, FA322CEE0CEF74B1001761B3 /* irc-info.c */, FA322CEF0CEF74B1001761B3 /* irc-info.h */, FA322CF00CEF74B1001761B3 /* irc-login.c */, @@ -359,8 +375,6 @@ 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 */, @@ -750,6 +764,8 @@ 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; }; blob - 5093eea9f3ace44b40b5c6388f0395dcc66f4693 blob + 3d2cda6cb23f8bdd33dee20bc643dbfd59dec19c --- doc/Protocol.txt +++ doc/Protocol.txt @@ -1,9 +1,8 @@ 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. @@ -181,3 +180,34 @@ first command sent to the server, even before USER and The 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: + 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 blob - dec6db7c0c9ba81a28b3f91590cb11040cd288d3 blob + 27b5c40837a6244dac0c2ff8d375997afc91edbb --- src/ngircd/Makefile.ng +++ src/ngircd/Makefile.ng @@ -29,6 +29,7 @@ ngircd_SOURCES = \ client-cap.c \ conf.c \ conn.c \ + conn-encoding.c \ conn-func.c \ conn-ssl.c \ conn-zip.c \ @@ -37,6 +38,7 @@ ngircd_SOURCES = \ irc.c \ irc-cap.c \ irc-channel.c \ + irc-encoding.c \ irc-info.c \ irc-login.c \ irc-mode.c \ @@ -70,6 +72,7 @@ noinst_HEADERS = \ conf.h \ conf-ssl.h \ conn.h \ + conn-encoding.h \ conn-func.h \ conn-ssl.h \ conn-zip.h \ @@ -79,6 +82,7 @@ noinst_HEADERS = \ irc.h \ irc-cap.h \ irc-channel.h \ + irc-encoding.h \ irc-info.h \ irc-login.h \ irc-mode.h \ blob - /dev/null blob + 71ab58848a5aa87d258f85156ab98021d5c0cd7a (mode 644) --- /dev/null +++ src/ngircd/conn-encoding.c @@ -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 +#include +#include + +#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- */ blob - /dev/null blob + 7b50ed654b4662b53b1c3e0dbd7bb7c234582896 (mode 644) --- /dev/null +++ src/ngircd/conn-encoding.h @@ -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 blob - f4511642c7c7b309c0e302de58cd7e184c172166 blob + 5d086857dcd2f634ab4ec5b506d57ddf3f9d3ce2 --- src/ngircd/conn.c +++ src/ngircd/conn.c @@ -63,6 +63,7 @@ #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" @@ -861,6 +862,9 @@ va_dcl #endif { char buffer[COMMAND_LEN]; +#ifdef ICONV + char *ptr, *message; +#endif size_t len; bool ok; va_list ap; @@ -901,6 +905,16 @@ va_dcl 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); @@ -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); + +#ifdef ICONV + My_Connections[Idx].iconv_from = (iconv_t)(-1); + My_Connections[Idx].iconv_to = (iconv_t)(-1); +#endif } /* Init_Conn_Struct */ blob - e42a2ae6a7ac1c1466ade3a8124650a489e61715 blob + 9236c58ba7767a7be858a6a331abeedc78e02221 --- src/ngircd/conn.h +++ src/ngircd/conn.h @@ -54,6 +54,10 @@ typedef int CONN_ID; #include "tool.h" #include "ng_ipaddr.h" +#ifdef ICONV +# include +#endif + #ifdef ZLIB #include typedef struct _ZipData @@ -95,6 +99,10 @@ typedef struct _Connection #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; blob - /dev/null blob + b1d3a697ca0b55c0e3f9bc858fe5b0c3c534d8a1 (mode 644) --- /dev/null +++ src/ngircd/irc-encoding.c @@ -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 +#include + +#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- */ blob - /dev/null blob + 4349c91043fd4d3339fb022ba0b815e847416cc6 (mode 644) --- /dev/null +++ src/ngircd/irc-encoding.h @@ -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- */ blob - efc34d4b2e087f8e3742c1d44ea6a820e2073f92 blob + ceb649ecf350159d1db1bc969d0a5bb496372a2a --- src/ngircd/irc.c +++ src/ngircd/irc.c @@ -25,6 +25,7 @@ #include "conn-func.h" #include "conf.h" #include "channel.h" +#include "conn-encoding.h" #include "defines.h" #include "irc-write.h" #include "log.h" @@ -359,6 +360,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int Force CHANNEL *chan; char *currentTarget = Req->argv[0]; char *lastCurrentTarget = NULL; + char *message = NULL; assert(Client != NULL); assert(Req != NULL); @@ -390,6 +392,13 @@ Send_Message(CLIENT * Client, REQUEST * Req, int Force 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); @@ -523,12 +532,12 @@ Send_Message(CLIENT * Client, REQUEST * Req, int Force } 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, - SendErrors, Req->argv[1])) + SendErrors, message)) 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 Force && strchr(currentTarget, '.')) { /* targetmask */ if (!Send_Message_Mask(from, Req->command, currentTarget, - Req->argv[1], SendErrors)) + message, SendErrors)) return DISCONNECTED; } else { if (!SendErrors) blob - efc7524e11d35b22479c3726ac700844abd798f5 blob + 35d621a6e685f988007325f54974623093b54215 --- src/ngircd/messages.h +++ src/ngircd/messages.h @@ -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_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(qaohv)~&@%%+ 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=(qaohv)~&@%%+ 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" @@ -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_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" @@ -151,9 +150,17 @@ #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 +#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- */ blob - a4c2fe8aabc07c72ff5fa00b21330ea087612856 blob + 50d91ce8e2dbff20c87e9dc54505e0bac3406019 --- src/ngircd/ngircd.c +++ src/ngircd/ngircd.c @@ -351,6 +351,13 @@ Fill_Version(void) { NGIRCd_VersionAddition[0] = '\0'; +#ifdef ICONV + if (NGIRCd_VersionAddition[0]) + strlcat(NGIRCd_VersionAddition, "+", + sizeof NGIRCd_VersionAddition); + strlcat(NGIRCd_VersionAddition, "CHARCONV", + sizeof NGIRCd_VersionAddition); +#endif #ifdef DEBUG if (NGIRCd_VersionAddition[0]) strlcat(NGIRCd_VersionAddition, "+", blob - e9c5d53a3f584bc2fda3a13cc5625e63ca37e3c7 blob + f3b04d0c2ee8617ceb21d32ce919859e640b55f4 --- src/ngircd/parse.c +++ src/ngircd/parse.c @@ -38,6 +38,7 @@ #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" @@ -114,6 +115,9 @@ static COMMAND My_Commands[] = #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