Statistics
| Revision:

root / trunk / nntpgrab_core / configuration.c @ 1637

History | View | Annotate | Download (31.4 KB)

1
/* 
2
    Copyright (C) 2005-2009  Erik van Pienbroek
3

                
4
    This program is free software; you can redistribute it and/or modify
5
    it under the terms of the GNU General Public License as published by
6
    the Free Software Foundation; either version 2 of the License, or
7
    (at your option) any later version.
8

                
9
    This program is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
    GNU General Public License for more details.
13

                
14
    You should have received a copy of the GNU General Public License
15
    along with this program; if not, write to the Free Software
16
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
*/
18

                
19
#include 
20
#include 
21
#include 
22
#include 
23
#ifdef WIN32
24
#include 
25
#include 
26
#include 
27
#endif
28

                
29
#include "configuration.h"
30
#include "nntpgrab_internal.h"
31

                
32
typedef struct ConfigurationClass ConfigurationClass;
33

                
34
Configuration *configuration_get_object(void);
35

                
36
typedef struct _config_server_details
37
{
38
    GList *groups;                  // containing ConfigGroupInfo's
39
} ConfigServerDetails;
40

                
41
struct Configuration
42
{
43
    GObject parent;
44

                
45
    GStaticRWLock rwlock;
46
    GList *servers;                 // containing ConfigServer's
47
    GHashTable *group_details;      // containing ConfigGroupInfo's
48

                
49
    ConfigOpts opts;
50
};
51

                
52
struct ConfigurationClass
53
{
54
    GObjectClass parent;
55
};
56

                
57
enum
58
{
59
    CONFIG_CHANGED_SIGNAL,
60
    LAST_SIGNAL
61
};
62

                
63
static guint signals[LAST_SIGNAL] = { 0 };
64

                
65
G_DEFINE_TYPE(Configuration, configuration, G_TYPE_OBJECT)
66

                
67
static void
68
group_details_free_func(gpointer data)
69
{
70
    g_slice_free(ConfigGroupInfo, data);
71
}
72

                
73
static void
74
configuration_init (Configuration *obj)
75
{
76
    g_static_rw_lock_init(&obj->rwlock);
77

                
78
    obj->servers = NULL;
79
    obj->group_details = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, group_details_free_func);
80
}
81

                
82
static void
83
configuration_finalize (GObject *obj)
84
{
85
    char *errmsg = NULL;
86
    Configuration *config = CONFIGURATION(obj);
87
    GList *list;
88

                
89
    if (!(configuration_save(config, &errmsg))) {
90
        nntpgrab_core_emit_warning(FALSE, errmsg);
91
        g_free(errmsg);
92
    }
93

                
94
    g_static_rw_lock_writer_lock(&config->rwlock);
95

                
96
    list = config->servers;
97
    while (list) {
98
        g_slice_free(ConfigServer, list->data);
99
        list = g_list_next(list);
100
    }
101
    g_list_free(config->servers);
102

                
103
    g_hash_table_destroy(config->group_details);
104

                
105
    g_static_rw_lock_writer_unlock(&config->rwlock);
106
    g_static_rw_lock_free(&config->rwlock);
107
}
108

                
109
static void
110
configuration_class_init (ConfigurationClass *klass)
111
{
112
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
113

                
114
    gobject_class->finalize = configuration_finalize;
115

                
116
    signals[CONFIG_CHANGED_SIGNAL] = g_signal_new  ("config_changed",
117
                                                    G_OBJECT_CLASS_TYPE (klass),
118
                                                    G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
119
                                                    0,
120
                                                    NULL, NULL,
121
                                                    g_cclosure_marshal_VOID__INT,
122
                                                    G_TYPE_NONE, 1, G_TYPE_INT);
123
}
124

                
125
Configuration *
126
configuration_new(char **errmsg, char **warnings)
127
{
128
    Configuration *config = g_object_new(CONFIGURATION_TYPE_OBJECT, NULL);
129

                
130
    if (!configuration_load(config, errmsg)) {
131
        // Load of configuration failed..probably no configuration file created yet.
132
        // Create a default configuration file
133
        g_free(*errmsg);
134
        *errmsg = NULL;
135

                
136
        if (warnings) {
137
            *warnings = g_strdup(_("Configuration file for the NNTPGrab backend could not be loaded. Default configuration file is now created"));
138
        }
139
    }
140

                
141
    return config;
142
}
143

                
144
void
145
configuration_destroy(Configuration *obj)
146
{
147
    g_object_unref(obj);
148
}
149

                
150
/** 
151
 * Retrieve a list of all the available usenet servers
152
 *
153
 * @param obj   The configuration object
154
 * @return      a GList* containing g_malloc'ed char* strings with servernames
155
 */
156
GList *
157
configuration_get_avail_servers(Configuration *obj)
158
{
159
    Configuration *config = CONFIGURATION(obj);
160
    GList *list;
161
    GList *ret = NULL;
162

                
163
    g_static_rw_lock_reader_lock(&config->rwlock);
164

                
165
    list = config->servers;
166
    while (list) {
167
        ConfigServer *server = list->data;
168

                
169
        ret = g_list_append(ret, g_strdup(server->servername));
170

                
171
        list = g_list_next(list);
172
    }
173

                
174
    g_static_rw_lock_reader_unlock(&config->rwlock);
175

                
176
    return ret;
177
}
178

                
179
/** 
180
 * Frees the list returned by configuration_get_avail_servers()
181
 *
182
 * @param obj       The configuration object
183
 * @param servers   A GList* containing g_malloc'ed char* strings with servernames
184
 */
185
void
186
configuration_free_avail_servers(Configuration *obj, GList *servers)
187
{
188
    GList *list;
189

                
190
    list = servers;
191
    while (list) {
192
        g_free(list->data);
193
        list = g_list_next(list);
194
    }
195

                
196
    g_list_free(servers);
197
}
198

                
199
/** 
200
 * Retrieve information about a specific usenet server
201
 *
202
 * @param obj           The Configuration object
203
 * @param servername    The name of the usenet server whose info should be lookup up
204
 * @return              A g_slice_new'ed ConfigServer structure containing the requested info or NULL when the servername could not be found
205
 */
206
ConfigServer *
207
configuration_get_server_info(Configuration *obj, const char *servername)
208
{
209
    Configuration *config = CONFIGURATION(obj);
210
    GList *list;
211

                
212
    g_static_rw_lock_reader_lock(&config->rwlock);
213

                
214
    list = config->servers;
215
    while (list) {
216
        ConfigServer *server = list->data;
217

                
218
        if (!strcmp(server->servername, servername)) {
219
            ConfigServer *ret = g_slice_new0(ConfigServer);
220

                
221
            memcpy(ret, server, sizeof(ConfigServer));
222

                
223
            g_static_rw_lock_reader_unlock(&config->rwlock);
224

                
225
            return ret;
226
        }
227

                
228
        list = g_list_next(list);
229
    }
230

                
231
    g_static_rw_lock_reader_unlock(&config->rwlock);
232

                
233
    return NULL;
234
}
235

                
236
/** 
237
 * Add a new server to the list of known usenet servers
238
 *
239
 * @param obj           The configuration object
240
 * @param new_server    The structure containing the settings of the new server
241
 * @param errmsg        If an error occurs, an error message will be set in this variable
242
 * @return              TRUE on success, FALSE on error (errmsg will be set)
243
 */
244
gboolean
245
configuration_add_server(Configuration *obj, ConfigServer new_server, char **errmsg)
246
{
247
    Configuration *config = CONFIGURATION(obj);
248
    ConfigServer *server;
249
    GList *list;
250

                
251
    // Check is the new_server contains sane data
252
    g_assert(new_server.port > 0 && new_server.port < 65536);
253
    g_assert(new_server.max_threads > 0);
254

                
255
    if (!strcmp(new_server.servername, "options")) {
256
        if (errmsg) {
257
            *errmsg = g_strdup_printf("%s%s", _("The servername 'options' cannot be used.\n"), _("Please use a different servername"));
258
        }
259
        return FALSE;
260
    }
261

                
262
    // Check if the servername of the new_server is already known
263
    g_static_rw_lock_reader_lock(&config->rwlock);
264

                
265
    list = config->servers;
266
    while (list) {
267
        server = list->data;
268

                
269
        if (!strcmp(new_server.servername, server->servername)) {
270
            // servername already exists, refuse the addition of a new server
271
            g_static_rw_lock_reader_unlock(&config->rwlock);
272

                
273
            if (errmsg) {
274
                *errmsg = g_strdup_printf("%s%s", _("The given servername already exists in the configuration.\n"), _("Please use a different servername"));
275
            }
276

                
277
            return FALSE;
278
        }
279

                
280
        list = g_list_next(list);
281
    }
282

                
283
    // Prevent the addition of more than MAX_NNTP_SERVERS servers
284
    if (g_list_length(config->servers) == MAX_NNTP_SERVERS - 1) {
285
        g_static_rw_lock_reader_unlock(&config->rwlock);
286

                
287
        if (errmsg) {
288
            *errmsg = g_strdup(_("There are too many servers configured"));
289
        }
290

                
291
        return FALSE;
292
    }
293

                
294
    g_static_rw_lock_reader_unlock(&config->rwlock);
295

                
296
    // servername not found, it is safe to add the new configuration
297
    g_static_rw_lock_writer_lock(&config->rwlock);
298

                
299
    server = g_slice_new0(ConfigServer);
300
    memcpy(server, &new_server, sizeof(ConfigServer));
301
    config->servers = g_list_append(config->servers, server);
302

                
303
    g_static_rw_lock_writer_unlock(&config->rwlock);
304

                
305
    // Notify listeners that the configuration has changed
306
    g_static_rw_lock_reader_lock(&config->rwlock);
307
    g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_ADDED);
308
    g_static_rw_lock_reader_unlock(&config->rwlock);
309

                
310
    return TRUE;
311
}
312

                
313
/** 
314
 * Delete the settings from the specified servername from the list of known usenet servers
315
 *
316
 * @param obj           The configuration object
317
 * @param servername    The name of the server whose settings need to be removed
318
 * @param errmsg        If an error occurs, an error message will be set in this variable
319
 *
320
 * @return              TRUE on success, FALSE on error (errmsg will be set)
321
 */
322
gboolean
323
configuration_del_server(Configuration *obj, const char *servername, char **errmsg)
324
{
325
    Configuration *config = CONFIGURATION(obj);
326
    ConfigServer *server;
327
    GList *list;
328

                
329
    // Check if the servername is known
330
    g_static_rw_lock_reader_lock(&config->rwlock);
331

                
332
    list = config->servers;
333
    while (list) {
334
        server = list->data;
335

                
336
        if (!strcmp(servername, server->servername)) {
337
            // servername exists, remove it from the list
338
            g_static_rw_lock_reader_unlock(&config->rwlock);
339

                
340
            g_static_rw_lock_writer_lock(&config->rwlock);
341

                
342
            g_slice_free(ConfigServer, server);
343
            config->servers = g_list_remove(config->servers, server);
344

                
345
            g_static_rw_lock_writer_unlock(&config->rwlock);
346

                
347
            // Notify listeners that the configuration has changed
348
            g_static_rw_lock_reader_lock(&config->rwlock);
349
            g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_DELETED);
350
            g_static_rw_lock_reader_unlock(&config->rwlock);
351

                
352
            return TRUE;
353
        }
354

                
355
        list = g_list_next(list);
356
    }
357

                
358
    g_static_rw_lock_reader_unlock(&config->rwlock);
359

                
360
    if (errmsg) {
361
        *errmsg = g_strdup(_("The given servername doesn't exist in the NNTPGrab configuration"));
362
    }
363

                
364
    return FALSE;
365
}
366

                
367
/** 
368
 * Change the settings from the specified servername in the list of known usenet servers
369
 *
370
 * @param obj           The configuration object
371
 * @param servername    The name of the server whose settings need to be changed
372
 * @param new_server    The new settings of the server which need to be saved
373
 * @param errmsg        If an error occurs, an error message will be set in this variable
374
 *
375
 * @return              TRUE on success, FALSE on error (errmsg will be set)
376
 */
377
gboolean
378
configuration_edit_server(Configuration *obj, const char *servername, ConfigServer new_server, char **errmsg)
379
{
380
    Configuration *config = CONFIGURATION(obj);
381
    ConfigServer *server;
382
    GList *list;
383

                
384
    if (!strcmp(new_server.servername, "options")) {
385
        if (errmsg) {
386
            *errmsg = g_strdup_printf("%s%s", _("The servername 'options' cannot be used.\n"), _("Please use a different servername"));
387
        }
388
        return FALSE;
389
    }
390

                
391
    // Check if the servername of the new_server is already known
392
    g_static_rw_lock_reader_lock(&config->rwlock);
393

                
394
    list = config->servers;
395
    while (list) {
396
        server = list->data;
397

                
398
        if (!strcmp(servername, server->servername)) {
399
            // servername exists, edit the settings
400
            g_static_rw_lock_reader_unlock(&config->rwlock);
401

                
402
            g_static_rw_lock_writer_lock(&config->rwlock);
403

                
404
            // apply the new settings
405
            memcpy(server, &new_server, sizeof(ConfigServer));
406

                
407
            g_static_rw_lock_writer_unlock(&config->rwlock);
408

                
409
            // Notify listeners that the configuration has changed
410
            g_static_rw_lock_reader_lock(&config->rwlock);
411
            g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_ADDED);
412
            g_static_rw_lock_reader_unlock(&config->rwlock);
413

                
414
            return TRUE;
415
        }
416

                
417
        list = g_list_next(list);
418
    }
419

                
420
    g_static_rw_lock_reader_unlock(&config->rwlock);
421

                
422
    if (errmsg) {
423
        *errmsg = g_strdup(_("The given servername doesn't exist in the NNTPGrab configuration"));
424
    }
425

                
426
    return FALSE;
427
}
428

                
429
/** 
430
 * Retrieves the configuration options
431
 *
432
 * @param obj       The configuration object
433
 * @return          A structure containing configuration data
434
 */
435
ConfigOpts
436
configuration_get_opts(Configuration *obj)
437
{
438
    Configuration *config = CONFIGURATION(obj);
439
    ConfigOpts ret;
440

                
441
    g_static_rw_lock_reader_lock(&config->rwlock);
442

                
443
    ret = config->opts;
444

                
445
    g_static_rw_lock_reader_unlock(&config->rwlock);
446

                
447
    return ret;
448
}
449

                
450
/** 
451
 * Set the configuration options
452
 *
453
 * @param obj   The configuration object
454
 * @param opts  A structure containing configuration data
455
 */
456
void
457
configuration_set_opts(Configuration *obj, ConfigOpts opts)
458
{
459
    Configuration *config = CONFIGURATION(obj);
460

                
461
    g_static_rw_lock_writer_lock(&config->rwlock);
462

                
463
    // Hack for Win32, if the download folder or temp folder is the root of a drive, append an extra \ to it
464
#ifdef WIN32
465
    if (strlen(opts.download_directory) == 2 && opts.download_directory[1] == ':') {
466
        opts.download_directory[2] = '\\';
467
        opts.download_directory[3] = '\0';
468
    }
469

                
470
    if (strlen(opts.temp_directory) == 2 && opts.temp_directory[1] == ':') {
471
        opts.temp_directory[2] = '\\';
472
        opts.temp_directory[3] = '\0';
473
    }
474

                
475
    if (strlen(opts.auto_import_directory) == 2 && opts.auto_import_directory[1] == ':') {
476
        opts.temp_directory[2] = '\\';
477
        opts.temp_directory[3] = '\0';
478
    }
479
#endif
480

                
481
    config->opts = opts;
482

                
483
    g_static_rw_lock_writer_unlock(&config->rwlock);
484

                
485
    // Notify listeners that the configuration has changed
486
    g_static_rw_lock_reader_lock(&config->rwlock);
487
    g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_OPTS_CHANGED);
488
    g_static_rw_lock_reader_unlock(&config->rwlock);
489
}
490

                
491
/** 
492
 * Get the details concerning the given server and newsgroup
493
 *
494
 * @param obj           The configuration object
495
 * @param servername    The name of the server
496
 * @param newsgroup     The name of the newsgroup
497
 *
498
 * @return              Structure containing the details
499
 */
500
ConfigGroupInfo
501
configuration_get_newsgroup_info(Configuration *obj, const char *servername, const char *newsgroup)
502
{
503
    ConfigGroupInfo ret;
504
    ConfigGroupInfo *info;
505
    Configuration *config = CONFIGURATION(obj);
506
    char *hash;
507

                
508
    g_static_rw_lock_reader_lock(&config->rwlock);
509

                
510
    hash = g_strdup_printf("%s_%s", servername, newsgroup);
511
    info = g_hash_table_lookup(config->group_details, hash);
512
    g_free(hash);
513

                
514
    if (info) {
515
        memcpy(&ret, info, sizeof(ConfigGroupInfo));
516
    } else {
517
        memset(&ret, 0, sizeof(ConfigGroupInfo));
518
        strncpy((char *) ret.newsgroup, newsgroup, sizeof(ret.newsgroup));
519
    }
520

                
521
    g_static_rw_lock_reader_unlock(&config->rwlock);
522

                
523
    return ret;
524
}
525

                
526
/** 
527
 * Set the details concerning the given server and newsgroup
528
 *
529
 * @param obj           The configuration object
530
 * @param servername    The name of the server
531
 * @param newsgroup     The name of the newsgroup
532
 * @param info          Structure containing the details
533
 */
534
void
535
configuration_set_newsgroup_info(Configuration *obj, const char *servername, const char *newsgroup, ConfigGroupInfo info)
536
{
537
    Configuration *config = CONFIGURATION(obj);
538
    ConfigGroupInfo *info_new;
539
    char *hash;
540

                
541
    g_static_rw_lock_writer_lock(&config->rwlock);
542

                
543
    info_new = g_slice_new(ConfigGroupInfo);
544
    memcpy(info_new, &info, sizeof(ConfigGroupInfo));
545

                
546
    hash = g_strdup_printf("%s_%s", servername, newsgroup);
547
    g_hash_table_replace(config->group_details, hash, info_new);
548
    g_free(hash);
549

                
550
    g_static_rw_lock_writer_unlock(&config->rwlock);
551
}
552

                
553
/** 
554
 * Load all settings from a local file on the harddrive
555
 *
556
 * @param obj           The configuration object
557
 * @param errmsg        A pointer to a char* to save a possible error message
558
 * @return              TRUE on success, FALSE on failure (errmsg will be set and needs to be g_free'd after use)
559
 */
560
gboolean
561
configuration_load(Configuration *obj, char **errmsg)
562
{
563
    Configuration *config = CONFIGURATION(obj);
564
    GKeyFile *keyfile;
565
    GError *err = NULL;
566
    char *filename;
567
    char **groups;
568
    int i;
569
    GList *list;
570
    
571
    g_static_rw_lock_writer_lock(&config->rwlock);
572

                
573
    // Free the already known settings
574
    list = config->servers;
575
    while (list) {
576
        ConfigServer *server = list->data;
577

                
578
        g_slice_free(ConfigServer, server);
579

                
580
        list = g_list_next(list);
581
    }
582

                
583
    g_list_free(config->servers);
584
    config->servers = NULL;
585

                
586
    // Try to load the config file
587
    if (g_getenv("NNTPGRAB_CONFIG_DIR")) {
588
        filename = g_build_filename(g_getenv("NNTPGRAB_CONFIG_DIR"), "NNTPGrab", "nntpgrab.conf", NULL);
589
    } else {
590
        filename = g_build_filename(g_get_user_config_dir(), "NNTPGrab", "nntpgrab.conf", NULL);
591
    }
592
    keyfile = g_key_file_new();
593
    if (!g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, &err)) {
594
        char *tmp;
595
        const char *homedir;
596

                
597
        if (errmsg) {
598
            *errmsg = g_strdup_printf(_("configuration_load(): Error while opening file '%s'\n%s"), filename, err->message);
599
        }
600

                
601
        g_free(filename);
602
        g_error_free(err);
603
        g_key_file_free(keyfile);
604

                
605
#ifdef WIN32
606
        homedir = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS);
607
#else
608
        if (g_getenv("NNTPGRAB_DEFAULT_DL_DIR")) {
609
            homedir = g_getenv("NNTPGRAB_DEFAULT_DL_DIR");
610
        } else {
611
            homedir = g_get_home_dir();
612
        }
613
#endif
614
        // Set up sane defaults
615
        tmp = g_build_path(G_DIR_SEPARATOR_S, homedir, "NNTPGrab", "Downloads", NULL);
616
        strncpy(config->opts.download_directory, tmp, sizeof(config->opts.download_directory));
617
        g_mkdir_with_parents(tmp, 0700);
618
        g_free(tmp);
619

                
620
        tmp = g_build_path(G_DIR_SEPARATOR_S, homedir, "NNTPGrab", "Temp", NULL);
621
        strncpy(config->opts.temp_directory, tmp, sizeof(config->opts.temp_directory));
622
        g_mkdir_with_parents(tmp, 0700);
623
        g_free(tmp);
624

                
625
        tmp = g_build_path(G_DIR_SEPARATOR_S, homedir, "NNTPGrab", "NZB", NULL);
626
        strncpy(config->opts.auto_import_directory, tmp, sizeof(config->opts.auto_import_directory));
627
        g_mkdir_with_parents(tmp, 0700);
628
        g_free(tmp);
629

                
630
        config->opts.enable_par2_repair = TRUE;
631
        config->opts.enable_auto_unpack = TRUE;
632
        config->opts.enable_bandwidth_shaping = FALSE;
633
        config->opts.max_bandwidth = 100;
634
        config->opts.enable_webserver = FALSE;
635
        config->opts.webserver_port = 5423;
636
        config->opts.enable_logger = FALSE;
637
        config->opts.auto_remove_files = FALSE;
638

                
639
        g_static_rw_lock_writer_unlock(&config->rwlock);
640

                
641
        return FALSE;
642
    }
643

                
644
    g_free(filename);
645

                
646
    groups = g_key_file_get_groups(keyfile, NULL);
647
    i = 0;
648
    while (groups[i]) {
649
        char *value;
650
        ConfigServer *server;
651

                
652
        if (!strcmp(groups[i], "options")) {
653
            char *tmp;
654

                
655
            tmp = g_key_file_get_string(keyfile, groups[i], "download_directory", NULL);
656
            if (tmp) {
657
                strncpy(config->opts.download_directory, tmp, sizeof(config->opts.download_directory));
658
                g_free(tmp);
659
            }
660

                
661
            tmp = g_key_file_get_string(keyfile, groups[i], "temp_directory", NULL);
662
            if (tmp) {
663
                strncpy(config->opts.temp_directory, tmp, sizeof(config->opts.temp_directory));
664
                g_free(tmp);
665
            }
666

                
667
            if (g_key_file_has_key(keyfile, groups[i], "enable_intelligent_par2_downloading", NULL)) {
668
                config->opts.enable_intelligent_par2_downloading = g_key_file_get_boolean(keyfile, groups[i], "enable_intelligent_par2_downloading", NULL);
669
            } else {
670
                config->opts.enable_intelligent_par2_downloading = TRUE;
671
            }
672

                
673
            if (g_key_file_has_key(keyfile, groups[i], "enable_par2_repair", NULL)) {
674
                config->opts.enable_par2_repair = g_key_file_get_boolean(keyfile, groups[i], "enable_par2_repair", NULL);
675
            } else {
676
                config->opts.enable_par2_repair = TRUE;
677
            }
678

                
679
            if (g_key_file_has_key(keyfile, groups[i], "enable_auto_unpack", NULL)) {
680
                config->opts.enable_auto_unpack = g_key_file_get_boolean(keyfile, groups[i], "enable_auto_unpack", NULL);
681
            } else {
682
                config->opts.enable_auto_unpack = TRUE;
683
            }
684

                
685
            tmp = g_key_file_get_string(keyfile, groups[i], "auto_import_directory", NULL);
686
            if (tmp) {
687
                strncpy(config->opts.auto_import_directory, tmp, sizeof(config->opts.auto_import_directory));
688
                g_free(tmp);
689
            }
690

                
691
            if (g_key_file_has_key(keyfile, groups[i], "enable_auto_import", NULL)) {
692
                config->opts.enable_auto_import = g_key_file_get_boolean(keyfile, groups[i], "enable_auto_import", NULL);
693
            } else {
694
                config->opts.enable_auto_import = TRUE;
695
            }
696

                
697
            if (g_key_file_has_key(keyfile, groups[i], "move_file_after_auto_import", NULL)) {
698
                config->opts.move_file_after_auto_import = g_key_file_get_boolean(keyfile, groups[i], "move_file_after_auto_import", NULL);
699
            } else {
700
                config->opts.move_file_after_auto_import = TRUE;
701
            }
702

                
703
            if (g_key_file_has_key(keyfile, groups[i], "enable_bandwidth_shaping", NULL)) {
704
                config->opts.enable_bandwidth_shaping = g_key_file_get_boolean(keyfile, groups[i], "enable_bandwidth_shaping", NULL);
705
            } else {
706
                config->opts.enable_bandwidth_shaping = FALSE;
707
            }
708

                
709
            if (g_key_file_has_key(keyfile, groups[i], "max_bandwidth", NULL)) {
710
                config->opts.max_bandwidth = g_key_file_get_integer(keyfile, groups[i], "max_bandwidth", NULL);
711
            } else {
712
                config->opts.max_bandwidth = 100;
713
            }
714

                
715
            if (g_key_file_has_key(keyfile, groups[i], "enable_webserver", NULL)) {
716
                config->opts.enable_webserver = g_key_file_get_boolean(keyfile, groups[i], "enable_webserver", NULL);
717
            } else {
718
                config->opts.enable_webserver = FALSE;
719
            }
720

                
721
            if (g_key_file_has_key(keyfile, groups[i], "webserver_port", NULL)) {
722
                config->opts.webserver_port = g_key_file_get_integer(keyfile, groups[i], "webserver_port", NULL);
723
            } else {
724
                config->opts.webserver_port = 5423;
725
            }
726

                
727
            if (g_key_file_has_key(keyfile, groups[i], "enable_logger", NULL)) {
728
                config->opts.enable_logger = g_key_file_get_boolean(keyfile, groups[i], "enable_logger", NULL);
729
            } else {
730
                config->opts.enable_logger = FALSE;
731
            }
732

                
733
            if (g_key_file_has_key(keyfile, groups[i], "auto_remove_files", NULL)) {
734
                config->opts.auto_remove_files = g_key_file_get_boolean(keyfile, groups[i], "auto_remove_files", NULL);
735
            } else {
736
                config->opts.auto_remove_files = FALSE;
737
            }
738

                
739
            i++;
740
            continue;
741
        }
742

                
743
        server = g_slice_new(ConfigServer);
744

                
745
        strncpy(server->servername, groups[i], sizeof(server->servername));
746

                
747
        value = g_key_file_get_string(keyfile, groups[i], "hostname", NULL);
748
        if (!value) {
749
            g_print(_("No hostname could be found for servername '%s'. Ignoring server\n"), groups[i]);
750
            i++;
751
            continue;
752
        }
753

                
754
        strncpy(server->hostname, value, sizeof(server->hostname));
755
        g_free(value);
756

                
757
        server->port = g_key_file_get_integer(keyfile, groups[i], "port", NULL);
758

                
759
        value = g_key_file_get_string(keyfile, groups[i], "username", NULL);
760
        if (value) {
761
            strncpy(server->username, value, sizeof(server->username));
762
            g_free(value);
763
        }
764

                
765
        value = g_key_file_get_string(keyfile, groups[i], "password", NULL);
766
        if (value) {
767
            strncpy(server->password, value, sizeof(server->password));
768
            g_free(value);
769
        }
770

                
771
        server->max_threads = g_key_file_get_integer(keyfile, groups[i], "max_threads", NULL);
772
        server->use_ssl = g_key_file_get_boolean(keyfile, groups[i], "use_ssl", NULL);
773

                
774
        // backwards compatibility
775
        if (!g_key_file_has_key(keyfile, groups[i], "priority", NULL)) {
776
            server->priority = SERVER_PRIORITY_NORMAL;
777
        } else {
778
            server->priority = g_key_file_get_integer(keyfile, groups[i], "priority", NULL);
779
        }
780

                
781
        if (!g_key_file_has_key(keyfile, groups[i], "enabled", NULL)) {
782
            server->enabled = TRUE;
783
        } else {
784
            server->enabled = g_key_file_get_boolean(keyfile, groups[i], "enabled", NULL);
785
        }
786

                
787
        config->servers = g_list_append(config->servers, server);
788

                
789
        i++;
790
    }
791

                
792
    g_strfreev(groups);
793

                
794
    g_key_file_free(keyfile);
795

                
796
    // Do we have sane values for the download and temp directory ?
797
#ifdef WIN32
798
    if (strlen(config->opts.download_directory) == 2) {
799
        config->opts.download_directory[2] = '\\';
800
        config->opts.download_directory[3] = '\0';
801
    }
802

                
803
    if (strlen(config->opts.temp_directory) == 2) {
804
        config->opts.temp_directory[2] = '\\';
805
        config->opts.temp_directory[3] = '\0';
806
    }
807
#endif
808

                
809
    if (!g_file_test(config->opts.download_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
810
        char *tmp;
811

                
812
#ifdef WIN32
813
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS), "NNTPGrab", "Downloads", NULL);
814
#else
815
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_home_dir(), "NNTPGrab", "Downloads", NULL);
816
#endif
817
        strncpy(config->opts.download_directory, tmp, sizeof(config->opts.download_directory));
818
        g_mkdir_with_parents(tmp, 0700);
819
        g_free(tmp);
820
    }
821

                
822
    if (!g_file_test(config->opts.temp_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
823
        char *tmp;
824

                
825
#ifdef WIN32
826
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS), "NNTPGrab", "Temp", NULL);
827
#else
828
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_home_dir(), "NNTPGrab", "Temp", NULL);
829
#endif
830
        strncpy(config->opts.temp_directory, tmp, sizeof(config->opts.temp_directory));
831
        g_mkdir_with_parents(tmp, 0700);
832
        g_free(tmp);
833
    }
834

                
835
    if (!g_file_test(config->opts.auto_import_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
836
        char *tmp;
837

                
838
#ifdef WIN32
839
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS), "NNTPGrab", "NZB", NULL);
840
#else
841
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_home_dir(), "NNTPGrab", "NZB", NULL);
842
#endif
843
        strncpy(config->opts.auto_import_directory, tmp, sizeof(config->opts.auto_import_directory));
844
        g_mkdir_with_parents(tmp, 0700);
845
        g_free(tmp);
846
    }
847

                
848
    g_static_rw_lock_writer_unlock(&config->rwlock);
849

                
850
    // Notify listeners that the configuration has changed
851
    g_static_rw_lock_reader_lock(&config->rwlock);
852
    g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_ADDED | CONFIG_CHANGED_SERVER_DELETED);
853
    g_static_rw_lock_reader_unlock(&config->rwlock);
854

                
855
    return TRUE;
856
}
857

                
858
/** 
859
 * Save all settings to a local file on the harddrive
860
 *
861
 * @param obj           The configuration object
862
 * @param errmsg        A pointer to a char* to save a possible error message
863
 * @return              TRUE on success, FALSE on failure (errmsg will be set and needs to be g_free'd after use)
864
 */
865
gboolean
866
configuration_save(Configuration *obj, char **errmsg)
867
{
868
    Configuration *config = CONFIGURATION(obj);
869
    GKeyFile *keyfile;
870
    GError *err = NULL;
871
    char *filename;
872
    char *dirname;
873
    char *contents;
874
    GList *list;
875
    const char *config_dir;
876

                
877
    g_static_rw_lock_reader_lock(&config->rwlock);
878

                
879
    keyfile = g_key_file_new();
880

                
881
    g_key_file_set_string(keyfile, "options", "download_directory", config->opts.download_directory);
882
    g_key_file_set_string(keyfile, "options", "temp_directory", config->opts.temp_directory);
883
    g_key_file_set_boolean(keyfile, "options", "enable_intelligent_par2_downloading", config->opts.enable_intelligent_par2_downloading);
884
    g_key_file_set_boolean(keyfile, "options", "enable_par2_repair", config->opts.enable_par2_repair);
885
    g_key_file_set_boolean(keyfile, "options", "enable_auto_unpack", config->opts.enable_auto_unpack);
886
    g_key_file_set_boolean(keyfile, "options", "enable_auto_import", config->opts.enable_auto_import);
887
    g_key_file_set_string (keyfile, "options", "auto_import_directory", config->opts.auto_import_directory);
888
    g_key_file_set_boolean(keyfile, "options", "move_file_after_auto_import", config->opts.move_file_after_auto_import);
889
    g_key_file_set_boolean(keyfile, "options", "enable_bandwidth_shaping", config->opts.enable_bandwidth_shaping);
890
    g_key_file_set_integer(keyfile, "options", "max_bandwidth", config->opts.max_bandwidth);
891
    g_key_file_set_boolean(keyfile, "options", "enable_webserver", config->opts.enable_webserver);
892
    g_key_file_set_integer(keyfile, "options", "webserver_port", config->opts.webserver_port);
893
    g_key_file_set_boolean(keyfile, "options", "enable_logger", config->opts.enable_logger);
894
    g_key_file_set_boolean(keyfile, "options", "auto_remove_files", config->opts.auto_remove_files);
895

                
896
    list = config->servers;
897
    while (list) {
898
        ConfigServer *server = list->data;
899

                
900
        g_key_file_set_string (keyfile, server->servername, "hostname", server->hostname);
901
        g_key_file_set_integer(keyfile, server->servername, "port", server->port);
902
        g_key_file_set_string (keyfile, server->servername, "username", server->username);
903
        g_key_file_set_string (keyfile, server->servername, "password", server->password);
904
        g_key_file_set_integer(keyfile, server->servername, "max_threads", server->max_threads);
905
        g_key_file_set_boolean(keyfile, server->servername, "use_ssl", server->use_ssl);
906
        g_key_file_set_integer(keyfile, server->servername, "priority", server->priority);
907
        g_key_file_set_boolean(keyfile, server->servername, "enabled", server->enabled);
908

                
909
        list = g_list_next(list);
910
    }
911

                
912
    contents = g_key_file_to_data(keyfile, NULL, &err);
913
    if (!contents) {
914
        if (errmsg) {
915
            *errmsg = g_strdup(err->message);
916
        }
917

                
918
        g_error_free(err);
919
        g_free(contents);
920
        g_key_file_free(keyfile);
921
        g_static_rw_lock_reader_unlock(&config->rwlock);
922

                
923
        return FALSE;
924
    }
925

                
926
    // Create the folder ~/.config/NNTPGrab if it didn't exist already
927
    if (g_getenv("NNTPGRAB_CONFIG_DIR")) {
928
        config_dir = g_getenv("NNTPGRAB_CONFIG_DIR");
929
    } else {
930
        config_dir = g_get_user_config_dir();
931
    }
932

                
933
    dirname = g_build_path(G_DIR_SEPARATOR_S, config_dir, "NNTPGrab", NULL);
934
    g_mkdir_with_parents(dirname, 0700);
935
    g_free(dirname);
936

                
937
    filename = g_build_filename(config_dir, "NNTPGrab", "nntpgrab.conf", NULL);
938

                
939
    if (!g_file_set_contents(filename, contents, -1, &err)) {
940
        if (errmsg) {
941
            *errmsg = g_strdup_printf(_("configuration_save(): Error while opening file '%s'\n%s"), filename, err->message);
942
        }
943

                
944
        g_error_free(err);
945
        g_free(contents);
946
        g_free(filename);
947
        g_key_file_free(keyfile);
948
        g_static_rw_lock_reader_unlock(&config->rwlock);
949

                
950
        return FALSE;
951
    }
952

                
953
    g_free(contents);
954
    g_free(filename);
955
    g_key_file_free(keyfile);
956
    g_static_rw_lock_reader_unlock(&config->rwlock);
957

                
958
    return TRUE;
959
}