1 /*
2  *
3  *   Copyright (C) 2012-2018 by C.H. Huang
4  *   plushuang.tw@gmail.com
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2.1 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  *  ---
21  *
22  *  In addition, as a special exception, the copyright holders give
23  *  permission to link the code of portions of this program with the
24  *  OpenSSL library under certain conditions as described in each
25  *  individual source file, and distribute linked combinations
26  *  including the two.
27  *  You must obey the GNU Lesser General Public License in all respects
28  *  for all of the code used other than OpenSSL.  If you modify
29  *  file(s) with this exception, you may extend this exception to your
30  *  version of the file(s), but you are not obligated to do so.  If you
31  *  do not wish to do so, delete this exception statement from your
32  *  version.  If you delete this exception statement from all source
33  *  files in the program, then also delete it here.
34  *
35  */
36 
37 #include <UgStdio.h>
38 #include <UgString.h>
39 #include <UgJsonFile.h>
40 #include <UgetMedia.h>
41 #include <UgtkSetting.h>
42 #include <UgtkNodeView.h>
43 
44 #define UGTK_APP_CLIPBOARD_PATTERN  "BIN|ZIP|GZ|7Z|XZ|Z|TAR|TGZ|BZ2|"   \
45                                     "LZH|A[0-9]?|RAR|R[0-9][0-9]|ISO|"  \
46                                     "RPM|DEB|EXE|MSI|APK|"              \
47                                     "3GP|AAC|FLAC|M4A|M4P|MP3|OGG|WAV|WMA|" \
48                                     "MP4|MKV|WEBM|OGV|AVI|MOV|WMV|FLV|F4V|MPG|MPEG|RMVB"
49 
50 #define UGTK_ARIA2_PATH    "aria2c"
51 
52 #define UGTK_ARIA2_ARGS    "--enable-rpc=true -D " \
53                            "--disable-ipv6 "       \
54                            "--check-certificate=false"
55 
56 #define UGTK_ARIA2_URI     "http://localhost:6800/jsonrpc"
57 
58 // ----------------------------------------------------------------------------
59 // WindowSetting
60 
61 static const UgEntry  UgtkWindowSettingEntry[] =
62 {
63 	{"Toolbar",   offsetof (struct UgtkWindowSetting, toolbar),
64 			UG_ENTRY_BOOL,  NULL,  NULL},
65 	{"Statusbar", offsetof (struct UgtkWindowSetting, statusbar),
66 			UG_ENTRY_BOOL,  NULL,  NULL},
67 	{"Category",  offsetof (struct UgtkWindowSetting, category),
68 			UG_ENTRY_BOOL,  NULL,  NULL},
69 	{"Summary",   offsetof (struct UgtkWindowSetting, summary),
70 			UG_ENTRY_BOOL,  NULL,  NULL},
71 	{"Banner",    offsetof (struct UgtkWindowSetting, banner),
72 			UG_ENTRY_BOOL,  NULL,  NULL},
73 	{"x",         offsetof (struct UgtkWindowSetting, x),
74 			UG_ENTRY_INT,  NULL,  NULL},
75 	{"y",         offsetof (struct UgtkWindowSetting, y),
76 			UG_ENTRY_INT,  NULL,  NULL},
77 	{"width",     offsetof (struct UgtkWindowSetting, width),
78 			UG_ENTRY_INT,  NULL,  NULL},
79 	{"height",    offsetof (struct UgtkWindowSetting, height),
80 			UG_ENTRY_INT,  NULL,  NULL},
81 	{"maximized", offsetof (struct UgtkWindowSetting, maximized),
82 			UG_ENTRY_BOOL,  NULL,  NULL},
83 	{"NthCategory", offsetof (struct UgtkWindowSetting, nth_category),
84 			UG_ENTRY_INT,  NULL,  NULL},
85 	{"NthStatus",   offsetof (struct UgtkWindowSetting, nth_state),
86 			UG_ENTRY_INT,  NULL,  NULL},
87 	{"PanedPositionH", offsetof (struct UgtkWindowSetting, paned_position_h),
88 			UG_ENTRY_INT,  NULL,  NULL},
89 	{"PanedPositionV", offsetof (struct UgtkWindowSetting, paned_position_v),
90 			UG_ENTRY_INT,  NULL,  NULL},
91 	{NULL},    // null-terminated
92 };
93 
94 // ----------------------------------------------------------------------------
95 // SummarySetting
96 
97 static const UgEntry  UgtkSummarySettingEntry[] =
98 {
99 	{"name",     offsetof (struct UgtkSummarySetting, name),
100 			UG_ENTRY_BOOL,	NULL,	NULL},
101 	{"folder",   offsetof (struct UgtkSummarySetting, folder),
102 			UG_ENTRY_BOOL,	NULL,	NULL},
103 	{"category", offsetof (struct UgtkSummarySetting, category),
104 			UG_ENTRY_BOOL,	NULL,	NULL},
105 	{"uri",      offsetof (struct UgtkSummarySetting, uri),
106 			UG_ENTRY_BOOL,	NULL,	NULL},
107 	{"message",  offsetof (struct UgtkSummarySetting, message),
108 			UG_ENTRY_BOOL,	NULL,	NULL},
109 	{NULL}    // null-terminated
110 };
111 
112 // ----------------------------------------------------------------------------
113 // DownloadColumnSetting
114 
115 static const UgEntry  UgtkDownloadColumnWidthEntry[] =
116 {
117 	{"state",       offsetof (struct UgtkDownloadColumnWidth, state),
118 			UG_ENTRY_INT,  NULL,  NULL},
119 	{"name",        offsetof (struct UgtkDownloadColumnWidth, name),
120 			UG_ENTRY_INT,  NULL,  NULL},
121 	{"complete",    offsetof (struct UgtkDownloadColumnWidth, complete),
122 			UG_ENTRY_INT,  NULL,  NULL},
123 	{"total",       offsetof (struct UgtkDownloadColumnWidth, total),
124 			UG_ENTRY_INT,  NULL,  NULL},
125 	{"percent",     offsetof (struct UgtkDownloadColumnWidth, percent),
126 			UG_ENTRY_INT,  NULL,  NULL},
127 	{"elapsed",     offsetof (struct UgtkDownloadColumnWidth, elapsed),
128 			UG_ENTRY_INT,  NULL,  NULL},
129 	{"left",        offsetof (struct UgtkDownloadColumnWidth, left),
130 			UG_ENTRY_INT,  NULL,  NULL},
131 	{"speed",       offsetof (struct UgtkDownloadColumnWidth, speed),
132 			UG_ENTRY_INT,  NULL,  NULL},
133 	{"UploadSpeed", offsetof (struct UgtkDownloadColumnWidth, upload_speed),
134 			UG_ENTRY_INT,  NULL,  NULL},
135 	{"uploaded",    offsetof (struct UgtkDownloadColumnWidth, uploaded),
136 			UG_ENTRY_INT,  NULL,  NULL},
137 	{"ratio",       offsetof (struct UgtkDownloadColumnWidth, ratio),
138 			UG_ENTRY_INT,  NULL,  NULL},
139 	{"retry",       offsetof (struct UgtkDownloadColumnWidth, retry),
140 			UG_ENTRY_INT,  NULL,  NULL},
141 	{"category",    offsetof (struct UgtkDownloadColumnWidth, category),
142 			UG_ENTRY_INT,  NULL,  NULL},
143 	{"uri",         offsetof (struct UgtkDownloadColumnWidth, uri),
144 			UG_ENTRY_INT,  NULL,  NULL},
145 	{"AddedOn",     offsetof (struct UgtkDownloadColumnWidth, added_on),
146 			UG_ENTRY_INT,  NULL,  NULL},
147 	{"CompletedOn", offsetof (struct UgtkDownloadColumnWidth, completed_on),
148 			UG_ENTRY_INT,  NULL,  NULL},
149 	{NULL}    // null-terminated
150 };
151 
152 static const UgEntry  UgtkDownloadColumnSettingEntry[] =
153 {
154 	{"complete",    offsetof (struct UgtkDownloadColumnSetting, complete),
155 			UG_ENTRY_BOOL,  NULL,  NULL},
156 	{"total",       offsetof (struct UgtkDownloadColumnSetting, total),
157 			UG_ENTRY_BOOL,  NULL,  NULL},
158 	{"percent",     offsetof (struct UgtkDownloadColumnSetting, percent),
159 			UG_ENTRY_BOOL,  NULL,  NULL},
160 	{"elapsed",     offsetof (struct UgtkDownloadColumnSetting, elapsed),
161 			UG_ENTRY_BOOL,  NULL,  NULL},
162 	{"left",        offsetof (struct UgtkDownloadColumnSetting, left),
163 			UG_ENTRY_BOOL,  NULL,  NULL},
164 	{"speed",       offsetof (struct UgtkDownloadColumnSetting, speed),
165 			UG_ENTRY_BOOL,  NULL,  NULL},
166 	{"UploadSpeed", offsetof (struct UgtkDownloadColumnSetting, upload_speed),
167 			UG_ENTRY_BOOL,  NULL,  NULL},
168 	{"uploaded",    offsetof (struct UgtkDownloadColumnSetting, uploaded),
169 			UG_ENTRY_BOOL,  NULL,  NULL},
170 	{"ratio",       offsetof (struct UgtkDownloadColumnSetting, ratio),
171 			UG_ENTRY_BOOL,  NULL,  NULL},
172 	{"retry",       offsetof (struct UgtkDownloadColumnSetting, retry),
173 			UG_ENTRY_BOOL,  NULL,  NULL},
174 	{"category",    offsetof (struct UgtkDownloadColumnSetting, category),
175 			UG_ENTRY_BOOL,  NULL,  NULL},
176 	{"uri",         offsetof (struct UgtkDownloadColumnSetting, uri),
177 			UG_ENTRY_BOOL,  NULL,  NULL},
178 	{"AddedOn",     offsetof (struct UgtkDownloadColumnSetting, added_on),
179 			UG_ENTRY_BOOL,  NULL,  NULL},
180 	{"CompletedOn", offsetof (struct UgtkDownloadColumnSetting, completed_on),
181 			UG_ENTRY_BOOL,  NULL,  NULL},
182 
183 	{"SortType",    offsetof (struct UgtkDownloadColumnSetting, sort.type),
184 			UG_ENTRY_INT,  NULL,  NULL},
185 	{"SortNth",     offsetof (struct UgtkDownloadColumnSetting, sort.nth),
186 			UG_ENTRY_INT,  NULL,  NULL},
187 
188 	{"Width",       offsetof (struct UgtkDownloadColumnSetting, width),
189 			UG_ENTRY_OBJECT, (void*) UgtkDownloadColumnWidthEntry, NULL},
190 
191 	// deprecated
192 	{"completed",   offsetof (struct UgtkDownloadColumnSetting, complete),
193 			UG_ENTRY_BOOL,  NULL,  NULL},
194 
195 	{NULL}    // null-terminated
196 };
197 
198 // ----------------------------------------------------------------------------
199 // UserInterfaceSetting
200 
201 static const UgEntry  UgtkUserInterfaceSettingEntry[] =
202 {
203 	{"ExitConfirmation",   offsetof (struct UgtkUserInterfaceSetting, exit_confirmation),
204 			UG_ENTRY_BOOL,  NULL,  NULL},
205 	{"DeleteConfirmation", offsetof (struct UgtkUserInterfaceSetting, delete_confirmation),
206 			UG_ENTRY_BOOL,  NULL,  NULL},
207 	{"ShowTrayIcon",       offsetof (struct UgtkUserInterfaceSetting, show_trayicon),
208 			UG_ENTRY_BOOL,  NULL,  NULL},
209 	{"StartInTray",        offsetof (struct UgtkUserInterfaceSetting, start_in_tray),
210 			UG_ENTRY_BOOL,  NULL,  NULL},
211 	{"CloseToTray",        offsetof (struct UgtkUserInterfaceSetting, close_to_tray),
212 			UG_ENTRY_BOOL,  NULL,  NULL},
213 	{"StartInOfflineMode", offsetof (struct UgtkUserInterfaceSetting, start_in_offline_mode),
214 			UG_ENTRY_BOOL,  NULL,  NULL},
215 	{"StartNotification",  offsetof (struct UgtkUserInterfaceSetting, start_notification),
216 			UG_ENTRY_BOOL,  NULL,  NULL},
217 	{"SoundNotification",  offsetof (struct UgtkUserInterfaceSetting, sound_notification),
218 			UG_ENTRY_BOOL,  NULL,  NULL},
219 	{"ApplyRecently",      offsetof (struct UgtkUserInterfaceSetting, apply_recent),
220 			UG_ENTRY_BOOL,  NULL,  NULL},
221 	{"ApplyRecent",        offsetof (struct UgtkUserInterfaceSetting, apply_recent),
222 			UG_ENTRY_BOOL,  NULL,  NULL},
223 	{"SkipExisting",       offsetof (struct UgtkUserInterfaceSetting, skip_existing),
224 			UG_ENTRY_BOOL,  NULL,  NULL},
225 	{"LargeIcon",          offsetof (struct UgtkUserInterfaceSetting, large_icon),
226 			UG_ENTRY_BOOL,  NULL,  NULL},
227 #ifdef HAVE_APP_INDICATOR
228 	{"AppIndicator",       offsetof (struct UgtkUserInterfaceSetting, app_indicator),
229 			UG_ENTRY_BOOL,  NULL,  NULL},
230 #endif
231 	{NULL},    // null-terminated
232 };
233 
234 // ----------------------------------------------------------------------------
235 // ClipboardSetting
236 
237 static const UgEntry  UgtkClipboardSettingEntry[] =
238 {
239 	{"pattern",      offsetof (struct UgtkClipboardSetting, pattern),
240 			UG_ENTRY_STRING, NULL,  NULL},
241 	{"monitor",      offsetof (struct UgtkClipboardSetting, monitor),
242 			UG_ENTRY_BOOL,   NULL,  NULL},
243 	{"quiet",        offsetof (struct UgtkClipboardSetting, quiet),
244 			UG_ENTRY_BOOL,   NULL,  NULL},
245 	{"NthCategory",  offsetof (struct UgtkClipboardSetting, nth_category),
246 			UG_ENTRY_INT,    NULL,  NULL},
247 
248 	{"Website", offsetof (struct UgtkClipboardSetting, website),
249 			UG_ENTRY_BOOL,   NULL,  NULL},
250 
251 	// remove this in future verison
252 	{"MediaWebsite", offsetof (struct UgtkClipboardSetting, website),
253 			UG_ENTRY_BOOL,   NULL,  NULL},
254 	{NULL},    // null-terminated
255 };
256 
257 // ----------------------------------------------------------------------------
258 // BandwidthSetting
259 
260 static const UgEntry  UgtkBandwidthSettingEntry[] =
261 {
262 	{"NormalUpload",      offsetof (struct UgtkBandwidthSetting, normal.upload),
263 			UG_ENTRY_INT, NULL, NULL},
264 	{"NormalDownload",    offsetof (struct UgtkBandwidthSetting, normal.download),
265 			UG_ENTRY_INT, NULL, NULL},
266 	{"SchedulerUpload",   offsetof (struct UgtkBandwidthSetting, scheduler.upload),
267 			UG_ENTRY_INT, NULL, NULL},
268 	{"SchedulerDownload", offsetof (struct UgtkBandwidthSetting, scheduler.download),
269 			UG_ENTRY_INT, NULL, NULL},
270 	{NULL},    // null-terminated
271 };
272 
273 // ----------------------------------------------------------------------------
274 // SchedulerSetting
275 
276 static const UgEntry  UgtkSchedulerSettingEntry[] =
277 {
278 	{"enable", offsetof (struct UgtkSchedulerSetting, enable),
279 			UG_ENTRY_BOOL,  NULL, NULL},
280 	{"state",  offsetof (struct UgtkSchedulerSetting, state),
281 			UG_ENTRY_ARRAY, ug_json_parse_array_int, ug_json_write_array_int},
282 	{NULL},    // null-terminated
283 };
284 
285 // ----------------------------------------------------------------------------
286 // CommandlineSetting
287 
288 static const UgEntry  UgtkCommandlineSettingEntry[] =
289 {
290 	{"quiet",         offsetof (struct UgtkCommandlineSetting, quiet),
291 			UG_ENTRY_BOOL, NULL, NULL},
292 	{"NthCategory",   offsetof (struct UgtkCommandlineSetting, nth_category),
293 			UG_ENTRY_INT,  NULL, NULL},
294 	{NULL},    // null-terminated
295 };
296 
297 // ----------------------------------------------------------------------------
298 // PluginAria2Setting
299 
300 static const UgEntry  UgtkPluginAria2SettingEntry[] =
301 {
302 	{"launch",    offsetof (struct UgtkPluginAria2Setting, launch),
303 			UG_ENTRY_BOOL,  NULL,   NULL},
304 	{"shutdown",  offsetof (struct UgtkPluginAria2Setting, shutdown),
305 			UG_ENTRY_BOOL,  NULL,   NULL},
306 	{"token",     offsetof (struct UgtkPluginAria2Setting, token),
307 			UG_ENTRY_STRING,  NULL,   NULL},
308 	{"path",      offsetof (struct UgtkPluginAria2Setting, path),
309 			UG_ENTRY_STRING,  NULL,   NULL},
310 	{"arguments", offsetof (struct UgtkPluginAria2Setting, args),
311 			UG_ENTRY_STRING,  NULL,   NULL},
312 	{"uri",       offsetof (struct UgtkPluginAria2Setting, uri),
313 			UG_ENTRY_STRING,  NULL,   NULL},
314 	{"MaxUploadSpeed",   offsetof (struct UgtkPluginAria2Setting, limit.upload),
315 			UG_ENTRY_INT,     NULL,   NULL},
316 	{"MaxDownloadSpeed", offsetof (struct UgtkPluginAria2Setting, limit.download),
317 			UG_ENTRY_INT,     NULL,   NULL},
318 	{NULL},    // null-terminated
319 };
320 
321 // ----------------------------------------------------------------------------
322 // PluginMediaSetting
323 
324 static const UgEntry  UgtkPluginMediaSettingEntry[] =
325 {
326 	{"match_mode",  offsetof (struct UgtkPluginMediaSetting, match_mode),
327 			UG_ENTRY_INT,  NULL,   NULL},
328 	{"quality",     offsetof (struct UgtkPluginMediaSetting, quality),
329 			UG_ENTRY_INT,  NULL,   NULL},
330 	{"type",        offsetof (struct UgtkPluginMediaSetting, type),
331 			UG_ENTRY_INT,  NULL,   NULL},
332 	{NULL},    // null-terminated
333 };
334 
335 // ----------------------------------------------------------------------------
336 // UgtkCompletionSetting
337 
338 static const UgEntry  UgtkCompletionSettingEntry[] =
339 {
340 	{"remember",  offsetof (struct UgtkCompletionSetting, remember),
341 			UG_ENTRY_BOOL,  NULL,   NULL},
342 	{"action",    offsetof (struct UgtkCompletionSetting, action),
343 			UG_ENTRY_INT,   NULL,   NULL},
344 	{"command",   offsetof (struct UgtkCompletionSetting, command),
345 			UG_ENTRY_STRING,  NULL,   NULL},
346 	{"OnError",   offsetof (struct UgtkCompletionSetting, on_error),
347 			UG_ENTRY_STRING,  NULL,   NULL},
348 	{NULL},    // null-terminated
349 };
350 
351 // ----------------------------------------------------------------------------
352 // UgtkSetting
353 
354 static const UgEntry  UgtkSettingEntry[] =
355 {
356 	{"Window",          offsetof (UgtkSetting, window),
357 			UG_ENTRY_OBJECT, (void*) UgtkWindowSettingEntry,  NULL},
358 	{"Summary",         offsetof (UgtkSetting, summary),
359 			UG_ENTRY_OBJECT, (void*) UgtkSummarySettingEntry, NULL},
360 	{"DownloadColumn",  offsetof (UgtkSetting, download_column),
361 			UG_ENTRY_OBJECT, (void*) UgtkDownloadColumnSettingEntry, NULL},
362 	{"UserInterface",   offsetof (UgtkSetting, ui),
363 			UG_ENTRY_OBJECT, (void*) UgtkUserInterfaceSettingEntry,  NULL},
364 	{"Clipboard",       offsetof (UgtkSetting, clipboard),
365 			UG_ENTRY_OBJECT, (void*) UgtkClipboardSettingEntry,   NULL},
366 	{"Bandwidth",       offsetof (UgtkSetting, bandwidth),
367 			UG_ENTRY_OBJECT, (void*) UgtkBandwidthSettingEntry,  NULL},
368 	{"Commandline",     offsetof (UgtkSetting, commandline),
369 			UG_ENTRY_OBJECT, (void*) UgtkCommandlineSettingEntry, NULL},
370 
371 	{"PluginOrder",     offsetof (UgtkSetting, plugin_order),
372 			UG_ENTRY_INT,    NULL, NULL},
373 	{"PluginAria2",     offsetof (UgtkSetting, aria2),
374 			UG_ENTRY_OBJECT, (void*) UgtkPluginAria2SettingEntry, NULL},
375 	{"PluginMedia",     offsetof (UgtkSetting, media),
376 			UG_ENTRY_OBJECT, (void*) UgtkPluginMediaSettingEntry, NULL},
377 
378 	{"Completion",      offsetof (UgtkSetting, completion),
379 			UG_ENTRY_OBJECT, (void*) UgtkCompletionSettingEntry, NULL},
380 
381 	{"FolderHistory",   offsetof (UgtkSetting, folder_history),
382 			UG_ENTRY_ARRAY, ug_json_parse_list_string,  ug_json_write_list_string},
383 
384 	{"AutoSave",        offsetof (UgtkSetting, auto_save.enable),
385 			UG_ENTRY_INT,    NULL,  NULL},
386 	{"AutoSaveInterval",offsetof (UgtkSetting, auto_save.interval),
387 			UG_ENTRY_INT,    NULL,  NULL},
388 //	{"OfflineMode",     offsetof (UgtkSetting, offline_mode),
389 //			UG_ENTRY_BOOL,   NULL,  NULL},
390 
391 	{"Scheduler",       offsetof (UgtkSetting, scheduler),
392 			UG_ENTRY_OBJECT, (void*) UgtkSchedulerSettingEntry,   NULL},
393 	{NULL},    // null-terminated
394 };
395 
396 // ----------------------------------------------------------------------------
397 // "UgSetting" functions
398 //
ugtk_setting_init(UgtkSetting * setting)399 void  ugtk_setting_init (UgtkSetting* setting)
400 {
401 	// "SchedulerSetting"
402 	ug_array_init (&setting->scheduler.state, sizeof (int), 7*24);
403 	memset (setting->scheduler.state.at, UGTK_SCHEDULE_NORMAL, 7*24);
404 
405 	// default settings for media (or storage) website
406 	setting->clipboard.website = TRUE;
407 	setting->media.match_mode = UGET_MEDIA_MATCH_NEAR;
408 	setting->media.quality = UGET_MEDIA_QUALITY_360P;
409 	setting->media.type = UGET_MEDIA_TYPE_MP4;
410 }
411 
ugtk_setting_reset(UgtkSetting * setting)412 void  ugtk_setting_reset (UgtkSetting* setting)
413 {
414 	unsigned int  weekdays, dayhours;
415 
416 	// "WindowSetting"
417 	setting->window.toolbar   = TRUE;
418 	setting->window.statusbar = TRUE;
419 	setting->window.category  = TRUE;
420 	setting->window.summary   = TRUE;
421 	setting->window.banner    = TRUE;
422 	setting->window.x = 0;
423 	setting->window.y = 0;
424 	setting->window.width = 0;
425 	setting->window.height = 0;
426 	setting->window.maximized = FALSE;
427 	setting->window.paned_position_h = -1;
428 	setting->window.paned_position_v = -1;
429 
430 	// "SummarySetting"
431 	setting->summary.name     = TRUE;
432 	setting->summary.folder   = TRUE;
433 	setting->summary.category = FALSE;
434 	setting->summary.uri      = FALSE;
435 	setting->summary.message  = TRUE;
436 
437 	// "DownloadColumnSetting"
438 	setting->download_column.complete     = TRUE;
439 	setting->download_column.total        = TRUE;
440 	setting->download_column.percent      = TRUE;
441 	setting->download_column.elapsed      = TRUE;
442 	setting->download_column.left         = TRUE;
443 	setting->download_column.speed        = TRUE;
444 	setting->download_column.upload_speed = TRUE;
445 	setting->download_column.uploaded     = FALSE;
446 	setting->download_column.ratio        = TRUE;
447 	setting->download_column.retry        = TRUE;
448 	setting->download_column.category     = FALSE;
449 	setting->download_column.uri          = FALSE;
450 	setting->download_column.added_on     = TRUE;
451 	setting->download_column.completed_on = FALSE;
452 	// default sorted column
453 	setting->download_column.sort.type    = GTK_SORT_DESCENDING;
454 	setting->download_column.sort.nth     = UGTK_NODE_COLUMN_STATE;
455 	// "DownloadColumnWidth"
456 	memset (&setting->download_column.width, 0,
457 			sizeof (setting->download_column.width));
458 
459 	// "UserInterfaceSetting"
460 	setting->ui.exit_confirmation = TRUE;
461 	setting->ui.delete_confirmation = TRUE;
462 	setting->ui.show_trayicon = TRUE;
463 	setting->ui.start_in_tray = FALSE;
464 	setting->ui.close_to_tray = TRUE;
465 	setting->ui.start_in_offline_mode = FALSE;
466 	setting->ui.start_notification = TRUE;
467 	setting->ui.sound_notification = TRUE;
468 	setting->ui.apply_recent = TRUE;
469 	setting->ui.skip_existing = FALSE;
470 	setting->ui.large_icon = FALSE;
471 #ifdef HAVE_APP_INDICATOR
472 	setting->ui.app_indicator = TRUE;
473 #endif
474 
475 	// "ClipboardSetting"
476 	ug_free (setting->clipboard.pattern);
477 	setting->clipboard.pattern = ug_strdup (UGTK_APP_CLIPBOARD_PATTERN);
478 	setting->clipboard.monitor = TRUE;
479 	setting->clipboard.quiet = FALSE;
480 	setting->clipboard.nth_category = 0;
481 	setting->clipboard.website = TRUE;
482 
483 	// "BandwidthSetting"
484 	setting->bandwidth.normal.upload = 0;
485 	setting->bandwidth.normal.download = 0;
486 	setting->bandwidth.scheduler.upload = 0;
487 	setting->bandwidth.scheduler.download = 0;
488 
489 	// "SchedulerSetting"
490 	setting->scheduler.enable = FALSE;
491 	ug_array_init (&setting->scheduler.state, sizeof (int), 7*24);
492 	setting->scheduler.state.length = 7 * 24;
493 	for (weekdays = 0;  weekdays < 7;  weekdays++) {
494 		for (dayhours = 0;  dayhours < 24;  dayhours++) {
495 			setting->scheduler.state.at[weekdays*24 + dayhours] =
496 					UGTK_SCHEDULE_NORMAL;
497 		}
498 	}
499 
500 	// "CommandlineSetting"
501 	setting->commandline.quiet = FALSE;
502 	setting->commandline.nth_category = 0;
503 
504 	// "PluginSetting"
505 	setting->plugin_order = UGTK_PLUGIN_ORDER_CURL;
506 	// aria2 plug-in settings
507 	setting->aria2.limit.download = 0;
508 	setting->aria2.limit.upload = 0;
509 	setting->aria2.launch = TRUE;
510 	setting->aria2.shutdown = TRUE;
511 	setting->aria2.path = ug_strdup (UGTK_ARIA2_PATH);
512 	setting->aria2.args = ug_strdup (UGTK_ARIA2_ARGS);
513 	setting->aria2.uri  = ug_strdup (UGTK_ARIA2_URI);
514 	// media plug-in settings
515 	setting->media.match_mode = UGET_MEDIA_MATCH_NEAR;
516 	setting->media.quality = UGET_MEDIA_QUALITY_360P;
517 	setting->media.type = UGET_MEDIA_TYPE_MP4;
518 
519 	// Others
520 	setting->completion.remember = TRUE;
521 	setting->completion.action = 0;
522 	setting->completion.command = NULL;
523 	setting->completion.on_error = NULL;
524 	setting->auto_save.enable = TRUE;
525 	setting->auto_save.interval = 3;
526 
527 	setting->offline_mode = FALSE;
528 }
529 
530 // ----------------------------------------------------------------------------
531 // save/load settings
532 
ugtk_setting_save(UgtkSetting * setting,const char * file)533 int  ugtk_setting_save (UgtkSetting* setting, const char* file)
534 {
535 	int          action;
536 	char*        path;
537 	UgJsonFile*  jfile;
538 
539 	path = g_strconcat (file, ".temp", NULL);
540 	jfile = ug_json_file_new (4096);
541 	if (ug_json_file_begin_write (jfile, path, UG_JSON_FORMAT_ALL) == FALSE) {
542 		ug_json_file_free (jfile);
543 		g_free (path);
544 		return FALSE;
545 	}
546 
547 	// save completion.action
548 	action = setting->completion.action;
549 	if (setting->completion.remember == FALSE)
550 		setting->completion.action = 0;
551 
552 	ug_json_write_object_head (&jfile->json);
553 	ug_json_write_entry (&jfile->json, setting, UgtkSettingEntry);
554 	ug_json_write_object_tail (&jfile->json);
555 
556 	// restore completion.action
557 	if (setting->completion.remember == FALSE)
558 		setting->completion.action = action;
559 
560 	ug_json_file_end_write (jfile);
561 	ug_json_file_free (jfile);
562 
563 	ug_remove (file);
564 	ug_rename (path, file);
565 	g_free (path);
566 
567 	return TRUE;
568 }
569 
ugtk_setting_load(UgtkSetting * setting,const char * path)570 int  ugtk_setting_load (UgtkSetting* setting, const char* path)
571 {
572 	int          file_ok;
573 	char*        path_temp;
574 	UgJsonFile*  jfile;
575 
576 	path_temp = g_strconcat (path, ".temp", NULL);
577 	jfile = ug_json_file_new (4096);
578 	file_ok = ug_json_file_begin_parse (jfile, path);
579 	if (file_ok)
580 		ug_remove (path_temp);
581 	else if (ug_rename (path_temp, path) != -1)
582 		file_ok = ug_json_file_begin_parse (jfile, path);
583 	g_free (path_temp);
584 
585 	if (file_ok == FALSE) {
586 		ug_json_file_free (jfile);
587 		return FALSE;
588 	}
589 
590 	ug_json_push (&jfile->json, ug_json_parse_entry,
591 			setting, (void*) UgtkSettingEntry);
592 	ug_json_push (&jfile->json, ug_json_parse_object,
593 			NULL, NULL);
594 
595 	ug_json_file_end_parse (jfile);
596 	ug_json_file_free (jfile);
597 
598 	// check & fix settings
599 	ugtk_setting_fix_data (setting);
600 	return TRUE;
601 }
602 
ugtk_setting_add_folder(UgtkSetting * setting,const char * folder)603 void  ugtk_setting_add_folder (UgtkSetting* setting, const char* folder)
604 {
605 	UgList* list;
606 	UgLink* link;
607 
608 	if (folder == NULL || folder[0] == 0)
609 		return;
610 
611 	list = &setting->folder_history;
612 	for (link = list->head;  link;  link = link->next) {
613 		if (strcmp (folder, link->data) == 0) {
614 			ug_list_remove (list, link);
615 			ug_list_prepend (list, link);
616 			return;
617 		}
618 	}
619 
620 	if (list->size >= 8) {
621 		link = list->tail;
622 		ug_list_remove (list, link);
623 		ug_free (link->data);
624 		ug_link_free (link);
625 	}
626 	link = ug_link_new ();
627 	link->data = ug_strdup (folder);
628 	ug_list_prepend (list, link);
629 }
630 
ugtk_setting_fix_data(UgtkSetting * setting)631 void  ugtk_setting_fix_data (UgtkSetting* setting)
632 {
633 	unsigned int  index;
634 
635 	// "DownloadColumnSetting"
636 	// default sorted column
637 	if (setting->download_column.sort.type != GTK_SORT_ASCENDING &&
638 	    setting->download_column.sort.type != GTK_SORT_DESCENDING)
639 	{
640 		setting->download_column.sort.type = GTK_SORT_DESCENDING;
641 	}
642 	if (setting->download_column.sort.nth < 0 ||
643 	    setting->download_column.sort.nth >= UGTK_NODE_N_COLUMNS)
644 	{
645 		setting->download_column.sort.nth = UGTK_NODE_COLUMN_ADDED_ON;
646 	}
647 
648 	// "ClipboardSetting"
649 	if (setting->clipboard.pattern == NULL ||
650 	    setting->clipboard.pattern[0] == 0)
651 	{
652 		ug_free (setting->clipboard.pattern);
653 		setting->clipboard.pattern = ug_strdup (UGTK_APP_CLIPBOARD_PATTERN);
654 	}
655 
656 	// "SchedulerSetting"
657 	for (index = 0;  index < 7*24;  index++) {
658 		if (setting->scheduler.state.at[index] < 0 ||
659 		    setting->scheduler.state.at[index] >= UGTK_SCHEDULE_N_STATE)
660 		{
661 			setting->scheduler.state.at[index] = UGTK_SCHEDULE_NORMAL;
662 		}
663 	}
664 
665 	// "PluginSetting"
666 	if (setting->plugin_order < 0 ||
667 	    setting->plugin_order >= UGTK_PLUGIN_N_ORDER)
668 	{
669 		setting->plugin_order = UGTK_PLUGIN_ORDER_CURL;
670 	}
671 	// aria2 plug-in settings
672 	if (setting->aria2.path == NULL || setting->aria2.path[0] == 0) {
673 		ug_free (setting->aria2.path);
674 		setting->aria2.path = ug_strdup (UGTK_ARIA2_PATH);
675 	}
676 	if (setting->aria2.args == NULL || setting->aria2.args[0] == 0) {
677 		ug_free (setting->aria2.args);
678 		setting->aria2.args = ug_strdup (UGTK_ARIA2_ARGS);
679 	}
680 	if (setting->aria2.uri == NULL || setting->aria2.uri[0] == 0) {
681 		ug_free (setting->aria2.uri);
682 		setting->aria2.uri  = ug_strdup (UGTK_ARIA2_URI);
683 	}
684 	// media plug-in settings
685 	if (setting->media.match_mode < 0 || setting->media.match_mode > UGET_MEDIA_N_MATCH_MODE)
686 		setting->media.match_mode = UGET_MEDIA_MATCH_NEAR;
687 	if (setting->media.quality < 0 || setting->media.quality > UGET_MEDIA_N_QUALITY)
688 		setting->media.quality = UGET_MEDIA_QUALITY_360P;
689 	if (setting->media.type < 0 || setting->media.type > UGET_MEDIA_N_TYPE)
690 		setting->media.type = UGET_MEDIA_TYPE_MP4;
691 }
692