Statistics
| Revision:

root / trunk / plugins / unpack / plugin_unpack.c @ 1788

History | View | Annotate | Download (23 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
#include 
24
#include 
25

                
26
#include "nntpgrab_plugin.h"
27
#include "nntpgrab_utils.h"
28
#include "marshalers.h"
29
#include "config.h"
30

                
31
#if GLIB_CHECK_VERSION(2,16,0)
32
#include "fr-archive.h"
33
#include "fr-command.h"
34
#include "fr-mime.h"
35

                
36
typedef struct _plugin_unpack_priv {
37
    const char *collection_name;
38
    const char *filename;
39
    GThreadPool *thread_pool;
40
} PluginUnpackPriv;
41

                
42
struct _unpack_data {
43
    NGPlugin *plugin_data;
44
    FrArchive *archive;
45
    gboolean now_loading;
46
    GMutex *mutex;
47
    GCond *cond;
48
    gboolean error_occured;
49
    FrProcErrorType error_type;
50
    char errmsg[1024];
51
    char filename[1024];
52
    char target_directory[1024];
53
    GList *files_extracted;
54
};
55

                
56
static gboolean unpack_do_unpack(NGPlugin *plugin_data, const char *collection_name, const char *filename, const char *target_directory, char **errmsg);
57
static void perform_automatic_unpack(gpointer data, gpointer user_data);
58

                
59
static void on_collection_downloaded(NGPlugin *plugin_data, const char *collection_name, gpointer data);
60
static void on_par2_repair_success(NGPlugin *plugin_data, const char *plugin_name, const char **params);
61
static void on_par2_no_repair_required(NGPlugin *plugin_data, const char *plugin_name, const char **params);
62
#endif
63

                
64
void
65
nntpgrab_plugin_initialize(NGPlugin *plugin_data)
66
{
67
    ng_plugin_set_name(plugin_data, "Unpack");
68
    ng_plugin_set_version(plugin_data, PACKAGE_VERSION);
69
    ng_plugin_set_author(plugin_data, "Erik van Pienbroek");
70
    ng_plugin_set_url(plugin_data, "https://www.nntpgrab.nl");
71
    ng_plugin_set_description(plugin_data, "This plugin is responsible for unpacking files after they've been completely downloaded");
72

                
73
#if GLIB_CHECK_VERSION(2,16,0)
74
    /* Register all the functions which are implemented by this plugin */
75
    ng_plugin_register_function(plugin_data,
76
                                "unpack_do_unpack",
77
                                NG_PLUGIN_FUNCTION(unpack_do_unpack),
78
                                ng_plugin_marshal_BOOLEAN__STRING_STRING_STRING_POINTER,
79
                                G_TYPE_BOOLEAN,
80
                                4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
81

                
82
    /* Indicate the events which we can emit */
83
    ng_plugin_create_event(plugin_data, "unpack_progress_update", 3);
84
    ng_plugin_create_event(plugin_data, "unpack_message_received", 3);
85
    ng_plugin_create_event(plugin_data, "unpack_working_archive_changed", 3);
86
    ng_plugin_create_event(plugin_data, "unpack_success", 2);
87
    ng_plugin_create_event(plugin_data, "unpack_failure", 3);
88

                
89
    /* Add a dependency on the NNTPGrab Core and the PAR2 plugin */
90
    ng_plugin_set_required_event(plugin_data, "collection_downloaded");
91
    ng_plugin_set_required_event(plugin_data, "par2_repair_success");
92
    ng_plugin_set_required_event(plugin_data, "par2_no_repair_required");
93
#endif
94
}
95

                
96
ngboolean
97
nntpgrab_plugin_load(NGPlugin *plugin_data, char **errmsg)
98
{
99
    GError *err = NULL;
100

                
101
#if GLIB_CHECK_VERSION(2,16,0)
102
    plugin_data->priv = g_slice_new0(PluginUnpackPriv);
103
    ((PluginUnpackPriv *) plugin_data->priv)->thread_pool = g_thread_pool_new(perform_automatic_unpack, plugin_data, 1, FALSE, &err);
104

                
105
    if (!((PluginUnpackPriv *) plugin_data->priv)->thread_pool) {
106
        *errmsg = g_strdup_printf(_("%s:%i Unable to create Unpack thread pool: %s"), __FILE__, __LINE__, err->message);
107
        g_error_free(err);
108
        return FALSE;
109
    }
110

                
111
    ng_plugin_connect_event(plugin_data, "collection_downloaded", NG_PLUGIN_FUNCTION(on_collection_downloaded), NULL);
112
    ng_plugin_connect_event(plugin_data, "par2_repair_success", NG_PLUGIN_FUNCTION(on_par2_repair_success), NULL);
113
    ng_plugin_connect_event(plugin_data, "par2_no_repair_required", NG_PLUGIN_FUNCTION(on_par2_no_repair_required), NULL);
114

                
115
    fr_command_register_commands();
116
    return TRUE;
117
#else
118
    /* GLib version too old */
119
    return TRUE;
120
#endif
121
}
122

                
123
ngboolean
124
nntpgrab_plugin_can_unload(NGPlugin *plugin_data, char **reason)
125
{
126
    return TRUE;
127
}
128

                
129
void
130
nntpgrab_plugin_unload(NGPlugin *plugin_data)
131
{
132
#if GLIB_CHECK_VERSION(2,16,0)
133
    /* TODO: fr_command_unregister_commands() */
134

                
135
    g_thread_pool_free(((PluginUnpackPriv *) plugin_data->priv)->thread_pool, TRUE, FALSE);
136
    g_slice_free(PluginUnpackPriv, plugin_data->priv);
137
    plugin_data->priv = NULL;
138
#endif
139
}
140

                
141
void
142
nntpgrab_plugin_destroy(NGPlugin *plugin_data)
143
{
144

                
145
}
146

                
147
int
148
nntpgrab_plugin_get_version(void)
149
{
150
    return NNTPGRAB_PLUGIN_API_VERSION;
151
}
152

                
153
#if GLIB_CHECK_VERSION(2,16,0)
154
static void
155
on_start(FrArchive *archive, FrAction action, gpointer data)
156
{
157
g_print("start: action = %i\n", action);
158
}
159

                
160
static void
161
on_message(FrArchive *archive, const char *message, gpointer data)
162
{
163
    const char *params[4];
164
    struct _unpack_data *unpack_data = data;
165
    PluginUnpackPriv *priv = unpack_data->plugin_data->priv;
166

                
167
    params[0] = priv->collection_name;
168
    params[1] = priv->filename;
169
    params[2] = message;
170
    params[3] = NULL;
171
    ng_plugin_emit_event(unpack_data->plugin_data, "unpack_message_received", params);
172
}
173

                
174
static void
175
on_progress(FrArchive *archive, double progress, gpointer data)
176
{
177
    const char *params[4];
178
    char progress_str[16];
179
    struct _unpack_data *unpack_data = data;
180
    PluginUnpackPriv *priv = unpack_data->plugin_data->priv;
181

                
182
    memset(&progress_str, 0, sizeof(progress_str));
183
    snprintf(progress_str, sizeof(progress_str) - 1, "%.2f", progress);
184

                
185
    params[0] = priv->collection_name;
186
    params[1] = priv->filename;
187
    params[2] = progress_str;
188
    params[3] = NULL;
189

                
190
    ng_plugin_emit_event(unpack_data->plugin_data, "unpack_progress_update", params);
191
}
192

                
193
static void
194
on_working_archive(FrArchive *archive, const char *filename, gpointer data)
195
{
196
    const char *params[4];
197
    struct _unpack_data *unpack_data = data;
198
    char *filename_local = g_filename_from_uri(filename, NULL, NULL);
199
    char *filename_short;
200
    PluginUnpackPriv *priv = unpack_data->plugin_data->priv;
201

                
202
    params[0] = priv->collection_name;
203
    params[1] = priv->filename;
204
    params[3] = NULL;
205

                
206
    if (filename_local) {
207
        /* Maintain a list of all extracted files so we can remove them afterwards */
208
        unpack_data->files_extracted = g_list_append(unpack_data->files_extracted, g_strdup(filename_local));
209

                
210
        filename_short = g_path_get_basename(filename_local);
211
        params[2] = filename_short;
212
        ng_plugin_emit_event(unpack_data->plugin_data, "unpack_working_archive_changed", params);
213
    } else {
214
        filename_short = g_path_get_basename(filename);
215
        params[2] = filename_short;
216
        ng_plugin_emit_event(unpack_data->plugin_data, "unpack_working_archive_changed", params);
217
    }
218

                
219
    g_free(filename_short);
220
    g_free(filename_local);
221
}
222

                
223
static gboolean
224
do_start_unpack(gpointer data)
225
{
226
    struct _unpack_data *unpack_data = data;
227

                
228
    ng_plugin_emit_log_msg(unpack_data->plugin_data, NG_LOG_LEVEL_DEBUG, "Now starting with extract phase");
229

                
230
    unpack_data->now_loading = FALSE;
231
    fr_process_clear (unpack_data->archive->process);
232
    fr_archive_extract_to_local(unpack_data->archive, NULL, unpack_data->target_directory, NULL, FALSE, TRUE, FALSE, NULL);
233
    fr_process_start (unpack_data->archive->process);
234

                
235
    return FALSE;
236
}
237

                
238
static void
239
on_done(FrArchive *archive, FrAction action, FrProcError *error, gpointer data)
240
{
241
    /* Signal the unpack thread that we're finished */
242
    struct _unpack_data *unpack_data = data;
243

                
244
    unpack_data->error_type = error->type;
245
    unpack_data->error_occured = (error->status != 0 || error->type != 0);
246

                
247
    if (error->gerror && error->gerror->message && strlen(error->gerror->message) > 0) {
248
        strncpy(unpack_data->errmsg, error->gerror->message, sizeof(unpack_data->errmsg) - 1);
249
    } else if (error->status != 0) {
250
        snprintf(unpack_data->errmsg, sizeof(unpack_data->errmsg) - 1, "Unknown error occured while unpacking, error->status = %i, error->type = %i", error->status, error->type);
251
    }
252

                
253
    if (action == FR_ACTION_LISTING_CONTENT && !unpack_data->error_occured) {
254
        g_idle_add(do_start_unpack, unpack_data);
255
    }
256

                
257
    if (action == FR_ACTION_EXTRACTING_FILES || unpack_data->error_occured) {
258
        on_progress(archive, 1.0, unpack_data);
259
        if (unpack_data->error_occured) {
260
            on_message(archive, unpack_data->errmsg, unpack_data);
261
        }
262

                
263
        /* Send a signal to the unpack thread that we're done */
264
        g_mutex_lock(unpack_data->mutex);
265
        g_cond_signal(unpack_data->cond);
266
        g_mutex_unlock(unpack_data->mutex);
267
    }
268
}
269

                
270
static gboolean
271
unpack_do_unpack(NGPlugin *plugin_data, const char *collection_name, const char *filename, const char *target_directory, char **errmsg)
272
{
273
    struct _unpack_data *unpack_data;
274
    FrArchive *archive = fr_archive_new();
275
    gboolean ret;
276
    char *filename_uri;
277
    char *filename_short;
278
    GError *err = NULL;
279
    PluginUnpackPriv *priv = plugin_data->priv;
280
    GList *list;
281
    NGConfigOpts opts;
282

                
283
    filename_uri = g_filename_to_uri(filename, NULL, &err);
284
    if (!filename_uri) {
285
        if (errmsg) {
286
            *errmsg = g_strdup_printf(_("Unable to convert filename to URI: %s (filename = %s)"), err->message, filename);
287
        } else {
288
            g_warning(_("Unable to convert filename to URI: %s (filename = %s)"), err->message, filename);
289
        }
290
        g_error_free(err);
291
        return FALSE;
292
    }
293

                
294
    priv->collection_name = collection_name;
295
    priv->filename = filename;
296

                
297
    /* The File Roller code is heavily integrated in the GLib mainloop 
298
     * As this is a seperate thread, we just have to wait here until
299
     * we have received a signal that the extracting has completed */
300
    unpack_data = g_slice_new0(struct _unpack_data);
301
    unpack_data->plugin_data = plugin_data;
302
    unpack_data->cond = g_cond_new();
303
    unpack_data->mutex = g_mutex_new();
304
    unpack_data->archive = archive;
305
    unpack_data->files_extracted = NULL;
306

                
307
    filename_short = g_path_get_basename(filename);
308
    strncpy(unpack_data->filename, filename_short, sizeof(unpack_data->filename) - 1);
309
    g_free(filename_short);
310
    strncpy(unpack_data->target_directory, target_directory, sizeof(unpack_data->target_directory) - 1);
311

                
312
    g_signal_connect(archive, "start", G_CALLBACK(on_start), unpack_data);
313
    g_signal_connect(archive, "done", G_CALLBACK(on_done), unpack_data);
314
    g_signal_connect(archive, "progress", G_CALLBACK(on_progress), unpack_data);
315
    g_signal_connect(archive, "working_archive", G_CALLBACK(on_working_archive), unpack_data);
316
    g_signal_connect(archive, "message", G_CALLBACK(on_message), unpack_data);
317

                
318
    if (!fr_archive_load_local(archive, filename_uri, NULL)) {
319
        if (errmsg) {
320
            *errmsg = g_strdup_printf("Unable to load files to unpack");
321
        }
322

                
323
        g_object_unref(archive);
324
        g_slice_free(struct _unpack_data, unpack_data);
325
        g_free(filename_uri);
326

                
327
        priv->collection_name = NULL;
328
        priv->filename = NULL;
329

                
330
        return FALSE;
331
    }
332

                
333
    /* Wait for a confirmation that extraction was successfull */
334
    g_mutex_lock(unpack_data->mutex);
335
    g_cond_wait(unpack_data->cond, unpack_data->mutex);
336
    g_mutex_unlock(unpack_data->mutex);
337

                
338
    ret = !unpack_data->error_occured;
339
    if (!ret && errmsg) {
340
        *errmsg = g_strdup(unpack_data->errmsg);
341
    }
342

                
343
    /* Add the archive itself to the list of files which need to be removed. 
344
     * For .rar archives spanning multiple files this will be done automatically
345
     * in the 'working_archive_signal' signal, but this signal doesn't occur
346
     * for single file archives */
347
    unpack_data->files_extracted = g_list_append(unpack_data->files_extracted, g_strdup(filename));
348

                
349
    /* Automatically remove the archives if the users wants this */
350
    opts = plugin_data->core_funcs.config_get_opts();
351
    list = unpack_data->files_extracted;
352
    while (list) {
353
        char *path = list->data;
354

                
355
        if (ret && opts.auto_remove_files) {
356
            ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_DEBUG, _("Now automatically removing file '%s'"), path);
357
            g_unlink(path);
358
        }
359

                
360
        g_free(path);
361

                
362
        list = g_list_next(list);
363
    }
364
    g_list_free(unpack_data->files_extracted);
365

                
366
    g_mutex_free(unpack_data->mutex);
367
    g_cond_free(unpack_data->cond);
368
    g_object_unref(archive);
369
    g_slice_free(struct _unpack_data, unpack_data);
370

                
371
    g_free(filename_uri);
372

                
373
    priv->collection_name = NULL;
374
    priv->filename = NULL;
375

                
376
    return ret;
377
}
378

                
379
typedef struct _unpack_file {
380
    char filename_without_extension[256];
381
    char filename[256];
382
} UnpackFile;
383

                
384
struct _unpack_thread_data {
385
    NGPlugin *plugin_data;
386
    char collection_name[256];
387
    NGConfigOpts opts;
388
};
389

                
390
static void
391
perform_automatic_unpack(gpointer data, gpointer user_data)
392
{
393
    struct _unpack_thread_data *thread_data = (struct _unpack_thread_data *) data;
394
    static NGRegex *re = NULL;
395
    const char *filename;
396
    char *target_directory;
397
    char *errmsg = NULL;
398
    GError *err= NULL;
399
    GDir *dir;
400
    GList *list;
401
    GList *files = NULL;
402
    NGPlugin *plugin_data;
403
    const char *collection_name;
404
    NGConfigOpts opts;
405
    static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
406

                
407
    g_static_mutex_lock(&mutex);
408
    if (!re) {
409
        re = nntpgrab_utils_regex_compile(".*\\.part(\\d+)\\.rar$");
410
    }
411

                
412
    plugin_data = thread_data->plugin_data;
413
    collection_name = thread_data->collection_name;
414
    opts = thread_data->opts;
415

                
416
    target_directory = g_build_filename(opts.download_directory, collection_name, NULL);
417
    dir = g_dir_open(target_directory, 0, &err);
418
    if (!dir) {
419
        ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_WARNING, _("Unable to open directory '%s': %s"), target_directory, err->message);
420
        g_error_free(err);
421
        g_free(target_directory);
422
        g_slice_free(struct _unpack_thread_data, thread_data);
423
        g_static_mutex_unlock(&mutex);
424
        return;
425
    }
426

                
427
    while ((filename = g_dir_read_name(dir))) {
428
        /* Is this a file in the notation '.partXXX.rar' ? */
429
        char *filename_lowercase = g_ascii_strdown(filename, -1);
430
        const char **matches;
431

                
432
        if ((matches = nntpgrab_utils_regex_match(re, filename_lowercase))) {
433
            /* Is this .part001.rar ? */
434
            if (matches[0] && matches[1] && atoi(matches[1]) == 1) {
435
                UnpackFile *file = g_slice_new0(UnpackFile);
436

                
437
                strncpy(file->filename, filename, sizeof(file->filename) - 1);
438

                
439
                files = g_list_append(files, file);
440
            }
441

                
442
            nntpgrab_utils_regex_matches_free(matches);
443
        } else if (!strcmp(filename_lowercase + strlen(filename_lowercase) - 4, ".rar")) {
444
            /* A .rar file detected which isn't part of a .partXX.rar set */
445
            UnpackFile *file = g_slice_new0(UnpackFile);
446

                
447
            strncpy(file->filename, filename, sizeof(file->filename) - 1);
448

                
449
            files = g_list_append(files, file);
450
        } else if (!strcmp(filename_lowercase + strlen(filename_lowercase) - 4, ".zip")) {
451
            /* A .zip file detected */
452
            UnpackFile *file = g_slice_new0(UnpackFile);
453

                
454
            strncpy(file->filename, filename, sizeof(file->filename) - 1);
455

                
456
            files = g_list_append(files, file);
457
        } else if (!strcmp(filename_lowercase + strlen(filename_lowercase) -4, ".001")) {
458
            /* Some .001 files can be rar archives, check the mime type for such files */
459
            GFile *file;
460
            GFileInfo *info;
461
            char *path = g_build_filename(target_directory, filename, NULL);
462

                
463
            file = g_file_new_for_path(path);
464
            info = g_file_query_info(file, "standard::content-type", G_FILE_QUERY_INFO_NONE, NULL, NULL);
465
            g_free(path);
466
            if (info) {
467
                if (!strcmp(g_file_info_get_content_type(info), "application/x-rar")) {
468
                    UnpackFile *file = g_slice_new0(UnpackFile);
469

                
470
                    ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_DEBUG, "A .001 file was detected which actually is an rar archive: %s", filename);
471

                
472
                    strncpy(file->filename, filename, sizeof(file->filename) - 1);
473

                
474
                    files = g_list_append(files, file);
475
                } else {
476
                    ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_DEBUG, "A .001 file was detected, but it isn't an rar archive, ignoring: %s", filename);
477
                }
478
                g_object_unref(info);
479
            }
480
            g_object_unref(file);
481
#if 0 
482
        } else {
483
            g_print(__FILE__ ":%i file ignored\n\n", __LINE__);
484
#endif
485
        }
486

                
487
        g_free(filename_lowercase);
488
    }
489

                
490
    g_dir_close(dir);
491

                
492
    /* Perform the unpack */
493
    list = files;
494
    while (list) {
495
        UnpackFile *file = (UnpackFile*) list->data;
496
        char *total_filename = g_build_filename(target_directory, file->filename, NULL);
497
        ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_INFO, _("Now unpacking '%s'"), file->filename);
498

                
499
        if (!unpack_do_unpack(plugin_data, collection_name, total_filename, target_directory, &errmsg)) {
500
            char *params[4];
501

                
502
            if (!errmsg || strlen(errmsg) == 0) {
503
                errmsg = g_strdup_printf(_("process stopped unexpectedly"));
504
            }
505

                
506
            params[0] = collection_name;
507
            params[1] = file->filename;
508
            params[2] = errmsg;
509
            params[3] = NULL;
510
            ng_plugin_emit_event(plugin_data, "unpack_failure", params);
511

                
512
            ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_WARNING, _("Automatic unpack failed due to an error: %s"), errmsg);
513
            g_free(errmsg);
514
        } else {
515
            char *params[3];
516
            params[0] = collection_name;
517
            params[1] = file->filename;
518
            params[2] = NULL;
519
            ng_plugin_emit_event(plugin_data, "unpack_success", params);
520
        }
521

                
522
        ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_INFO, _("Unpack of '%s' finished"), file->filename);
523

                
524
        g_free(total_filename);
525
        g_slice_free(UnpackFile, file);
526
        list = g_list_next(list);
527
    }
528
    g_list_free(files);
529

                
530
    g_free(target_directory);
531
    g_slice_free(struct _unpack_thread_data, thread_data);
532

                
533
    g_static_mutex_unlock(&mutex);
534
}
535

                
536
static gboolean
537
check_if_folder_contains_par2_files(NGPlugin *plugin_data, const char *collection_name)
538
{
539
    NGConfigOpts opts;
540
    char *directory;
541
    GDir *dir;
542
    GError *err;
543
    const char *filename;
544

                
545
    opts = plugin_data->core_funcs.config_get_opts();
546
    directory = g_build_filename(opts.download_directory, collection_name, NULL);
547
    dir = g_dir_open(directory, 0, &err);
548
    if (!dir) {
549
        ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_WARNING, _("Unable to open directory '%s': %s"), directory, err->message);
550
        g_error_free(err);
551
        g_free(directory);
552
        return FALSE;
553
    }
554

                
555
    while ((filename = g_dir_read_name(dir))) {
556
        char *extension;
557

                
558
        extension = g_strrstr(filename, ".");
559
        if (!extension) {
560
            /* File without extension, ignore */
561
            continue;
562
        }
563

                
564
        if (g_ascii_strncasecmp(extension, ".par", 4) != 0) {
565
            /* Different extension, ignore */
566
            continue;
567
        }
568

                
569
        /* File with .par or .par2 extension found */
570
        g_dir_close(dir);
571

                
572
        return TRUE;
573
    }
574

                
575
    g_dir_close(dir);
576

                
577
    return FALSE;
578
}
579

                
580
static void
581
on_collection_downloaded(NGPlugin *plugin_data, const char *collection_name, gpointer data)
582
{
583
    struct _unpack_thread_data *thread_data;
584
    NGConfigOpts opts;
585

                
586
    /* Only try to unpack files here when automatic PAR2 repair is disabled */
587
    opts = plugin_data->core_funcs.config_get_opts();
588

                
589
    if (!opts.enable_auto_unpack || plugin_data->core_funcs.schedular_get_state() != SCHEDULAR_STATE_RUNNING ||
590
        /* If the collection doesn't contain any par2 files, unpack directly */
591
        (opts.enable_par2_repair && check_if_folder_contains_par2_files(plugin_data, collection_name))) {
592

                
593
        /* Come back after the PAR2 repair has completed */
594
        return;
595
    }
596

                
597
    thread_data = g_slice_new0(struct _unpack_thread_data);
598
    thread_data->plugin_data = plugin_data;
599
    strncpy(thread_data->collection_name, collection_name, sizeof(thread_data->collection_name) - 1);
600
    thread_data->opts = opts;
601

                
602
    g_thread_pool_push(((PluginUnpackPriv *) plugin_data->priv)->thread_pool, thread_data, NULL);
603
}
604

                
605
static void
606
on_par2_repair_success(NGPlugin *plugin_data, const char *plugin_name, const char **params)
607
{
608
    struct _unpack_thread_data *thread_data;
609
    NGConfigOpts opts;
610

                
611
    if (!strcmp(params[2], "TRUE")) {
612
        /* This collection still has more PAR2 sets. Try again later when all PAR2 sets in this collection have been verified */
613
        ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_INFO, _("Ignoring automatic unpack for collection '%s' for now because there are more PAR2 sets to process first"), params[0]);
614
        return;
615
    }
616

                
617
    /* Only try to unpack files here when the schedular is still running */
618
    opts = plugin_data->core_funcs.config_get_opts();
619

                
620
    if (!opts.enable_auto_unpack || plugin_data->core_funcs.schedular_get_state() != SCHEDULAR_STATE_RUNNING) {
621
        return;
622
    }
623

                
624
    thread_data = g_slice_new0(struct _unpack_thread_data);
625
    thread_data->plugin_data = plugin_data;
626
    strncpy(thread_data->collection_name, params[0], sizeof(thread_data->collection_name) - 1);
627
    thread_data->opts = opts;
628

                
629
    g_thread_pool_push(((PluginUnpackPriv *) plugin_data->priv)->thread_pool, thread_data, NULL);
630
}
631

                
632
static void
633
on_par2_no_repair_required(NGPlugin *plugin_data, const char *plugin_name, const char **params)
634
{
635
    struct _unpack_thread_data *thread_data;
636
    NGConfigOpts opts;
637

                
638
    if (!strcmp(params[2], "TRUE")) {
639
        /* This collection still has more PAR2 sets. Try again later when all PAR2 sets in this collection have been verified */
640
        ng_plugin_emit_log_msg(plugin_data, NG_LOG_LEVEL_INFO, _("Ignoring automatic unpack for collection '%s' for now because there are more PAR2 sets to process first"), params[0]);
641
        return;
642
    }
643

                
644
    /* Only try to unpack files here when the schedular is still running */
645
    opts = plugin_data->core_funcs.config_get_opts();
646

                
647
    if (!opts.enable_auto_unpack ||plugin_data->core_funcs.schedular_get_state() != SCHEDULAR_STATE_RUNNING) {
648
        return;
649
    }
650

                
651
    thread_data = g_slice_new0(struct _unpack_thread_data);
652
    thread_data->plugin_data = plugin_data;
653
    strncpy(thread_data->collection_name, params[0], sizeof(thread_data->collection_name) - 1);
654
    thread_data->opts = opts;
655

                
656
    g_thread_pool_push(((PluginUnpackPriv *) plugin_data->priv)->thread_pool, thread_data, NULL);
657
}
658
#endif
659