Statistics
| Revision:

root / trunk / client / gui / par2.c @ 1788

History | View | Annotate | Download (28.5 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 "gui.h"
21

                
22
static GtkWidget *treeviewPAR2AndUnpack = NULL;
23
static GtkTreeStore *store = NULL;
24
static GList *items_to_pulse = NULL;
25

                
26
enum {
27
    ACTION_PAR2,
28
    ACTION_UNPACK,
29
};
30

                
31
enum {
32
    FIELD_COLLECTION_NAME,
33
    FIELD_COLLECTION_NAME_HASH,
34
    FIELD_ACTION,
35
    FIELD_ACTION_STR,
36
    FIELD_PAR2_OR_UNPACK_FILENAME,
37
    FIELD_FILENAME,
38
    FIELD_FILENAME_HASH,
39
    FIELD_PROGRESS_VALUE,
40
    FIELD_PROGRESS_STR,
41
    FIELD_PROGRESS_PULSE,
42
    LAST_FIELD,
43
};
44

                
45
static gboolean
46
lookup_collection(const char *collection_name, GtkTreeIter *collection_iter)
47
{
48
    GtkTreeIter iter;
49
    guint hash;
50

                
51
    if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
52
        return FALSE;
53
    }
54

                
55
    hash = g_str_hash(collection_name);
56
    do {
57
        guint hash_row = 0;
58

                
59
        gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FIELD_COLLECTION_NAME_HASH, &hash_row, -1);
60

                
61
        if (hash == hash_row) {
62
            /* Also verify the collection name itself to be sure */
63
            char *collection_name_row = NULL;
64

                
65
            gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FIELD_COLLECTION_NAME, &collection_name_row, -1);
66

                
67
            if (!strcmp(collection_name, collection_name_row)) {
68
                *collection_iter = iter;
69
                g_free(collection_name_row);
70
                return TRUE;
71
            }
72

                
73
            g_free(collection_name_row);
74
        }
75
    } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
76

                
77
    return FALSE;
78
}
79

                
80
static gboolean
81
lookup_filename(GtkTreeIter parent_iter, const char *filename, GtkTreeIter *filename_iter)
82
{
83
    GtkTreeIter iter;
84
    guint hash;
85

                
86
    if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, &parent_iter)) {
87
        return FALSE;
88
    }
89

                
90
    hash = g_str_hash(filename);
91
    do {
92
        guint hash_row = 0;
93

                
94
        gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FIELD_FILENAME_HASH, &hash_row, -1);
95

                
96
        if (hash == hash_row) {
97
            /* Also verify the filename itself to be sure */
98
            char *filename_row = NULL;
99

                
100
            gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FIELD_FILENAME, &filename_row, -1);
101

                
102
            if (!strcmp(filename, filename_row)) {
103
                *filename_iter = iter;
104
                g_free(filename_row);
105
                return TRUE;
106
            }
107

                
108
            g_free(filename_row);
109
        }
110
    } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
111

                
112
    return FALSE;
113
}
114

                
115
static void
116
scroll_to_bottom(GtkTreeIter iter)
117
{
118
    GtkTreePath *path;
119

                
120
    gtk_tree_view_expand_all(GTK_TREE_VIEW(treeviewPAR2AndUnpack));
121
    path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
122
    gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(treeviewPAR2AndUnpack), path, NULL, FALSE, 0.0, 0.0);
123
    gtk_tree_path_free(path);
124
}
125

                
126
static void
127
par2_begin_verify (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, gpointer data)
128
{
129
    GtkTreeIter collection_iter;
130
    GtkTreeIter par2set_iter;
131
    GtkTreePath *path;
132
    char *filename = g_path_get_basename(active_par2_filename);
133

                
134
    if (!lookup_collection(collection_name, &collection_iter)) {
135
        /* Collection not found yet, create a new entry */
136
        gtk_tree_store_append(store, &collection_iter, NULL);
137
        gtk_tree_store_set(store, &collection_iter, FIELD_COLLECTION_NAME, collection_name,
138
                                                    FIELD_COLLECTION_NAME_HASH, g_str_hash(collection_name),
139
                                                    FIELD_FILENAME, collection_name,
140
                                                    FIELD_PROGRESS_PULSE, 1,
141
                                                    FIELD_PROGRESS_STR, "",
142
                                                    -1);
143

                
144
        path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &collection_iter);
145
        items_to_pulse = g_list_prepend(items_to_pulse, gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path));
146
        gtk_tree_path_free(path);
147
    }
148

                
149
    if (lookup_filename(collection_iter, filename, &par2set_iter)) {
150
        /* PAR2 set was already found, clear all the previous contents */
151
        gtk_tree_store_remove(store, &par2set_iter);
152
        memset(&par2set_iter, 0, sizeof(par2set_iter));
153
    }
154

                
155
    gtk_tree_store_append(store, &par2set_iter, &collection_iter);
156
    scroll_to_bottom(par2set_iter);
157
    gtk_tree_store_set(store, &par2set_iter,    FIELD_FILENAME, filename,
158
                                                FIELD_FILENAME_HASH, g_str_hash(filename),
159
                                                FIELD_PAR2_OR_UNPACK_FILENAME, filename,
160
                                                FIELD_ACTION, ACTION_PAR2,
161
                                                FIELD_ACTION_STR, _("PAR2 repair"),
162
                                                FIELD_PROGRESS_STR, _("Now verifying files"),
163
                                                FIELD_PROGRESS_PULSE, 1,
164
                                                -1);
165

                
166
    path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &par2set_iter);
167
    items_to_pulse = g_list_prepend(items_to_pulse, gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path));
168
    gtk_tree_path_free(path);
169

                
170
    g_free(filename);
171
}
172

                
173
static void
174
par2_load_progress_update (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, const char *filename, double progress, gpointer data)
175
{
176
    GtkTreeIter collection_iter;
177
    GtkTreeIter par2set_iter;
178
    GtkTreeIter filename_iter;
179
    char *par2_filename = g_path_get_basename(active_par2_filename);
180

                
181
    if (!lookup_collection(collection_name, &collection_iter)) {
182
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
183
        g_return_if_fail(lookup_collection(collection_name, &collection_iter));
184
    }
185

                
186
    if (!lookup_filename(collection_iter, par2_filename, &par2set_iter)) {
187
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
188
        g_return_if_fail(lookup_filename(collection_iter, par2_filename, &par2set_iter));
189
    }
190

                
191
    if (lookup_filename(par2set_iter, filename, &filename_iter)) {
192
        /* Update the contents of the row */
193
        gtk_tree_store_set(store, &filename_iter, FIELD_PROGRESS_VALUE, (int) (progress), -1);
194
    } else {
195
        gtk_tree_store_append(store, &filename_iter, &par2set_iter);
196
        scroll_to_bottom(filename_iter);
197
        gtk_tree_store_set(store, &filename_iter,   FIELD_FILENAME, filename,
198
                                                    FIELD_FILENAME_HASH, g_str_hash(filename),
199
                                                    FIELD_PROGRESS_VALUE, (int) (progress),
200
                                                    FIELD_PROGRESS_PULSE, -1,
201
                                                    -1);
202
    }
203

                
204
    g_free(par2_filename);
205
}
206

                
207
static void
208
par2_recovery_file_loaded (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, const char *filename, int num_new_packets, int num_blocks_found, gpointer data)
209
{
210
    GtkTreeIter collection_iter;
211
    GtkTreeIter par2set_iter;
212
    GtkTreeIter filename_iter;
213
    char *msg;
214
    char *par2_filename = g_path_get_basename(active_par2_filename);
215

                
216
    if (!lookup_collection(collection_name, &collection_iter)) {
217
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
218
        g_return_if_fail(lookup_collection(collection_name, &collection_iter));
219
    }
220

                
221
    g_return_if_fail(lookup_filename(collection_iter, par2_filename, &par2set_iter));
222

                
223
    msg = g_strdup_printf(_("%i new PAR2 recovery blocks found"), num_blocks_found);
224
    if (lookup_filename(par2set_iter, filename, &filename_iter)) {
225
        /* Update the contents of the row */
226
        gtk_tree_store_set(store, &filename_iter,   FIELD_PROGRESS_VALUE, 100,
227
                                                    FIELD_PROGRESS_STR, msg,
228
                                                    -1);
229
    } else {
230
        gtk_tree_store_append(store, &filename_iter, &par2set_iter);
231
        scroll_to_bottom(filename_iter);
232
        gtk_tree_store_set(store, &filename_iter,   FIELD_FILENAME, filename,
233
                                                    FIELD_FILENAME_HASH, g_str_hash(filename),
234
                                                    FIELD_PROGRESS_VALUE, 100,
235
                                                    FIELD_PROGRESS_STR, msg,
236
                                                    FIELD_PROGRESS_PULSE, -1,
237
                                                    -1);
238
    }
239

                
240
    g_free(msg);
241
    g_free(par2_filename);
242

                
243
    // TODO: Process num_new_packets
244
}
245

                
246
static void
247
par2_file_loaded (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, const char *filename, const char *state, int num_blocks_found, int num_blocks_expected, gpointer data)
248
{
249
    GtkTreeIter collection_iter;
250
    GtkTreeIter par2set_iter;
251
    GtkTreeIter filename_iter;
252
    char *msg;
253
    int progress;
254
    char *par2_filename = g_path_get_basename(active_par2_filename);
255

                
256
    if (!lookup_collection(collection_name, &collection_iter)) {
257
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
258
        g_return_if_fail(lookup_collection(collection_name, &collection_iter));
259
    }
260

                
261
    g_return_if_fail(lookup_filename(collection_iter, par2_filename, &par2set_iter));
262

                
263
    if (!strcmp(state, "MISSING")) {
264
        msg = g_strdup(_("File is missing"));
265
        progress = 0;
266
    } else if (!strcmp(state, "NO_NEW_BLOCKS_FOUND")) {
267
        msg = g_strdup(_("No new blocks found"));
268
        progress = 100;
269
    } else if (num_blocks_expected == num_blocks_found) {
270
        progress = 100;
271
        msg = g_strdup(_("File is complete"));
272
    } else {
273
        double progress_tmp = num_blocks_found;
274
        progress_tmp /= num_blocks_expected;
275
        progress_tmp *= 100.0;
276
        progress = (int) progress_tmp;
277
        msg = g_strdup_printf(_("%i blocks found (expected: %i)"), num_blocks_found, num_blocks_expected);
278
    }
279

                
280
    if (lookup_filename(par2set_iter, filename, &filename_iter)) {
281
        /* Update the contents of the row */
282
        gtk_tree_store_set(store, &filename_iter,   FIELD_PROGRESS_VALUE, progress,
283
                                                    FIELD_PROGRESS_STR, msg,
284
                                                    FIELD_PROGRESS_PULSE, -1,
285
                                                    -1);
286
    } else {
287
        gtk_tree_store_append(store, &filename_iter, &par2set_iter);
288
        scroll_to_bottom(filename_iter);
289
        gtk_tree_store_set(store, &filename_iter,   FIELD_FILENAME, filename,
290
                                                    FIELD_FILENAME_HASH, g_str_hash(filename),
291
                                                    FIELD_PROGRESS_VALUE, progress,
292
                                                    FIELD_PROGRESS_STR, msg,
293
                                                    FIELD_PROGRESS_PULSE, -1,
294
                                                    -1);
295
    }
296

                
297
    g_free(msg);
298
    g_free(par2_filename);
299

                
300
    // TODO: Update the row of the PAR2 set itself with the new progress
301
}
302

                
303
static void
304
par2_repair_progress_update (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, double progress, gpointer data)
305
{
306
    GtkTreeIter collection_iter;
307
    GtkTreeIter par2set_iter;
308
    char *par2_filename = g_path_get_basename(active_par2_filename);
309

                
310
    if (!lookup_collection(collection_name, &collection_iter)) {
311
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
312
        g_return_if_fail(lookup_collection(collection_name, &collection_iter));
313
    }
314

                
315
    g_return_if_fail(lookup_filename(collection_iter, par2_filename, &par2set_iter));
316

                
317
    gtk_tree_store_set(store, &par2set_iter,    FIELD_PROGRESS_VALUE, (int) (progress),
318
                                                FIELD_PROGRESS_STR, _("Repairing"),
319
                                                FIELD_PROGRESS_PULSE, -1,
320
                                                -1);
321

                
322
    g_free(par2_filename);
323
}
324

                
325
static void
326
par2_repair_failure (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, const char *message, int num_blocks_more_required, gpointer data)
327
{
328
    GtkTreeIter collection_iter;
329
    GtkTreeIter par2set_iter;
330
    char *msg;
331
    char *par2_filename = g_path_get_basename(active_par2_filename);
332

                
333
    if (!lookup_collection(collection_name, &collection_iter)) {
334
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
335
        g_return_if_fail(lookup_collection(collection_name, &collection_iter));
336
    }
337

                
338
    gtk_tree_store_set(store, &collection_iter, FIELD_PROGRESS_PULSE, -1, -1);
339

                
340
    g_return_if_fail(lookup_filename(collection_iter, par2_filename, &par2set_iter));
341

                
342
    if (num_blocks_more_required == -1) {
343
        msg = g_strdup(message);
344
    } else {
345
        msg = g_strdup_printf(_("PAR2 repair failed: %i more blocks required"), num_blocks_more_required);
346
    }
347

                
348
    gtk_tree_store_set(store, &par2set_iter,    FIELD_PROGRESS_VALUE, 100,
349
                                                FIELD_PROGRESS_STR, msg,
350
                                                FIELD_PROGRESS_PULSE, -1,
351
                                                -1);
352
    g_free(msg);
353
    g_free(par2_filename);
354
}
355

                
356
static void
357
par2_repair_success (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, gpointer data)
358
{
359
    GtkTreeIter collection_iter;
360
    GtkTreeIter par2set_iter;
361
    char *par2_filename = g_path_get_basename(active_par2_filename);
362

                
363
    if (!lookup_collection(collection_name, &collection_iter)) {
364
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
365
        g_return_if_fail(lookup_collection(collection_name, &collection_iter));
366
    }
367

                
368
    gtk_tree_store_set(store, &collection_iter, FIELD_PROGRESS_PULSE, -1, -1);
369

                
370
    g_return_if_fail(lookup_filename(collection_iter, par2_filename, &par2set_iter));
371

                
372
    gtk_tree_store_set(store, &par2set_iter,    FIELD_PROGRESS_VALUE, 100,
373
                                                FIELD_PROGRESS_STR, _("PAR2 repair succeeded"),
374
                                                FIELD_PROGRESS_PULSE, -1,
375
                                                -1);
376

                
377
    g_free(par2_filename);
378
}
379

                
380
static void
381
par2_no_repair_required (NntpgrabGlue *obj, const char *collection_name, const char *active_par2_filename, gpointer data)
382
{
383
    GtkTreeIter collection_iter;
384
    GtkTreeIter par2set_iter;
385
    char *par2_filename = g_path_get_basename(active_par2_filename);
386

                
387
    if (!lookup_collection(collection_name, &collection_iter)) {
388
        par2_begin_verify(glue, collection_name, active_par2_filename, data);
389
        g_return_if_fail(lookup_collection(collection_name, &collection_iter));
390
    }
391

                
392
    gtk_tree_store_set(store, &collection_iter, FIELD_PROGRESS_PULSE, -1, -1);
393

                
394
    g_return_if_fail(lookup_filename(collection_iter, par2_filename, &par2set_iter));
395

                
396
    gtk_tree_store_set(store, &par2set_iter,    FIELD_PROGRESS_VALUE, 100,
397
                                                FIELD_PROGRESS_STR, _("No repair needed"),
398
                                                FIELD_PROGRESS_PULSE, -1,
399
                                                -1);
400

                
401
    g_free(par2_filename);
402
}
403

                
404
static void
405
unpack_progress_update (NntpgrabGlue *obj, const char *collection_name, const char *filename, double progress, gpointer data)
406
{
407
    GtkTreeIter collection_iter;
408
    GtkTreeIter filename_iter;
409
    int pulse = -1;
410
    char *unpack_filename = g_path_get_basename(filename);
411

                
412
    if (!lookup_collection(collection_name, &collection_iter)) {
413
        /* Collection not found yet, create a new entry */
414
        gtk_tree_store_append(store, &collection_iter, NULL);
415
        gtk_tree_store_set(store, &collection_iter, FIELD_COLLECTION_NAME, collection_name,
416
                                                    FIELD_COLLECTION_NAME_HASH, g_str_hash(collection_name),
417
                                                    FIELD_FILENAME, collection_name,
418
                                                    FIELD_PROGRESS_STR, "",
419
                                                    -1);
420
    }
421

                
422
    if (progress <= 0 ) {
423
        GtkTreePath *path;
424

                
425
        progress = 0;
426
        pulse = 1;
427

                
428
        gtk_tree_store_set(store, &collection_iter, FIELD_PROGRESS_PULSE, pulse, -1);
429

                
430
        path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &collection_iter);
431
        items_to_pulse = g_list_prepend(items_to_pulse, gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path));
432
        gtk_tree_path_free(path);
433
    }
434

                
435
    if (progress == 1.0) {
436
        gtk_tree_store_set(store, &collection_iter, FIELD_PROGRESS_PULSE, -1, -1);
437
    }
438

                
439
    if (lookup_filename(collection_iter, unpack_filename, &filename_iter)) {
440
        /* Unpack file was already found yet, update it */
441
        gtk_tree_store_set(store, &filename_iter,   FIELD_PROGRESS_VALUE, (int) (progress * 100),
442
                                                    FIELD_PROGRESS_PULSE, pulse,
443
                                                    -1);
444

                
445
        if (progress == 1.0) {
446
            gtk_tree_store_set(store, &filename_iter, FIELD_PROGRESS_STR, _("Unpack completed"), -1);
447
        }
448
    } else {
449
        /* Create a new entry */
450
        gtk_tree_store_append(store, &filename_iter, &collection_iter);
451
        scroll_to_bottom(filename_iter);
452
        gtk_tree_store_set(store, &filename_iter,   FIELD_FILENAME, unpack_filename,
453
                                                    FIELD_FILENAME_HASH, g_str_hash(unpack_filename),
454
                                                    FIELD_PAR2_OR_UNPACK_FILENAME, unpack_filename,
455
                                                    FIELD_ACTION, ACTION_UNPACK,
456
                                                    FIELD_ACTION_STR, _("Unpack"),
457
                                                    FIELD_PROGRESS_VALUE, (int) (progress * 100),
458
                                                    FIELD_PROGRESS_STR, _("Now unpacking"),
459
                                                    FIELD_PROGRESS_PULSE, pulse,
460
                                                    -1);
461
    }
462

                
463
    if (pulse > 0) {
464
        GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &filename_iter);
465
        items_to_pulse = g_list_prepend(items_to_pulse, gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path));
466
        gtk_tree_path_free(path);
467
    }
468

                
469
    g_free(unpack_filename);
470
}
471

                
472
static void
473
unpack_message_received (NntpgrabGlue *obj, const char *collection_name, const char *filename, const char *message, gpointer data)
474
{
475
    GtkTreeIter collection_iter;
476
    GtkTreeIter filename_iter;
477
    char *unpack_filename = g_path_get_basename(filename);
478

                
479
    if (!lookup_collection(collection_name, &collection_iter)) {
480
        /* Collection not found yet, create a new entry */
481
        gtk_tree_store_append(store, &collection_iter, NULL);
482
        gtk_tree_store_set(store, &collection_iter, FIELD_COLLECTION_NAME, collection_name,
483
                                                    FIELD_COLLECTION_NAME_HASH, g_str_hash(collection_name),
484
                                                    FIELD_FILENAME, collection_name,
485
                                                    FIELD_PROGRESS_STR, "",
486
                                                    -1);
487
    }
488

                
489
    if (lookup_filename(collection_iter, unpack_filename, &filename_iter)) {
490
        /* Unpack file was already found yet, update it */
491
        gtk_tree_store_set(store, &filename_iter, FIELD_PROGRESS_STR, message, -1);
492
    } else {
493
        /* Create a new entry */
494
        gtk_tree_store_append(store, &filename_iter, &collection_iter);
495
        scroll_to_bottom(filename_iter);
496
        gtk_tree_store_set(store, &filename_iter,   FIELD_FILENAME, unpack_filename,
497
                                                    FIELD_FILENAME_HASH, g_str_hash(unpack_filename),
498
                                                    FIELD_PAR2_OR_UNPACK_FILENAME, unpack_filename,
499
                                                    FIELD_ACTION, ACTION_UNPACK,
500
                                                    FIELD_ACTION_STR, _("Unpack"),
501
                                                    FIELD_PROGRESS_STR, message,
502
                                                    -1);
503
    }
504

                
505
    g_free(unpack_filename);
506
}
507

                
508
static void
509
unpack_working_archive_changed (NntpgrabGlue *obj, const char *collection_name, const char *filename, const char *working_archive, gpointer data)
510
{
511
    GtkTreeIter collection_iter;
512
    GtkTreeIter filename_iter;
513
    char *msg;
514
    char *unpack_filename = g_path_get_basename(filename);
515

                
516
    if (!lookup_collection(collection_name, &collection_iter)) {
517
        /* Collection not found yet, create a new entry */
518
        gtk_tree_store_append(store, &collection_iter, NULL);
519
        gtk_tree_store_set(store, &collection_iter, FIELD_COLLECTION_NAME, collection_name,
520
                                                    FIELD_COLLECTION_NAME_HASH, g_str_hash(collection_name),
521
                                                    FIELD_FILENAME, collection_name,
522
                                                    FIELD_PROGRESS_STR, "",
523
                                                    -1);
524
    }
525

                
526
    msg = g_strdup_printf(_("Now unpacking archive '%s'"), working_archive);
527
    if (lookup_filename(collection_iter, unpack_filename, &filename_iter)) {
528
        /* Unpack file was already found yet, update it */
529
        gtk_tree_store_set(store, &filename_iter, FIELD_PROGRESS_STR, msg, -1);
530
    } else {
531
        /* Create a new entry */
532
        gtk_tree_store_append(store, &filename_iter, &collection_iter);
533
        scroll_to_bottom(filename_iter);
534
        gtk_tree_store_set(store, &filename_iter,   FIELD_FILENAME, unpack_filename,
535
                                                    FIELD_FILENAME_HASH, g_str_hash(unpack_filename),
536
                                                    FIELD_PAR2_OR_UNPACK_FILENAME, unpack_filename,
537
                                                    FIELD_ACTION, ACTION_UNPACK,
538
                                                    FIELD_ACTION_STR, _("Unpack"),
539
                                                    FIELD_PROGRESS_STR, msg,
540
                                                    -1);
541
    }
542

                
543
    g_free(msg);
544
    g_free(unpack_filename);
545
}
546

                
547
static void
548
plugin_event_cb(NntpgrabGlue *obj, const char *plugin_name, const char *event_name, const char **values, gpointer data)
549
{
550
    if (!strcmp(plugin_name, "PAR2")) {
551
        if (!strcmp(event_name, "par2_begin_verify")) {
552
            par2_begin_verify(glue, values[0], values[1], data);
553
        } else if (!strcmp(event_name, "par2_load_progress_update")) {
554
            par2_load_progress_update(glue, values[0], values[1], values[2], g_ascii_strtod(values[3], NULL), data);
555
        } else if (!strcmp(event_name, "par2_recovery_file_loaded")) {
556
            par2_recovery_file_loaded(glue, values[0], values[1], values[2], atoi(values[3]), atoi(values[4]), data);
557
        } else if (!strcmp(event_name, "par2_file_loaded")) {
558
            par2_file_loaded(glue, values[0], values[1], values[2], values[3], atoi(values[4]), atoi(values[5]), data);
559
        } else if (!strcmp(event_name, "par2_repair_progress_update")) {
560
            par2_repair_progress_update(glue, values[0], values[1], g_ascii_strtod(values[2], NULL), data);
561
        } else if (!strcmp(event_name, "par2_repair_failure")) {
562
            par2_repair_failure(glue, values[0], values[1], values[2], atoi(values[3]), data);
563
        } else if (!strcmp(event_name, "par2_repair_success")) {
564
            par2_repair_success(glue, values[0], values[1], data);
565
        } else if (!strcmp(event_name, "par2_no_repair_required")) {
566
            par2_no_repair_required(glue, values[0], values[1], data);
567
        } else {
568
            g_warning("Unknown plugin event received from %s plugin: %s\n", plugin_name, event_name);
569
        }
570
    } else if (!strcmp(plugin_name, "Unpack")) {
571
        if (!strcmp(event_name, "unpack_progress_update")) {
572
            unpack_progress_update(glue, values[0], values[1], g_ascii_strtod(values[2], NULL), data);
573
        } else if (!strcmp(event_name, "unpack_message_received")) {
574
            unpack_message_received(glue, values[0], values[1], values[2], data);
575
        } else if (!strcmp(event_name, "unpack_working_archive_changed")) {
576
            unpack_working_archive_changed(glue, values[0], values[1], values[2], data);
577
        } else if (!strcmp(event_name, "unpack_success")) {
578
            // already handled in unpack_progress_update
579
        } else if (!strcmp(event_name, "unpack_failure")) {
580
            // already handled in unpack_progress_update
581
        } else {
582
            g_warning("Unknown plugin event received from %s plugin: %s\n", plugin_name, event_name);
583
        }
584
    }
585
}
586

                
587
static gboolean
588
update_items_to_pulse(gpointer data)
589
{
590
    GList *list = items_to_pulse;
591

                
592
    while (list) {
593
        GtkTreeRowReference *ref = list->data;
594
        GtkTreeIter iter;
595
        GtkTreePath *path;
596
        int pulse_val;
597

                
598
        if (!gtk_tree_row_reference_valid(ref)) {
599
            items_to_pulse = list = g_list_remove(items_to_pulse, ref);
600
            gtk_tree_row_reference_free(ref);
601
            continue;
602
        }
603

                
604
        path = gtk_tree_row_reference_get_path(ref);
605
        gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path);
606
        gtk_tree_path_free(path);
607

                
608
        gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FIELD_PROGRESS_PULSE, &pulse_val, -1);
609
        if (pulse_val == -1) {
610
            items_to_pulse = list = g_list_remove(items_to_pulse, ref);
611
            gtk_tree_row_reference_free(ref);
612
            continue;
613
        }
614

                
615
        pulse_val++;
616

                
617
        gtk_tree_store_set(store, &iter, FIELD_PROGRESS_PULSE, pulse_val, -1);
618
        list = g_list_next(list);
619
    }
620

                
621
    /* Come back here in a few moments*/
622
    return TRUE;
623
}
624

                
625
void
626
gui_par2_initialize(void)
627
{
628
    GtkCellRenderer *cellRenderer;
629
    GtkTreeViewColumn *col;
630

                
631
    treeviewPAR2AndUnpack = nntpgrab_gui_base_get_widget("treeviewPAR2AndUnpack");
632

                
633
    cellRenderer = gtk_cell_renderer_text_new();
634
    col = gtk_tree_view_column_new_with_attributes(_("Filename"), cellRenderer, "text", 5, NULL);
635
    gtk_tree_view_column_set_resizable(col, TRUE);
636
    gtk_tree_view_column_set_reorderable(col, TRUE);
637
    gtk_tree_view_insert_column(GTK_TREE_VIEW(treeviewPAR2AndUnpack), col, -1);
638

                
639
    cellRenderer = gtk_cell_renderer_text_new();
640
    col = gtk_tree_view_column_new_with_attributes(_("Action"), cellRenderer, "text", 3, NULL);
641
    gtk_tree_view_column_set_resizable(col, TRUE);
642
    gtk_tree_view_column_set_reorderable(col, TRUE);
643
    gtk_tree_view_insert_column(GTK_TREE_VIEW(treeviewPAR2AndUnpack), col, -1);
644

                
645
    cellRenderer = gtk_cell_renderer_progress_new();
646
#if GTK_CHECK_VERSION(2,12,0)
647
    col = gtk_tree_view_column_new_with_attributes(_("Progress"), cellRenderer, "value", 7, "text", 8, "pulse", 9, NULL);
648
#else
649
    col = gtk_tree_view_column_new_with_attributes(_("Progress"), cellRenderer, "value", 7, "text", 8, NULL);
650
#endif
651
    gtk_tree_view_column_set_resizable(col, TRUE);
652
    gtk_tree_view_column_set_reorderable(col, TRUE);
653
    gtk_tree_view_insert_column(GTK_TREE_VIEW(treeviewPAR2AndUnpack), col, -1);
654

                
655
    store = gtk_tree_store_new (LAST_FIELD,
656
                                G_TYPE_STRING,  /* FIELD_COLLECTION_NAME */
657
                                G_TYPE_UINT,    /* FIELD_COLLECTION_NAME_HASH */
658
                                G_TYPE_INT,     /* FIELD_ACTION */
659
                                G_TYPE_STRING,  /* FIELD_ACTION_STR */
660
                                G_TYPE_STRING,  /* FIELD_PAR2_OR_UNPACK_FILENAME */
661
                                G_TYPE_STRING,  /* FIELD_FILENAME */
662
                                G_TYPE_UINT,    /* FIELD_FILENAME_HASH */
663
                                G_TYPE_INT,     /* FIELD_PROGRESS_VALUE */
664
                                G_TYPE_STRING,  /* FIELD_PROGRESS_STR */
665
                                G_TYPE_UINT    /* FIELD_PROGRESS_PULSE */
666
                               );
667

                
668
    gtk_tree_view_set_model(GTK_TREE_VIEW(treeviewPAR2AndUnpack), GTK_TREE_MODEL(store));
669

                
670
    nntpgrab_glue_signal_connect(glue, "plugin_event", NG_CALLBACK(plugin_event_cb), NULL);
671

                
672
    g_timeout_add(500, update_items_to_pulse, NULL);
673
}