ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/contrib/recode.c
Revision: 812
Committed: Thu Sep 7 09:41:54 2006 UTC (17 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 6744 byte(s)
Log Message:
- Imported contrib/

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * recode.c: Adds codepage option to listen{} blocks.
4 *
5 * Copyright (C) 2006 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id: $
23 */
24
25 #include "stdinc.h"
26 #include "client.h"
27 #include "listener.h"
28 #include "packet.h"
29 #include "send.h"
30 #include "conf/conf.h"
31
32 struct Conversion
33 {
34 unsigned short port;
35 char first;
36 void *to_utf8;
37 void *from_utf8;
38 struct Conversion *hnext;
39 };
40
41 /*
42 * Hashing doesn't affect performance here, as we are almost guaranteed
43 * to have at most 1 entry per bucket. Using 65536 as CONVSIZE would just
44 * be a waste of 1 MB on 64-bit.
45 */
46
47 #define CONVSIZE 1024
48
49 static struct Conversion *convtab[CONVSIZE];
50 static dlink_node *hreset, *hiorecv, *hiosend;
51 static struct ConfSection *section;
52 static struct ConfField *codepage;
53 static char *last_codepage = NULL;
54 static struct ConfField *port;
55 static CONFF_HANDLER *old_port_handler;
56
57 extern void *iconv_open(const char *, const char *);
58 extern size_t iconv(void *, const char **, size_t *, char **, size_t *);
59 extern int iconv_close(void *);
60
61 /*
62 * free_convtab()
63 *
64 * Deletes all used recode entries and clears the TCP port hash table.
65 *
66 * inputs: none
67 * output: none
68 */
69 static void
70 free_convtab(void)
71 {
72 int i;
73 struct Conversion *p;
74
75 for (i = 0; i < CONVSIZE; i++)
76 while ((p = convtab[i]) != NULL)
77 {
78 if (p->first)
79 {
80 iconv_close(p->to_utf8);
81 iconv_close(p->from_utf8);
82 }
83
84 convtab[i] = p->hnext;
85 MyFree(p);
86 }
87 }
88
89 /*
90 * reset_convtab()
91 *
92 * Wrapper around free_convtab(), used as reset_conf handler.
93 *
94 * inputs: none
95 * output: none
96 */
97 static void *
98 reset_convtab(va_list args)
99 {
100 free_convtab();
101
102 return pass_callback(hreset);
103 }
104
105 /*
106 * my_port_handler()
107 *
108 * Overrides default port= handler, adding a conversion if requested.
109 *
110 * inputs:
111 * list - pointer to dlink_list of longs
112 * var - where to write it
113 * output: none
114 */
115 static void
116 my_port_handler(void *list, void *var)
117 {
118 if (last_codepage != NULL)
119 {
120 dlink_node *ptr;
121 void *to_utf8 = iconv_open("UTF-8", last_codepage);
122 void *from_utf8 = iconv_open(last_codepage, "UTF-8");
123
124 if (to_utf8 == (void *) -1 || from_utf8 == (void *) -1)
125 {
126 parse_error("Unable to open character set [%s]: %s",
127 last_codepage, strerror(errno));
128
129 if (to_utf8 != (void *) -1)
130 iconv_close(to_utf8);
131 if (from_utf8 != (void *) -1)
132 iconv_close(from_utf8);
133 }
134 else
135 {
136 char first = YES;
137
138 DLINK_FOREACH(ptr, ((dlink_list *) list)->head)
139 {
140 unsigned short port = (unsigned short) (long) ptr->data;
141 struct Conversion *conv = MyMalloc(sizeof(struct Conversion));
142
143 conv->port = port;
144 conv->first = first;
145 conv->to_utf8 = to_utf8;
146 conv->from_utf8 = from_utf8;
147 conv->hnext = convtab[port % CONVSIZE];
148
149 convtab[port % CONVSIZE] = conv;
150 first = NO;
151 }
152 }
153
154 MyFree(last_codepage);
155 last_codepage = NULL;
156 }
157
158 old_port_handler(list, port);
159 }
160
161 /*
162 * my_iorecv()
163 *
164 * Called when data is received from the network.
165 *
166 * inputs:
167 * client_p - the client we get input from
168 * length - amound of data read
169 * buf - data buffer
170 * output: none
171 */
172 static void *
173 my_iorecv(va_list args)
174 {
175 struct Client *client_p = va_arg(args, struct Client *);
176 size_t inlen = va_arg(args, int);
177 size_t saved_inlen = inlen;
178 const char *inbuf = va_arg(args, char *);
179 struct Listener *li = client_p->localClient->listener;
180 struct Conversion *conv;
181
182 if (li != NULL)
183 for (conv = convtab[li->port % CONVSIZE]; conv != NULL; conv = conv->hnext)
184 if (conv->port == li->port)
185 {
186 char transbuf[2 * READBUF_SIZE];
187 size_t outlen = sizeof(transbuf);
188 char *outbuf = transbuf;
189
190 iconv(conv->to_utf8, NULL, NULL, NULL, NULL);
191 iconv(conv->to_utf8, &inbuf, &inlen, &outbuf, &outlen);
192
193 if ((inlen = outbuf - transbuf) > 0)
194 inbuf = transbuf;
195 else
196 inlen = saved_inlen;
197 }
198
199 return pass_callback(hiorecv, client_p, inlen, inbuf);
200 }
201
202 /*
203 * my_iosend()
204 *
205 * Called when data is to be sent over the network.
206 *
207 * inputs:
208 * client_p - the client we write to
209 * length - amount of output data
210 * buf - data buffer
211 * output: none
212 */
213 static void *
214 my_iosend(va_list args)
215 {
216 struct Client *client_p = va_arg(args, struct Client *);
217 size_t inlen = va_arg(args, int);
218 size_t saved_inlen = inlen;
219 const char *inbuf = va_arg(args, char *);
220 struct Listener *li = client_p->localClient->listener;
221 struct Conversion *conv;
222
223 if (li != NULL)
224 for (conv = convtab[li->port % CONVSIZE]; conv != NULL; conv = conv->hnext)
225 if (conv->port == li->port)
226 {
227 char transbuf[2 * IRCD_BUFSIZE];
228 size_t outlen = sizeof(transbuf);
229 char *outbuf = transbuf;
230
231 iconv(conv->from_utf8, NULL, NULL, NULL, NULL);
232 iconv(conv->from_utf8, &inbuf, &inlen, &outbuf, &outlen);
233
234 if ((inlen = outbuf - transbuf) > 0)
235 inbuf = transbuf;
236 else
237 inlen = saved_inlen;
238 }
239
240 return pass_callback(hiosend, client_p, inlen, inbuf);
241 }
242
243 /*
244 * Module entry point.
245 */
246 INIT_MODULE(recode, "$Revision: $")
247 {
248 memset(&convtab, 0, sizeof(convtab));
249
250 hreset = install_hook(reset_conf, reset_convtab);
251
252 section = find_conf_section("listen");
253 codepage = add_conf_field(section, "codepage", CT_STRING, NULL,
254 &last_codepage);
255
256 port = find_conf_field(section, "port");
257 old_port_handler = port->handler;
258 port->handler = my_port_handler;
259
260 hiorecv = install_hook(iorecv_cb, my_iorecv);
261 hiosend = install_hook(iosend_cb, my_iosend);
262 }
263
264 /*
265 * Module uninstaller.
266 */
267 CLEANUP_MODULE
268 {
269 uninstall_hook(iorecv_cb, my_iorecv);
270 uninstall_hook(iosend_cb, my_iosend);
271
272 port->handler = old_port_handler;
273
274 delete_conf_field(section, codepage);
275
276 uninstall_hook(reset_conf, reset_convtab);
277
278 free_convtab();
279 }

Properties

Name Value
svn:eol-style native
svn:keywords "Id Revision"