1 #define USE_HTTP 1
2 #if USE_HTTP
3 #include <errno.h>
4 #include <curl/curl.h>
5 #else
6 #if UNIX
7 #include <netdb.h>
8 #include <netinet/in.h>
9 #include <sys/socket.h>
10 typedef int SOCKET;
11 #define closesocket(a) close(a)
12 #else
13 #include <WinSock2.h>
14 #include <ws2tcpip.h>
15 #define write(a,b,c) send(a,b,c,0)
16 #define read(a,b,c) recv(a,b,c,0)
17 #endif
18 #endif
19
20 #include "gcin.h"
21 #include "pho.h"
22 #include "config.h"
23 #if GCIN_i18n_message
24 #include <libintl.h>
25 #endif
26 #include "lang.h"
27 #include "tsin.h"
28 #include "gtab.h"
29 #include <gdk/gdkkeysyms.h>
30 #if GTK_CHECK_VERSION(2,90,7)
31 #include <gdk/gdkkeysyms-compat.h>
32 #endif
33 #include "ts-share.h"
34 #include "gcin-conf.h"
35
36 extern int tsN;
37 void load_tsin_at_ts_idx(int ts_row, char *len, usecount_t *usecount, void *pho, u_char *ch);
38
39 char *get_tag();
40 extern gboolean b_en;
41 int connect_ts_share_svr();
42 extern char downloaded_file_src[];
43 #if !USE_HTTP
44 void send_format(SOCKET sock);
45 #endif
46 int get_key_sz();
47 void write_tsin_src(FILE *fw, char len, phokey_t *pho, char *s);
48 FILE *en_file_head(char *fname);
49
50 #if USE_HTTP
51 enum fcurl_type_e {
52 CFTYPE_NONE=0,
53 CFTYPE_FILE=1,
54 CFTYPE_CURL=2
55 };
56
57 struct fcurl_data
58 {
59 enum fcurl_type_e type; /* type of handle */
60 union {
61 CURL *curl;
62 FILE *file;
63 } handle; /* handle */
64
65 char *buffer; /* buffer to store cached data*/
66 size_t buffer_len; /* currently allocated buffers length */
67 size_t buffer_pos; /* end of data in buffer*/
68 int still_running; /* Is background url fetch still in progress */
69 };
70
71 typedef struct fcurl_data URL_FILE;
72
73 /* exported functions */
74 URL_FILE *url_fopen(const char *url, const char *operation);
75 int url_fclose(URL_FILE *file);
76 int url_feof(URL_FILE *file);
77 size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file);
78 char *url_fgets(char *ptr, size_t size, URL_FILE *file);
79 void url_rewind(URL_FILE *file);
80
81 /* we use a global one for convenience */
82 CURLM *multi_handle;
83
84 /* curl calls this routine to get more data */
write_callback(char * buffer,size_t size,size_t nitems,void * userp)85 static size_t write_callback(char *buffer,
86 size_t size,
87 size_t nitems,
88 void *userp)
89 {
90 char *newbuff;
91 size_t rembuff;
92
93 URL_FILE *url = (URL_FILE *)userp;
94 size *= nitems;
95
96 rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */
97
98 if(size > rembuff) {
99 /* not enough space in buffer */
100 newbuff=(char *)realloc(url->buffer, url->buffer_len + (size - rembuff));
101 if(newbuff==NULL) {
102 fprintf(stderr, "callback buffer grow failed\n");
103 size=rembuff;
104 }
105 else {
106 /* realloc succeeded increase buffer size*/
107 url->buffer_len+=size - rembuff;
108 url->buffer=newbuff;
109 }
110 }
111
112 memcpy(&url->buffer[url->buffer_pos], buffer, size);
113 url->buffer_pos += size;
114
115 return size;
116 }
117
118 /* use to attempt to fill the read buffer up to requested number of bytes */
fill_buffer(URL_FILE * file,size_t want)119 static int fill_buffer(URL_FILE *file, size_t want)
120 {
121 fd_set fdread;
122 fd_set fdwrite;
123 fd_set fdexcep;
124 struct timeval timeout;
125 int rc;
126 CURLMcode mc; /* curl_multi_fdset() return code */
127
128 /* only attempt to fill buffer if transactions still running and buffer
129 * doesn't exceed required size already
130 */
131 if((!file->still_running) || (file->buffer_pos > want))
132 return 0;
133
134 /* attempt to fill buffer */
135 do {
136 int maxfd = -1;
137 long curl_timeo = -1;
138
139 FD_ZERO(&fdread);
140 FD_ZERO(&fdwrite);
141 FD_ZERO(&fdexcep);
142
143 /* set a suitable timeout to fail on */
144 timeout.tv_sec = 60; /* 1 minute */
145 timeout.tv_usec = 0;
146
147 curl_multi_timeout(multi_handle, &curl_timeo);
148 if(curl_timeo >= 0) {
149 timeout.tv_sec = curl_timeo / 1000;
150 if(timeout.tv_sec > 1)
151 timeout.tv_sec = 1;
152 else
153 timeout.tv_usec = (curl_timeo % 1000) * 1000;
154 }
155
156 /* get file descriptors from the transfers */
157 mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
158
159 if(mc != CURLM_OK) {
160 fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
161 break;
162 }
163
164 /* On success the value of maxfd is guaranteed to be >= -1. We call
165 select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
166 no fds ready yet so we call select(0, ...) --or Sleep() on Windows--
167 to sleep 100ms, which is the minimum suggested value in the
168 curl_multi_fdset() doc. */
169
170 if(maxfd == -1) {
171 #ifdef _WIN32
172 Sleep(100);
173 rc = 0;
174 #else
175 /* Portable sleep for platforms other than Windows. */
176 struct timeval wait = { 0, 100 * 1000 }; /* 100ms */
177 rc = select(0, NULL, NULL, NULL, &wait);
178 #endif
179 }
180 else {
181 /* Note that on some platforms 'timeout' may be modified by select().
182 If you need access to the original value save a copy beforehand. */
183 rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
184 }
185
186 switch(rc) {
187 case -1:
188 /* select error */
189 break;
190
191 case 0:
192 default:
193 /* timeout or readable/writable sockets */
194 curl_multi_perform(multi_handle, &file->still_running);
195 break;
196 }
197 } while(file->still_running && (file->buffer_pos < want));
198 return 1;
199 }
200
201 /* use to remove want bytes from the front of a files buffer */
use_buffer(URL_FILE * file,size_t want)202 static int use_buffer(URL_FILE *file, size_t want)
203 {
204 /* sort out buffer */
205 if((file->buffer_pos - want) <=0) {
206 /* ditch buffer - write will recreate */
207 free(file->buffer);
208 file->buffer=NULL;
209 file->buffer_pos=0;
210 file->buffer_len=0;
211 }
212 else {
213 /* move rest down make it available for later */
214 memmove(file->buffer,
215 &file->buffer[want],
216 (file->buffer_pos - want));
217
218 file->buffer_pos -= want;
219 }
220 return 0;
221 }
222
url_fopen(const char * url,const char * operation)223 URL_FILE *url_fopen(const char *url, const char *operation)
224 {
225 /* this code could check for URLs or types in the 'url' and
226 basically use the real fopen() for standard files */
227
228 URL_FILE *file;
229 (void)operation;
230
231 file = (URL_FILE *)malloc(sizeof(URL_FILE));
232 if(!file)
233 return NULL;
234
235 memset(file, 0, sizeof(URL_FILE));
236
237 if((file->handle.file=fopen(url, operation)))
238 file->type = CFTYPE_FILE; /* marked as URL */
239
240 else {
241 file->type = CFTYPE_CURL; /* marked as URL */
242 file->handle.curl = curl_easy_init();
243
244 curl_easy_setopt(file->handle.curl, CURLOPT_URL, url);
245 curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file);
246 curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L);
247 curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback);
248
249 if(!multi_handle)
250 multi_handle = curl_multi_init();
251
252 curl_multi_add_handle(multi_handle, file->handle.curl);
253
254 /* lets start the fetch */
255 curl_multi_perform(multi_handle, &file->still_running);
256
257 if((file->buffer_pos == 0) && (!file->still_running)) {
258 /* if still_running is 0 now, we should return NULL */
259
260 /* make sure the easy handle is not in the multi handle anymore */
261 curl_multi_remove_handle(multi_handle, file->handle.curl);
262
263 /* cleanup */
264 curl_easy_cleanup(file->handle.curl);
265
266 free(file);
267
268 file = NULL;
269 }
270 }
271 return file;
272 }
273
url_fclose(URL_FILE * file)274 int url_fclose(URL_FILE *file)
275 {
276 int ret=0;/* default is good return */
277
278 switch(file->type) {
279 case CFTYPE_FILE:
280 ret=fclose(file->handle.file); /* passthrough */
281 break;
282
283 case CFTYPE_CURL:
284 /* make sure the easy handle is not in the multi handle anymore */
285 curl_multi_remove_handle(multi_handle, file->handle.curl);
286
287 /* cleanup */
288 curl_easy_cleanup(file->handle.curl);
289 break;
290
291 default: /* unknown or supported type - oh dear */
292 ret=EOF;
293 errno=EBADF;
294 break;
295 }
296
297 free(file->buffer);/* free any allocated buffer space */
298 free(file);
299
300 return ret;
301 }
302
url_feof(URL_FILE * file)303 int url_feof(URL_FILE *file)
304 {
305 int ret=0;
306
307 switch(file->type) {
308 case CFTYPE_FILE:
309 ret=feof(file->handle.file);
310 break;
311
312 case CFTYPE_CURL:
313 if((file->buffer_pos == 0) && (!file->still_running))
314 ret = 1;
315 break;
316
317 default: /* unknown or supported type - oh dear */
318 ret=-1;
319 errno=EBADF;
320 break;
321 }
322 return ret;
323 }
324
url_fread(void * ptr,size_t size,size_t nmemb,URL_FILE * file)325 size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file)
326 {
327 size_t want;
328
329 switch(file->type) {
330 case CFTYPE_FILE:
331 want=fread(ptr, size, nmemb, file->handle.file);
332 break;
333
334 case CFTYPE_CURL:
335 want = nmemb * size;
336
337 fill_buffer(file, want);
338
339 /* check if there's data in the buffer - if not fill_buffer()
340 * either errored or EOF */
341 if(!file->buffer_pos)
342 return 0;
343
344 /* ensure only available data is considered */
345 if(file->buffer_pos < want)
346 want = file->buffer_pos;
347
348 /* xfer data to caller */
349 memcpy(ptr, file->buffer, want);
350
351 use_buffer(file, want);
352
353 want = want / size; /* number of items */
354 break;
355
356 default: /* unknown or supported type - oh dear */
357 want=0;
358 errno=EBADF;
359 break;
360
361 }
362 return want;
363 }
364
365 #endif
366
367
ts_download()368 void ts_download()
369 {
370 #if !USE_HTTP
371 int sock = connect_ts_share_svr();
372
373 REQ_HEAD head;
374 bzero(&head, sizeof(head));
375 head.cmd = REQ_DOWNLOAD2;
376 write(sock, (char *)&head, sizeof(head));
377
378 REQ_DOWNLOAD_S req;
379 bzero(&req, sizeof(req));
380 strcpy(req.tag, get_tag());
381 #endif
382
383 static char DL_CONF[]="ts-share-download-time";
384 static char DL_CONF_EN[]="ts-share-download-time-en";
385 int rn, wn;
386 char *dl_conf = b_en?DL_CONF_EN:DL_CONF;
387 #if USE_HTTP
388 int last_dl_time = get_gcin_conf_int(dl_conf, 0);
389 // last_dl_time = 1480473779;
390 // last_dl_time = 1375473779;
391 // last_dl_time = 1489366066;
392 dbg("last_dl_time %d\n", last_dl_time);
393 #else
394 req.last_dl_time = get_gcin_conf_int(dl_conf, 0);
395 // req.last_dl_time = 0;
396 wn = write(sock, (char*)&req, sizeof(req));
397 REQ_DOWNLOAD_REPLY_S rep;
398 rn = read(sock, (char*)&rep, sizeof(rep));
399 send_format(sock);
400 #endif
401
402 int key_sz = get_key_sz();
403
404 #if USE_HTTP
405 char url[128];
406 sprintf(url, "http://hyperrate.com/ts-share/d.php?ti=%d&tag=%s&key_sz=%d",last_dl_time, get_tag(), key_sz);
407 URL_FILE *handle = url_fopen(url, "r");
408 int this_dl_time;
409 rn = url_fread(&this_dl_time, 1, sizeof(this_dl_time), handle);
410 dbg("this_dl_time %d\n", this_dl_time);
411 #endif
412
413 FILE *fw;
414 if (b_en)
415 fw = en_file_head(downloaded_file_src);
416 else
417 if ((fw=fopen(downloaded_file_src,"a"))==NULL)
418 p_err("cannot create %s:%s", downloaded_file_src, sys_err_strA());
419
420 int N=0;
421 for(;;) {
422 char len=0;
423 #if USE_HTTP
424 rn = url_fread(&len, 1, sizeof(len), handle);
425 dbg("len %d\n", len);
426 #else
427 rn = read(sock, &len, sizeof(len));
428 #endif
429 if (len<=0)
430 break;
431 phokey_t pho[128];
432 #if USE_HTTP
433 rn = url_fread((char*)pho, 1, len * key_sz, handle);
434 #else
435 rn = read(sock, (char*)pho, len * key_sz);
436 #endif
437
438 if (b_en) {
439 char *s = (char *)pho;
440 s[len]=0;
441 dbg("dl %s\n", s);
442 #if 1
443 save_phrase_to_db(&en_hand, pho, NULL, len, 0);
444 write_tsin_src(fw, len, NULL, s);
445 #endif
446 } else {
447 char slen=0;
448 char s[256];
449 #if USE_HTTP
450 rn = url_fread(&slen, 1, sizeof(slen), handle);
451 dbg("slen %d\n", slen);
452 if (slen < 0)
453 break;
454 rn = url_fread(s, 1, slen, handle);
455 #else
456 rn = read(sock, &slen, sizeof(slen));
457 rn = read(sock, s, slen);
458 #endif
459 s[slen]=0;
460 dbg("dl %s\n", s);
461 #if 1
462 save_phrase_to_db(&tsin_hand, pho, s, len, 0);
463 write_tsin_src(fw, len, pho, s);
464 #endif
465 }
466
467 N++;
468 }
469
470 dbg("N:%d\n", N);
471 if (N)
472 #if USE_HTTP
473 save_gcin_conf_int(dl_conf, (int)this_dl_time);
474 #else
475 save_gcin_conf_int(dl_conf, (int)rep.this_dl_time);
476 #endif
477
478 fclose(fw);
479 #if USE_HTTP
480 url_fclose(handle);
481 #else
482 closesocket(sock);
483 #endif
484 }
485