From: Alexander Barton Date: Sun, 16 Sep 2012 22:36:10 +0000 (+0200) Subject: Implement new IRC+ "CHARCONV" command X-Git-Tag: rel-20-rc1~51^2~3 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=commitdiff_plain;h=222ecbffbb5f0c21e64002c95fe9447b4f6b6320 Implement new IRC+ "CHARCONV" command See bug 109 and doc/Protocol.txt for details and documentation. --- diff --git a/contrib/MacOSX/config.h b/contrib/MacOSX/config.h index 5b47e9da..a25d8861 100644 --- a/contrib/MacOSX/config.h +++ b/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. */ diff --git a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj b/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj index ac3f6235..b904c763 100644 --- a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj +++ b/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; }; diff --git a/doc/Protocol.txt b/doc/Protocol.txt index 5093eea9..3d2cda6c 100644 --- a/doc/Protocol.txt +++ b/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 NICK commands! 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 diff --git a/src/ngircd/Makefile.am b/src/ngircd/Makefile.am index 3a411a96..c1fd4240 100644 --- a/src/ngircd/Makefile.am +++ b/src/ngircd/Makefile.am @@ -27,6 +27,7 @@ ngircd_SOURCES = \ client-cap.c \ conf.c \ conn.c \ + conn-encoding.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-encoding.c \ irc-info.c \ irc-login.c \ irc-mode.c \ @@ -68,6 +70,7 @@ noinst_HEADERS = \ conf.h \ conf-ssl.h \ conn.h \ + conn-encoding.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-encoding.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 index 00000000..71ab5884 --- /dev/null +++ b/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- */ diff --git a/src/ngircd/conn-encoding.h b/src/ngircd/conn-encoding.h new file mode 100644 index 00000000..7b50ed65 --- /dev/null +++ b/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 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index f4511642..5d086857 100644 --- a/src/ngircd/conn.c +++ b/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 */ diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h index e42a2ae6..9236c58b 100644 --- a/src/ngircd/conn.h +++ b/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; diff --git a/src/ngircd/irc-encoding.c b/src/ngircd/irc-encoding.c new file mode 100644 index 00000000..b1d3a697 --- /dev/null +++ b/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- */ diff --git a/src/ngircd/irc-encoding.h b/src/ngircd/irc-encoding.h new file mode 100644 index 00000000..4349c910 --- /dev/null +++ b/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- */ diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index efc34d4b..ceb649ec 100644 --- a/src/ngircd/irc.c +++ b/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 ForceType, bool SendErrors) 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 ForceType, bool SendErrors) 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 ForceType, bool SendErrors) } 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 ForceType, bool SendErrors) && strchr(currentTarget, '.')) { /* targetmask */ if (!Send_Message_Mask(from, Req->command, currentTarget, - Req->argv[1], SendErrors)) + message, SendErrors)) return DISCONNECTED; } else { if (!SendErrors) diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index 4f3a397b..99d25828 100644 --- a/src/ngircd/messages.h +++ b/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=(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" @@ -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" @@ -149,9 +148,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- */ diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index e9c5d53a..f3b04d0c 100644 --- a/src/ngircd/parse.c +++ b/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