Statistics
| Revision:

root / trunk / nntpgrab_core / configuration.c @ 1913

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

                
33
typedef struct ConfigurationClass ConfigurationClass;
34

                
35
Configuration *configuration_get_object(void);
36

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

                
42
struct Configuration
43
{
44
    GObject parent;
45

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

                
50
    NGConfigOpts opts;
51
};
52

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

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

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

                
66
G_DEFINE_TYPE(Configuration, configuration, G_TYPE_OBJECT)
67

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

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

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

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

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

                
95
    g_static_rw_lock_writer_lock(&config->rwlock);
96

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

                
104
    g_hash_table_destroy(config->group_details);
105

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

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

                
115
    gobject_class->finalize = configuration_finalize;
116

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

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

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

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

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

                
147
    return config;
148
}
149

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

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

                
169
    g_static_rw_lock_reader_lock(&config->rwlock);
170

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

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

                
177
        list = g_list_next(list);
178
    }
179

                
180
    g_static_rw_lock_reader_unlock(&config->rwlock);
181

                
182
    return ret;
183
}
184

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

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

                
202
    g_list_free(servers);
203
}
204

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

                
218
    g_static_rw_lock_reader_lock(&config->rwlock);
219

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

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

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

                
229
            g_static_rw_lock_reader_unlock(&config->rwlock);
230

                
231
            return ret;
232
        }
233

                
234
        list = g_list_next(list);
235
    }
236

                
237
    g_static_rw_lock_reader_unlock(&config->rwlock);
238

                
239
    return NULL;
240
}
241

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

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

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

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

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

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

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

                
283
            return FALSE;
284
        }
285

                
286
        list = g_list_next(list);
287
    }
288

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

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

                
297
        return FALSE;
298
    }
299

                
300
    g_static_rw_lock_reader_unlock(&config->rwlock);
301

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

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

                
309
    g_static_rw_lock_writer_unlock(&config->rwlock);
310

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

                
316
    return TRUE;
317
}
318

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

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

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

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

                
346
            g_static_rw_lock_writer_lock(&config->rwlock);
347

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

                
351
            g_static_rw_lock_writer_unlock(&config->rwlock);
352

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

                
358
            return TRUE;
359
        }
360

                
361
        list = g_list_next(list);
362
    }
363

                
364
    g_static_rw_lock_reader_unlock(&config->rwlock);
365

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

                
370
    return FALSE;
371
}
372

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

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

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

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

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

                
408
            g_static_rw_lock_writer_lock(&config->rwlock);
409

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

                
413
            g_static_rw_lock_writer_unlock(&config->rwlock);
414

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

                
420
            return TRUE;
421
        }
422

                
423
        list = g_list_next(list);
424
    }
425

                
426
    g_static_rw_lock_reader_unlock(&config->rwlock);
427

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

                
432
    return FALSE;
433
}
434

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

                
447
    g_static_rw_lock_reader_lock(&config->rwlock);
448

                
449
    ret = config->opts;
450

                
451
    g_static_rw_lock_reader_unlock(&config->rwlock);
452

                
453
    return ret;
454
}
455

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

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

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

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

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

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

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

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

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

                
521
    g_static_rw_lock_reader_lock(&config->rwlock);
522

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

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

                
534
    g_static_rw_lock_reader_unlock(&config->rwlock);
535

                
536
    return ret;
537
}
538

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

                
554
    g_static_rw_lock_writer_lock(&config->rwlock);
555

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

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

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

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

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

                
602
    g_static_rw_lock_writer_lock(&config->rwlock);
603

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

                
609
        g_slice_free(NGConfigServer, server);
610

                
611
        list = g_list_next(list);
612
    }
613

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

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

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

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

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

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

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

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

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

                
672
        g_static_rw_lock_writer_unlock(&config->rwlock);
673

                
674
        return FALSE;
675
    }
676

                
677
    g_free(filename);
678

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                
793
        server = g_slice_new(NGConfigServer);
794

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

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

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

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

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

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

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

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

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

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

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

                
845
        i++;
846
    }
847

                
848
    g_strfreev(groups);
849

                
850
    g_key_file_free(keyfile);
851

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

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

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

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

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

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

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

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

                
904
    g_static_rw_lock_writer_unlock(&config->rwlock);
905

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

                
911
    return TRUE;
912
}
913

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

                
932
    g_static_rw_lock_reader_lock(&config->rwlock);
933

                
934
    keyfile = g_key_file_new();
935

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

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

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

                
967
        list = g_list_next(list);
968
    }
969

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

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

                
981
        return FALSE;
982
    }
983

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

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

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

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

                
1003
        return FALSE;
1004
    }
1005

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

                
1011
    return TRUE;
1012
}