1 #include <stdio.h>
2 #include "utility.h"
3 #include "urlgfe.h"
4 #include "download_thread.h"
5 #include "download_backend.h"
6
7 static gpointer download_thread_func (DownloadThread* dt);
8
9 #ifdef G_OS_WIN32
10
11 #include <windows.h>
download_thread_retry_delay(DownloadThread * dt)12 void download_thread_retry_delay (DownloadThread* dt)
13 {
14 int count = DOWNLOAD_SETTING (dt->download_data)->retry_delay*2;
15
16 while (dt->thread_state < DOWNLOAD_THREAD_SKIP && count) {
17 Sleep (500); // check state every 0.5 second.
18 count--;
19 }
20 }
21
22 #else
download_thread_retry_delay(DownloadThread * dt)23 void download_thread_retry_delay (DownloadThread* dt)
24 {
25 int count = DOWNLOAD_SETTING (dt->download_data)->retry_delay;
26
27 while (dt->thread_state < DOWNLOAD_THREAD_SKIP && count) {
28 sleep (1); // check state every 1 second.
29 count--;
30 }
31 }
32
33 #endif
34
35
download_thread_new(Category * cate,GtkTreeIter * iter_download)36 DownloadThread* download_thread_new (Category* cate,
37 GtkTreeIter* iter_download)
38 {
39 DownloadThread* dt = g_malloc (sizeof(DownloadThread));
40
41 g_static_rec_mutex_init (&dt->mutex);
42
43 // list
44 dt->prev = NULL;
45 dt->next = NULL;
46
47 // category
48 dt->category = cate;
49 category_ref (cate);
50
51 dt->out_filename = g_string_sized_new (128);
52
53 // DownloadStore
54 dt->iter_download = *iter_download;
55 download_store_get_data (&dt->category->waiting_store,
56 &dt->iter_download,
57 &dt->download_data);
58 download_store_set_thread (&dt->category->waiting_store,
59 &dt->iter_download, dt);
60 download_ref (dt->download_data);
61
62
63 // timer
64 dt->timer = g_timer_new ();
65 dt->timer_count = 0.0;
66 g_timer_stop (dt->timer);
67
68 dt->thread_state = DOWNLOAD_THREAD_READY;
69
70 category_thread_add (cate, dt);
71 return dt;
72 }
73
download_thread_free_resource(DownloadThread * dt)74 void download_thread_free_resource (DownloadThread* dt)
75 {
76 printf ("thread free : %p\n", dt);
77
78 gdk_threads_enter ();
79 category_thread_remove (dt->category, dt);
80 category_unref (dt->category);
81 gdk_threads_leave ();
82
83 g_string_free (dt->out_filename, TRUE);
84 g_timer_destroy (dt->timer);
85 g_static_rec_mutex_free (&dt->mutex);
86
87 g_free (dt);
88 }
89
download_thread_activate(DownloadThread * dt)90 void download_thread_activate (DownloadThread* dt)
91 {
92 download_thread_lock(dt);
93
94 if (dt->thread_state == DOWNLOAD_THREAD_READY ) {
95 dt->thread_state = DOWNLOAD_THREAD_ACTIVE;
96
97 dt->gthread = g_thread_create ((GThreadFunc)download_thread_func,
98 dt,TRUE,NULL);
99 }
100
101 download_thread_unlock(dt);
102 }
103
download_thread_skip(DownloadThread * dt)104 void download_thread_skip (DownloadThread* dt)
105 {
106 download_thread_lock(dt);
107
108 if (dt->thread_state < DOWNLOAD_THREAD_SKIP )
109 dt->thread_state = DOWNLOAD_THREAD_SKIP;
110
111 download_thread_unlock(dt);
112 }
113
download_thread_stop(DownloadThread * dt)114 void download_thread_stop (DownloadThread* dt)
115 {
116 download_thread_lock(dt);
117
118 if (dt->thread_state == DOWNLOAD_THREAD_JOB_ERASED )
119 dt->thread_state = DOWNLOAD_THREAD_DESTROY;
120 else if (dt->thread_state < DOWNLOAD_THREAD_STOP )
121 dt->thread_state = DOWNLOAD_THREAD_STOP;
122
123 download_thread_unlock(dt);
124 }
125
download_thread_job_erased(DownloadThread * dt)126 void download_thread_job_erased (DownloadThread* dt)
127 {
128 download_thread_lock(dt);
129
130 if (dt->thread_state == DOWNLOAD_THREAD_STOP )
131 dt->thread_state = DOWNLOAD_THREAD_DESTROY;
132 else if (dt->thread_state < DOWNLOAD_THREAD_JOB_ERASED )
133 dt->thread_state = DOWNLOAD_THREAD_JOB_ERASED;
134
135 download_thread_unlock(dt);
136 }
137
download_thread_destroy(DownloadThread * dt)138 void download_thread_destroy (DownloadThread* dt)
139 {
140 download_thread_lock(dt);
141
142 if (dt->thread_state < DOWNLOAD_THREAD_DESTROY )
143 dt->thread_state = DOWNLOAD_THREAD_DESTROY;
144
145 download_thread_unlock(dt);
146 }
147
download_thread_job_redraw(DownloadThread * dt)148 void download_thread_job_redraw (DownloadThread* dt)
149 {
150 download_store_lock (&dt->category->waiting_store);
151 download_thread_lock (dt);
152
153 if (dt->thread_state < DOWNLOAD_THREAD_JOB_ERASED) {
154 gdk_threads_enter ();
155 #ifdef _WIN32
156 // avoid crash in GTK+ for Win32 ...
157 gtk_widget_queue_draw (GTK_WIDGET (dt->category->waiting_view.self));
158 #else
159 download_store_row_changed (&dt->category->waiting_store,
160 &dt->iter_download);
161 #endif
162 gdk_threads_leave ();
163 }
164
165 download_thread_unlock (dt);
166 download_store_unlock (&dt->category->waiting_store);
167 }
168
download_thread_test_file(DownloadThread * dt)169 gboolean download_thread_test_file (DownloadThread* dt)
170 {
171 gint temp;
172 gint directory_len;
173 gboolean return_val = FALSE;
174 GString* name = dt->out_filename;
175 DownloadSetting* setting = DOWNLOAD_SETTING (dt->download_data);
176 gchar* utf8_file_name;
177 gchar* os_dir_name;
178 gchar* os_file_name;
179
180 if (setting->directory==NULL || setting->filename==NULL)
181 return FALSE;
182
183 // remove '\n' from url
184 temp = strlen (setting->url);
185 if (setting->url[temp-1]=='\n')
186 setting->url[temp-1] = 0;
187 // remove '\n' from directory and filename before convert
188 temp = strlen (setting->directory);
189 if (setting->directory[temp-1]=='\n')
190 setting->directory[temp-1] = 0;
191 temp = strlen (setting->filename);
192 if (setting->filename[temp-1]=='\n')
193 setting->filename[temp-1] = 0;
194
195 os_dir_name = g_filename_from_utf8 (setting->directory, -1,
196 NULL, NULL, NULL);
197 os_file_name = g_filename_from_utf8 (setting->filename, -1,
198 NULL, NULL, NULL);
199 g_string_truncate (name, 0);
200 g_string_append (name, os_dir_name);
201
202 download_thread_lock (dt);
203 if (dt->thread_state < DOWNLOAD_THREAD_SKIP && os_dir_name) {
204 if ( name->str[name->len-1] != G_DIR_SEPARATOR )
205 g_string_append_c (name, G_DIR_SEPARATOR);
206 directory_len = name->len;
207
208 g_string_append (name, os_file_name);
209
210 if (make_path_exist (os_dir_name) && os_file_name) {
211 temp = 0;
212 do {
213 if (g_file_test (name->str, G_FILE_TEST_EXISTS)==FALSE) {
214 return_val = TRUE;
215 break;
216 }
217
218 g_string_truncate (name, directory_len);
219 g_string_append_printf (name, "%s.%u",
220 setting->filename,
221 temp++);
222 } while (temp<100);
223
224 utf8_file_name = g_filename_to_utf8 (name->str + directory_len,
225 -1, NULL, NULL, NULL);
226 download_setting_set_filename (setting, utf8_file_name);
227 g_free (utf8_file_name);
228 g_string_append (name, ".ug_");
229 }
230 }
231 download_thread_unlock (dt);
232
233 g_free (os_dir_name);
234 g_free (os_file_name);
235
236 download_thread_job_redraw (dt);
237
238 return return_val;
239 }
240
download_thread_load_next_job(DownloadThread * dt)241 gboolean download_thread_load_next_job (DownloadThread* dt)
242 {
243 gboolean return_val = FALSE;
244
245 download_store_lock (&dt->category->waiting_store);
246 download_thread_lock (dt);
247
248 if (dt->thread_state==DOWNLOAD_THREAD_JOB_ERASED
249 || dt->thread_state < DOWNLOAD_THREAD_STOP)
250 {
251 dt->thread_state = DOWNLOAD_THREAD_ACTIVE;
252 gdk_threads_enter ();
253 if (category_thread_count_request (dt->category) >=0
254 && download_store_find_waiting (&dt->category->waiting_store,
255 &dt->iter_download) )
256 {
257 download_store_get_data (&dt->category->waiting_store,
258 &dt->iter_download,
259 &dt->download_data);
260 download_store_set_thread (&dt->category->waiting_store,
261 &dt->iter_download,
262 dt);
263 download_ref (dt->download_data);
264
265 return_val = TRUE;
266 }
267 gdk_threads_leave ();
268 }
269
270 download_thread_unlock (dt);
271 download_store_unlock (&dt->category->waiting_store);
272
273 return return_val;
274 }
275
276
download_thread_get_timer(DownloadThread * dt)277 gdouble download_thread_get_timer (DownloadThread* dt)
278 {
279 if (dt->timer_count==0) {
280 g_timer_start (dt->timer);
281 dt->timer_count = 1.0;
282 }
283 else {
284 dt->timer_count = g_timer_elapsed (dt->timer, NULL);
285 g_timer_start (dt->timer);
286 }
287
288 return dt->timer_count;
289 }
290
291 // ===========================================================================
292
download_thread_func(DownloadThread * dt)293 static gpointer download_thread_func (DownloadThread* dt)
294 {
295 gint backend_code;
296 guint n_retry;
297 gpointer backend;
298 gchar* temp_string;
299
300 backend = download_backend_new (dt);
301
302 do {
303 if (download_thread_test_file (dt)==FALSE) {
304 download_thread_job_set_state (dt, DOWNLOAD_STATE_ERROR);
305 download_thread_job_set_message (dt, _("Filename error or repeat."));
306 download_thread_job_redraw (dt);
307
308 download_store_lock (&dt->category->waiting_store);
309 download_thread_lock (dt);
310 gdk_threads_enter ();
311 download_store_set_thread (&dt->category->waiting_store,
312 &dt->iter_download, NULL);
313 gdk_threads_leave ();
314 download_thread_unlock (dt);
315 download_store_unlock (&dt->category->waiting_store);
316
317 continue;
318 }
319
320 dt->resumable = TRUE;
321 n_retry = 0;
322
323 // download & retry loop
324 while (1) {
325 if (dt->thread_state >= DOWNLOAD_THREAD_SKIP) {
326 download_thread_job_set_state (dt, DOWNLOAD_STATE_PAUSE);
327 break;
328 }
329 if (n_retry > DOWNLOAD_SETTING(dt->download_data)->n_retries) {
330 download_thread_job_set_state (dt, DOWNLOAD_STATE_ERROR);
331 download_thread_job_set_message (dt, _("Retry too many times."));
332 break;
333 }
334 download_thread_job_set_speed (dt, 0);
335 download_thread_job_set_state (dt, DOWNLOAD_STATE_EXECUTING);
336 download_thread_job_set_retry (dt, n_retry);
337 download_thread_job_set_total (dt, 0);
338 download_thread_job_set_completed (dt, 0);
339 download_thread_job_set_percent (dt, 0);
340 download_thread_job_redraw (dt);
341 n_retry++;
342
343 dt->timer_count = 0.0;
344 // begin download here
345 backend_code = download_backend_run (backend, dt);
346
347 // check download backend return code
348 if (backend_code==DOWNLOAD_BACKEND_ABORT) {
349 download_thread_job_set_state (dt, DOWNLOAD_STATE_PAUSE);
350 break;
351 }
352 else if (backend_code==DOWNLOAD_BACKEND_OK) {
353 temp_string = g_strndup (dt->out_filename->str,
354 dt->out_filename->len-4);
355 rename (dt->out_filename->str, temp_string);
356 g_free (temp_string);
357 download_thread_job_set_state (dt, DOWNLOAD_STATE_COMPLETED);
358 break;
359 }
360 else if (backend_code==DOWNLOAD_BACKEND_ERROR) {
361 download_thread_job_set_state (dt, DOWNLOAD_STATE_ERROR);
362 break;
363 }
364
365 download_thread_job_set_state (dt, DOWNLOAD_STATE_RETRY);
366 download_thread_job_redraw (dt);
367 download_thread_retry_delay (dt);
368 }
369 download_thread_job_redraw (dt);
370
371 // do some thing after download
372 download_unref (dt->download_data);
373
374 download_store_lock (&dt->category->waiting_store);
375 download_thread_lock (dt);
376 if (dt->thread_state < DOWNLOAD_THREAD_JOB_ERASED)
377 {
378 gdk_threads_enter ();
379 download_store_set_thread (&dt->category->waiting_store,
380 &dt->iter_download, NULL);
381 if (backend_code==DOWNLOAD_BACKEND_OK) {
382 download_store_move_to_store (&dt->category->waiting_store,
383 &dt->category->completed_store,
384 &dt->iter_download);
385 category_changed_with_children (dt->category, CATEGORY_COMPLETED);
386 }
387 gdk_threads_leave ();
388 }
389 download_thread_unlock (dt);
390 download_store_unlock (&dt->category->waiting_store);
391
392 } while (download_thread_load_next_job (dt));
393
394 download_backend_destroy (backend);
395 download_thread_free_resource (dt);
396 return NULL;
397 }
398
399