1 /*
2 LibRCC - external module interfacying libtranslate library
3
4 Copyright (C) 2005-2008 Suren A. Chilingaryan <csa@dside.dyndns.org>
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License version 2.1 or later
8 as published by the Free Software Foundation.
9
10 This library is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24
25 #include "../config.h"
26
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif /* HAVE_UNISTD_H */
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif /* HAVE_SYS_TYPES_H */
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
35 #endif /* HAVE_SYS_STAT_H */
36
37 #ifdef HAVE_LIBTRANSLATE
38 #include <translate.h>
39 #endif /* HAVE_LIBTRANSLATE */
40
41 #include "../src/rccexternal.h"
42 #include "../src/rcctranslate.h"
43 #include "../src/rccdb4.h"
44 #include "rcclibtranslate.h"
45 #include "compat.h"
46
47 #ifdef HAVE_LIBTRANSLATE
48 static TranslateSession *session = NULL;
49 static db4_context db4ctx = NULL;
50
51 static int exitflag = 0;
52 static GMutex *mutex = NULL;
53 static GCond *cond = NULL;
54 static GQueue *queue = NULL;
55 static GThread *thread = NULL;
56
57 extern char rcc_external_offline;
58
rccCreateKey(const char * from,const char * to,const char * data,size_t * keysize)59 static char *rccCreateKey(const char *from, const char *to, const char *data, size_t *keysize) {
60 char *res;
61
62 *keysize = strlen(data) + 4;
63 res = (char*)malloc((*keysize+1)*sizeof(char));
64 if (res) sprintf(res,"%s%s%s",from,to,data);
65 return res;
66 }
67
rccTranslateFixEOL(char * result,const char * text)68 static char *rccTranslateFixEOL(char *result, const char *text) {
69 size_t i,j;
70 char *res;
71
72 if (!result) return result;
73 if (strstr(text, "\r\n")) return result;
74
75 res = (char*)malloc((strlen(result)+1)*sizeof(char));
76 if (!res) {
77 free(result);
78 return NULL;
79 }
80
81 for (i=0, j=0;result[i];i++) {
82 if ((result[i]=='\r')&&(result[i+1]=='\n')) i++;
83 else res[j++] = result[i];
84 }
85 res[j] = 0;
86 free(result);
87 return res;
88 }
89
rccLibPostponed(void * info)90 static void *rccLibPostponed(void *info) {
91 char *result;
92 char *data;
93 char from[3];
94 char to[3];
95 size_t datalen;
96
97 from[2] = 0;
98 to[2] = 0;
99
100 g_mutex_lock(mutex);
101 while ((!exitflag)||(rcc_external_offline)) {
102 data = (char*)g_queue_pop_head(queue);
103 if (data) {
104 g_mutex_unlock(mutex);
105
106 datalen = strlen(data);
107
108 memcpy(from, data, 2);
109 memcpy(to, data + 2, 2);
110
111 result = rccDb4GetKey(db4ctx, data, datalen);
112 if (result) free(result);
113 else {
114 result = translate_session_translate_text(session, data + 4, from, to, NULL, NULL, NULL);
115
116 if (result) {
117 result = rccTranslateFixEOL(result, data+4);
118 rccDb4SetKey(db4ctx, data, datalen, result);
119 free(result);
120 }
121 }
122
123 free(data);
124 g_mutex_lock(mutex);
125 } else {
126 if (exitflag) break;
127 g_cond_wait(cond, mutex);
128 }
129 }
130 g_mutex_unlock(mutex);
131 return NULL;
132 }
133
134 #endif /* HAVE_LIBTRANSLATE */
135
136
rccLibTranslateInit(const char * rcc_home_dir)137 int rccLibTranslateInit(const char *rcc_home_dir) {
138 #ifdef HAVE_LIBTRANSLATE
139 size_t size;
140 char *dbname;
141 GSList *list = NULL;
142
143 const char *http_proxy;
144
145 if (!translate_init(NULL)) return -1;
146
147 http_proxy = getenv("HTTP_PROXY");
148 if (!http_proxy) http_proxy = getenv("http_proxy");
149 translate_set_proxy(http_proxy);
150
151 list = translate_get_services();
152
153 session = translate_session_new(list);
154
155 g_slist_foreach(list, (GFunc) g_object_unref, NULL);
156 g_slist_free(list);
157
158
159 size = strlen(rcc_home_dir) + 32;
160 dbname = (char*)malloc(size*sizeof(char));
161 if (dbname) {
162 sprintf(dbname,"%s/.rcc/",rcc_home_dir);
163 mkdir(dbname, 00755);
164
165 sprintf(dbname,"%s/.rcc/libtranslate.db/",rcc_home_dir);
166 mkdir(dbname, 00755);
167
168 db4ctx = rccDb4CreateContext(dbname, 0);
169 free(dbname);
170 }
171 if (db4ctx) {
172 mutex = g_mutex_new_compat();
173 cond = g_cond_new_compat();
174 if ((mutex)&&(cond))
175 queue = g_queue_new();
176 if (queue)
177 thread = g_thread_create_compat(rccLibPostponed, NULL, TRUE);
178 }
179 #endif /* HAVE_LIBTRANSLATE */
180
181 return 0;
182 }
183
rccLibTranslateFree()184 void rccLibTranslateFree() {
185 #ifdef HAVE_LIBTRANSLATE
186 char *ptr;
187 if (session) {
188 if (thread) {
189 exitflag = 1;
190 g_mutex_lock(mutex);
191 g_cond_signal(cond);
192 g_mutex_unlock(mutex);
193 g_thread_join(thread);
194 thread = NULL;
195 exitflag = 0;
196 }
197 if (queue) {
198 do {
199 ptr = g_queue_pop_head(queue);
200 if (ptr) free(ptr);
201 } while (ptr);
202 g_queue_free(queue);
203 queue = NULL;
204 }
205 if (mutex) {
206 g_mutex_free_compat(mutex);
207 mutex = NULL;
208 }
209 if (cond) {
210 g_cond_free_compat(cond);
211 cond = NULL;
212 }
213 if (db4ctx) rccDb4FreeContext(db4ctx);
214 g_object_unref(session);
215 session = NULL;
216 }
217 #endif /* HAVE_LIBTRANSLATE */
218 }
219
220
rccLibTranslateQueue(const char * from,const char * to,const char * text)221 static void rccLibTranslateQueue(const char *from, const char *to, const char *text) {
222 #ifdef HAVE_LIBTRANSLATE
223 char *key = NULL;
224 size_t keysize;
225
226 if ((!session)||(!from)||(!to)||(!text)) return;
227 if ((strlen(from)!=2)||(strlen(to)!=2)) return;
228
229 if (db4ctx) {
230 key = rccCreateKey(from,to,text,&keysize);
231 if (key) {
232 g_mutex_lock(mutex);
233 g_queue_push_tail(queue, key);
234 g_mutex_unlock(mutex);
235 g_cond_signal(cond);
236 }
237 }
238 #endif /* HAVE_LIBTRANSLATE */
239 }
240
rccLibTranslateDo(const char * from,const char * to,const char * text,unsigned long timeout)241 static char *rccLibTranslateDo(const char *from, const char *to, const char *text, unsigned long timeout) {
242 #ifdef HAVE_LIBTRANSLATE
243 char *result;
244 char *key = NULL;
245 size_t keysize;
246
247 if ((!session)||(!from)||(!to)||(!text)) return NULL;
248 if ((strlen(from)!=2)||(strlen(to)!=2)) return NULL;
249
250 if (db4ctx) {
251 key = rccCreateKey(from,to,text,&keysize);
252 if (key) {
253 result = rccDb4GetKey(db4ctx, key, keysize);
254 if (result) {
255 free(key);
256 return result;
257 }
258 }
259 }
260 # ifdef HAVE_LIBTRANSLATE_TIMED_TRANSLATE
261 result = translate_session_timed_translate_text(session, text, from, to, timeout, NULL, NULL, NULL);
262 # else
263 result = translate_session_translate_text(session, text, from, to, NULL, NULL, NULL);
264 # endif /* HAVE_LIBTRANSLATE_TIMED_TRANSLATE */
265
266 result = rccTranslateFixEOL(result, text);
267
268 if ((db4ctx)&&(key)) {
269 if (result) {
270 rccDb4SetKey(db4ctx, key, keysize, result);
271 free(key);
272 }
273 else {
274 g_mutex_lock(mutex);
275 g_queue_push_tail(queue, key);
276 g_mutex_unlock(mutex);
277 g_cond_signal(cond);
278 }
279 }
280
281 return result;
282 #else
283 return NULL;
284 #endif /* HAVE_LIBTRANSLATE */
285 }
286
287
rccLibTranslate(void * info)288 void *rccLibTranslate(void *info) {
289 int s;
290 #ifdef HAVE_LIBTRANSLATE
291 unsigned char connected = 1;
292 rcc_translate_prefix_s prefix;
293 ssize_t readed, writed, res;
294 char *buffer;
295 size_t size;
296 char *translated = NULL;
297 #endif /* HAVE_LIBTRANSLATE */
298
299 if (!info) return NULL;
300
301 s = ((rcc_external_info)info)->s;
302 free(info);
303
304 #ifdef HAVE_LIBTRANSLATE
305 while (connected) {
306 readed = read(s, &prefix, sizeof(rcc_translate_prefix_s)-1);
307 if ((readed<=0)||(readed != (sizeof(rcc_translate_prefix_s)-1))) break;
308
309 switch (prefix.cmd.cmd) {
310 case RCC_EXTERNAL_COMMAND_CLOSE:
311 connected = 0;
312 break;
313 case RCC_EXTERNAL_COMMAND_TRANSLATE:
314 size = 1 + prefix.cmd.size + sizeof(rcc_external_command_s) - sizeof(rcc_translate_prefix_s);
315 buffer = (char*)malloc(size);
316 if (buffer) {
317 for (readed = 0; (readed < size)&&(connected); readed += res) {
318 res = read(s, buffer + readed, size - readed);
319 if (res<=0) connected = 0;
320 }
321 if (!connected) goto clear;
322
323 prefix.cmd.cmd = 0;
324 prefix.cmd.size = 0;
325
326 if ((prefix.from[2])||(prefix.to[2])||(buffer[readed-1])) goto respond;
327
328 translated = rccLibTranslateDo(prefix.from, prefix.to, buffer, prefix.timeout);
329 if (translated) {
330 prefix.cmd.cmd = RCC_EXTERNAL_COMMAND_TRANSLATE;
331 prefix.cmd.size = strlen(translated) + 1;
332 }
333
334 respond:
335 res = write(s, &prefix.cmd, sizeof(rcc_external_command_s));
336 if (res == sizeof(rcc_external_command_s)) {
337 for (writed = 0; (writed < prefix.cmd.size)&&(connected); writed += res) {
338 res = write(s, translated + writed, prefix.cmd.size - writed);
339 if (res<=0) connected = 0;
340 }
341 } else connected = 0;
342
343 if (prefix.cmd.size) free(translated);
344 clear:
345 free(buffer);
346 } else connected = 0;
347 break;
348 case RCC_EXTERNAL_COMMAND_TRANSLATE_QUEUE:
349 size = 1 + prefix.cmd.size + sizeof(rcc_external_command_s) - sizeof(rcc_translate_prefix_s);
350 buffer = (char*)malloc(size);
351 if (buffer) {
352 for (readed = 0; (readed < size)&&(connected); readed += res) {
353 res = read(s, buffer + readed, size - readed);
354 if (res<=0) connected = 0;
355 }
356 if ((connected)&&(!prefix.from[2])&&(!prefix.to[2])&&(!buffer[readed-1])) {
357 rccLibTranslateQueue(prefix.from, prefix.to, buffer);
358 }
359 free(buffer);
360 } else connected = 0;
361 break;
362 default:
363 size = 1 + prefix.cmd.size + sizeof(rcc_external_command_s) - sizeof(rcc_translate_prefix_s);
364 buffer = (char*)malloc(size);
365 if (buffer) {
366 for (readed = 0; (readed < size)&&(connected); readed += res) {
367 res = read(s, buffer + readed, size - readed);
368 if (res<=0) connected = 0;
369 }
370 free(buffer);
371 } else connected = 0;
372 }
373 }
374 #endif /* HAVE_LIBTRANSLATE */
375
376 close(s);
377 return NULL;
378 }
379
380