Statistics
| Revision:

root / trunk / nntpgrab_core / configuration.c @ 1914

History | View | Annotate | Download (34.3 KB)

1
/* 
2
    Copyright (C) 2005-2010  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
#include "nntpgrab_plugin.h"
32
#include "collections.h"
33

                
34
typedef struct ConfigurationClass ConfigurationClass;
35

                
36
Configuration *configuration_get_object(void);
37

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

                
43
struct Configuration
44
{
45
    GObject parent;
46

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

                
51
    NGConfigOpts opts;
52
};
53

                
54
struct ConfigurationClass
55
{
56
    GObjectClass parent;
57
};
58

                
59
enum
60
{
61
    CONFIG_CHANGED_SIGNAL,
62
    LAST_SIGNAL
63
};
64

                
65
static guint signals[LAST_SIGNAL] = { 0 };
66

                
67
G_DEFINE_TYPE(Configuration, configuration, G_TYPE_OBJECT)
68

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

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

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

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

                
91
    if (!(configuration_save(config, &errmsg))) {
92
        ng_plugin_emit_log_msg(NULL, NG_LOG_LEVEL_WARNING, "%s", errmsg);
93
        g_free(errmsg);
94
    }
95

                
96
    g_static_rw_lock_writer_lock(&config->rwlock);
97

                
98
    list = config->servers;
99
    while (list) {
100
        g_slice_free(NGConfigServer, list->data);
101
        list = g_list_next(list);
102
    }
103
    g_list_free(config->servers);
104

                
105
    g_hash_table_destroy(config->group_details);
106

                
107
    g_static_rw_lock_writer_unlock(&config->rwlock);
108
    g_static_rw_lock_free(&config->rwlock);
109
}
110

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

                
116
    gobject_class->finalize = configuration_finalize;
117

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

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

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

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

                
142
        if (!configuration_save(config, errmsg)) {
143
            g_object_unref(config);
144
            return NULL;
145
        }
146
    }
147

                
148
    return config;
149
}
150

                
151
void
152
configuration_destroy(Configuration *obj)
153
{
154
    g_object_unref(obj);
155
}
156

                
157
/** 
158
 * Retrieve a list of all the available usenet servers
159
 *
160
 * @param obj   The configuration object
161
 * @return      a GList* containing g_malloc'ed char* strings with servernames
162
 */
163
GList *
164
configuration_get_avail_servers(Configuration *obj)
165
{
166
    Configuration *config = CONFIGURATION(obj);
167
    GList *list;
168
    GList *ret = NULL;
169

                
170
    g_static_rw_lock_reader_lock(&config->rwlock);
171

                
172
    list = config->servers;
173
    while (list) {
174
        NGConfigServer *server = list->data;
175

                
176
        ret = g_list_append(ret, g_strdup(server->servername));
177

                
178
        list = g_list_next(list);
179
    }
180

                
181
    g_static_rw_lock_reader_unlock(&config->rwlock);
182

                
183
    return ret;
184
}
185

                
186
/** 
187
 * Frees the list returned by configuration_get_avail_servers()
188
 *
189
 * @param obj       The configuration object
190
 * @param servers   A GList* containing g_malloc'ed char* strings with servernames
191
 */
192
void
193
configuration_free_avail_servers(Configuration *obj, GList *servers)
194
{
195
    GList *list;
196

                
197
    list = servers;
198
    while (list) {
199
        g_free(list->data);
200
        list = g_list_next(list);
201
    }
202

                
203
    g_list_free(servers);
204
}
205

                
206
/** 
207
 * Retrieve information about a specific usenet server
208
 *
209
 * @param obj           The Configuration object
210
 * @param servername    The name of the usenet server whose info should be lookup up
211
 * @return              A g_slice_new'ed ConfigServer structure containing the requested info or NULL when the servername could not be found
212
 */
213
NGConfigServer *
214
configuration_get_server_info(Configuration *obj, const char *servername)
215
{
216
    Configuration *config = CONFIGURATION(obj);
217
    GList *list;
218

                
219
    g_static_rw_lock_reader_lock(&config->rwlock);
220

                
221
    list = config->servers;
222
    while (list) {
223
        NGConfigServer *server = list->data;
224

                
225
        if (!strcmp(server->servername, servername)) {
226
            NGConfigServer *ret = g_slice_new0(NGConfigServer);
227

                
228
            memcpy(ret, server, sizeof(NGConfigServer));
229

                
230
            g_static_rw_lock_reader_unlock(&config->rwlock);
231

                
232
            return ret;
233
        }
234

                
235
        list = g_list_next(list);
236
    }
237

                
238
    g_static_rw_lock_reader_unlock(&config->rwlock);
239

                
240
    return NULL;
241
}
242

                
243
/** 
244
 * Add a new server to the list of known usenet servers
245
 *
246
 * @param obj           The configuration object
247
 * @param new_server    The structure containing the settings of the new server
248
 * @param errmsg        If an error occurs, an error message will be set in this variable
249
 * @return              TRUE on success, FALSE on error (errmsg will be set)
250
 */
251
gboolean
252
configuration_add_server(Configuration *obj, NGConfigServer new_server, char **errmsg)
253
{
254
    Configuration *config = CONFIGURATION(obj);
255
    NGConfigServer *server;
256
    GList *list;
257

                
258
    // Check is the new_server contains sane data
259
    g_assert(new_server.port > 0 && new_server.port < 65536);
260
    g_assert(new_server.max_threads > 0);
261

                
262
    if (!strcmp(new_server.servername, "options")) {
263
        if (errmsg) {
264
            *errmsg = g_strdup_printf("%s%s", _("The servername 'options' cannot be used.\n"), _("Please use a different servername"));
265
        }
266
        return FALSE;
267
    }
268

                
269
    // Check if the servername of the new_server is already known
270
    g_static_rw_lock_reader_lock(&config->rwlock);
271

                
272
    list = config->servers;
273
    while (list) {
274
        server = list->data;
275

                
276
        if (!strcmp(new_server.servername, server->servername)) {
277
            // servername already exists, refuse the addition of a new server
278
            g_static_rw_lock_reader_unlock(&config->rwlock);
279

                
280
            if (errmsg) {
281
                *errmsg = g_strdup_printf("%s%s", _("The given servername already exists in the configuration.\n"), _("Please use a different servername"));
282
            }
283

                
284
            return FALSE;
285
        }
286

                
287
        list = g_list_next(list);
288
    }
289

                
290
    // Prevent the addition of more than MAX_NNTP_SERVERS servers
291
    if (g_list_length(config->servers) == MAX_NNTP_SERVERS - 1) {
292
        g_static_rw_lock_reader_unlock(&config->rwlock);
293

                
294
        if (errmsg) {
295
            *errmsg = g_strdup(_("There are too many servers configured"));
296
        }
297

                
298
        return FALSE;
299
    }
300

                
301
    g_static_rw_lock_reader_unlock(&config->rwlock);
302

                
303
    // servername not found, it is safe to add the new configuration
304
    g_static_rw_lock_writer_lock(&config->rwlock);
305

                
306
    server = g_slice_new0(NGConfigServer);
307
    memcpy(server, &new_server, sizeof(NGConfigServer));
308
    config->servers = g_list_append(config->servers, server);
309

                
310
    g_static_rw_lock_writer_unlock(&config->rwlock);
311

                
312
    // Notify listeners that the configuration has changed
313
    g_static_rw_lock_reader_lock(&config->rwlock);
314
    g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_ADDED);
315
    g_static_rw_lock_reader_unlock(&config->rwlock);
316

                
317
    return TRUE;
318
}
319

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

                
336
    // Check if the servername is known
337
    g_static_rw_lock_reader_lock(&config->rwlock);
338

                
339
    list = config->servers;
340
    while (list) {
341
        server = list->data;
342

                
343
        if (!strcmp(servername, server->servername)) {
344
            // servername exists, remove it from the list
345
            g_static_rw_lock_reader_unlock(&config->rwlock);
346

                
347
            g_static_rw_lock_writer_lock(&config->rwlock);
348

                
349
            g_slice_free(NGConfigServer, server);
350
            config->servers = g_list_remove(config->servers, server);
351

                
352
            g_static_rw_lock_writer_unlock(&config->rwlock);
353

                
354
            // Notify listeners that the configuration has changed
355
            g_static_rw_lock_reader_lock(&config->rwlock);
356
            g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_DELETED);
357
            g_static_rw_lock_reader_unlock(&config->rwlock);
358

                
359
            return TRUE;
360
        }
361

                
362
        list = g_list_next(list);
363
    }
364

                
365
    g_static_rw_lock_reader_unlock(&config->rwlock);
366

                
367
    if (errmsg) {
368
        *errmsg = g_strdup(_("The given servername doesn't exist in the NNTPGrab configuration"));
369
    }
370

                
371
    return FALSE;
372
}
373

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

                
391
    if (!strcmp(new_server.servername, "options")) {
392
        if (errmsg) {
393
            *errmsg = g_strdup_printf("%s%s", _("The servername 'options' cannot be used.\n"), _("Please use a different servername"));
394
        }
395
        return FALSE;
396
    }
397

                
398
    // Check if the servername of the new_server is already known
399
    g_static_rw_lock_reader_lock(&config->rwlock);
400

                
401
    list = config->servers;
402
    while (list) {
403
        server = list->data;
404

                
405
        if (!strcmp(servername, server->servername)) {
406
            // servername exists, edit the settings
407
            g_static_rw_lock_reader_unlock(&config->rwlock);
408

                
409
            g_static_rw_lock_writer_lock(&config->rwlock);
410

                
411
            // apply the new settings
412
            memcpy(server, &new_server, sizeof(NGConfigServer));
413

                
414
            g_static_rw_lock_writer_unlock(&config->rwlock);
415

                
416
            // Notify listeners that the configuration has changed
417
            g_static_rw_lock_reader_lock(&config->rwlock);
418
            g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_ADDED);
419
            g_static_rw_lock_reader_unlock(&config->rwlock);
420

                
421
            return TRUE;
422
        }
423

                
424
        list = g_list_next(list);
425
    }
426

                
427
    g_static_rw_lock_reader_unlock(&config->rwlock);
428

                
429
    if (errmsg) {
430
        *errmsg = g_strdup(_("The given servername doesn't exist in the NNTPGrab configuration"));
431
    }
432

                
433
    return FALSE;
434
}
435

                
436
/** 
437
 * Retrieves the configuration options
438
 *
439
 * @param obj       The configuration object
440
 * @return          A structure containing configuration data
441
 */
442
NGConfigOpts
443
configuration_get_opts(Configuration *obj)
444
{
445
    Configuration *config = CONFIGURATION(obj);
446
    NGConfigOpts ret;
447

                
448
    g_static_rw_lock_reader_lock(&config->rwlock);
449

                
450
    ret = config->opts;
451

                
452
    g_static_rw_lock_reader_unlock(&config->rwlock);
453

                
454
    return ret;
455
}
456

                
457
/** 
458
 * Set the configuration options
459
 *
460
 * @param obj   The configuration object
461
 * @param opts  A structure containing configuration data
462
 */
463
void
464
configuration_set_opts(Configuration *obj, NGConfigOpts opts)
465
{
466
    Configuration *config = CONFIGURATION(obj);
467

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

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

                
480
    if (strlen(opts.auto_import_directory) == 2 && opts.auto_import_directory[1] == ':') {
481
        opts.temp_directory[2] = '\\';
482
        opts.temp_directory[3] = '\0';
483
    }
484
#endif
485

                
486
    /* Make sure that the download and temp folder really exist */
487
    if (!g_file_test(opts.download_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ||
488
        !g_file_test(opts.temp_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ||
489
        !g_file_test(opts.auto_import_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
490

                
491
        /* Refuse to accept the new configuration */
492
        return;
493
    }
494

                
495
    g_static_rw_lock_writer_lock(&config->rwlock);
496
    config->opts = opts;
497
    g_static_rw_lock_writer_unlock(&config->rwlock);
498

                
499
    // Notify listeners that the configuration has changed
500
    g_static_rw_lock_reader_lock(&config->rwlock);
501
    g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_OPTS_CHANGED);
502
    g_static_rw_lock_reader_unlock(&config->rwlock);
503
}
504

                
505
/** 
506
 * Get the details concerning the given server and newsgroup
507
 *
508
 * @param obj           The configuration object
509
 * @param servername    The name of the server
510
 * @param newsgroup     The name of the newsgroup
511
 *
512
 * @return              Structure containing the details
513
 */
514
ConfigGroupInfo
515
configuration_get_newsgroup_info(Configuration *obj, const char *servername, const char *newsgroup)
516
{
517
    ConfigGroupInfo ret;
518
    ConfigGroupInfo *info;
519
    Configuration *config = CONFIGURATION(obj);
520
    char *hash;
521

                
522
    g_static_rw_lock_reader_lock(&config->rwlock);
523

                
524
    hash = g_strdup_printf("%s_%s", servername, newsgroup);
525
    info = g_hash_table_lookup(config->group_details, hash);
526
    g_free(hash);
527

                
528
    if (info) {
529
        memcpy(&ret, info, sizeof(ConfigGroupInfo));
530
    } else {
531
        memset(&ret, 0, sizeof(ConfigGroupInfo));
532
        strncpy((char *) ret.newsgroup, newsgroup, sizeof(ret.newsgroup));
533
    }
534

                
535
    g_static_rw_lock_reader_unlock(&config->rwlock);
536

                
537
    return ret;
538
}
539

                
540
/** 
541
 * Set the details concerning the given server and newsgroup
542
 *
543
 * @param obj           The configuration object
544
 * @param servername    The name of the server
545
 * @param newsgroup     The name of the newsgroup
546
 * @param info          Structure containing the details
547
 */
548
void
549
configuration_set_newsgroup_info(Configuration *obj, const char *servername, const char *newsgroup, ConfigGroupInfo info)
550
{
551
    Configuration *config = CONFIGURATION(obj);
552
    ConfigGroupInfo *info_new;
553
    char *hash;
554

                
555
    g_static_rw_lock_writer_lock(&config->rwlock);
556

                
557
    info_new = g_slice_new(ConfigGroupInfo);
558
    memcpy(info_new, &info, sizeof(ConfigGroupInfo));
559

                
560
    hash = g_strdup_printf("%s_%s", servername, newsgroup);
561
    g_hash_table_replace(config->group_details, hash, info_new);
562
    g_free(hash);
563

                
564
    g_static_rw_lock_writer_unlock(&config->rwlock);
565
}
566

                
567
/** 
568
 * configuration_get_config_folder:
569
 *
570
 * Retrieve the folder where all configuration files can be stored
571
 *
572
 * Returns:             The folder where all configuration files can be stored. Needs to be g_free'd after use
573
 */
574
char *
575
configuration_get_config_folder(void)
576
{
577
    if (g_getenv("NNTPGRAB_CONFIG_DIR")) {
578
        return g_build_path(G_DIR_SEPARATOR_S, g_getenv("NNTPGRAB_CONFIG_DIR"), "NNTPGrab", NULL);
579
    } else {
580
        return g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), "NNTPGrab", NULL);
581
    }
582
}
583

                
584
/** 
585
 * Load all settings from a local file on the harddrive
586
 *
587
 * @param obj           The configuration object
588
 * @param errmsg        A pointer to a char* to save a possible error message
589
 * @return              TRUE on success, FALSE on failure (errmsg will be set and needs to be g_free'd after use)
590
 */
591
gboolean
592
configuration_load(Configuration *obj, char **errmsg)
593
{
594
    Configuration *config = CONFIGURATION(obj);
595
    GKeyFile *keyfile;
596
    GError *err = NULL;
597
    char *config_folder;
598
    char *filename;
599
    char **groups;
600
    int i;
601
    GList *list;
602

                
603
    g_static_rw_lock_writer_lock(&config->rwlock);
604

                
605
    /* Free the already known settings */
606
    list = config->servers;
607
    while (list) {
608
        NGConfigServer *server = list->data;
609

                
610
        g_slice_free(NGConfigServer, server);
611

                
612
        list = g_list_next(list);
613
    }
614

                
615
    g_list_free(config->servers);
616
    config->servers = NULL;
617

                
618
    /* Try to load the config file */
619
    config_folder = configuration_get_config_folder();
620
    filename = g_build_filename(config_folder, "nntpgrab.conf", NULL);
621
    g_free(config_folder);
622

                
623
    keyfile = g_key_file_new();
624
    if (!g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, &err)) {
625
        char *tmp;
626
        const char *homedir;
627

                
628
        if (errmsg) {
629
            *errmsg = g_strdup_printf(_("configuration_load(): Error while opening file '%s'\n%s"), filename, err->message);
630
        }
631

                
632
        g_free(filename);
633
        g_error_free(err);
634
        g_key_file_free(keyfile);
635

                
636
#ifdef WIN32
637
        homedir = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS);
638
#else
639
        if (g_getenv("NNTPGRAB_DEFAULT_DL_DIR")) {
640
            homedir = g_getenv("NNTPGRAB_DEFAULT_DL_DIR");
641
        } else {
642
            homedir = g_get_home_dir();
643
        }
644
#endif
645
        // Set up sane defaults
646
        tmp = g_build_path(G_DIR_SEPARATOR_S, homedir, "NNTPGrab", "Downloads", NULL);
647
        strncpy(config->opts.download_directory, tmp, sizeof(config->opts.download_directory));
648
        g_mkdir_with_parents(tmp, 0700);
649
        g_free(tmp);
650

                
651
        tmp = g_build_path(G_DIR_SEPARATOR_S, homedir, "NNTPGrab", "Temp", NULL);
652
        strncpy(config->opts.temp_directory, tmp, sizeof(config->opts.temp_directory));
653
        g_mkdir_with_parents(tmp, 0700);
654
        g_free(tmp);
655

                
656
        tmp = g_build_path(G_DIR_SEPARATOR_S, homedir, "NNTPGrab", "NZB", NULL);
657
        strncpy(config->opts.auto_import_directory, tmp, sizeof(config->opts.auto_import_directory));
658
        g_mkdir_with_parents(tmp, 0700);
659
        g_free(tmp);
660

                
661
        config->opts.enable_par2_repair = TRUE;
662
        config->opts.enable_intelligent_par2_downloading = TRUE;
663
        config->opts.enable_auto_unpack = TRUE;
664
        config->opts.enable_bandwidth_shaping = FALSE;
665
        config->opts.max_bandwidth = 100;
666
        config->opts.enable_webserver = FALSE;
667
        config->opts.webserver_port = 5423;
668
        config->opts.enable_logger = FALSE;
669
        config->opts.auto_remove_files_after_repair = FALSE;
670
        config->opts.auto_remove_files_after_unpack = FALSE;
671
        config->opts.auto_remove_collections_after_download = FALSE;
672

                
673
        g_static_rw_lock_writer_unlock(&config->rwlock);
674

                
675
        return FALSE;
676
    }
677

                
678
    g_free(filename);
679

                
680
    groups = g_key_file_get_groups(keyfile, NULL);
681
    i = 0;
682
    while (groups[i]) {
683
        char *value;
684
        NGConfigServer *server;
685

                
686
        if (!strcmp(groups[i], "options")) {
687
            char *tmp;
688

                
689
            tmp = g_key_file_get_string(keyfile, groups[i], "download_directory", NULL);
690
            if (tmp) {
691
                strncpy(config->opts.download_directory, tmp, sizeof(config->opts.download_directory));
692
                g_free(tmp);
693
            }
694

                
695
            tmp = g_key_file_get_string(keyfile, groups[i], "temp_directory", NULL);
696
            if (tmp) {
697
                strncpy(config->opts.temp_directory, tmp, sizeof(config->opts.temp_directory));
698
                g_free(tmp);
699
            }
700

                
701
            if (g_key_file_has_key(keyfile, groups[i], "enable_intelligent_par2_downloading", NULL)) {
702
                config->opts.enable_intelligent_par2_downloading = g_key_file_get_boolean(keyfile, groups[i], "enable_intelligent_par2_downloading", NULL);
703
            } else {
704
                config->opts.enable_intelligent_par2_downloading = TRUE;
705
            }
706

                
707
            if (g_key_file_has_key(keyfile, groups[i], "enable_par2_repair", NULL)) {
708
                config->opts.enable_par2_repair = g_key_file_get_boolean(keyfile, groups[i], "enable_par2_repair", NULL);
709
            } else {
710
                config->opts.enable_par2_repair = TRUE;
711
            }
712

                
713
            if (g_key_file_has_key(keyfile, groups[i], "enable_auto_unpack", NULL)) {
714
                config->opts.enable_auto_unpack = g_key_file_get_boolean(keyfile, groups[i], "enable_auto_unpack", NULL);
715
            } else {
716
                config->opts.enable_auto_unpack = TRUE;
717
            }
718

                
719
            tmp = g_key_file_get_string(keyfile, groups[i], "auto_import_directory", NULL);
720
            if (tmp) {
721
                strncpy(config->opts.auto_import_directory, tmp, sizeof(config->opts.auto_import_directory));
722
                g_free(tmp);
723
            }
724

                
725
            if (g_key_file_has_key(keyfile, groups[i], "enable_auto_import", NULL)) {
726
                config->opts.enable_auto_import = g_key_file_get_boolean(keyfile, groups[i], "enable_auto_import", NULL);
727
            } else {
728
                config->opts.enable_auto_import = TRUE;
729
            }
730

                
731
            if (g_key_file_has_key(keyfile, groups[i], "move_file_after_auto_import", NULL)) {
732
                config->opts.move_file_after_auto_import = g_key_file_get_boolean(keyfile, groups[i], "move_file_after_auto_import", NULL);
733
            } else {
734
                config->opts.move_file_after_auto_import = TRUE;
735
            }
736

                
737
            if (g_key_file_has_key(keyfile, groups[i], "enable_bandwidth_shaping", NULL)) {
738
                config->opts.enable_bandwidth_shaping = g_key_file_get_boolean(keyfile, groups[i], "enable_bandwidth_shaping", NULL);
739
            } else {
740
                config->opts.enable_bandwidth_shaping = FALSE;
741
            }
742

                
743
            if (g_key_file_has_key(keyfile, groups[i], "max_bandwidth", NULL)) {
744
                config->opts.max_bandwidth = g_key_file_get_integer(keyfile, groups[i], "max_bandwidth", NULL);
745
            } else {
746
                config->opts.max_bandwidth = 100;
747
            }
748

                
749
            if (g_key_file_has_key(keyfile, groups[i], "enable_webserver", NULL)) {
750
                config->opts.enable_webserver = g_key_file_get_boolean(keyfile, groups[i], "enable_webserver", NULL);
751
            } else {
752
                config->opts.enable_webserver = FALSE;
753
            }
754

                
755
            if (g_key_file_has_key(keyfile, groups[i], "webserver_port", NULL)) {
756
                config->opts.webserver_port = g_key_file_get_integer(keyfile, groups[i], "webserver_port", NULL);
757
            } else {
758
                config->opts.webserver_port = 5423;
759
            }
760

                
761
            if (g_key_file_has_key(keyfile, groups[i], "enable_logger", NULL)) {
762
                config->opts.enable_logger = g_key_file_get_boolean(keyfile, groups[i], "enable_logger", NULL);
763
            } else {
764
                config->opts.enable_logger = FALSE;
765
            }
766

                
767
            if (g_key_file_has_key(keyfile, groups[i], "auto_remove_files_after_repair", NULL)) {
768
                config->opts.auto_remove_files_after_repair = g_key_file_get_boolean(keyfile, groups[i], "auto_remove_files_after_repair", NULL);
769
            } else {
770
                config->opts.auto_remove_files_after_repair = FALSE;
771
            }
772

                
773
            if (g_key_file_has_key(keyfile, groups[i], "auto_remove_files_after_unpack", NULL)) {
774
                config->opts.auto_remove_files_after_unpack = g_key_file_get_boolean(keyfile, groups[i], "auto_remove_files_after_unpack", NULL);
775
            } else {
776
                config->opts.auto_remove_files_after_unpack = FALSE;
777
            }
778

                
779
            if (g_key_file_has_key(keyfile, groups[i], "auto_remove_collections_after_download", NULL)) {
780
                config->opts.auto_remove_collections_after_download = g_key_file_get_boolean(keyfile, groups[i], "auto_remove_collections_after_download", NULL);
781
            } else{
782
                config->opts.auto_remove_collections_after_download = FALSE;
783
            }
784

                
785
            /* backwards compatibility */
786
            if (g_key_file_has_key(keyfile, groups[i], "auto_remove_files", NULL)) {
787
                config->opts.auto_remove_files_after_repair = g_key_file_get_boolean(keyfile, groups[i], "auto_remove_files", NULL);
788
                config->opts.auto_remove_files_after_unpack = g_key_file_get_boolean(keyfile, groups[i], "auto_remove_files", NULL);
789
            }
790
            i++;
791
            continue;
792
        }
793

                
794
        server = g_slice_new(NGConfigServer);
795

                
796
        strncpy(server->servername, groups[i], sizeof(server->servername));
797

                
798
        value = g_key_file_get_string(keyfile, groups[i], "hostname", NULL);
799
        if (!value) {
800
            g_print(_("No hostname could be found for servername '%s'. Ignoring server\n"), groups[i]);
801
            i++;
802
            continue;
803
        }
804

                
805
        strncpy(server->hostname, value, sizeof(server->hostname));
806
        g_free(value);
807

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

                
810
        value = g_key_file_get_string(keyfile, groups[i], "username", NULL);
811
        if (value) {
812
            strncpy(server->username, value, sizeof(server->username));
813
            g_free(value);
814
        }
815

                
816
        value = g_key_file_get_string(keyfile, groups[i], "password", NULL);
817
        if (value) {
818
            strncpy(server->password, value, sizeof(server->password));
819
            g_free(value);
820
        }
821

                
822
        server->max_threads = g_key_file_get_integer(keyfile, groups[i], "max_threads", NULL);
823
        server->use_ssl = g_key_file_get_boolean(keyfile, groups[i], "use_ssl", NULL);
824

                
825
        // backwards compatibility
826
        if (!g_key_file_has_key(keyfile, groups[i], "priority", NULL)) {
827
            server->priority = SERVER_PRIORITY_NORMAL;
828
        } else {
829
            server->priority = g_key_file_get_integer(keyfile, groups[i], "priority", NULL);
830
        }
831

                
832
        if (!g_key_file_has_key(keyfile, groups[i], "enabled", NULL)) {
833
            server->enabled = TRUE;
834
        } else {
835
            server->enabled = g_key_file_get_boolean(keyfile, groups[i], "enabled", NULL);
836
        }
837

                
838
        if (!g_key_file_has_key(keyfile, groups[i], "send_group_command", NULL)) {
839
            server->send_group_command = FALSE;
840
        } else {
841
            server->send_group_command = g_key_file_get_boolean(keyfile, groups[i], "send_group_command", NULL);
842
        }
843

                
844
        config->servers = g_list_append(config->servers, server);
845

                
846
        i++;
847
    }
848

                
849
    g_strfreev(groups);
850

                
851
    g_key_file_free(keyfile);
852

                
853
    // Do we have sane values for the download and temp directory ?
854
#ifdef WIN32
855
    if (strlen(config->opts.download_directory) == 2) {
856
        config->opts.download_directory[2] = '\\';
857
        config->opts.download_directory[3] = '\0';
858
    }
859

                
860
    if (strlen(config->opts.temp_directory) == 2) {
861
        config->opts.temp_directory[2] = '\\';
862
        config->opts.temp_directory[3] = '\0';
863
    }
864
#endif
865

                
866
    if (!g_file_test(config->opts.download_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
867
        char *tmp;
868

                
869
#ifdef WIN32
870
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS), "NNTPGrab", "Downloads", NULL);
871
#else
872
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_home_dir(), "NNTPGrab", "Downloads", NULL);
873
#endif
874
        strncpy(config->opts.download_directory, tmp, sizeof(config->opts.download_directory));
875
        g_mkdir_with_parents(tmp, 0700);
876
        g_free(tmp);
877
    }
878

                
879
    if (!g_file_test(config->opts.temp_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
880
        char *tmp;
881

                
882
#ifdef WIN32
883
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS), "NNTPGrab", "Temp", NULL);
884
#else
885
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_home_dir(), "NNTPGrab", "Temp", NULL);
886
#endif
887
        strncpy(config->opts.temp_directory, tmp, sizeof(config->opts.temp_directory));
888
        g_mkdir_with_parents(tmp, 0700);
889
        g_free(tmp);
890
    }
891

                
892
    if (!g_file_test(config->opts.auto_import_directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
893
        char *tmp;
894

                
895
#ifdef WIN32
896
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS), "NNTPGrab", "NZB", NULL);
897
#else
898
        tmp = g_build_path(G_DIR_SEPARATOR_S, g_get_home_dir(), "NNTPGrab", "NZB", NULL);
899
#endif
900
        strncpy(config->opts.auto_import_directory, tmp, sizeof(config->opts.auto_import_directory));
901
        g_mkdir_with_parents(tmp, 0700);
902
        g_free(tmp);
903
    }
904

                
905
    g_static_rw_lock_writer_unlock(&config->rwlock);
906

                
907
    // Notify listeners that the configuration has changed
908
    g_static_rw_lock_reader_lock(&config->rwlock);
909
    g_signal_emit (config, signals[CONFIG_CHANGED_SIGNAL], 0, CONFIG_CHANGED_SERVER_ADDED | CONFIG_CHANGED_SERVER_DELETED);
910
    g_static_rw_lock_reader_unlock(&config->rwlock);
911

                
912
    return TRUE;
913
}
914

                
915
/** 
916
 * Save all settings to a local file on the harddrive
917
 *
918
 * @param obj           The configuration object
919
 * @param errmsg        A pointer to a char* to save a possible error message
920
 * @return              TRUE on success, FALSE on failure (errmsg will be set and needs to be g_free'd after use)
921
 */
922
gboolean
923
configuration_save(Configuration *obj, char **errmsg)
924
{
925
    Configuration *config = CONFIGURATION(obj);
926
    GKeyFile *keyfile;
927
    GError *err = NULL;
928
    char *config_folder;
929
    char *filename;
930
    char *contents;
931
    GList *list;
932

                
933
    g_static_rw_lock_reader_lock(&config->rwlock);
934

                
935
    keyfile = g_key_file_new();
936

                
937
    g_key_file_set_string(keyfile, "options", "download_directory", config->opts.download_directory);
938
    g_key_file_set_string(keyfile, "options", "temp_directory", config->opts.temp_directory);
939
    g_key_file_set_boolean(keyfile, "options", "enable_intelligent_par2_downloading", config->opts.enable_intelligent_par2_downloading);
940
    g_key_file_set_boolean(keyfile, "options", "enable_par2_repair", config->opts.enable_par2_repair);
941
    g_key_file_set_boolean(keyfile, "options", "enable_auto_unpack", config->opts.enable_auto_unpack);
942
    g_key_file_set_boolean(keyfile, "options", "enable_auto_import", config->opts.enable_auto_import);
943
    g_key_file_set_string (keyfile, "options", "auto_import_directory", config->opts.auto_import_directory);
944
    g_key_file_set_boolean(keyfile, "options", "move_file_after_auto_import", config->opts.move_file_after_auto_import);
945
    g_key_file_set_boolean(keyfile, "options", "enable_bandwidth_shaping", config->opts.enable_bandwidth_shaping);
946
    g_key_file_set_integer(keyfile, "options", "max_bandwidth", config->opts.max_bandwidth);
947
    g_key_file_set_boolean(keyfile, "options", "enable_webserver", config->opts.enable_webserver);
948
    g_key_file_set_integer(keyfile, "options", "webserver_port", config->opts.webserver_port);
949
    g_key_file_set_boolean(keyfile, "options", "enable_logger", config->opts.enable_logger);
950
    g_key_file_set_boolean(keyfile, "options", "auto_remove_files_after_repair", config->opts.auto_remove_files_after_repair);
951
    g_key_file_set_boolean(keyfile, "options", "auto_remove_files_after_unpack", config->opts.auto_remove_files_after_unpack);
952
    g_key_file_set_boolean(keyfile, "options", "auto_remove_collections_after_download", config->opts.auto_remove_collections_after_download);
953

                
954
    list = config->servers;
955
    while (list) {
956
        NGConfigServer *server = list->data;
957

                
958
        g_key_file_set_string (keyfile, server->servername, "hostname", server->hostname);
959
        g_key_file_set_integer(keyfile, server->servername, "port", server->port);
960
        g_key_file_set_string (keyfile, server->servername, "username", server->username);
961
        g_key_file_set_string (keyfile, server->servername, "password", server->password);
962
        g_key_file_set_integer(keyfile, server->servername, "max_threads", server->max_threads);
963
        g_key_file_set_boolean(keyfile, server->servername, "send_group_command", server->send_group_command);
964
        g_key_file_set_boolean(keyfile, server->servername, "use_ssl", server->use_ssl);
965
        g_key_file_set_integer(keyfile, server->servername, "priority", server->priority);
966
        g_key_file_set_boolean(keyfile, server->servername, "enabled", server->enabled);
967

                
968
        list = g_list_next(list);
969
    }
970

                
971
    contents = g_key_file_to_data(keyfile, NULL, &err);
972
    if (!contents) {
973
        if (errmsg) {
974
            *errmsg = g_strdup(err->message);
975
        }
976

                
977
        g_error_free(err);
978
        g_free(contents);
979
        g_key_file_free(keyfile);
980
        g_static_rw_lock_reader_unlock(&config->rwlock);
981

                
982
        return FALSE;
983
    }
984

                
985
    /* Create the folder ~/.config/NNTPGrab if it didn't exist already */
986
    config_folder = configuration_get_config_folder();
987
    g_mkdir_with_parents(config_folder, 0700);
988

                
989
    /* Write the configuration to disk */
990
    filename = g_build_filename(config_folder, "nntpgrab.conf", NULL);
991
    g_free(config_folder);
992

                
993
    if (!g_file_set_contents(filename, contents, -1, &err)) {
994
        if (errmsg) {
995
            *errmsg = g_strdup_printf(_("configuration_save(): Error while opening file '%s'\n%s"), filename, err->message);
996
        }
997

                
998
        g_error_free(err);
999
        g_free(contents);
1000
        g_free(filename);
1001
        g_key_file_free(keyfile);
1002
        g_static_rw_lock_reader_unlock(&config->rwlock);
1003

                
1004
        return FALSE;
1005
    }
1006

                
1007
    g_free(contents);
1008
    g_free(filename);
1009
    g_key_file_free(keyfile);
1010
    g_static_rw_lock_reader_unlock(&config->rwlock);
1011

                
1012
    return TRUE;
1013
}