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 (20 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 6744 byte(s)
Log Message:
- Imported contrib/

File Contents

# User Rev Content
1 michael 812 /*
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"