1 /*
2 LibRCC - module responsible for translation service
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
23 #include <string.h>
24 #ifdef HAVE_STRINGS_H
25 # include <strings.h>
26 #endif /* HAVE_STRINGS_H */
27
28 #include "internal.h"
29 #include "rccconfig.h"
30 #include "rccexternal.h"
31 #include "rccmutex.h"
32 #include "rcctranslate.h"
33
34 #define RCC_TRANSLATE_DEFAULT_TIMEOUT 1000000 /* 1s */
35
rccTranslateInit()36 int rccTranslateInit() {
37
38 return 0;
39 }
40
rccTranslateFree()41 void rccTranslateFree() {
42 }
43
44
rccTranslateOpen(const char * from,const char * to)45 rcc_translate rccTranslateOpen(const char *from, const char *to) {
46 #ifdef HAVE_LIBTRANSLATE
47 rcc_translate translate;
48
49 if ((!from)||(!to)||(!strcasecmp(from,to))) return NULL;
50 if ((strlen(from)!=2)||(strlen(to)!=2)) return NULL;
51
52 translate = (rcc_translate)malloc(sizeof(rcc_translate_s));
53 if (!translate) return NULL;
54
55 translate->mutex = rccMutexCreate();
56 translate->wmutex = rccMutexCreate();
57 if ((!translate->mutex)||(!translate->wmutex)) {
58 if (translate->mutex) rccMutexFree(translate->mutex);
59 if (translate->wmutex) rccMutexFree(translate->wmutex);
60 free(translate);
61 return NULL;
62 }
63
64 translate->sock = rccExternalConnect(RCC_EXTERNAL_MODULE_LIBRTRANSLATE);
65 if (translate->sock == -1) {
66 rccMutexFree(translate->mutex);
67 rccMutexFree(translate->wmutex);
68 free(translate);
69 return NULL;
70 }
71
72 translate->remaining = 0;
73 translate->werror = 0;
74
75 translate->prefix.cmd.cmd = RCC_EXTERNAL_COMMAND_TRANSLATE;
76 translate->prefix.cmd.size = sizeof(rcc_translate_prefix_s);
77 memcpy(translate->prefix.from, from, 3*sizeof(char));
78 memcpy(translate->prefix.to, to, 3*sizeof(char));
79
80 translate->wprefix.cmd.cmd = RCC_EXTERNAL_COMMAND_TRANSLATE_QUEUE;
81 translate->wprefix.cmd.size = sizeof(rcc_translate_prefix_s);
82 memcpy(translate->wprefix.from, from, 3*sizeof(char));
83 memcpy(translate->wprefix.to, to, 3*sizeof(char));
84
85 rccTranslateSetTimeout(translate, RCC_TRANSLATE_DEFAULT_TIMEOUT);
86
87 return translate;
88 #else
89 return NULL;
90 #endif /* HAVE_LIBTRANSLATE */
91 }
92
rccTranslateClose(rcc_translate translate)93 void rccTranslateClose(rcc_translate translate) {
94 #ifdef HAVE_LIBTRANSLATE
95 if (!translate) return;
96 if (translate->sock != -1) rccExternalClose(translate->sock);
97 rccMutexFree(translate->mutex);
98 rccMutexFree(translate->wmutex);
99 free(translate);
100 #endif /* HAVE_LIBTRANSLATE */
101 }
102
rccTranslateSetTimeout(rcc_translate translate,unsigned long us)103 int rccTranslateSetTimeout(rcc_translate translate, unsigned long us) {
104 if (!translate) return -1;
105 translate->prefix.timeout = us;
106 return 0;
107 }
108
rccTranslateAllowOfflineMode(rcc_translate translate)109 int rccTranslateAllowOfflineMode(rcc_translate translate) {
110 return rccExternalAllowOfflineMode();
111 }
112
113 #ifdef HAVE_LIBTRANSLATE
114 # define RCC_UNLOCK_W 1
115 # define RCC_UNLOCK_R 2
116 # define RCC_UNLOCK_RW 3
117 # define RCC_UNLOCK_WR 3
rccTranslateReturn(rcc_translate translate,char * ret,int unlock)118 static char *rccTranslateReturn(rcc_translate translate, char *ret, int unlock) {
119 if (unlock&RCC_UNLOCK_R) rccMutexUnLock(translate->mutex);
120 if (unlock&RCC_UNLOCK_W) rccMutexUnLock(translate->wmutex);
121 return ret;
122 }
123 # define rccTranslateReturnNULL(translate, unlock) rccTranslateReturn(translate, NULL, unlock)
124
rccTranslateQueue(rcc_translate translate,const char * buf)125 static int rccTranslateQueue(rcc_translate translate, const char *buf) {
126 size_t len, err;
127
128
129 len = strlen(buf);
130 translate->wprefix.cmd.size = sizeof(rcc_translate_prefix_s) + len - sizeof(rcc_external_command_s);
131
132 err = rccExternalWrite(translate->sock, (char*)&translate->wprefix, sizeof(rcc_translate_prefix_s) - 1, 0);
133 if (!err) err = rccExternalWrite(translate->sock, buf, len + 1, 0);
134 return err?1:0;
135 }
136 #endif /* HAVE_LIBTRANSLATE */
137
rccTranslate(rcc_translate translate,const char * buf)138 char *rccTranslate(rcc_translate translate, const char *buf) {
139 #ifdef HAVE_LIBTRANSLATE
140 rcc_external_command_s resp;
141 size_t err, len;
142 char *buffer;
143 size_t i;
144
145 if ((!translate)||(!buf)) return NULL;
146
147 if (!strcmp(translate->prefix.to, rcc_english_language_sn)) {
148 for (i=0;buf[i];i++) {
149 if ((unsigned char)buf[i]>0x7F) break;
150 if ((buf[i]>='A')&&(buf[i]<='Z')) break;
151 if ((buf[i]>='a')&&(buf[i]<='z')) break;
152 }
153 if (!buf[i]) return NULL;
154 }
155
156 rccMutexLock(translate->wmutex);
157
158 if (rccMutexTryLock(translate->mutex)) {
159 if ((translate->werror)||(translate->sock == -1)) return rccTranslateReturnNULL(translate,RCC_UNLOCK_W);
160
161 if (rccTranslateQueue(translate, buf)) translate->werror = 1;
162 return rccTranslateReturnNULL(translate, RCC_UNLOCK_W);
163 }
164
165 if (translate->werror) {
166 rccExternalClose(translate->sock);
167 translate->sock = -1;
168 translate->werror = 0;
169 }
170
171 if (translate->sock == -1) {
172 translate->sock = rccExternalConnect(RCC_EXTERNAL_MODULE_LIBRTRANSLATE);
173 if (translate->sock == -1) {
174 return rccTranslateReturnNULL(translate,RCC_UNLOCK_RW);
175 } else {
176 translate->werror = 0;
177 translate->remaining = 0;
178 }
179 } else if (translate->remaining) {
180 if (translate->remaining == (size_t)-1) {
181 err = rccExternalRead(translate->sock, (char*)&resp, sizeof(rcc_external_command_s), 0);
182 if (err) {
183 if (err == sizeof(rcc_external_command_s)) {
184 if (rccTranslateQueue(translate, buf)) {
185 rccExternalClose(translate->sock);
186 translate->sock = -1;
187 }
188 } else {
189 rccExternalClose(translate->sock);
190 translate->sock = -1;
191 }
192 return rccTranslateReturnNULL(translate,RCC_UNLOCK_RW);
193 }
194 translate->remaining = resp.size;
195 }
196
197 buffer = (char*)malloc(translate->remaining*sizeof(char));
198 if (!buffer) {
199 rccExternalClose(translate->sock);
200 translate->sock = -1;
201 return rccTranslateReturnNULL(translate,RCC_UNLOCK_RW);
202 }
203
204 err = rccExternalRead(translate->sock, buffer, translate->remaining, 0);
205 free(buffer);
206 if (err) {
207 translate->remaining = err;
208 if (rccTranslateQueue(translate, buf)) {
209 rccExternalClose(translate->sock);
210 translate->sock = -1;
211 }
212 return rccTranslateReturnNULL(translate,RCC_UNLOCK_RW);
213 }
214 translate->remaining = 0;
215 }
216
217 len = strlen(buf);
218 translate->prefix.cmd.size = sizeof(rcc_translate_prefix_s) + len - sizeof(rcc_external_command_s);
219 err = rccExternalWrite(translate->sock, (char*)&translate->prefix, sizeof(rcc_translate_prefix_s) - 1, 0);
220 if (err) {
221 rccExternalClose(translate->sock);
222 translate->sock = -1;
223 return rccTranslateReturnNULL(translate,RCC_UNLOCK_RW);
224 }
225 err = rccExternalWrite(translate->sock, buf, len + 1, 0);
226 if (err) {
227 rccExternalClose(translate->sock);
228 translate->sock = -1;
229 return rccTranslateReturnNULL(translate,RCC_UNLOCK_RW);
230 }
231 rccMutexUnLock(translate->wmutex);
232
233 err = rccExternalRead(translate->sock, (char*)&resp, sizeof(rcc_external_command_s), translate->prefix.timeout);
234 if (err) {
235 if (err == sizeof(rcc_external_command_s)) {
236 translate->remaining = (size_t)-1;
237 } else {
238 rccMutexLock(translate->wmutex);
239 rccExternalClose(translate->sock);
240 translate->sock = -1;
241 rccMutexUnLock(translate->wmutex);
242 }
243 return rccTranslateReturnNULL(translate,RCC_UNLOCK_R);
244 }
245
246 if ((resp.cmd!=RCC_EXTERNAL_COMMAND_TRANSLATE)||(!resp.size))
247 return rccTranslateReturnNULL(translate,RCC_UNLOCK_R);
248
249 buffer = (char*)malloc(resp.size*sizeof(char));
250 if (!buffer) {
251 rccMutexLock(translate->wmutex);
252 rccExternalClose(translate->sock);
253 translate->sock = -1;
254 rccMutexUnLock(translate->wmutex);
255
256 return rccTranslateReturnNULL(translate,RCC_UNLOCK_R);
257 }
258
259 err = rccExternalRead(translate->sock, buffer, resp.size, 0);
260 if (err) {
261 translate->remaining = err;
262 free(buffer);
263 return rccTranslateReturnNULL(translate,RCC_UNLOCK_R);
264 }
265
266 return rccTranslateReturn(translate, buffer, RCC_UNLOCK_R);
267 #else
268 return NULL;
269 #endif /* HAVE_LIBTRANSLATE */
270 }
271