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