Revision 1644

tags/nntpgrab-0.6.2/NNTPGrab.includes (revision 1644)
1
automation
2
base
3
client/gui
4
client/macosx
5
client/web/module
6
glue
7
gui_base
8
indexer
9
nntpgrab_core
10
plugins/decoder
11
plugins/jsonrpc
12
plugins/par2/par2cmdline
13
plugins/par2
14
plugins/unpack/file-roller/copy-n-paste
15
plugins/unpack/file-roller/nautilus
16
plugins/unpack/file-roller/src
17
plugins/unpack
18
server_qt
19
../deps/include
20
../deps/include/gio-unix-2.0
21
../deps/include/gio-unix-2.0/gio
22
../deps/include/glib-2.0
23
../deps/include/glib-2.0/gio
24
../deps/include/glib-2.0/glib
25
../deps/include/glib-2.0/gobject
26
../deps/include/libsoup-2.4
27
../deps/include/libsoup-2.4/libsoup
28
/usr/include
29
/usr/include/libxml2
30
/usr/include/glib-2.0
31
/usr/include/glib-2.0/glib
32
/usr/include/glib-2.0/gobject
33
/usr/include/glib-2.0/gthread
34
/usr/include/pango-1.0
35
/usr/include/pango-1.0/pango
36
/usr/include/gtk-2.0
37
/usr/include/gtk-2.0/gdk
38
/usr/include/gtk-2.0/gdk-pixbuf
39
/usr/include/gtk-2.0/gdk-pixbuf-xlib
40
/usr/include/libgtkhtml-3.14
41
/usr/include/libgtkhtml-3.14/editor
42
/usr/include/libgtkhtml-3.14/gtkhtml
43
/usr/lib64/glib-2.0/include
tags/nntpgrab-0.6.2/nntpgrab_core/decoder_thread.h (revision 1644)
1
/*
2
    Copyright (C) 2005-2009  Erik van Pienbroek
3

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

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

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

                
19
#ifndef _DECODER_THREAD_H_
20
#define _DECODER_THREAD_H_
21

                
22
#include "collections.h"
23
#include "configuration.h"
24

                
25
typedef struct _decoder_data {
26
    NNTPCollection  *collection;
27
    NNTPFile        *file;
28
    //GThreadPool     *poolPar2verify;
29
    //GThreadPool     *poolPar2repair;
30
    //GThreadPool     *poolUnpack;
31
} DecoderData;
32

                
33
void         decoder_thread_initialize(Configuration *config);
34
void         decoder_thread_destroy(void);
35
gboolean     decoder_thread_start(void);
36
gboolean     decoder_thread_stop(void);
37
void         decoder_thread_push_task(DecoderData *task);
38

                
39
#endif /* _DECODER_THREAD_H_ */
tags/nntpgrab-0.6.2/nntpgrab_core/collection_alloc.c (revision 1644)
1
/*
2
    Copyright (C) 2005-2009  Erik van Pienbroek
3

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

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

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

                
19
#ifdef _MSC_VER
20
#include "config.h.win32"
21
#else
22
#include "config.h"
23
#endif
24

                
25
#include 
26
#include "nntpgrab_types.h"
27
#include "collections.h"
28
#include "collection_alloc.h"
29

                
30
NNTPFile *
31
file_new(void)
32
{
33
    NNTPFile *file = g_slice_new0(NNTPFile);
34
    file_ref(file);
35
    return file;
36
}
37

                
38
void
39
file_ref(NNTPFile *file)
40
{
41
    g_atomic_int_inc(&file->refcount);
42
//    g_print("file_ref: refcount = %i for subject %s\n", file->refcount, file->subject);
43
}
44

                
45
void
46
file_unref(NNTPFile *file)
47
{
48
    GList *groups;
49
    GList *parts;
50

                
51
    if (!g_atomic_int_dec_and_test(&file->refcount)) {
52
//        g_print("file_unref: refcount = %i for subject %s\n", file->refcount, file->subject);
53
        return;
54
    }
55

                
56
//    g_print("file_unref: refcount = %i for subject %s\n", file->refcount, file->subject);
57
//    g_print("releasing file\n");
58

                
59
    groups = file->groups;
60
    while (groups) {
61
        g_free(groups->data);
62
        groups = g_list_next(groups);
63
    }
64

                
65
    g_list_free(file->groups);
66

                
67
    parts = file->parts;
68
    while (parts) {
69
        g_slice_free(NNTPPart, parts->data);
70
        parts = g_list_next(parts);
71
    }
72

                
73
    g_list_free(file->parts);
74

                
75
    g_slice_free(NNTPFile, file);
76
}
77

                
78
NNTPCollection *
79
collection_new(void)
80
{
81
    NNTPCollection *collection = g_slice_new0(NNTPCollection);
82
    g_static_mutex_init(&collection->mutex);
83
    collection_ref(collection);
84
    return collection;
85
}
86

                
87
void
88
collection_ref(NNTPCollection *collection)
89
{
90
    g_atomic_int_inc(&collection->refcount);
91
//    g_print("collection_ref: refcount = %i for collection %s\n", collection->refcount, collection->collection_name);
92
}
93

                
94
void
95
collection_unref(NNTPCollection *collection)
96
{
97
    GList *files;
98

                
99
    if (!g_atomic_int_dec_and_test(&collection->refcount)) {
100
//        g_print("collection_unref: refcount = %i for collection %s\n", collection->refcount, collection->collection_name);
101
        return;
102
    }
103

                
104
//    g_print("collection_unref: refcount = %i for collection %s\n", collection->refcount, collection->collection_name);
105
//    g_print("releasing collection\n");
106

                
107
    files = collection->files;
108
    while (files) {
109
        NNTPFile *file = (NNTPFile *) files->data;
110

                
111
        file_unref(file);
112

                
113
        files = g_list_next(files);
114
    }
115

                
116
    g_list_free(collection->files);
117
    g_list_free(collection->files_to_download);
118

                
119
    g_slice_free(NNTPCollection, collection);
120
}
tags/nntpgrab-0.6.2/nntpgrab_core/throttle.c (revision 1644)
1
/*
2
    Copyright (C) 2005-2009  Erik van Pienbroek
3

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

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

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

                
19
/* Parts of this file are taken from ProFTP's throttle.c */
20

                
21
#include 
22
#include 
23
#include 
24
#include 
25
#include 
26
#ifdef WIN32
27
#include 
28
#endif
29
#include "nntpgrab.h"
30
#include "nntpgrab_plugin.h"
31

                
32
/* This allows a throttling process to be killed by the admin */
33
#ifndef WIN32
34
static void
35
xfer_rate_sigmask(int block)
36
{
37
    static sigset_t sig_set;
38

                
39
    if (block) {
40
        sigemptyset(&sig_set);
41

                
42
        sigaddset(&sig_set, SIGCHLD);
43
        sigaddset(&sig_set, SIGUSR1);
44
        sigaddset(&sig_set, SIGINT);
45
        sigaddset(&sig_set, SIGQUIT);
46
#ifdef SIGIO
47
        sigaddset(&sig_set, SIGIO);
48
#endif /* SIGIO */
49
#ifdef SIGBUS
50
        sigaddset(&sig_set, SIGBUS);
51
#endif /* SIGBUS */
52
        sigaddset(&sig_set, SIGHUP);
53

                
54
        while (sigprocmask(SIG_BLOCK, &sig_set, NULL) < 0) {
55
            if (errno == EINTR) {
56
                continue;
57
            }
58

                
59
            break;
60
        }
61
    } else {
62
        while (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
63
            if (errno == EINTR) {
64
                continue;
65
            }
66

                
67
            break;
68
        }
69
    }
70
}
71
#endif
72

                
73
/* Returns the difference, in milliseconds, between the given timeval and now */
74
static long
75
xfer_rate_since(struct timeval *then)
76
{
77
    struct timeval now;
78
    gettimeofday(&now, NULL);
79

                
80
    return (((now.tv_sec - then->tv_sec) * 1000L) + ((now.tv_usec - then->tv_usec) / 1000L));
81
}
82

                
83
void
84
throttle_pause(struct timeval start_time, off_t xferlen, int max_bandwidth)
85
{
86
    long double xfer_rate_bps;
87
    long ideal = 0, elapsed = 0;
88

                
89
    /* Calculate the time interval since the transfer of data started. */
90
    elapsed = xfer_rate_since(&start_time);
91
    xfer_rate_bps = max_bandwidth * 1024.0;
92

                
93
    ideal = (xferlen * 1000L) / xfer_rate_bps;
94

                
95
    if (ideal > elapsed) {
96
        struct timeval tv;
97

                
98
        /* Setup for the select.  We use select() instead of usleep() because it
99
         * seems to be far more portable across platforms.
100
         *
101
         * ideal and elapsed are in milleconds, but tv_usec will be microseconds,
102
         * so be sure to convert properly.
103
         */
104
        tv.tv_usec = (ideal - elapsed) * 1000;
105
        tv.tv_sec = tv.tv_usec / 1000000L;
106
        tv.tv_usec = tv.tv_usec % 1000000L;
107

                
108
        ng_plugin_emit_log_msg(NULL, NG_LOG_LEVEL_DEBUG, "transferring too fast, delaying %ld sec%s, %ld usecs",
109
            (long int) tv.tv_sec, tv.tv_sec == 1 ? "" : "s", (long int) tv.tv_usec);
110

                
111
#ifdef WIN32
112
        /* Stupid Win32 doesn't support the select() function with no sockets attached.. */
113
        Sleep(ideal - elapsed);
114
#else
115
        /* No interruptions, please... */
116
        xfer_rate_sigmask(TRUE);
117

                
118
        if (select(0, NULL, NULL, NULL, &tv) < 0) {
119
            ng_plugin_emit_log_msg(NULL, NG_LOG_LEVEL_WARNING, "warning: unable to throttle bandwidth: %s", strerror(errno));
120
        }
121

                
122
        xfer_rate_sigmask(FALSE);
123
#endif
124
    }
125

                
126
    return;
127
}
tags/nntpgrab-0.6.2/nntpgrab_core/collection_alloc.h (revision 1644)
1
/*
2
    Copyright (C) 2005-2009  Erik van Pienbroek
3

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

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

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

                
19
#ifndef _COLLECTION_ALLOC_H_
20
#define _COLLECTION_ALLOC_H_
21

                
22
NNTPFile        *file_new(void);
23
void             file_ref(NNTPFile *file);
24
void             file_unref(NNTPFile *file);
25
NNTPCollection  *collection_new(void);
26
void             collection_ref(NNTPCollection *collection);
27
void             collection_unref(NNTPCollection *collection);
28

                
29
#endif /* _COLLECTION_ALLOC_H_ */
tags/nntpgrab-0.6.2/nntpgrab_core/download_queue.c (revision 1644)
1
/*
2
    Copyright (C) 2005-2009  Erik van Pienbroek
3

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

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

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

                
19
#include 
20
#include 
21
#include 
22
#include 
23
#include "nntpgrab.h"
24
#include "nntpgrab_internal.h"
25
#include "nntpgrab_plugin.h"
26
#include "nntpgrab_utils.h"
27
#include "nntpconnection.h"
28
#include "queue_sqlite.h"
29
#include "download_queue.h"
30
#include "collection_alloc.h"
31
#include "configuration.h"
32
#include "decoder_thread.h"
33
#include "download_thread.h"
34

                
35
static GStaticMutex  mutex = G_STATIC_MUTEX_INIT;
36
static GList        *download_queue = NULL;
37
static int           num_servers = 0;
38
static int           num_enabled_servers = 0;
39
static unsigned int  is_high_priority_server;  /* These are actually a bit-masked variable where every server has one bit */
40
static unsigned int  is_normal_priority_server;
41
static unsigned int  is_server_enabled;
42
static ConfigOpts    opts;
43

                
44
static void
45
rebuild_download_queue_list(NNTPCollection *collection)
46
{
47
    GList *list_file;
48

                
49
    // Clear out any old items in the list
50
    g_list_free(collection->files_to_download);
51
    collection->files_to_download = NULL;
52

                
53
    list_file = collection->files;
54
    while (list_file) {
55
        NNTPFile *file = list_file->data;
56

                
57
        if (!file->file_is_downloaded) {
58
            collection->files_to_download = g_list_append(collection->files_to_download, file);
59
        }
60

                
61
        list_file = g_list_next(list_file);
62
    }
63
}
64

                
65
static gboolean
66
get_bit_value(unsigned int param, int pos)
67
{
68
    unsigned int shifted = param >> pos;
69

                
70
    return ((shifted & 0x1) == 0x1);
71
}
72

                
73
static void
74
set_bit_value(unsigned int *param, int pos, gboolean value)
75
{
76
    unsigned int mask = 0x1 << pos;
77

                
78
    if (value) {
79
        *param = *param ^ mask;
80
    } else {
81
        mask = ~mask;
82
        *param = *param & mask;
83
    }
84
}
85

                
86
static gboolean
87
test_server_may_download_part(NNTPPart *part, int server_id)
88
{
89
    if (!get_bit_value(is_server_enabled, server_id)) {
90
        return FALSE;
91
    }
92

                
93
    if (get_bit_value(part->servers_already_tried, server_id)) {
94
        return FALSE;
95
    }
96

                
97
    // Is this server one with the highest priority ?
98
    if (get_bit_value(is_high_priority_server, server_id)) {
99
        return TRUE;
100
    }
101

                
102
    // Are all the other high-priority servers already tried ?
103
    if ((is_high_priority_server & part->servers_already_tried) != is_high_priority_server) {
104
        return FALSE;
105
    }
106

                
107
    // All the high-priority servers are already tried, now test against the servers with the 'normal' priority
108
    if (get_bit_value(is_normal_priority_server, server_id)) {
109
        return TRUE;
110
    }
111

                
112
    if ((is_normal_priority_server & part->servers_already_tried) != is_normal_priority_server) {
113
        return FALSE;
114
    }
115

                
116
    // All the normal priority servers are also tried, allow the part
117

                
118
    return TRUE;
119
}
120

                
121
static gboolean
122
on_config_changed(Configuration *config, gpointer data)
123
{
124
    GList *list, *avail_servers;
125
    int i;
126

                
127
    g_static_mutex_lock(&mutex);
128

                
129
    opts = configuration_get_opts(config);
130

                
131
    is_high_priority_server = 0;
132
    is_normal_priority_server = 0;
133
    is_server_enabled = 0;
134
    num_enabled_servers = 0;
135
    num_servers = 0;
136

                
137
    avail_servers = configuration_get_avail_servers(config);
138
    list = avail_servers;
139
    i = 0;
140

                
141
    while (list) {
142
        char *servername = list->data;
143
        ConfigServer *server = configuration_get_server_info(config, servername);
144

                
145
        g_return_val_if_fail(server != NULL, FALSE);
146

                
147
        if (server->enabled) {
148
            num_enabled_servers++;
149

                
150
            if (server->priority == SERVER_PRIORITY_HIGH) {
151
                set_bit_value(&is_high_priority_server, i, TRUE);
152
                set_bit_value(&is_normal_priority_server, i, FALSE);
153
            } else if (server->priority == SERVER_PRIORITY_LOW) {
154
                set_bit_value(&is_high_priority_server, i, FALSE);
155
                set_bit_value(&is_normal_priority_server, i, FALSE);
156
            } else {
157
                set_bit_value(&is_high_priority_server, i, FALSE);
158
                set_bit_value(&is_normal_priority_server, i, TRUE);;
159
            }
160
        }
161

                
162
        set_bit_value(&is_server_enabled, i, server->enabled);
163

                
164
        i++;
165
        num_servers++;
166

                
167
        g_free(servername);
168
        g_slice_free(ConfigServer, server);
169

                
170
        list = g_list_next(list);
171
    }
172

                
173
    g_list_free(avail_servers);
174

                
175
    g_static_mutex_unlock(&mutex);
176

                
177
    return FALSE;
178
}
179

                
180
gboolean
181
download_queue_init(Configuration *config, char **errmsg)
182
{
183
    GList *list;
184

                
185
    g_return_val_if_fail(download_queue == NULL, FALSE);
186

                
187
    if (!queue_sqlite_load(&download_queue, errmsg)) {
188
        return FALSE;
189
    }
190

                
191
    g_signal_connect(config, "config_changed", G_CALLBACK(on_config_changed), NULL);
192
    on_config_changed(config, NULL);
193

                
194
    list = download_queue;
195
    while (list) {
196
        NNTPCollection *collection = list->data;
197

                
198
        rebuild_download_queue_list(collection);
199

                
200
        list = g_list_next(list);
201
    }
202

                
203
    return TRUE;
204
}
205

                
206
gboolean
207
download_queue_destroy(char **errmsg)
208
{
209
    g_static_mutex_lock(&mutex);
210

                
211
    if (!queue_sqlite_save(download_queue, errmsg)) {
212
        g_static_mutex_unlock(&mutex);
213
        return FALSE;
214
    }
215

                
216
    queue_sqlite_free(download_queue);
217
    download_queue = NULL;
218

                
219
    g_static_mutex_unlock(&mutex);
220

                
221
    return TRUE;
222
}
223

                
224
gboolean
225
download_queue_save(char **errmsg)
226
{
227
    gboolean retval;
228

                
229
    g_static_mutex_lock(&mutex);
230
    retval = queue_sqlite_save(download_queue, errmsg);
231
    g_static_mutex_unlock(&mutex);
232

                
233
    return retval;
234
}
235

                
236
gboolean
237
download_queue_get_next_part_to_download(NNTPCollection **collection, NNTPFile **file, NNTPPart **part, int server_id, gboolean *nothing_to_download)
238
{
239
    GList *list;
240

                
241
    g_return_val_if_fail(collection != NULL, FALSE);
242
    g_return_val_if_fail(file != NULL, FALSE);
243
    g_return_val_if_fail(part != NULL, FALSE);
244
    g_return_val_if_fail(server_id >= 0, FALSE);
245
    g_return_val_if_fail(nothing_to_download != NULL, FALSE);
246

                
247
    ng_plugin_emit_log_msg(NULL, NG_LOG_LEVEL_INFO, "download_queue_get_next_part_to_download for server_id %i", server_id);
248

                
249
    *nothing_to_download = TRUE;
250

                
251
    if (num_enabled_servers == 0) {
252
        /* No enabled servers found, don't even bother checking the queue */
253
        return FALSE;
254
    }
255

                
256
    g_static_mutex_lock(&mutex);
257

                
258
    list = download_queue;
259
    while (list) {
260
        GList *list2;
261

                
262
        *collection = (NNTPCollection *) list->data;
263

                
264
        // Is this collection being removed ?
265
        if ((*collection)->stop_flag) {
266
            list = g_list_next(list);
267
            continue;
268
        }
269

                
270
        list2 = (*collection)->files_to_download;
271
        while (list2) {
272
            GList *list3;
273
            gboolean complete_flag;
274

                
275
            *file = (NNTPFile *) list2->data;
276

                
277
            // Is this file already downloaded?
278
            if ((*file)->file_is_downloaded) {
279
                // Yes, remove it from the files_to_download list and start over
280
                (*collection)->files_to_download = g_list_remove((*collection)->files_to_download, list2->data);
281
                list2 = (*collection)->files_to_download;
282
                continue;
283
            }
284

                
285
            if ((*file)->now_decoding) {
286
                list2 = g_list_next(list2);
287
                continue;
288
            }
289

                
290
            // Is this file being removed?
291
            if ((*file)->stop_flag) {
292
                list2 = g_list_next(list2);
293
                continue;
294
            }
295

                
296
            complete_flag = TRUE;
297
            list3 = (*file)->parts;
298
            while (list3) {
299
                *part = (NNTPPart *) list3->data;
300

                
301
                if ((*part)->now_downloading) {
302
                    complete_flag = FALSE;
303
                    *nothing_to_download = FALSE;
304
                }
305

                
306
                if (!(*part)->downloaded) {
307
                    if (!(*part)->now_downloading && test_server_may_download_part(*part, server_id)) {
308
                        (*part)->now_downloading = TRUE;
309
                        (*file)->file_is_downloading = TRUE;
310

                
311
                        g_static_mutex_unlock(&mutex);
312

                
313
                        *nothing_to_download = FALSE;
314

                
315
                        ng_plugin_emit_log_msg(NULL, NG_LOG_LEVEL_DEBUG, "Returned part %i from file '%s' from collection '%s'", (*part)->part_num, (*file)->subject, (*collection)->collection_name);
316

                
317
                        return TRUE;
318
                    }
319

                
320
                    // Are all the servers already tried ?
321
                    if ((is_server_enabled & (*part)->servers_already_tried) == is_server_enabled) {
322
                        complete_flag = TRUE;
323
                    } else {
324
                        complete_flag = FALSE;
325
                        *nothing_to_download = FALSE;
326
                    }
327
                }
328

                
329
                list3 = g_list_next(list3);
330
            }
331

                
332
            // All the parts are already downloaded?
333
            if (complete_flag && !(*file)->now_decoding) {
334
                DecoderData *decoder_data;
335

                
336
                ng_plugin_emit_log_msg(NULL, NG_LOG_LEVEL_DEBUG, "File '%s' from collection '%s' is now ready to be decoded", (*file)->subject, (*collection)->collection_name);
337

                
338
                (*file)->now_decoding = TRUE;
339

                
340
                nntpgrab_core_emit_file_state_changed(FALSE, (*collection)->collection_name, (*file)->subject, NULL, (*file)->status, TASK_STATE_WAITING_FOR_DECODE);
341

                
342
                (*file)->status = TASK_STATE_WAITING_FOR_DECODE;
343

                
344
                decoder_data = g_slice_new0(DecoderData);
345
                decoder_data->collection = (*collection);
346
                decoder_data->file = (*file);
347
                //decoder_data->poolPar2verify = poolPar2verify;
348
                //decoder_data->poolPar2repair = poolPar2repair;
349
                //decoder_data->poolUnpack = poolUnpack;
350

                
351
                file_ref(*file);
352
                collection_ref(*collection);
353

                
354
                decoder_thread_push_task(decoder_data);
355
            }
356

                
357
            list2 = g_list_next(list2);
358
        }
359

                
360
        list = g_list_next(list);
361
    }
362

                
363
    *collection = NULL;
364
    *file = NULL;
365
    *part = NULL;
366

                
367
    g_static_mutex_unlock(&mutex);
368

                
369
    return FALSE;
370
}
371

                
372
void
373
download_queue_update_part_status(NNTPConnectionInfo *conn, NNTPCollection *collection, NNTPFile *file, NNTPPart *part, int server_id, gboolean success, gboolean reset_to_zero, gboolean dont_retry_anymore)
374
{
375
    GList *list;
376

                
377
    g_return_if_fail(conn != NULL);
378
    g_return_if_fail(collection != NULL);
379
    g_return_if_fail(file != NULL);
380
    g_return_if_fail(part != NULL);
381
    g_return_if_fail(server_id >= 0);
382

                
383
    g_static_mutex_lock(&collection->mutex);
384

                
385
    part->now_downloading = FALSE;
386
    part->downloaded = success;
387
    file->file_is_downloading = FALSE;
388

                
389
    if (!file->file_is_new) {
390
        file->file_is_changed = TRUE;
391
    }
392

                
393
    if (success) {
394
        if (file->file_size_remaining < part->size) {
395
            g_print("Invalid file size remaining!\n");
396
            g_print("file->file_size_remaining = %"G_GUINT64_FORMAT"\n", file->file_size_remaining);
397
            g_print("part->size = %i\n", part->size);
398
            file->file_size_remaining = part->size;
399
        }
400

                
401
        if (collection->total_size_remaining < part->size) {
402
            g_print("Invalid collection size remaining!\n");
403
            g_print("collection->total_size_remaining = %"G_GUINT64_FORMAT"\n", collection->total_size_remaining);
404
            g_print("part->size = %i\n", part->size);
405
            collection->total_size_remaining = part->size;
406
        }
407

                
408
        file->file_size_remaining -= part->size;
409
        collection->total_size_remaining -= part->size;
410
        file->num_parts_downloaded++;
411

                
412
        nntpgrab_core_emit_part_done(FALSE, conn->server_info.servername, conn->poll_fd.fd, collection->collection_name, file->subject, part->part_num, part->size);
413

                
414
        nntpgrab_core_emit_file_download_state_update(FALSE, collection->collection_name, file->subject, file->num_parts, file->num_parts_downloaded, file->num_parts_failed, file->file_size, file->file_size_remaining, collection->total_size, collection->total_size_remaining);
415
    } else if (!success && dont_retry_anymore) {
416
        set_bit_value(&part->servers_already_tried, server_id, TRUE);
417
    }
418

                
419
    // Are other threads downloading parts of this file ?
420
    list = file->parts;
421
    while (list) {
422
        NNTPPart *part2 = list->data;
423

                
424
        if (part2->now_downloading) {
425
            file->file_is_downloading = TRUE;
426
        }
427

                
428
        list = g_list_next(list);
429
    }
430

                
431
    // Are all the servers already tried ?
432
    if (!success && dont_retry_anymore) {
433
        gboolean all_servers_tried = TRUE;
434

                
435
        if ((is_server_enabled & part->servers_already_tried) == is_server_enabled) {
436
            all_servers_tried = TRUE;
437
        } else {
438
            all_servers_tried = FALSE;
439
        }
440

                
441
        nntpgrab_core_emit_part_failed(FALSE, conn->server_info.servername, conn->poll_fd.fd, collection->collection_name, file->subject, part->part_num, part->size, all_servers_tried);
442

                
443
        if (all_servers_tried && !reset_to_zero) {
444
            if (file->file_size_remaining < part->size) {
445
                g_print("Invalid file size remaining!\n");
446
                g_print("file->file_size_remaining = %"G_GUINT64_FORMAT"\n", file->file_size_remaining);
447
                g_print("part->size = %i\n", part->size);
448
                file->file_size_remaining = part->size;
449
            }
450

                
451
            if (collection->total_size_remaining < part->size) {
452
                g_print("Invalid collection size remaining!\n");
453
                g_print("collection->total_size_remaining = %"G_GUINT64_FORMAT"\n", collection->total_size_remaining);
454
                g_print("part->size = %i\n", part->size);
455
                collection->total_size_remaining = part->size;
456
            }
457

                
458
            /* Assume the part was downloaded as all servers were tried and no one had the part we requested */
459
            part->downloaded = TRUE;
460

                
461
            file->num_parts_failed++;
462
            file->file_size_remaining -= part->size;
463
            collection->total_size_remaining -= part->size;
464

                
465
            nntpgrab_core_emit_file_download_state_update(FALSE, collection->collection_name, file->subject, file->num_parts, file->num_parts_downloaded, file->num_parts_failed, file->file_size, file->file_size_remaining, collection->total_size, collection->total_size_remaining);
466
        }
467
    }
468

                
469
    if (reset_to_zero) {
470
        file->num_parts_downloaded = 0;
471
        file->num_parts_failed = 0;
472

                
473
        nntpgrab_core_emit_file_download_state_update(FALSE, collection->collection_name, file->subject, file->num_parts, file->num_parts_downloaded, file->num_parts_failed, file->file_size, file->file_size_remaining, collection->total_size, collection->total_size_remaining);
474
    }
475

                
476
    g_static_mutex_unlock(&collection->mutex);
477
}
478

                
479
static gboolean
480
test_is_subject_already_in_collection(NNTPCollection *collection, const char *subject)
481
{
482
    GList *list;
483

                
484
    list = collection->files;
485
    while (list) {
486
        NNTPFile *file = (NNTPFile *) list->data;
487

                
488
        if (!strcmp(file->subject, subject)) {
489
            return TRUE;
490
        }
491

                
492
        list = g_list_next(list);
493
    }
494

                
495
    return FALSE;
496
}
497

                
498
static gboolean
499
test_if_collection_contains_same_poster(NNTPCollection *collection, const char *poster)
500
{
501
    GList *list;
502

                
503
    list = collection->files;
504
    while (list) {
505
        NNTPFile *file = (NNTPFile *) list->data;
506

                
507
        if (strcmp(file->poster, poster)) {
508
            /* Different poster found */
509
            return FALSE;
510
        }
511

                
512
        list = g_list_next(list);
513
    }
514

                
515
    return TRUE;
516
}
517

                
518
gboolean
519
download_queue_add_file_to_queue_internal(const char *collection_name, NNTPFile *file, char **errmsg)
520
{
521
    GList *list;
522
    NNTPCollection *collection;
523

                
524
    g_static_mutex_lock(&mutex);
525

                
526
    // Find out if the collection_name already exists in the download queue
527
    list = download_queue;
528
    while (list) {
529
        collection = (NNTPCollection *) list->data;
530

                
531
        if (!strcmp(collection->collection_name, collection_name)) {
532
            // Collection found!
533

                
534
            // Does the subject already exists in this collection ?
535
            if (test_is_subject_already_in_collection(collection, file->subject)) {
536
                if (errmsg) {
537
                    *errmsg = g_strdup_printf(_("There already is a file with subject '%s' part of collection '%s'"), file->subject, collection_name);
538
                }
539

                
540
                g_static_mutex_unlock(&mutex);
541

                
542
                return FALSE;
543
            }
544

                
545
            // Add the file to this collection
546
            collection->files = g_list_append(collection->files, file);
547
            collection->files_to_download = g_list_append(collection->files_to_download, file);
548
            collection->total_size += file->file_size;
549
            collection->total_size_remaining += file->file_size;
550
            file->file_size_remaining = file->file_size;
551

                
552
            file->position = g_list_index(collection->files, file) + 1;
553
            file->file_is_new = TRUE;
554

                
555
            nntpgrab_core_emit_file_added(FALSE, collection->collection_name, file->subject, file->poster, file->stamp, file->file_size, collection->total_size, collection->total_size_remaining, file->status, file->num_parts, file->groups);
556

                
557
            // Is this the same poster as all the other files in this collection?
558
            if (test_if_collection_contains_same_poster(collection, file->poster)) {
559
                if (strcmp(collection->poster, file->poster)) {
560
                    // The poster wasn't set for this collection yet
561
                    strncpy(collection->poster, file->poster, sizeof(collection->poster) - 1);
562
                    nntpgrab_core_emit_collection_modified(FALSE, collection_name, collection->poster);
563
                    if (!collection->collection_is_new) {
564
                        collection->collection_is_changed = TRUE;
565
                    }
566
                }
567
            } else {
568
                // Some other file contained a different poster, reset to empty
569
                if (strcmp(collection->poster, file->poster)) {
570
                    memset(collection->poster, 0, sizeof(collection->poster));
571
                    nntpgrab_core_emit_collection_modified(FALSE, collection_name, collection->poster);
572
                    if (!collection->collection_is_new) {
573
                        collection->collection_is_changed = TRUE;
574
                    }
575
                }
576
            }
577

                
578
            g_static_mutex_unlock(&mutex);
579

                
580
            download_thread_awaken_if_needed();
581

                
582
            return TRUE;
583
        }
584

                
585
        list = g_list_next(list);
586
    }
587

                
588
    // Collection doesn't exist yet, add a new one
589
    collection = collection_new();
590
    strncpy((char *) collection->collection_name, collection_name, sizeof(collection->collection_name));
591
    strncpy((char *) collection->poster, file->poster, sizeof(collection->poster));
592
    download_queue = g_list_append(download_queue, collection);
593

                
594
    nntpgrab_core_emit_collection_added(FALSE, collection_name, collection->poster);
595

                
596
    // Finally add the task to the collection
597
    collection->files = g_list_append(collection->files, file);
598
    collection->files_to_download = g_list_append(collection->files_to_download, file);
599
    collection->total_size = file->file_size;
600
    collection->total_size_remaining = file->file_size;
601
    collection->collection_is_new = TRUE;
602
    file->file_is_new = TRUE;
603
    file->position = 1;
604

                
605
    nntpgrab_core_emit_file_added(FALSE, collection->collection_name, file->subject, file->poster, file->stamp, file->file_size, collection->total_size, collection->total_size_remaining, file->status, file->num_parts, file->groups);
606

                
607
    g_static_mutex_unlock(&mutex);
608

                
609
    download_thread_awaken_if_needed();
610

                
611
    return TRUE;
612
}
613

                
614
gboolean
615
download_queue_add_file_to_queue(const char *collection_name, const char *subject, const char *poster, time_t stamp, nguint64 file_size, NGList *groups, NGList *parts, char **errmsg)
616
{
617
    NNTPFile *file;
618
    GList *list;
619
    char *tmp;
620
    char *tmp2;
621
    GHashTable *hashtable;
622
    char collection_name_copy[256];          /* This parameter needs to be of the same size as defined in base/collections.h! */
623

                
624
    g_return_val_if_fail(collection_name != NULL, FALSE);
625
    g_return_val_if_fail(subject != NULL, FALSE);
626
    g_return_val_if_fail(poster != NULL, FALSE);
627
    g_return_val_if_fail(file_size >= 0, FALSE);
628
    g_return_val_if_fail(groups != NULL, FALSE);
629
    g_return_val_if_fail(parts != NULL, FALSE);
630

                
631
    memset(&collection_name_copy, 0, sizeof(collection_name_copy));
632
    strncpy(collection_name_copy, collection_name, sizeof(collection_name_copy) - 1);
633

                
634
    file = file_new();
635
    strncpy((char *) file->subject, subject, sizeof(file->subject));
636
    strncpy((char *) file->poster, poster, sizeof(file->poster));
637
    file->stamp = stamp;
638
    file->file_size = file_size;
639
    file->file_size_remaining = file_size;
640

                
641
    tmp = tempnam(opts.temp_directory, NULL);
642
    tmp2 = g_path_get_basename(tmp);
643
    strncpy((char *) file->tmp_filename, tmp2, sizeof(file->tmp_filename));
644
    g_free(tmp2);
645
    free(tmp);                  // Don't use g_free here as tempnam is a libc function!
646

                
647
    // Detect the file type and the par2 blocks
648
    if (!nntpgrab_utils_strip_subject(file->subject, NULL, NULL, NULL, NULL, NULL, &file->file_type, &file->par2_start_num, &file->par2_num_blocks, NULL, &file->num_parts)) {
649
        // Sanitize values
650
        file->file_type = NNTP_FILE_TYPE_UNKNOWN;
651
        file->par2_start_num = -1;
652
        file->par2_num_blocks =-1;
653
        file->num_parts = g_list_length((GList*) parts);
654
    }
655

                
656
    file->status = TASK_STATE_WAITING_FOR_DOWNLOAD;
657

                
658
    if (file->par2_start_num == -1) {
659
        file->par2_end_num = -1;
660
    } else {
661
        file->par2_end_num = file->par2_start_num + file->par2_num_blocks;
662
    }
663

                
664
    list = (GList*) groups;
665
    while (list) {
666
        const char *group = list->data;
667
        file->groups = g_list_append(file->groups, g_strdup(group));
668
        list = g_list_next(list);
669
    }
670

                
671
    // When adding parts, prevent the adding of duplicate part numbers
672
    hashtable = g_hash_table_new(g_direct_hash, g_direct_equal);
673

                
674
    list = (GList*) parts;
675
    while (list) {
676
        NNTPGrabPart *part = list->data;
677
        NNTPPart *new_part;
678

                
679
        new_part = g_hash_table_lookup(hashtable, GINT_TO_POINTER(part->part_num));
680
        if (new_part) {
681
            // Hey, we've seen this part before!
682
            // Only keep the newest only
683
            memset(new_part, 0, sizeof(NNTPPart));
684
        } else {
685
            // We've never seen this part before
686
            new_part = g_slice_new0(NNTPPart);
687
            file->parts = g_list_append(file->parts, new_part);
688
            g_hash_table_insert(hashtable, GINT_TO_POINTER(part->part_num), new_part);
689
        }
690

                
691
        strncpy((char *) new_part->message_id, part->message_id, sizeof(new_part->message_id));
692
        new_part->size = part->size;
693
        new_part->part_num = part->part_num;
694

                
695
        list = g_list_next(list);
696
    }
697

                
698
    g_hash_table_destroy(hashtable);
699

                
700
    return download_queue_add_file_to_queue_internal(collection_name_copy, file, errmsg);
701
}
702

                
703
gboolean
704
download_queue_del_file_from_queue(const char *collection_name, const char *subject, char **errmsg)
705
{
706
    GList *list;
707
    NNTPCollection *collection;
708
    int i;
709
    sqlite3 *db;
710
    char collection_name_copy[256];          /* This parameter needs to be of the same size as defined in base/collections.h! */
711

                
712
    g_return_val_if_fail(collection_name != NULL, FALSE);
713
    /* subject can be NULL */
714

                
715
    memset(&collection_name_copy, 0, sizeof(collection_name_copy));
716
    strncpy(collection_name_copy, collection_name, sizeof(collection_name_copy) - 1);
717

                
718
    g_static_mutex_lock(&mutex);
719

                
720
    if (!(db = queue_sqlite_open(errmsg))) {
721
        g_static_mutex_unlock(&mutex);
722
        return FALSE;
723
    }
724

                
725
    if (!queue_sqlite_begin_transaction(db, errmsg)) {
726
        g_static_mutex_unlock(&mutex);
727
        queue_sqlite_close(db);
728
        return FALSE;
729
    }
730

                
731
    // Find out if the collection_name exists in the download queue
732
    list = download_queue;
733
    while (list) {
734
        collection = (NNTPCollection *) list->data;
735

                
736
        if (!strcmp(collection->collection_name, collection_name_copy)) {
737
            // Collection found!
738
            GList *list2;
739
            gboolean delete_flag = FALSE;
740

                
741
            // Do we have a subject?
742
            if (!subject) {
743
                // Delete the whole collection
744
                delete_flag = TRUE;
745

                
746
                // Mark the whole collection as being removed
747
                collection->stop_flag = TRUE;
748
            }
749

                
750
            // Try to find the subject
751
            list2 = collection->files;
752
            while (list2) {
753
                NNTPFile *file = (NNTPFile *) list2->data;
754

                
755
                list2 = g_list_next(list2);
756

                
757
                if (delete_flag || !strcmp(file->subject, subject)) {
758
                    // Bingo!
759
                    // Is this file being downloaded ?
760
                    while (file->file_is_downloading || file->now_decoding) {
761
                        // Mark this file as being removed
762
                        file->stop_flag = TRUE;
763

                
764
                        // Release the lock and wait for the download to complete
765
                        g_static_mutex_unlock(&mutex);
766

                
767
                        g_usleep(G_USEC_PER_SEC / 10);
768

                
769
                        g_static_mutex_lock(&mutex);
770

                
771
                        // Make sure that when all parts are downloaded, but the decoder isn't triggered, we reset the flag
772
                        if (file->file_is_downloading && !file->now_decoding) {
773
                            GList *list3 = file->parts;
774
                            gboolean is_downloading_flag = FALSE;
775

                
776
                            while (list3) {
777
                                NNTPPart *part = (NNTPPart*) list3->data;
778

                
779
                                if (part->now_downloading) {
780
                                    is_downloading_flag = TRUE;
781
                                }
782

                
783
                                list3 = g_list_next(list3);
784
                            }
785

                
786
                            file->file_is_downloading = is_downloading_flag;
787
                        }
788
                    }
789

                
790
                    // Remove the entry from the database
791
                    if (!queue_sqlite_remove_file_from_db(db, collection, file, TRUE, errmsg)) {
792
                        g_static_mutex_unlock(&mutex);
793
                        queue_sqlite_close(db);
794
                        return FALSE;
795
                    }
796

                
797
                    // Unlink any possible downloaded parts
798
                    for (i = 0; i < file->num_parts; i++) {
799
                        char *filename = g_strdup_printf("%s%s%s.%i", opts.temp_directory, G_DIR_SEPARATOR_S, file->tmp_filename, i + 1);
800
                        g_unlink(filename);
801
                        g_free(filename);
802
                    }
803

                
804
                    // Update the file size
805
                    collection->total_size -= file->file_size;
806
                    collection->total_size_remaining -= file->file_size_remaining;
807

                
808
                    // Remove it from the list
809
                    collection->files = g_list_remove(collection->files, file);
810
                    collection->files_to_download = g_list_remove(collection->files_to_download, file);
811

                
812
                    nntpgrab_core_emit_file_removed(FALSE, collection_name_copy, file->subject, collection->total_size, collection->total_size_remaining);
813

                
814
                    file_unref(file);
815

                
816
                    // Does the collection still got any items in it ?
817
                    if (g_list_length(collection->files) == 0) {
818
                        // Yes, remove the entire collection
819
                        if (!queue_sqlite_remove_collection_from_db(db, collection, errmsg)) {
820
                            g_static_mutex_unlock(&mutex);
821
                            queue_sqlite_close(db);
822
                            return FALSE;
823
                        }
824

                
825
                        download_queue = g_list_remove(download_queue, collection);
826

                
827
                        nntpgrab_core_emit_collection_removed(FALSE, collection_name_copy);
828

                
829
                        collection_unref(collection);
830

                
831
                        g_static_mutex_unlock(&mutex);
832

                
833
                        if (!queue_sqlite_end_transaction(db, errmsg)) {
834
                            queue_sqlite_close(db);
835
                            return FALSE;
836
                        }
837

                
838
                        queue_sqlite_close(db);
839
                        return TRUE;
840
                    }
841

                
842
                    if (!delete_flag) {
843
                        // Is this the same poster as all the other files in this collection?
844
                        file = collection->files->data;
845
                        if (test_if_collection_contains_same_poster(collection, file->poster)) {
846
                            if (strcmp(collection->poster, file->poster)) {
847
                                // The poster wasn't set for this collection yet
848
                                strncpy(collection->poster, file->poster, sizeof(collection->poster) - 1);
849
                                nntpgrab_core_emit_collection_modified(FALSE, collection_name_copy, collection->poster);
850

                
851
                                if (!collection->collection_is_new) {
852
                                    collection->collection_is_changed = TRUE;
853
                                }
854
                            }
855
                        } else {
856
                            // Some other file contained a different poster, reset to empty
857
                            if (strcmp(collection->poster, file->poster)) {
858
                                memset(collection->poster, 0, sizeof(collection->poster));
859
                                nntpgrab_core_emit_collection_modified(FALSE, collection_name_copy, collection->poster);
860

                
861
                                if (!collection->collection_is_new) {
862
                                    collection->collection_is_changed = TRUE;
863
                                }
864
                            }
865
                        }
866

                
867
                        if (!queue_sqlite_end_transaction(db, errmsg)) {
868
                            g_static_mutex_unlock(&mutex);
869
                            queue_sqlite_close(db);
870
                            return FALSE;
871
                        }
872

                
873
                        g_static_mutex_unlock(&mutex);
874
                        queue_sqlite_close(db);
875
                        return TRUE;
876
                    }
877
                }
878
            }
879

                
880
            if (delete_flag) {
881
                g_static_mutex_unlock(&mutex);
882

                
883
                if (!queue_sqlite_end_transaction(db, errmsg)) {
884
                    return FALSE;
885
                }
886

                
887
                queue_sqlite_close(db);
888
                return TRUE;
889
            }
890
        }
891

                
892
        list = g_list_next(list);
893
    }
894

                
895
    if (errmsg) {
896
        *errmsg = g_strdup_printf(_("Subject '%s' was not found in collection '%s'"), subject, collection_name_copy);
897
    }
898

                
899
    g_static_mutex_unlock(&mutex);
900

                
901
    queue_sqlite_close(db);
902

                
903
    return FALSE;
904
}
905

                
906
gboolean
907
download_queue_restart_file(const char *collection_name, const char *subject, char **errmsg)
908
{
909
    GList *list;
910
    int pos_last_file_to_download;
911
    NNTPCollection *collection;
912
    char collection_name_copy[256];          /* This parameter needs to be of the same size as defined in base/collections.h! */
913

                
914
    g_return_val_if_fail(collection_name != NULL, FALSE);
915
    /* subject can be NULL */
916

                
917
    memset(&collection_name_copy, 0, sizeof(collection_name_copy));
918
    strncpy(collection_name_copy, collection_name, sizeof(collection_name_copy) - 1);
919

                
920
    g_static_mutex_lock(&mutex);
921

                
922
    // Find out if the collection_name already exists in the download queue
923
    list = download_queue;
924
    while (list) {
925
        collection = (NNTPCollection *) list->data;
926

                
927
        pos_last_file_to_download = 0;
928

                
929
        if (!strcmp(collection->collection_name, collection_name_copy)) {
930
            // Collection found!
931
            GList *list2;
932
            gboolean restart_flag = FALSE;
933

                
934
            // Do we have a subject?
935
            if (!subject) {
936
                // Restart the whole collection
937
                restart_flag = TRUE;
938

                
939
                // Clear out the old list with items which still need to be downloaded
940
                g_list_free(collection->files_to_download);
941
                collection->files_to_download = NULL;
942
            }
943

                
944
            list2 = collection->files;
945
            while (list2) {
946
                int pos;
947
                NNTPFile *file = list2->data;
948

                
949
                if (restart_flag || !strcmp(file->subject, subject)) {
950
                    // Subject found!
951
                    GList *list3;
952
                    gboolean file_is_downloading = FALSE;
953
                    int filesize_remaining_active = 0;
954

                
955
                    list3 = file->parts;
956
                    while (list3) {
957
                        NNTPPart *part = list3->data;
958

                
959
                        if (part->now_downloading) {
960
                            list3 = g_list_next(list3);
961
                            file_is_downloading = TRUE;
962
                            filesize_remaining_active += part->size;
963
                            continue;
964
                        }
965

                
966
                        part->downloaded = FALSE;
967
                        part->now_downloading = FALSE;
968
                        part->servers_already_tried = 0;
969

                
970
                        list3 = g_list_next(list3);
971
                    }
972

                
973
                    file->file_is_downloading = file_is_downloading;
974
                    file->file_is_downloaded = FALSE;
975
                    file->now_decoding = FALSE;
976
                    file->num_parts_downloaded = 0;
977
                    file->num_parts_failed = 0;
978

                
979
                    if (restart_flag) {
980
                        // If the whole collection is restarted, don't bother with merging at the right position in the files_to_download list
981
                        collection->files_to_download = g_list_append(collection->files_to_download, file);
982
                    } else if (!file_is_downloading) {
983
                        // Only a part of the collection has been restarted
984
                        // The position of the previous item which still needs to be downloaded
985
                        // has already been saved in list_last_file_to_download
986
                        if (pos_last_file_to_download > 0) {
987
                            pos_last_file_to_download++;
988
                        }
989
                        collection->files_to_download = g_list_insert(collection->files_to_download, file,  pos_last_file_to_download);
990
                    }
991

                
992
                    collection->total_size_remaining += file->file_size - file->file_size_remaining - filesize_remaining_active;
993
                    file->file_size_remaining = file->file_size - filesize_remaining_active;
994

                
995
                    if (!file->file_is_new) {
996
                        file->file_is_changed = TRUE;
997
                    }
998

                
999
                    nntpgrab_core_emit_file_state_changed(FALSE, collection_name_copy, file->subject, NULL, file->status, TASK_STATE_WAITING_FOR_DOWNLOAD);
1000
                    file->status = TASK_STATE_WAITING_FOR_DOWNLOAD;
1001

                
1002
                    if (!restart_flag) {
1003
                        g_static_mutex_unlock(&mutex);
1004

                
1005
                        download_thread_awaken_if_needed();
1006

                
1007
                        return TRUE;
1008
                    }
1009
                }
1010

                
1011
                pos = g_list_index(collection->files_to_download, file);
1012
                if (pos > 0) {
1013
                    pos_last_file_to_download = pos;
1014
                }
1015

                
1016
                list2 = g_list_next(list2);
1017
            }
1018

                
1019
            if (restart_flag) {
1020
                g_static_mutex_unlock(&mutex);
1021

                
1022
                download_thread_awaken_if_needed();
1023

                
1024
                return TRUE;
1025
            }
1026
        }
1027

                
1028
        list = g_list_next(list);
1029
    }
1030

                
1031
    g_static_mutex_unlock(&mutex);
1032

                
1033
    if (errmsg) {
1034
        *errmsg = g_strdup_printf(_("Subject '%s' was not found in collection '%s'"), subject, collection_name_copy);
1035
    }
1036

                
1037
    return FALSE;
1038
}
1039

                
1040
struct _foreach_data
1041
{
1042
    ForeachCollectionFunc collection_func;
1043
    ForeachFileFunc file_func;
1044
    ForeachGroupFunc group_func;
1045
    gpointer data;
1046
};
1047

                
1048
static void
1049
foreach_func(gpointer data, gpointer user_data)
1050
{
1051
    struct _foreach_data *foreach_data = (struct _foreach_data *) user_data;
1052
    NNTPCollection *collection = (NNTPCollection *) data;
1053
    GList *list, *list2;
1054

                
1055
    if (foreach_data->collection_func) {
1056
        foreach_data->collection_func(collection->collection_name, collection->poster, collection->total_size, collection->total_size_remaining, collection->position, foreach_data->data);
1057
    }
1058

                
1059
    if (!foreach_data->group_func && !foreach_data->file_func) {
1060
        return;
1061
    }
1062

                
1063
    list = collection->files;
1064
    while (list) {
1065
        NNTPFile *file = (NNTPFile *) list->data;
1066

                
1067
        if (foreach_data->file_func) {
1068
            foreach_data->file_func(collection->collection_name, file->subject, file->poster, (gint64) file->stamp, file->file_size, file->file_size_remaining, file->position, g_list_length(file->parts), file->num_parts_downloaded, file->num_parts_failed, file->status, file->real_filename, foreach_data->data);
1069
        }
1070

                
1071
        if (foreach_data->group_func) {
1072
            list2 = file->groups;
1073
            while (list2) {
1074
                const char *group = (const char *) list2->data;
1075

                
1076
                foreach_data->group_func(collection->collection_name, file->subject, group, foreach_data->data);
1077

                
1078
                list2 = g_list_next(list2);
1079
            }
1080
        }
1081

                
1082
        list = g_list_next(list);
1083
    }
1084
}
1085

                
1086
void
1087
download_queue_foreach_file(ForeachCollectionFunc collection_func, ForeachFileFunc file_func, ForeachGroupFunc group_func, gpointer data)
1088
{
1089
    struct _foreach_data foreach_data;
1090

                
1091
    foreach_data.collection_func = collection_func;
1092
    foreach_data.file_func = file_func;
1093
    foreach_data.group_func = group_func;
1094
    foreach_data.data = data;
1095

                
1096
    g_static_mutex_lock(&mutex);
1097
    g_list_foreach(download_queue, foreach_func, &foreach_data);
1098
    g_static_mutex_unlock(&mutex);
1099
}
1100

                
1101
gboolean
1102
download_queue_move_file(const char *collection_name_src, const char *subject_src, const char *collection_name_dest, int position_dest)
1103
{
1104
    GList *list;
1105
    NNTPCollection *collection_src = NULL;
1106
    NNTPCollection *collection_dest = NULL;
1107
    NNTPFile *file = NULL;
1108
    gboolean found = FALSE;
1109
    int old_position = 0;
1110
    int i;
1111
    guint hash_collection_name_src;
1112
    guint hash_subject_src;
1113

                
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff