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