0 | 0 |
/***************************************************************************
|
1 | |
* Copyright (C) 2011~2011 by CSSlayer *
|
|
1 |
* Copyright (C) 2011~2012 by CSSlayer *
|
2 | 2 |
* wengxt@gmail.com *
|
3 | 3 |
* *
|
4 | 4 |
* This program is free software; you can redistribute it and/or modify *
|
|
14 | 14 |
* You should have received a copy of the GNU General Public License *
|
15 | 15 |
* along with this program; if not, write to the *
|
16 | 16 |
* Free Software Foundation, Inc., *
|
17 | |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
17 |
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
18 | 18 |
***************************************************************************/
|
|
19 |
|
|
20 |
#include <errno.h>
|
|
21 |
#include <iconv.h>
|
|
22 |
#include <unistd.h>
|
|
23 |
|
|
24 |
#include <curl/curl.h>
|
|
25 |
#include <fcntl.h>
|
19 | 26 |
|
20 | 27 |
#include <fcitx/fcitx.h>
|
21 | 28 |
#include <fcitx/module.h>
|
22 | 29 |
#include <fcitx/instance.h>
|
23 | 30 |
#include <fcitx/hook.h>
|
24 | |
#include <curl/curl.h>
|
25 | |
#include "cloudpinyin.h"
|
26 | 31 |
#include <fcitx-utils/log.h>
|
27 | 32 |
#include <fcitx/candidate.h>
|
28 | 33 |
#include <fcitx-config/xdg.h>
|
29 | 34 |
#include <fcitx/module/pinyin/pydef.h>
|
30 | |
#include <errno.h>
|
31 | |
#include <iconv.h>
|
|
35 |
|
|
36 |
#include "config.h"
|
|
37 |
#include "cloudpinyin.h"
|
|
38 |
#include "fetch.h"
|
32 | 39 |
|
33 | 40 |
#define CHECK_VALID_IM (im && \
|
34 | 41 |
(strcmp(im->uniqueName, "pinyin") == 0 || \
|
|
42 |
strcmp(im->uniqueName, "pinyin-libpinyin") == 0 || \
|
|
43 |
strcmp(im->uniqueName, "shuangpin-libpinyin") == 0 || \
|
35 | 44 |
strcmp(im->uniqueName, "googlepinyin") == 0 || \
|
36 | 45 |
strcmp(im->uniqueName, "sunpinyin") == 0 || \
|
37 | 46 |
strcmp(im->uniqueName, "shuangpin") == 0))
|
|
47 |
|
|
48 |
#define CLOUDPINYIN_CHECK_PAGE_NUMBER 3
|
38 | 49 |
|
39 | 50 |
#define LOGLEVEL DEBUG
|
|
51 |
|
|
52 |
#ifdef LIBICONV_SECOND_ARGUMENT_IS_CONST
|
|
53 |
typedef const char* IconvStr;
|
|
54 |
#else
|
|
55 |
typedef char* IconvStr;
|
|
56 |
#endif
|
40 | 57 |
|
41 | 58 |
typedef struct _CloudCandWord {
|
42 | 59 |
boolean filled;
|
|
57 | 74 |
static void CloudPinyinAddCandidateWord(void* arg);
|
58 | 75 |
static void CloudPinyinRequestKey(FcitxCloudPinyin* cloudpinyin);
|
59 | 76 |
static void CloudPinyinAddInputRequest(FcitxCloudPinyin* cloudpinyin, const char* strPinyin);
|
60 | |
static void CloudPinyinHandleReqest(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue);
|
|
77 |
static void CloudPinyinHandleRequest(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue);
|
61 | 78 |
static size_t CloudPinyinWriteFunction(char *ptr, size_t size, size_t nmemb, void *userdata);
|
62 | 79 |
static CloudPinyinCache* CloudPinyinCacheLookup(FcitxCloudPinyin* cloudpinyin, const char* pinyin);
|
63 | 80 |
static CloudPinyinCache* CloudPinyinAddToCache(FcitxCloudPinyin* cloudpinyin, const char* pinyin, char* string);
|
64 | |
static INPUT_RETURN_VALUE CloudPinyinGetCandWord(void* arg, CandidateWord* candWord);
|
|
81 |
static INPUT_RETURN_VALUE CloudPinyinGetCandWord(void* arg, FcitxCandidateWord* candWord);
|
65 | 82 |
static void _CloudPinyinAddCandidateWord(FcitxCloudPinyin* cloudpinyin, const char* pinyin);
|
66 | 83 |
static void CloudPinyinFillCandidateWord(FcitxCloudPinyin* cloudpinyin, const char* pinyin);
|
67 | 84 |
static boolean LoadCloudPinyinConfig(FcitxCloudPinyinConfig* fs);
|
68 | 85 |
static void SaveCloudPinyinConfig(FcitxCloudPinyinConfig* fs);
|
69 | 86 |
static char *GetCurrentString(FcitxCloudPinyin* cloudpinyin);
|
70 | 87 |
static char* SplitHZAndPY(char* string);
|
71 | |
void CloudPinyinHookForNewRequest(void* arg);
|
|
88 |
static void CloudPinyinHookForNewRequest(void* arg);
|
|
89 |
static CURL* CloudPinyinGetFreeCurlHandle(FcitxCloudPinyin* cloudpinyin);
|
|
90 |
static void CloudPinyinReleaseCurlHandle(FcitxCloudPinyin* cloudpinyin, CURL* curl);
|
72 | 91 |
|
73 | 92 |
void SogouParseKey(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue);
|
74 | 93 |
char* SogouParsePinyin(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue);
|
|
140 | 159 |
|
141 | 160 |
void* CloudPinyinCreate(FcitxInstance* instance)
|
142 | 161 |
{
|
143 | |
FcitxCloudPinyin* cloudpinyin = fcitx_malloc0(sizeof(FcitxCloudPinyin));
|
|
162 |
FcitxCloudPinyin* cloudpinyin = fcitx_utils_malloc0(sizeof(FcitxCloudPinyin));
|
144 | 163 |
bindtextdomain("fcitx-cloudpinyin", LOCALEDIR);
|
145 | 164 |
cloudpinyin->owner = instance;
|
|
165 |
int pipe1[2];
|
|
166 |
int pipe2[2];
|
146 | 167 |
|
147 | 168 |
if (!LoadCloudPinyinConfig(&cloudpinyin->config))
|
148 | 169 |
{
|
|
150 | 171 |
return NULL;
|
151 | 172 |
}
|
152 | 173 |
|
153 | |
cloudpinyin->curlm = curl_multi_init();
|
154 | |
if (cloudpinyin->curlm == NULL)
|
|
174 |
if (pipe(pipe1) < 0)
|
155 | 175 |
{
|
156 | 176 |
free(cloudpinyin);
|
157 | 177 |
return NULL;
|
158 | 178 |
}
|
159 | 179 |
|
160 | |
curl_multi_setopt(cloudpinyin->curlm, CURLMOPT_MAXCONNECTS, 10l);
|
161 | |
|
162 | |
cloudpinyin->queue = fcitx_malloc0(sizeof(CurlQueue));
|
|
180 |
if (pipe(pipe2) < 0) {
|
|
181 |
close(pipe1[0]);
|
|
182 |
close(pipe1[1]);
|
|
183 |
free(cloudpinyin);
|
|
184 |
return NULL;
|
|
185 |
}
|
|
186 |
|
|
187 |
cloudpinyin->pipeRecv = pipe1[0];
|
|
188 |
cloudpinyin->pipeNotify = pipe2[1];
|
|
189 |
|
|
190 |
fcntl(pipe1[0], F_SETFL, O_NONBLOCK);
|
|
191 |
fcntl(pipe1[1], F_SETFL, O_NONBLOCK);
|
|
192 |
fcntl(pipe2[0], F_SETFL, O_NONBLOCK);
|
|
193 |
fcntl(pipe2[1], F_SETFL, O_NONBLOCK);
|
|
194 |
|
|
195 |
cloudpinyin->pendingQueue = fcitx_utils_malloc0(sizeof(CurlQueue));
|
|
196 |
cloudpinyin->finishQueue = fcitx_utils_malloc0(sizeof(CurlQueue));
|
|
197 |
pthread_mutex_init(&cloudpinyin->pendingQueueLock, NULL);
|
|
198 |
pthread_mutex_init(&cloudpinyin->finishQueueLock, NULL);
|
|
199 |
|
|
200 |
FcitxFetchThread* fetch = fcitx_utils_malloc0(sizeof(FcitxFetchThread));
|
|
201 |
cloudpinyin->fetch = fetch;
|
|
202 |
fetch->owner = cloudpinyin;
|
|
203 |
fetch->pipeRecv = pipe2[0];
|
|
204 |
fetch->pipeNotify = pipe1[1];
|
|
205 |
fetch->pendingQueueLock = &cloudpinyin->pendingQueueLock;
|
|
206 |
fetch->finishQueueLock = &cloudpinyin->finishQueueLock;
|
|
207 |
fetch->queue = fcitx_utils_malloc0(sizeof(CurlQueue));
|
163 | 208 |
|
164 | 209 |
FcitxIMEventHook hook;
|
165 | 210 |
hook.arg = cloudpinyin;
|
166 | 211 |
hook.func = CloudPinyinAddCandidateWord;
|
167 | 212 |
|
168 | |
RegisterUpdateCandidateWordHook(instance, hook);
|
|
213 |
FcitxInstanceRegisterUpdateCandidateWordHook(instance, hook);
|
169 | 214 |
|
170 | 215 |
hook.arg = cloudpinyin;
|
171 | 216 |
hook.func = CloudPinyinHookForNewRequest;
|
172 | 217 |
|
173 | |
RegisterResetInputHook(instance, hook);
|
174 | |
RegisterInputFocusHook(instance, hook);
|
175 | |
RegisterInputUnFocusHook(instance, hook);
|
176 | |
RegisterTriggerOnHook(instance, hook);
|
|
218 |
FcitxInstanceRegisterResetInputHook(instance, hook);
|
|
219 |
FcitxInstanceRegisterInputFocusHook(instance, hook);
|
|
220 |
FcitxInstanceRegisterInputUnFocusHook(instance, hook);
|
|
221 |
FcitxInstanceRegisterTriggerOnHook(instance, hook);
|
|
222 |
|
|
223 |
pthread_create(&cloudpinyin->pid, NULL, FetchThread, fetch);
|
177 | 224 |
|
178 | 225 |
CloudPinyinRequestKey(cloudpinyin);
|
179 | 226 |
|
180 | 227 |
return cloudpinyin;
|
181 | 228 |
}
|
182 | 229 |
|
|
230 |
CURL* CloudPinyinGetFreeCurlHandle(FcitxCloudPinyin* cloudpinyin)
|
|
231 |
{
|
|
232 |
int i = 0;
|
|
233 |
for (i = 0; i < MAX_HANDLE; i ++) {
|
|
234 |
if (!cloudpinyin->freeList[i].used) {
|
|
235 |
cloudpinyin->freeList[i].used = true;
|
|
236 |
if (cloudpinyin->freeList[i].curl == NULL) {
|
|
237 |
cloudpinyin->freeList[i].curl = curl_easy_init();
|
|
238 |
}
|
|
239 |
return cloudpinyin->freeList[i].curl;
|
|
240 |
}
|
|
241 |
}
|
|
242 |
/* return a stalled handle */
|
|
243 |
return curl_easy_init();
|
|
244 |
}
|
|
245 |
|
|
246 |
void CloudPinyinReleaseCurlHandle(FcitxCloudPinyin* cloudpinyin, CURL* curl)
|
|
247 |
{
|
|
248 |
if (curl == NULL)
|
|
249 |
return;
|
|
250 |
int i = 0;
|
|
251 |
for (i = 0; i < MAX_HANDLE; i ++) {
|
|
252 |
if (cloudpinyin->freeList[i].curl == curl) {
|
|
253 |
cloudpinyin->freeList[i].used = false;
|
|
254 |
return;
|
|
255 |
}
|
|
256 |
}
|
|
257 |
/* if handle is stalled, free it */
|
|
258 |
curl_easy_cleanup(curl);
|
|
259 |
}
|
|
260 |
|
|
261 |
|
183 | 262 |
void CloudPinyinAddCandidateWord(void* arg)
|
184 | 263 |
{
|
185 | 264 |
FcitxCloudPinyin* cloudpinyin = (FcitxCloudPinyin*) arg;
|
186 | |
FcitxIM* im = GetCurrentIM(cloudpinyin->owner);
|
|
265 |
FcitxIM* im = FcitxInstanceGetCurrentIM(cloudpinyin->owner);
|
187 | 266 |
FcitxInputState* input = FcitxInstanceGetInputState(cloudpinyin->owner);
|
188 | 267 |
|
189 | 268 |
if (cloudpinyin->initialized == false)
|
|
217 | 296 |
|
218 | 297 |
void CloudPinyinRequestKey(FcitxCloudPinyin* cloudpinyin)
|
219 | 298 |
{
|
220 | |
int still_running;
|
221 | 299 |
if (cloudpinyin->isrequestkey)
|
222 | 300 |
return;
|
223 | 301 |
|
|
230 | 308 |
return;
|
231 | 309 |
}
|
232 | 310 |
|
233 | |
CURL* curl = curl_easy_init();
|
|
311 |
CURL* curl = CloudPinyinGetFreeCurlHandle(cloudpinyin);
|
234 | 312 |
if (!curl)
|
235 | 313 |
return;
|
236 | |
CurlQueue* queue = fcitx_malloc0(sizeof(CurlQueue)), *head = cloudpinyin->queue;
|
|
314 |
CurlQueue* queue = fcitx_utils_malloc0(sizeof(CurlQueue)), *head = cloudpinyin->pendingQueue;
|
237 | 315 |
queue->curl = curl;
|
238 | 316 |
queue->next = NULL;
|
239 | |
|
240 | |
while (head->next != NULL)
|
241 | |
head = head->next;
|
242 | |
head->next = queue;
|
243 | 317 |
queue->type = RequestKey;
|
244 | 318 |
queue->source = cloudpinyin->config.source;
|
245 | 319 |
|
|
247 | 321 |
curl_easy_setopt(curl, CURLOPT_WRITEDATA, queue);
|
248 | 322 |
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CloudPinyinWriteFunction);
|
249 | 323 |
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20l);
|
250 | |
curl_multi_add_handle(cloudpinyin->curlm, curl);
|
251 | |
CURLMcode mcode;
|
252 | |
do {
|
253 | |
mcode = curl_multi_perform(cloudpinyin->curlm, &still_running);
|
254 | |
} while (mcode == CURLM_CALL_MULTI_PERFORM);
|
255 | |
|
256 | |
if (mcode != CURLM_OK)
|
257 | |
{
|
258 | |
FcitxLog(ERROR, "curl error");
|
259 | |
}
|
|
324 |
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1l);
|
|
325 |
|
|
326 |
/* push into pending queue */
|
|
327 |
pthread_mutex_lock(&cloudpinyin->pendingQueueLock);
|
|
328 |
while (head->next != NULL)
|
|
329 |
head = head->next;
|
|
330 |
head->next = queue;
|
|
331 |
pthread_mutex_unlock(&cloudpinyin->pendingQueueLock);
|
|
332 |
|
|
333 |
char c = 0;
|
|
334 |
write(cloudpinyin->pipeNotify, &c, sizeof(char));
|
260 | 335 |
}
|
261 | 336 |
|
262 | 337 |
|
|
265 | 340 |
{
|
266 | 341 |
FcitxCloudPinyin* cloudpinyin = (FcitxCloudPinyin*) arg;
|
267 | 342 |
FcitxInstance* instance = cloudpinyin->owner;
|
268 | |
int maxfd = 0;
|
269 | |
curl_multi_fdset(cloudpinyin->curlm,
|
270 | |
FcitxInstanceGetReadFDSet(instance),
|
271 | |
FcitxInstanceGetWriteFDSet(instance),
|
272 | |
FcitxInstanceGetExceptFDSet(instance),
|
273 | |
&maxfd);
|
|
343 |
int maxfd = cloudpinyin->pipeRecv;
|
|
344 |
FD_SET(maxfd, FcitxInstanceGetReadFDSet(instance));
|
274 | 345 |
if (maxfd > FcitxInstanceGetMaxFD(instance))
|
275 | 346 |
FcitxInstanceSetMaxFD(instance, maxfd);
|
276 | 347 |
}
|
|
278 | 349 |
void CloudPinyinProcessEvent(void* arg)
|
279 | 350 |
{
|
280 | 351 |
FcitxCloudPinyin* cloudpinyin = (FcitxCloudPinyin*) arg;
|
281 | |
CURLMcode mcode;
|
282 | |
int still_running;
|
283 | |
do {
|
284 | |
mcode = curl_multi_perform(cloudpinyin->curlm, &still_running);
|
285 | |
} while (mcode == CURLM_CALL_MULTI_PERFORM);
|
286 | |
|
287 | |
int num_messages = 0;
|
288 | |
CURLMsg* curl_message = curl_multi_info_read(cloudpinyin->curlm, &num_messages);;
|
289 | |
CurlQueue* queue, *previous;
|
290 | |
|
291 | |
while (curl_message != NULL) {
|
292 | |
if (curl_message->msg == CURLMSG_DONE) {
|
293 | |
int curl_result = curl_message->data.result;
|
294 | |
previous = cloudpinyin->queue;
|
295 | |
queue = cloudpinyin->queue->next;
|
296 | |
while (queue != NULL &&
|
297 | |
queue->curl != curl_message->easy_handle)
|
298 | |
{
|
299 | |
previous = queue;
|
300 | |
queue = queue->next;
|
301 | |
}
|
302 | |
if (queue != NULL) {
|
303 | |
curl_multi_remove_handle(cloudpinyin->curlm, queue->curl);
|
304 | |
previous->next = queue->next;
|
305 | |
queue->curl_result = curl_result;
|
306 | |
curl_easy_getinfo(queue->curl, CURLINFO_HTTP_CODE, &queue->http_code);
|
307 | |
CloudPinyinHandleReqest(cloudpinyin, queue);
|
308 | |
}
|
309 | |
} else {
|
310 | |
FcitxLog(ERROR, "Unknown CURL message received: %d\n",
|
311 | |
(int)curl_message->msg);
|
312 | |
}
|
313 | |
curl_message = curl_multi_info_read(cloudpinyin->curlm, &num_messages);
|
314 | |
}
|
|
352 |
char c;
|
|
353 |
while (read(cloudpinyin->pipeRecv, &c, sizeof(char)) > 0);
|
|
354 |
pthread_mutex_lock(&cloudpinyin->finishQueueLock);
|
|
355 |
CurlQueue* queue;
|
|
356 |
queue = cloudpinyin->finishQueue;
|
|
357 |
while (queue->next != NULL)
|
|
358 |
{
|
|
359 |
CurlQueue* pivot = queue->next;
|
|
360 |
queue->next = queue->next->next;
|
|
361 |
CloudPinyinHandleRequest(cloudpinyin, pivot);
|
|
362 |
}
|
|
363 |
pthread_mutex_unlock(&cloudpinyin->finishQueueLock);
|
315 | 364 |
}
|
316 | 365 |
|
317 | 366 |
void CloudPinyinDestroy(void* arg)
|
|
333 | 382 |
|
334 | 383 |
void CloudPinyinAddInputRequest(FcitxCloudPinyin* cloudpinyin, const char* strPinyin)
|
335 | 384 |
{
|
336 | |
int still_running;
|
337 | |
CURL* curl = curl_easy_init();
|
|
385 |
CURL* curl = CloudPinyinGetFreeCurlHandle(cloudpinyin);
|
338 | 386 |
if (!curl)
|
339 | 387 |
return;
|
340 | |
CurlQueue* queue = fcitx_malloc0(sizeof(CurlQueue)), *head = cloudpinyin->queue;
|
|
388 |
CurlQueue* queue = fcitx_utils_malloc0(sizeof(CurlQueue)), *head = cloudpinyin->pendingQueue;
|
341 | 389 |
queue->curl = curl;
|
342 | 390 |
queue->next = NULL;
|
343 | |
|
344 | |
while (head->next != NULL)
|
345 | |
head = head->next;
|
346 | |
head->next = queue;
|
347 | 391 |
queue->type = RequestPinyin;
|
348 | 392 |
queue->pinyin = strdup(strPinyin);
|
349 | 393 |
queue->source = cloudpinyin->config.source;
|
|
353 | 397 |
asprintf(&url, engine[cloudpinyin->config.source].RequestPinyin, cloudpinyin->key, urlstring);
|
354 | 398 |
else
|
355 | 399 |
asprintf(&url, engine[cloudpinyin->config.source].RequestPinyin, urlstring);
|
356 | |
free(urlstring);
|
|
400 |
curl_free(urlstring);
|
357 | 401 |
|
358 | 402 |
curl_easy_setopt(curl, CURLOPT_URL, url);
|
359 | 403 |
curl_easy_setopt(curl, CURLOPT_WRITEDATA, queue);
|
360 | 404 |
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CloudPinyinWriteFunction);
|
361 | |
curl_multi_add_handle(cloudpinyin->curlm, curl);
|
362 | 405 |
|
363 | 406 |
free(url);
|
364 | |
CURLMcode mcode;
|
365 | |
do {
|
366 | |
mcode = curl_multi_perform(cloudpinyin->curlm, &still_running);
|
367 | |
} while (mcode == CURLM_CALL_MULTI_PERFORM);
|
368 | |
|
369 | |
if (mcode != CURLM_OK)
|
370 | |
{
|
371 | |
FcitxLog(ERROR, "curl error");
|
372 | |
}
|
373 | |
}
|
374 | |
|
375 | |
void CloudPinyinHandleReqest(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
|
|
407 |
|
|
408 |
/* push into pending queue */
|
|
409 |
pthread_mutex_lock(&cloudpinyin->pendingQueueLock);
|
|
410 |
while (head->next != NULL)
|
|
411 |
head = head->next;
|
|
412 |
head->next = queue;
|
|
413 |
pthread_mutex_unlock(&cloudpinyin->pendingQueueLock);
|
|
414 |
|
|
415 |
char c = 0;
|
|
416 |
write(cloudpinyin->pipeNotify, &c, sizeof(char));
|
|
417 |
}
|
|
418 |
|
|
419 |
void CloudPinyinHandleRequest(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
|
376 | 420 |
{
|
377 | 421 |
if (queue->type == RequestKey)
|
378 | 422 |
{
|
|
397 | 441 |
if (cacheEntry == NULL)
|
398 | 442 |
cacheEntry = CloudPinyinAddToCache(cloudpinyin, queue->pinyin, realstring);
|
399 | 443 |
|
400 | |
FcitxIM* im = GetCurrentIM(cloudpinyin->owner);
|
|
444 |
FcitxIM* im = FcitxInstanceGetCurrentIM(cloudpinyin->owner);
|
401 | 445 |
|
402 | 446 |
char* strToFree = NULL, *inputString;
|
403 | 447 |
strToFree = GetCurrentString(cloudpinyin);
|
|
431 | 475 |
}
|
432 | 476 |
}
|
433 | 477 |
}
|
434 | |
curl_easy_cleanup(queue->curl);
|
|
478 |
CloudPinyinReleaseCurlHandle(cloudpinyin, queue->curl);
|
435 | 479 |
if (queue->str)
|
436 | 480 |
free(queue->str);
|
437 | 481 |
if (queue->pinyin)
|
|
461 | 505 |
if (queue->str != NULL)
|
462 | 506 |
queue->str = realloc(queue->str, queue->size + realsize + 1);
|
463 | 507 |
else
|
464 | |
queue->str = fcitx_malloc0(realsize + 1);
|
|
508 |
queue->str = fcitx_utils_malloc0(realsize + 1);
|
465 | 509 |
|
466 | 510 |
if (queue->str != NULL) {
|
467 | 511 |
memcpy(&(queue->str[queue->size]), ptr, realsize);
|
|
480 | 524 |
|
481 | 525 |
CloudPinyinCache* CloudPinyinAddToCache(FcitxCloudPinyin* cloudpinyin, const char* pinyin, char* string)
|
482 | 526 |
{
|
483 | |
CloudPinyinCache* cacheEntry = fcitx_malloc0(sizeof(CloudPinyinCache));
|
|
527 |
CloudPinyinCache* cacheEntry = fcitx_utils_malloc0(sizeof(CloudPinyinCache));
|
484 | 528 |
cacheEntry->pinyin = strdup(pinyin);
|
485 | 529 |
cacheEntry->str = strdup(string);
|
486 | 530 |
HASH_ADD_KEYPTR(hh, cloudpinyin->cache, cacheEntry->pinyin, strlen(cacheEntry->pinyin), cacheEntry);
|
|
501 | 545 |
{
|
502 | 546 |
CloudPinyinCache* cacheEntry = CloudPinyinCacheLookup(cloudpinyin, pinyin);
|
503 | 547 |
FcitxInputState* input = FcitxInstanceGetInputState(cloudpinyin->owner);
|
504 | |
|
505 | |
CandidateWord candWord;
|
506 | |
CloudCandWord* cloudCand = fcitx_malloc0(sizeof(CloudCandWord));
|
|
548 |
struct _FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
|
|
549 |
|
|
550 |
if (cacheEntry) {
|
|
551 |
FcitxCandidateWord* cand;
|
|
552 |
/* only check the first three page */
|
|
553 |
int size = FcitxCandidateWordGetPageSize(candList) * CLOUDPINYIN_CHECK_PAGE_NUMBER;
|
|
554 |
int i = 0;
|
|
555 |
for (cand = FcitxCandidateWordGetFirst(FcitxInputStateGetCandidateList(input));
|
|
556 |
cand != NULL;
|
|
557 |
cand = FcitxCandidateWordGetNext(FcitxInputStateGetCandidateList(input), cand))
|
|
558 |
{
|
|
559 |
if (strcmp(cand->strWord, cacheEntry->str) == 0)
|
|
560 |
return;
|
|
561 |
i ++;
|
|
562 |
if (i >= size)
|
|
563 |
break;
|
|
564 |
}
|
|
565 |
}
|
|
566 |
|
|
567 |
FcitxCandidateWord candWord;
|
|
568 |
CloudCandWord* cloudCand = fcitx_utils_malloc0(sizeof(CloudCandWord));
|
507 | 569 |
if (cacheEntry)
|
508 | 570 |
{
|
509 | 571 |
cloudCand->filled = true;
|
|
518 | 580 |
candWord.callback = CloudPinyinGetCandWord;
|
519 | 581 |
candWord.owner = cloudpinyin;
|
520 | 582 |
candWord.priv = cloudCand;
|
|
583 |
candWord.wordType = MSG_TIPS;
|
521 | 584 |
if (cloudpinyin->config.bDontShowSource)
|
522 | 585 |
candWord.strExtra = NULL;
|
523 | |
else
|
|
586 |
else {
|
524 | 587 |
candWord.strExtra = strdup(_(" (via cloud)"));
|
|
588 |
candWord.extraType = MSG_TIPS;
|
|
589 |
}
|
525 | 590 |
|
526 | 591 |
int order = cloudpinyin->config.iCandidateOrder - 1;
|
527 | 592 |
if (order < 0)
|
528 | 593 |
order = 0;
|
529 | 594 |
|
530 | |
CandidateWordInsert(FcitxInputStateGetCandidateList(input), &candWord, order);
|
|
595 |
FcitxCandidateWordInsert(candList, &candWord, order);
|
531 | 596 |
}
|
532 | 597 |
|
533 | 598 |
void CloudPinyinFillCandidateWord(FcitxCloudPinyin* cloudpinyin, const char* pinyin)
|
534 | 599 |
{
|
535 | 600 |
CloudPinyinCache* cacheEntry = CloudPinyinCacheLookup(cloudpinyin, pinyin);
|
536 | 601 |
FcitxInputState* input = FcitxInstanceGetInputState(cloudpinyin->owner);
|
|
602 |
struct _FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
|
537 | 603 |
if (cacheEntry)
|
538 | 604 |
{
|
539 | |
CandidateWord* candWord;
|
540 | |
for (candWord = CandidateWordGetFirst(FcitxInputStateGetCandidateList(input));
|
541 | |
candWord != NULL;
|
542 | |
candWord = CandidateWordGetNext(FcitxInputStateGetCandidateList(input), candWord))
|
|
605 |
FcitxCandidateWord* candWord;
|
|
606 |
for (candWord = FcitxCandidateWordGetFirst(candList);
|
|
607 |
candWord != NULL;
|
|
608 |
candWord = FcitxCandidateWordGetNext(candList, candWord))
|
543 | 609 |
{
|
544 | 610 |
if (candWord->owner == cloudpinyin)
|
545 | 611 |
break;
|
546 | 612 |
}
|
547 | 613 |
|
|
614 |
if (candWord == NULL)
|
|
615 |
return;
|
|
616 |
|
|
617 |
CloudCandWord* cloudCand = candWord->priv;
|
|
618 |
if (cloudCand->filled)
|
|
619 |
return;
|
|
620 |
|
|
621 |
FcitxCandidateWord* cand;
|
|
622 |
int i = 0;
|
|
623 |
int size = FcitxCandidateWordGetPageSize(candList) * CLOUDPINYIN_CHECK_PAGE_NUMBER;
|
|
624 |
for (cand = FcitxCandidateWordGetFirst(candList);
|
|
625 |
cand != NULL;
|
|
626 |
cand = FcitxCandidateWordGetNext(candList, cand))
|
|
627 |
{
|
|
628 |
if (strcmp(cand->strWord, cacheEntry->str) == 0) {
|
|
629 |
FcitxCandidateWordRemove(candList, candWord);
|
|
630 |
FcitxUIUpdateInputWindow(cloudpinyin->owner);
|
|
631 |
candWord = NULL;
|
|
632 |
break;
|
|
633 |
}
|
|
634 |
i ++;
|
|
635 |
if (i >= size)
|
|
636 |
break;
|
|
637 |
}
|
|
638 |
|
548 | 639 |
if (candWord)
|
549 | 640 |
{
|
550 | |
CloudCandWord* cloudCand = candWord->priv;
|
551 | 641 |
if (cloudCand->filled == false)
|
552 | 642 |
{
|
553 | 643 |
cloudCand->filled = true;
|
554 | 644 |
free(candWord->strWord);
|
555 | 645 |
candWord->strWord = strdup(cacheEntry->str);
|
556 | |
UpdateInputWindow(cloudpinyin->owner);
|
|
646 |
FcitxUIUpdateInputWindow(cloudpinyin->owner);
|
557 | 647 |
}
|
558 | 648 |
}
|
559 | 649 |
}
|
560 | 650 |
}
|
561 | 651 |
|
562 | |
INPUT_RETURN_VALUE CloudPinyinGetCandWord(void* arg, CandidateWord* candWord)
|
|
652 |
INPUT_RETURN_VALUE CloudPinyinGetCandWord(void* arg, FcitxCandidateWord* candWord)
|
563 | 653 |
{
|
564 | 654 |
FcitxCloudPinyin* cloudpinyin = (FcitxCloudPinyin*) arg;
|
565 | 655 |
CloudCandWord* cloudCand = candWord->priv;
|
|
572 | 662 |
{
|
573 | 663 |
*py = 0;
|
574 | 664 |
|
575 | |
snprintf(GetOutputString(input), MAX_USER_INPUT, "%s%s", string, candWord->strWord);
|
576 | |
|
577 | |
FcitxIM* im = GetCurrentIM(cloudpinyin->owner);
|
|
665 |
snprintf(FcitxInputStateGetOutputString(input), MAX_USER_INPUT, "%s%s", string, candWord->strWord);
|
|
666 |
|
|
667 |
FcitxIM* im = FcitxInstanceGetCurrentIM(cloudpinyin->owner);
|
578 | 668 |
FcitxModuleFunctionArg args;
|
579 | |
args.args[0] = GetOutputString(input);
|
|
669 |
args.args[0] = FcitxInputStateGetOutputString(input);
|
580 | 670 |
if (im)
|
581 | 671 |
{
|
582 | |
if (strcmp(im->strIconName, "sunpinyin") == 0)
|
|
672 |
if (strcmp(im->uniqueName, "sunpinyin") == 0)
|
583 | 673 |
{
|
584 | 674 |
//InvokeModuleFunctionWithName(cloudpinyin->owner, "fcitx-sunpinyin", 1, args);
|
585 | 675 |
}
|
586 | |
else if (strcmp(im->strIconName, "shuangpin") == 0 || strcmp(im->strIconName, "pinyin") == 0)
|
|
676 |
else if (strcmp(im->uniqueName, "shuangpin") == 0 || strcmp(im->uniqueName, "pinyin") == 0)
|
587 | 677 |
{
|
588 | |
InvokeModuleFunctionWithName(cloudpinyin->owner, "fcitx-pinyin", 7, args);
|
|
678 |
FcitxModuleInvokeFunctionByName(cloudpinyin->owner, "fcitx-pinyin", 7, args);
|
589 | 679 |
}
|
590 | 680 |
}
|
591 | 681 |
}
|
|
605 | 695 |
**/
|
606 | 696 |
boolean LoadCloudPinyinConfig(FcitxCloudPinyinConfig* fs)
|
607 | 697 |
{
|
608 | |
ConfigFileDesc *configDesc = GetCloudPinyinConfigDesc();
|
|
698 |
FcitxConfigFileDesc *configDesc = GetCloudPinyinConfigDesc();
|
609 | 699 |
if (configDesc == NULL)
|
610 | 700 |
return false;
|
611 | 701 |
|
612 | |
FILE *fp = GetXDGFileUserWithPrefix("conf", "fcitx-cloudpinyin.config", "rt", NULL);
|
|
702 |
FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-cloudpinyin.config", "rt", NULL);
|
613 | 703 |
|
614 | 704 |
if (!fp)
|
615 | 705 |
{
|
616 | 706 |
if (errno == ENOENT)
|
617 | 707 |
SaveCloudPinyinConfig(fs);
|
618 | 708 |
}
|
619 | |
ConfigFile *cfile = ParseConfigFileFp(fp, configDesc);
|
|
709 |
FcitxConfigFile *cfile = FcitxConfigParseConfigFileFp(fp, configDesc);
|
620 | 710 |
FcitxCloudPinyinConfigConfigBind(fs, cfile, configDesc);
|
621 | |
ConfigBindSync(&fs->config);
|
|
711 |
FcitxConfigBindSync(&fs->config);
|
622 | 712 |
|
623 | 713 |
if (fp)
|
624 | 714 |
fclose(fp);
|
|
633 | 723 |
**/
|
634 | 724 |
void SaveCloudPinyinConfig(FcitxCloudPinyinConfig* fs)
|
635 | 725 |
{
|
636 | |
ConfigFileDesc *configDesc = GetCloudPinyinConfigDesc();
|
637 | |
FILE *fp = GetXDGFileUserWithPrefix("conf", "fcitx-cloudpinyin.config", "wt", NULL);
|
638 | |
SaveConfigFileFp(fp, &fs->config, configDesc);
|
|
726 |
FcitxConfigFileDesc *configDesc = GetCloudPinyinConfigDesc();
|
|
727 |
FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-cloudpinyin.config", "wt", NULL);
|
|
728 |
FcitxConfigSaveConfigFileFp(fp, &fs->config, configDesc);
|
639 | 729 |
if (fp)
|
640 | 730 |
fclose(fp);
|
641 | 731 |
}
|
642 | 732 |
|
643 | 733 |
char *GetCurrentString(FcitxCloudPinyin* cloudpinyin)
|
644 | 734 |
{
|
645 | |
FcitxIM* im = GetCurrentIM(cloudpinyin->owner);
|
|
735 |
FcitxIM* im = FcitxInstanceGetCurrentIM(cloudpinyin->owner);
|
646 | 736 |
if (!im)
|
647 | 737 |
return NULL;
|
648 | 738 |
FcitxInputState* input = FcitxInstanceGetInputState(cloudpinyin->owner);
|
649 | |
char* string = MessagesToCString(FcitxInputStateGetPreedit(input));
|
|
739 |
char* string = FcitxUIMessagesToCString(FcitxInputStateGetPreedit(input));
|
650 | 740 |
char p[MAX_USER_INPUT + 1], *pinyin, *lastpos;
|
651 | 741 |
pinyin = SplitHZAndPY(string);
|
652 | 742 |
lastpos = pinyin;
|
|
669 | 759 |
FcitxModuleFunctionArg arg;
|
670 | 760 |
arg.args[0] = lastpos;
|
671 | 761 |
boolean isshuangpin = false;
|
672 | |
if (strcmp(im->strIconName, "sunpinyin") == 0)
|
|
762 |
if (strcmp(im->uniqueName, "sunpinyin") == 0)
|
673 | 763 |
{
|
674 | 764 |
boolean issp = false;
|
675 | 765 |
arg.args[1] = &issp;
|
676 | |
result = InvokeModuleFunctionWithName(cloudpinyin->owner, "fcitx-sunpinyin", 0, arg);
|
|
766 |
result = FcitxModuleInvokeFunctionByName(cloudpinyin->owner, "fcitx-sunpinyin", 0, arg);
|
677 | 767 |
isshuangpin = issp;
|
678 | 768 |
}
|
679 | |
else if (strcmp(im->strIconName, "shuangpin") == 0)
|
|
769 |
else if (strcmp(im->uniqueName, "shuangpin") == 0)
|
680 | 770 |
{
|
681 | 771 |
isshuangpin = true;
|
682 | 772 |
result = InvokeFunction(cloudpinyin->owner, FCITX_PINYIN, SP2QP, arg);
|
|
737 | 827 |
char* p;
|
738 | 828 |
int chr;
|
739 | 829 |
|
740 | |
p = utf8_get_char(s, &chr);
|
|
830 |
p = fcitx_utf8_get_char(s, &chr);
|
741 | 831 |
if (p - s == 1)
|
742 | 832 |
break;
|
743 | 833 |
s = p;
|
|
748 | 838 |
|
749 | 839 |
void SogouParseKey(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
|
750 | 840 |
{
|
751 | |
char* str = fcitx_trim(queue->str);
|
|
841 |
char* str = fcitx_utils_trim(queue->str);
|
752 | 842 |
const char* ime_patch_key = "ime_patch_key = \"";
|
753 | 843 |
size_t len = strlen(str);
|
754 | 844 |
if (len == SOGOU_KEY_LENGTH + strlen(ime_patch_key) + 1
|
|
774 | 864 |
{
|
775 | 865 |
size_t length = end - start;
|
776 | 866 |
int conv_length;
|
777 | |
char *realstring = curl_easy_unescape(queue->curl, start, length, &conv_length);
|
|
867 |
char *unescapedstring = curl_easy_unescape(queue->curl, start, length, &conv_length);
|
|
868 |
char *realstring = strdup(unescapedstring);
|
|
869 |
curl_free(unescapedstring);
|
778 | 870 |
return realstring;
|
779 | 871 |
}
|
780 | 872 |
}
|
|
783 | 875 |
|
784 | 876 |
void QQParseKey(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
|
785 | 877 |
{
|
786 | |
char* str = fcitx_trim(queue->str);
|
|
878 |
char* str = fcitx_utils_trim(queue->str);
|
787 | 879 |
const char* ime_patch_key = "{\"key\":\"";
|
788 | 880 |
if (strncmp(str, ime_patch_key, strlen(ime_patch_key)) == 0)
|
789 | 881 |
{
|
|
806 | 898 |
if ((end = strstr(start, "\"")) != NULL)
|
807 | 899 |
{
|
808 | 900 |
size_t length = end - start;
|
809 | |
char *realstring = fcitx_malloc0(sizeof(char) * (length + 1));
|
|
901 |
char *realstring = fcitx_utils_malloc0(sizeof(char) * (length + 1));
|
810 | 902 |
strncpy(realstring, start, length);
|
811 | 903 |
realstring[length] = '\0';
|
812 | 904 |
return realstring;
|
|
824 | 916 |
if ((end = strstr(start, "\"")) != NULL)
|
825 | 917 |
{
|
826 | 918 |
size_t length = end - start;
|
827 | |
char *realstring = fcitx_malloc0(sizeof(char) * (length + 1));
|
|
919 |
char *realstring = fcitx_utils_malloc0(sizeof(char) * (length + 1));
|
828 | 920 |
strncpy(realstring, start, length);
|
829 | 921 |
realstring[length] = '\0';
|
830 | 922 |
return realstring;
|
|
852 | 944 |
return NULL;
|
853 | 945 |
|
854 | 946 |
size_t i = 0, j = 0;
|
855 | |
char* buf = fcitx_malloc0((length / 6 + 1) * 2);
|
|
947 |
char* buf = fcitx_utils_malloc0((length / 6 + 1) * 2);
|
856 | 948 |
while (i < length)
|
857 | 949 |
{
|
858 | 950 |
if (start[i] == '\\' && start[i+1] == 'u')
|
|
877 | 969 |
buf[j++] = 0;
|
878 | 970 |
buf[j++] = 0;
|
879 | 971 |
size_t len = UTF8_MAX_LENGTH * (length / 6) * sizeof(char);
|
880 | |
char* realstring = fcitx_malloc0(UTF8_MAX_LENGTH * (length / 6) * sizeof(char));
|
881 | |
char* p = buf, *pp = realstring;
|
|
972 |
char* realstring = fcitx_utils_malloc0(UTF8_MAX_LENGTH * (length / 6) * sizeof(char));
|
|
973 |
IconvStr p = buf; char *pp = realstring;
|
882 | 974 |
iconv(conv, &p, &j, &pp, &len);
|
883 | 975 |
|
884 | 976 |
free(buf);
|
885 | |
if (utf8_check_string(realstring))
|
|
977 |
if (fcitx_utf8_check_string(realstring))
|
886 | 978 |
return realstring;
|
887 | 979 |
else
|
888 | 980 |
{
|