1 
2 #include "config.h"
3 
4 #include <string.h>
5 #include <fcitx-utils/utils.h>
6 #include <fcitx-utils/utf8.h>
7 #include <iconv.h>
8 #include <ctype.h>
9 #include "cloudpinyin.h"
10 
ishex(char ch)11 static inline boolean ishex(char ch)
12 {
13     if ((ch >= '0' && ch <= '9') || (ch >='a' && ch <='f') || (ch >='A' && ch <='F'))
14         return true;
15     return false;
16 }
17 
tohex(char ch)18 static inline unsigned char tohex(char ch)
19 {
20     if (ch >= '0' && ch <= '9')
21         return ch - '0';
22     if (ch >='a' && ch <='f')
23         return ch - 'a' + 10;
24     if (ch >='A' && ch <='F')
25         return ch - 'A' + 10;
26     return 0;
27 }
28 
SogouParseKey(FcitxCloudPinyin * cloudpinyin,CurlQueue * queue)29 void SogouParseKey(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
30 {
31     char* str = fcitx_utils_trim(queue->str);
32     const char* ime_patch_key = "ime_patch_key = \"";
33     size_t len = strlen(str);
34     if (len == SOGOU_KEY_LENGTH + strlen(ime_patch_key) + 1
35         && strncmp(str, ime_patch_key, strlen(ime_patch_key)) == 0
36         && str[len - 1] == '\"') {
37         sscanf(str,"ime_patch_key = \"%s\"", cloudpinyin->key);
38         cloudpinyin->initialized = true;
39         cloudpinyin->key[SOGOU_KEY_LENGTH] = '\0';
40     }
41 
42     free(str);
43 }
44 
MapSogouStringToHalf(const char * string)45 char* MapSogouStringToHalf(const char* string)
46 {
47     const char* s = string;
48     const char* sn;
49     size_t len = strlen(string);
50     char* half = fcitx_utils_malloc0(sizeof(char) * (len + 1));
51     char* halfp = half;
52     int upperCount = 0;
53 
54     while (*s) {
55         unsigned int chr = 0;
56 
57         sn = fcitx_utf8_get_char(s, &chr);
58 
59         /* from A to Z */
60         if ((chr >= 0xff21 && chr <= 0xff3a) || (chr >= 0xff41 && chr <= 0xff5a)) {
61             *halfp = (char) (chr & 0xff) + 0x20;
62             if (isupper(*halfp))
63                 upperCount ++;
64             halfp ++;
65         }
66         else {
67             while(s < sn) {
68                 *halfp = *s;
69                 if (isupper(*halfp))
70                     upperCount ++;
71                 s++;
72                 halfp++;
73             }
74         }
75 
76         s = sn;
77     }
78     if (*half && isupper(*half) && upperCount == 1) {
79         *half = tolower(*half);
80     }
81     return half;
82 }
83 
SogouParsePinyin(FcitxCloudPinyin * cloudpinyin,CurlQueue * queue)84 char* SogouParsePinyin(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
85 {
86     char *start = NULL, *end = NULL;
87     if ((start = strchr(queue->str, '"')) != NULL && (end = strstr(queue->str, "%EF%BC%9A")) != NULL)
88     {
89         start ++;
90         if (start < end)
91         {
92             size_t length = end - start;
93             int conv_length;
94             char *unescapedstring = curl_easy_unescape(queue->curl, start, length, &conv_length);
95             char *realstring = MapSogouStringToHalf(unescapedstring);
96             curl_free(unescapedstring);
97             return realstring;
98         }
99     }
100     return NULL;
101 }
102 
QQParseKey(FcitxCloudPinyin * cloudpinyin,CurlQueue * queue)103 void QQParseKey(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
104 {
105     char* str = fcitx_utils_trim(queue->str);
106     const char* ime_patch_key = "{\"key\":\"";
107     if (strncmp(str, ime_patch_key, strlen(ime_patch_key)) == 0)
108     {
109         if (sscanf(str,"{\"key\":\"%32s\",\"ret\":\"suc\"}", cloudpinyin->key) > 0)
110         {
111             cloudpinyin->initialized = true;
112             cloudpinyin->key[QQ_KEY_LENGTH] = '\0';
113         }
114     }
115 
116     free(str);
117 }
118 
QQParsePinyin(FcitxCloudPinyin * cloudpinyin,CurlQueue * queue)119 char* QQParsePinyin(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
120 {
121     char *start = NULL, *end = NULL;
122     if ((start = strstr(queue->str, "\"rs\":[\"")) != NULL)
123     {
124         start += strlen( "\"rs\":[\"");
125         if ((end = strstr(start, "\"")) != NULL)
126         {
127             size_t length = end - start;
128             char *realstring = fcitx_utils_malloc0(sizeof(char) * (length + 1));
129             strncpy(realstring, start, length);
130             realstring[length] = '\0';
131             return realstring;
132         }
133     }
134     return NULL;
135 }
136 
GoogleParsePinyin(FcitxCloudPinyin * cloudpinyin,CurlQueue * queue)137 char* GoogleParsePinyin(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
138 {
139     char *start = NULL, *end = NULL;
140     if ((start = strstr(queue->str, "\",[\"")) != NULL)
141     {
142         start += strlen( "\",[\"");
143         if ((end = strstr(start, "\"")) != NULL)
144         {
145             size_t length = end - start;
146             char *realstring = fcitx_utils_malloc0(sizeof(char) * (length + 1));
147             strncpy(realstring, start, length);
148             realstring[length] = '\0';
149             return realstring;
150         }
151     }
152     return NULL;
153 }
154 
BaiduParsePinyin(FcitxCloudPinyin * cloudpinyin,CurlQueue * queue)155 char* BaiduParsePinyin(FcitxCloudPinyin* cloudpinyin, CurlQueue* queue)
156 {
157     char *start = NULL, *end = NULL;
158     static iconv_t conv = 0;
159     if (conv == 0)
160         conv = iconv_open("utf-8", "utf-16be");
161 
162     if (conv == (iconv_t)(-1))
163         return NULL;
164     if ((start = strstr(queue->str, "[[[\"")) != NULL)
165     {
166         start += strlen( "[[[\"");
167         if ((end = strstr(start, "\",")) != NULL)
168         {
169             size_t length = end - start;
170             if (length % 6 != 0 || length == 0)
171                 return NULL;
172 
173             size_t i = 0, j = 0;
174             char* buf = fcitx_utils_malloc0((length / 6 + 1) * 2);
175             while (i < length)
176             {
177                 if (start[i] == '\\' && start[i+1] == 'u')
178                 {
179                     if (ishex(start[i+2]) && ishex(start[i+3]) && ishex(start[i+4]) && ishex(start[i+5]))
180                     {
181                         buf[j++] = (tohex(start[i+2]) << 4) | tohex(start[i+3]);
182                         buf[j++] = (tohex(start[i+4]) << 4) | tohex(start[i+5]);
183                     }
184                     else
185                         break;
186                 }
187 
188                 i += 6;
189             }
190 
191             if (i != length)
192             {
193                 free(buf);
194                 return NULL;
195             }
196             buf[j++] = 0;
197             buf[j++] = 0;
198             size_t len = UTF8_MAX_LENGTH * (length / 6) * sizeof(char);
199             char* realstring = fcitx_utils_malloc0(UTF8_MAX_LENGTH * (length / 6) * sizeof(char));
200             IconvStr p = buf; char *pp = realstring;
201             iconv(conv, &p, &j, &pp, &len);
202 
203             free(buf);
204             if (fcitx_utf8_check_string(realstring))
205                 return realstring;
206             else
207             {
208                 free(realstring);
209                 return NULL;
210             }
211         }
212     }
213     return NULL;
214 }
215