Send "fake '*' key" in "MODE -k" replies
[ngircd-alex.git] / src / ngircd / conn-encoding.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * Please read the file COPYING, README and AUTHORS for more information.
10  */
11
12 #define __conn_encoding_c__
13
14 #define CONN_MODULE
15
16 #include "portab.h"
17
18 /**
19  * @file
20  * Functions to deal with character encodings and conversions
21  */
22
23 #include "imp.h"
24 #include <assert.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "defines.h"
29 #include "conn.h"
30 #include "log.h"
31
32 #include "exp.h"
33 #include "conn-encoding.h"
34
35 #ifdef ICONV
36
37 char Encoding_Buffer[COMMAND_LEN];
38
39 char *Convert_Message PARAMS((iconv_t Handle, char *Message));
40
41
42 /**
43  * Set client character encoding on a connection.
44  *
45  * @param Conn Connection identifier.
46  * @param ClientEnc Client encoding (for example "ASCII", "MacRoman", ...).
47  * @return true on success, false otherwise.
48  */
49 GLOBAL bool
50 Conn_SetEncoding(CONN_ID Conn, const char *ClientEnc)
51 {
52         char client_enc[25], server_enc[25];
53
54         assert(Conn > NONE);
55         assert(ClientEnc != NULL);
56
57         Conn_UnsetEncoding(Conn);
58
59         /* Is the client character set identical to server character set? */
60         if (strcasecmp(ClientEnc, "UTF-8") == 0)
61                 return true;
62
63         snprintf(client_enc, sizeof(client_enc), "%s//TRANSLIT", ClientEnc);
64         snprintf(server_enc, sizeof(server_enc), "%s//TRANSLIT", "UTF-8");
65
66         My_Connections[Conn].iconv_from = iconv_open(server_enc, client_enc);
67         if (My_Connections[Conn].iconv_from == (iconv_t)(-1)) {
68                 Conn_UnsetEncoding(Conn);
69                 return false;
70         }
71         My_Connections[Conn].iconv_to = iconv_open(client_enc, server_enc);
72         if (My_Connections[Conn].iconv_to == (iconv_t)(-1)) {
73                 Conn_UnsetEncoding(Conn);
74                 return false;
75         }
76
77         LogDebug("Set client character set of connection \"%d\" to \"%s\".",
78                  Conn, client_enc);
79         return true;
80 }
81
82 /**
83  * Remove client character encoding conversion on a connection.
84  *
85  * @param Conn Connection identifier.
86  */
87 GLOBAL void
88 Conn_UnsetEncoding(CONN_ID Conn)
89 {
90         assert(Conn > NONE);
91
92         if (My_Connections[Conn].iconv_from != (iconv_t)(-1))
93                 iconv_close(My_Connections[Conn].iconv_from);
94         if (My_Connections[Conn].iconv_to != (iconv_t)(-1))
95                 iconv_close(My_Connections[Conn].iconv_to);
96
97         My_Connections[Conn].iconv_from = (iconv_t)(-1);
98         My_Connections[Conn].iconv_to = (iconv_t)(-1);
99
100         LogDebug("Unset character conversion of connection %d.", Conn);
101 }
102
103 /**
104  * Convert the encoding of a given message.
105  *
106  * This function uses a static buffer for the result of the encoding
107  * conversion which is overwritten by subsequent calls to this function!
108  *
109  * @param Handle libiconv handle.
110  * @param Message The message to convert.
111  * @return Pointer to the result.
112  */
113 char *
114 Convert_Message(iconv_t Handle, char *Message)
115 {
116         size_t in_left, out_left;
117         char *out = Encoding_Buffer;
118
119         assert (Handle != (iconv_t)(-1));
120         assert (Message != NULL);
121
122         in_left = strlen(Message);
123         out_left = sizeof(Encoding_Buffer) - 1;
124
125         if (iconv(Handle, &Message, &in_left, &out, &out_left) == (size_t)(-1)) {
126                 /* An error occurred! */
127                 LogDebug("Error converting message encoding!");
128                 strlcpy(Encoding_Buffer, Message, sizeof(Encoding_Buffer));
129                 iconv(Handle, NULL, NULL, NULL, NULL);
130         } else
131                 *out = '\0';
132
133         return Encoding_Buffer;
134 }
135
136 #endif
137
138 /**
139  * Convert encoding of a message received from a connection.
140  *
141  * Note 1: If no conversion is required, this function returns the original
142  * pointer to the message.
143  *
144  * Note 2: This function uses Convert_Message(), so subsequent calls to this
145  * function will overwrite the earlier results.
146  *
147  * @param Conn Connection identifier.
148  * @param Message The message to convert.
149  * @return Pointer to the result.
150  * @see Convert_Message
151  */
152 GLOBAL char *
153 Conn_EncodingFrom(UNUSED CONN_ID Conn, char *Message)
154 {
155         assert(Conn > NONE);
156         assert (Message != NULL);
157
158 #ifdef ICONV
159         if (My_Connections[Conn].iconv_from != (iconv_t)(-1))
160                 return Convert_Message(My_Connections[Conn].iconv_from, Message);
161 #endif
162         return Message;
163 }
164
165 /**
166  * Convert encoding of a message for sending on a connection.
167  *
168  * Note 1: If no conversion is required, this function returns the original
169  * pointer to the message.
170  *
171  * Note 2: This function uses Convert_Message(), so subsequent calls to this
172  * function will overwrite the earlier results.
173  *
174  * @param Conn Connection identifier.
175  * @param Message The message to convert.
176  * @return Pointer to the result.
177  * @see Convert_Message
178  */
179 GLOBAL char *
180 Conn_EncodingTo(UNUSED CONN_ID Conn, char *Message)
181 {
182         assert(Conn > NONE);
183         assert (Message != NULL);
184
185 #ifdef ICONV
186         if (My_Connections[Conn].iconv_to != (iconv_t)(-1))
187                 return Convert_Message(My_Connections[Conn].iconv_to, Message);
188 #endif
189         return Message;
190 }
191
192 /* -eof- */