Statistics
| Revision:

root / trunk / glue / glue.c @ 1853

History | View | Annotate | Download (63.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 
21
#include 
22
#include 
23
#include 
24
#ifdef WIN32
25
#include 
26
#include 
27
#include 
28
#else
29
#include 
30
#include 
31
#include 
32
#include 
33
#endif
34
#include 
35
#include 
36
#include 
37
#include 
38
#include 
39
#include "marshalers.h"
40
#include "nntpgrab_glue.h"
41
#include "nntpgrab.h"
42
#include "nntpgrab_glue_internal.h"
43
#include "nntpgrab_internal.h"
44
#include "nntpgrab_utils.h"
45
#include "nntpgrab_plugin.h"
46

                
47
#ifdef _MSC_VER
48
#include "config.h.win32"
49
#else
50
#include "config.h"
51
#endif
52

                
53
#ifdef WIN32
54
#define CLOSE(x)    closesocket(x)
55
#else
56
#define CLOSE(x)    close(x)
57
#endif
58

                
59
#ifdef _MSC_VER
60
#undef atoll
61
#define atoll _atoi64
62

                
63
#undef gai_strerror
64
#define gai_strerror gai_strerrorA
65
#endif
66

                
67
#define DEBUG(x)                            \
68
    g_print("%s\n", x);                     \
69
    nntpgrab_core_emit_log_message(FALSE, "Glue layer", NG_LOG_LEVEL_DEBUG, x, TRUE, FALSE);
70

                
71
static NntpgrabGlue *glue = NULL;
72
static gboolean abort_flag = FALSE;
73
static GThread *thread_listener = NULL;
74

                
75
struct NntpgrabGlueClass
76
{
77
    GObjectClass parent;
78
};
79

                
80
static guint signals[LAST_SIGNAL] = { 0 };
81
static GModule *module = NULL;
82

                
83
G_DEFINE_TYPE(NntpgrabGlue, glue, G_TYPE_OBJECT)
84

                
85
NGType
86
nntpgrab_glue_get_type(void)
87
{
88
    return (NGType) glue_get_type();
89
}
90

                
91
static void
92
glue_init (NntpgrabGlue *obj)
93
{
94
    obj->socket.socket_id = -1;
95
    obj->socket.recv_buf = g_string_new("");
96
    obj->glue_version = -1;
97
    obj->standalone_core = NULL;
98
    obj->is_initialized = FALSE;
99
}
100

                
101
static void
102
glue_finalize (GObject *obj)
103
{
104
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
105

                
106
    if (glue->standalone_core) {
107
        g_object_unref(glue->standalone_core);
108
        glue->standalone_core = NULL;
109
    }
110

                
111
    if (glue->socket.socket_id > 0) {
112
        CLOSE(glue->socket.socket_id);
113
        glue->socket.socket_id = -1;
114
    }
115

                
116
    g_string_free(glue->socket.recv_buf, TRUE);
117
}
118

                
119
static void
120
glue_class_init (NntpgrabGlueClass *klass)
121
{
122
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
123

                
124
    gobject_class->finalize = glue_finalize;
125

                
126
    /** 
127
     * NntpgrabGlue::config-changed:
128
     * @obj: An instance of the NntpgrabGlue
129
     *
130
     * Something in the configuration has changed
131
     */
132
    signals[CONFIG_CHANGED_SIGNAL] =       g_signal_new("config_changed",
133
                                                        G_OBJECT_CLASS_TYPE (klass),
134
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
135
                                                        0,
136
                                                        NULL, NULL,
137
                                                        nntpgrab_marshal_VOID__VOID,
138
                                                        G_TYPE_NONE, 0);
139

                
140
    /** 
141
     * NntpgrabGlue::part-download-start:
142
     * @obj:              An instance of the NntpgrabGlue
143
     * @servername:       The name of the server on which this part is being downloaded
144
     * @conn_id:          The connection id which is used to download this part
145
     * @collection_name:  The name of the collection from which this part is
146
     * @subject:          The name of the subject from which this part is
147
     * @part_num:         The number of the part
148
     *
149
     * The download of a part has just started
150
     */
151
    signals[PART_DOWNLOAD_START_SIGNAL] = g_signal_new ("part_download_start",
152
                                                        G_OBJECT_CLASS_TYPE (klass),
153
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
154
                                                        0,
155
                                                        NULL, NULL,
156
                                                        nntpgrab_marshal_VOID__STRING_INT_STRING_STRING_INT,
157
                                                        G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
158

                
159
    /** 
160
     * NntpgrabGlue::part-done:
161
     * @obj:                An instance of the NntpgrabGlue
162
     * @servername:         The name of the server on which this part has just been downloaded
163
     * @conn_id:            The connection id which was used to download this part
164
     * @collection_name:    The name of the collection from which this part is
165
     * @subject:            The name of the subject from which this part is
166
     * @part_num:           The number of the part
167
     * @size:               The size of the part in bytes. This can be different from the size which was mentioned earlier in other calls like nntpgrab_core_schedular_foreach_task()
168
     *
169
     * The download of a part has completed successfully
170
     */
171
    signals[PART_DONE_SIGNAL] =           g_signal_new ("part_done",
172
                                                        G_OBJECT_CLASS_TYPE (klass),
173
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
174
                                                        0,
175
                                                        NULL, NULL,
176
                                                        nntpgrab_marshal_VOID__STRING_INT_STRING_STRING_INT_INT,
177
                                                        G_TYPE_NONE, 6, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
178

                
179
    /** 
180
     * NntpgrabGlue::part-failed:
181
     * @obj:                An instance of the NntpgrabGlue
182
     * @servername:         The name of the server on which this part was tried
183
     * @conn_id:            The connection id which was used to try to download this part
184
     * @collection_name:    The name of the collection from which this part is
185
     * @subject:            The name of the subject from which this part is
186
     * @part_num:           The number of the part
187
     * @size:               The size of the part in bytes
188
     * @all_servers_tried:  If TRUE, all configured servers have tried to download this file and none of them succeeded
189
     *
190
     * The download of a part has failed (probably because the part isn't available on the server)
191
     */
192
    signals[PART_FAILED_SIGNAL] =         g_signal_new ("part_failed",
193
                                                        G_OBJECT_CLASS_TYPE (klass),
194
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
195
                                                        0,
196
                                                        NULL, NULL,
197
                                                        nntpgrab_marshal_VOID__STRING_INT_STRING_STRING_INT_INT_BOOLEAN,
198
                                                        G_TYPE_NONE, 7, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_BOOLEAN);
199

                
200
    /** 
201
     * NntpgrabGlue::part-progress-update:
202
     * @obj:                An instance of the NntpgrabGlue
203
     * @servername:         The name of the server on which this part is being downloaded
204
     * @conn_id:            The connection id which is being used to download this part
205
     * @collection_name:    The name of the collection from which this part is
206
     * @subject:            The name of the subject from which this part is
207
     * @part_num:           The number of the part
208
     * @bytes_downloaded:   The number of bytes already downloaded from this part
209
     * @bytes_total:        The total size of this part in bytes. This can be different from the size which was mentioned earlier in other calls like nntpgrab_schedular_foreach_task()
210
     *
211
     * Every 1/10th second of a part download, this message will be sent
212
     */
213
    signals[PART_PROGRESS_UPDATE_SIGNAL] = g_signal_new ("part_progress_update",
214
                                                         G_OBJECT_CLASS_TYPE (klass),
215
                                                         G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
216
                                                         0,
217
                                                         NULL, NULL,
218
                                                         nntpgrab_marshal_VOID__STRING_INT_STRING_STRING_INT_INT_INT,
219
                                                         G_TYPE_NONE, 7, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
220

                
221
    /** 
222
     * NntpgrabGlue::traffic-monitor-update:
223
     * @obj:                An instance of the NntpgrabGlue
224
     * @bytes_received1:    The number of bytes received in now() - 10
225
     * @bytes_received2:    The number of bytes received in now() - 9
226
     * @bytes_received3:    The number of bytes received in now() - 8
227
     * @bytes_received4:    The number of bytes received in now() - 7
228
     * @bytes_received5:    The number of bytes received in now() - 6
229
     * @bytes_received6:    The number of bytes received in now() - 5
230
     * @bytes_received7:    The number of bytes received in now() - 4
231
     * @bytes_received8:    The number of bytes received in now() - 3
232
     * @bytes_received9:    The number of bytes received in now() - 2
233
     * @bytes_received10:   The number of bytes received in now() - 1
234
     * @stamp:              The timestamp of the last measurement
235
     * @average:            The average number of bytes per second
236
     *
237
     * Every second, traffic statistics about the last 10 seconds are given
238
     */
239
    signals[TRAFFIC_MONITOR_UPDATE_SIGNAL] = g_signal_new ("traffic_monitor_update",
240
                                                         G_OBJECT_CLASS_TYPE (klass),
241
                                                         G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
242
                                                         0,
243
                                                         NULL, NULL,
244
                                                         nntpgrab_marshal_VOID__INT_INT_INT_INT_INT_INT_INT_INT_INT_INT_INT64_DOUBLE,
245
                                                         G_TYPE_NONE, 12, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT64, G_TYPE_DOUBLE);
246

                
247
    /** 
248
     * NntpgrabGlue::collection-added:
249
     * @obj:                                An instance of the NntpgrabGlue
250
     * @collection_name:                    The name of the collection which was just added
251
     * @poster:             (allow-none):   The poster of this collection. If multiple posters are involved, this value will be NULL
252
     *
253
     * A new collection was added
254
     */
255
    signals[COLLECTION_ADDED_SIGNAL] =    g_signal_new ("collection_added",
256
                                                        G_OBJECT_CLASS_TYPE (klass),
257
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
258
                                                        0,
259
                                                        NULL, NULL,
260
                                                        nntpgrab_marshal_VOID__STRING_STRING,
261
                                                        G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
262

                
263
    /** 
264
     * NntpgrabGlue::collection-removed:
265
     * @obj:                An instance of the NntpgrabGlue
266
     * @collection_name:    The name of the collection which was just removed
267
     *
268
     * A collection was removed
269
     */
270
    signals[COLLECTION_REMOVED_SIGNAL] =  g_signal_new ("collection_removed",
271
                                                        G_OBJECT_CLASS_TYPE (klass),
272
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
273
                                                        0,
274
                                                        NULL, NULL,
275
                                                        nntpgrab_marshal_VOID__STRING,
276
                                                        G_TYPE_NONE, 1, G_TYPE_STRING);
277

                
278
    /** 
279
     * NntpgrabGlue::collection-modified:
280
     * @obj:                                An instance of the NntpgrabGlue
281
     * @collection_name:                    The name of the collection which was just changed
282
     * @poster:             (allow-none):   The name of the poster of this collection. This value can be NULL if multiple posters are involved
283
     *
284
     * The poster of a collection was modified
285
     */
286
    signals[COLLECTION_MODIFIED_SIGNAL] =  g_signal_new ("collection_modified",
287
                                                        G_OBJECT_CLASS_TYPE (klass),
288
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
289
                                                        0,
290
                                                        NULL, NULL,
291
                                                        nntpgrab_marshal_VOID__STRING_STRING,
292
                                                        G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
293

                
294
    /** 
295
     * NntpgrabGlue::file-added:
296
     * @obj:                                            An instance of the NntpgrabGlue
297
     * @collection_name:                                The name of the collection in which this file belongs
298
     * @subject:                                        The subject of the file which was just added
299
     * @poster:                                         The poster of the file which was just added
300
     * @stamp:                                          The stamp mentioning when the first part of this file was posted
301
     * @file_size:                                      The size of this file in bytes
302
     * @total_size:                                     The size of the entire collection in bytes
303
     * @total_size_remaining:                           The number of bytes which still need to be downloaded from the entire collection
304
     * @status:                                         The current status of this file. This is of the type #NGTaskState
305
     * @num_parts:                                      The number of parts of which this file consists
306
     * @groups:                 (element-type utf8):    A list containing the groups in which this file is posted
307
     *
308
     * A file was added to a already existing collection
309
     */
310
    signals[FILE_ADDED_SIGNAL] =          g_signal_new ("file_added",
311
                                                        G_OBJECT_CLASS_TYPE (klass),
312
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
313
                                                        0,
314
                                                        NULL, NULL,
315
                                                        nntpgrab_marshal_VOID__STRING_STRING_STRING_UINT64_UINT64_UINT64_UINT64_INT_INT_POINTER,
316
                                                        G_TYPE_NONE, 10, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_INT, G_TYPE_INT, G_TYPE_POINTER);
317

                
318
    /** 
319
     * NntpgrabGlue::file-removed:
320
     * @obj:                    An instance of the NntpgrabGlue
321
     * @collection_name:        The name of the collection in which this file was situated
322
     * @subject:                The subject of the file
323
     * @total_size:             The new total size of the entire collection
324
     * @total_size_remaining:   The new total size remaining of the entire collection
325
     *
326
     * A file was removed from the download queue
327
     */
328
    signals[FILE_REMOVED_SIGNAL] =        g_signal_new ("file_removed",
329
                                                        G_OBJECT_CLASS_TYPE (klass),
330
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
331
                                                        0,
332
                                                        NULL, NULL,
333
                                                        nntpgrab_marshal_VOID__STRING_STRING_UINT64_UINT64,
334
                                                        G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_UINT64);
335

                
336
    /** 
337
     * NntpgrabGlue::file-download-state-update:
338
     * @obj:                    An instance of the NntpgrabGlue
339
     * @collection_name:        The collection name
340
     * @subject:                The subject
341
     * @num_parts_total:        The number of parts of which this file consists
342
     * @num_parts_done:         The number of parts of this file which are already downloaded
343
     * @num_parts_failed:       The number of parts of this file which failed to download
344
     * @file_size:              The size of this file in bytes
345
     * @file_size_remaining:    The number of bytes remaining from this file
346
     * @total_size:             The total size of the entire collection in bytes
347
     * @total_size_remaining:   The number of bytes remaining from the entire collection
348
     *
349
     * The state of a file in the download queue has changed
350
     */
351
    signals[FILE_DOWNLOAD_STATE_UPDATE_SIGNAL] =  g_signal_new ("file_download_state_update",
352
                                                                G_OBJECT_CLASS_TYPE (klass),
353
                                                                G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
354
                                                                0,
355
                                                                NULL, NULL,
356
                                                                nntpgrab_marshal_VOID__STRING_STRING_INT_INT_INT_UINT64_UINT64_UINT64_UINT64,
357
                                                                G_TYPE_NONE, 9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_UINT64);
358

                
359
    /** 
360
     * NntpgrabGlue::file-state-changed:
361
     * @obj:                                An instance of the NntpgrabGlue
362
     * @collection_name:                    The name of the collection in which the state changed
363
     * @subject:                            The subject of the file which changed state
364
     * @real_filename:      (allow-none):   The file name of the physical resulting file. Will be NULL if the file isn't completely downloaded and decoded yet
365
     * @old_state:                          The old state of the file
366
     * @new_state:                          The new state of the file
367
     *
368
     * A file in the download queue was restarted
369
     */
370
    signals[FILE_STATE_CHANGED_SIGNAL] =  g_signal_new ("file_state_changed",
371
                                                        G_OBJECT_CLASS_TYPE (klass),
372
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
373
                                                        0,
374
                                                        NULL, NULL,
375
                                                        nntpgrab_marshal_VOID__STRING_STRING_STRING_INT_INT_UINT64_UINT64_UINT64,
376
                                                        G_TYPE_NONE, 8, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_UINT64);
377

                
378
    /** 
379
     * NntpgrabGlue::connection-connecting:
380
     * @obj:                An instance of the NntpgrabGlue
381
     * @servername:         The name of the server to which a connection is being made
382
     * @conn_id:            An identifier for this connection
383
     *
384
     * A new connection is being made to a usenet server
385
     */
386
    signals[CONNECTION_CONNECTING_SIGNAL] =  g_signal_new   ("connection_connecting",
387
                                                             G_OBJECT_CLASS_TYPE (klass),
388
                                                             G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
389
                                                             0,
390
                                                             NULL, NULL,
391
                                                             nntpgrab_marshal_VOID__STRING_INT,
392
                                                             G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
393

                
394
    /** 
395
     * NntpgrabGlue::connection-connected:
396
     * @obj:                An instance of the NntpgrabGlue
397
     * @servername:         The name of the server to which a connection has just been made
398
     * @conn_id:            An identifier for this connection
399
     * @welcome_msg:        The welcome message which was returned from the server
400
     *
401
     * A connection attempt has succeeded
402
     */
403
    signals[CONNECTION_CONNECTED_SIGNAL] =  g_signal_new    ("connection_connected",
404
                                                             G_OBJECT_CLASS_TYPE (klass),
405
                                                             G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
406
                                                             0,
407
                                                             NULL, NULL,
408
                                                             nntpgrab_marshal_VOID__STRING_INT_STRING,
409
                                                             G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
410

                
411
    /** 
412
     * NntpgrabGlue::connection-disconnect:
413
     * @obj:                             An instance of the NntpgrabGlue
414
     * @servername:                      The name of the server which was just disconnected
415
     * @conn_id:                         An identifier for this connection
416
     * @disconnect_type:                 One of the values from #NNTPDisconnectType
417
     * @reason:           (allow-none):  The reason which indicates why the disconnect occured. Can be NULL
418
     *
419
     * A connection to a usenet server was disconnected
420
     */
421
    signals[CONNECTION_DISCONNECT_SIGNAL] = g_signal_new ("connection_disconnect",
422
                                                          G_OBJECT_CLASS_TYPE (klass),
423
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
424
                                                          0,
425
                                                          NULL, NULL,
426
                                                          nntpgrab_marshal_VOID__STRING_INT_ENUM_STRING,
427
                                                          G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING);
428

                
429

                
430
    /** 
431
     * NntpgrabGlue::schedular-state-changed:
432
     * @obj:                        An instance of the NntpgrabGlue
433
     * @new_state:                  The new state of the schedular
434
     * @reason:     (allow-none):   The reason why the schedular changed state. Will be NULL if it's caused by request of the user (nntpgrab_core_schedular_start() / nntpgrab_core_schedular_stop())
435
     *
436
     * The state of the schedular has changed
437
     */
438
    signals[SCHEDULAR_STATE_CHANGED_SIGNAL] = g_signal_new ("schedular_state_changed",
439
                                                          G_OBJECT_CLASS_TYPE (klass),
440
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
441
                                                          0,
442
                                                          NULL, NULL,
443
                                                          nntpgrab_marshal_VOID__INT_STRING,
444
                                                          G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING);
445

                
446
    /** 
447
     * NntpgrabGlue::log-message:
448
     * @obj:                    An instance of the NntpgrabGlue
449
     * @component:              The component which emit this log message
450
     * @log_level:              One of the values from #NGLogLevel
451
     * @msg:                    The log message which was emit
452
     *
453
     * A log message has been emitted
454
     */
455
    signals[LOG_MESSAGE_SIGNAL] =           g_signal_new ("log_message",
456
                                                          G_OBJECT_CLASS_TYPE (klass),
457
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
458
                                                          0,
459
                                                          NULL, NULL,
460
                                                          nntpgrab_marshal_VOID__STRING_INT_STRING,
461
                                                          G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
462

                
463
    /** 
464
     * NntpgrabGlue::connection-lost:
465
     * @obj:                    An instance of the NntpgrabGlue
466
     * @reason:                 The reason why the connection was lost
467
     *
468
     * The connection to the NNTPGrab Server has been lost
469
     */
470
    signals[CONNECTION_LOST_SIGNAL] =       g_signal_new ("connection_lost",
471
                                                          G_OBJECT_CLASS_TYPE (klass),
472
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
473
                                                          0,
474
                                                          NULL, NULL,
475
                                                          nntpgrab_marshal_VOID__STRING,
476
                                                          G_TYPE_NONE, 1, G_TYPE_STRING);
477

                
478
    /** 
479
     * NntpgrabGlue::task-moved:
480
     * @obj:                    An instance of the NntpgrabGlue
481
     * @orig_collection_name:   The name of the original collection of which the file was a member of
482
     * @subject:                The subject of the file
483
     * @new_collection_name:    The name of the new collection to which the file is moved (which can be the same of @orig_collection_name)
484
     * @old_position:           The original position of the file in the original collection
485
     * @new_position:           The new position of the file in the new collection
486
     *
487
     * The position of a task in the download queue has changed
488
     */
489
    signals[TASK_MOVED_SIGNAL] =            g_signal_new ("task_moved",
490
                                                          G_OBJECT_CLASS_TYPE (klass),
491
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
492
                                                          0,
493
                                                          NULL, NULL,
494
                                                          nntpgrab_marshal_VOID__STRING_STRING_STRING_INT_INT,
495
                                                          G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
496

                
497
    /** 
498
     * NntpgrabGlue::collection-moved:
499
     * @obj:                    An instance of the NntpgrabGlue
500
     * @collection_name:        The name of the collection which has just been moved
501
     * @old_position:           The original position in the download queue of the collection
502
     * @new_position:           The new position in the download queue of the collection
503
     *
504
     * The position of a collection in the download queue has changed
505
     */
506
    signals[COLLECTION_MOVED_SIGNAL] =      g_signal_new ("collection_moved",
507
                                                          G_OBJECT_CLASS_TYPE (klass),
508
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
509
                                                          0,
510
                                                          NULL, NULL,
511
                                                          nntpgrab_marshal_VOID__STRING_INT_INT,
512
                                                          G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
513

                
514
    /** 
515
     * NntpgrabGlue::collection-downloaded:
516
     * @obj:                     An instance of the NntpgrabGlue
517
     * @collection_name:         The name of the collection which has been fully downloaded
518
     *
519
     * A collection has been completely downloaded
520
     */
521
    signals[COLLECTION_DOWNLOADED_SIGNAL] =    g_signal_new("collection_downloaded",
522
                                                            G_OBJECT_CLASS_TYPE (klass),
523
                                                            G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
524
                                                            0,
525
                                                            NULL, NULL,
526
                                                            nntpgrab_marshal_VOID__STRING,
527
                                                            G_TYPE_NONE, 1, G_TYPE_STRING);
528

                
529
    /** 
530
     * NntpgrabGlue::all-downloads-completed:
531
     * @obj:                   An instance of the NntpgrabGlue
532
     *
533
     * This message is emit when all the items in the download queue are completed
534
     */
535
    signals[ALL_DOWNLOADS_COMPLETED_SIGNAL] =  g_signal_new("all_downloads_completed",
536
                                                            G_OBJECT_CLASS_TYPE (klass),
537
                                                            G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
538
                                                            0,
539
                                                            NULL, NULL,
540
                                                            nntpgrab_marshal_VOID__VOID,
541
                                                            G_TYPE_NONE, 0);
542

                
543
    /** 
544
     * NntpgrabGlue::plugin-loaded:
545
     * @obj:                   An instance of the NntpgrabGlue
546
     * @plugin_name:           The name of the plugin
547
     * @is_persistent:         Unused in NNTPGrab 0.7
548
     *
549
     * A plugin has been loaded
550
     */
551
    signals[PLUGIN_LOADED_SIGNAL] =          g_signal_new("plugin_loaded",
552
                                                          G_OBJECT_CLASS_TYPE (klass),
553
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
554
                                                          0,
555
                                                          NULL, NULL,
556
                                                          nntpgrab_marshal_VOID__STRING_BOOL,
557
                                                          G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
558

                
559
    /** 
560
     * NntpgrabGlue::plugin-unloaded:
561
     * @obj:                 An instance of the NntpgrabGlue
562
     * @plugin_name:         The name of the plugin
563
     *
564
     * A plugin has been unloaded
565
     */
566
    signals[PLUGIN_UNLOADED_SIGNAL] =        g_signal_new("plugin_unloaded",
567
                                                          G_OBJECT_CLASS_TYPE (klass),
568
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
569
                                                          0,
570
                                                          NULL, NULL,
571
                                                          nntpgrab_marshal_VOID__STRING,
572
                                                          G_TYPE_NONE, 1, G_TYPE_STRING);
573

                
574
    /** 
575
     * NntpgrabGlue::plugin-event:
576
     * @obj:                 An instance of the NntpgrabGlue
577
     * @plugin_name:         The name of the plugin
578
     * @event_name:          The name of the plugin event
579
     * @values:              The values belonging to this event. This is a NULL-terminated array
580
     *
581
     * A plugin has emit an event
582
     */
583
    signals[PLUGIN_EVENT_SIGNAL] =           g_signal_new("plugin_event",
584
                                                          G_OBJECT_CLASS_TYPE (klass),
585
                                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
586
                                                          0,
587
                                                          NULL, NULL,
588
                                                          nntpgrab_marshal_VOID__STRING_STRING_BOXED,
589
                                                          G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRV);
590
}
591

                
592
static void
593
strip_newline(char *line)
594
{
595
    if (strlen(line) <= 1) {
596
        return;
597
    }
598

                
599
    if (line[strlen(line) - 1]  == '\n') {
600
        line[strlen(line) - 1] = '\0';
601
    }
602

                
603
    if (line[strlen(line) - 1]  == '\r') {
604
        line[strlen(line) - 1] = '\0';
605
    }
606

                
607
}
608

                
609
static gboolean
610
read_line(Connection *sock, char **ret_line, int timeout, gboolean *error_flag)
611
{
612
    int i;
613
    int len;
614
    char *line;
615
    time_t stamp;
616
    char buf[1024];
617

                
618
    g_return_val_if_fail(ret_line != NULL, FALSE);
619

                
620
    if (error_flag) {
621
        *error_flag = FALSE;
622
    }
623

                
624
    g_return_val_if_fail(sock > 0, FALSE);
625

                
626
    stamp = time(NULL);
627

                
628
    do {
629
        struct timeval tv;
630
        fd_set recv_fds;
631

                
632
        // Check is there is a newline in the buffer
633
        for (i = 0; i < sock->recv_buf->len; i++) {
634
            if (sock->recv_buf->str[i] == '\n') {
635
                // Newline found, split the buffer into a line and process it
636
                line = g_strndup(sock->recv_buf->str, i);
637

                
638
                strip_newline(line);
639

                
640
                g_string_erase(sock->recv_buf, 0, i + 1);
641

                
642
                /* Shrink the recv buffer if it became really large by the last line */
643
                if (sock->recv_buf->allocated_len > 1024 && sock->recv_buf->len < 1024) {
644
                    /* GLib doesn't have an API function to shrink a GString so we do it manually here */
645
                    sock->recv_buf->str = g_realloc (sock->recv_buf->str, 1024);
646
                    sock->recv_buf->allocated_len = 1024;
647
                }
648
                *ret_line = line;
649

                
650
                return TRUE;
651
            }
652
        }
653

                
654
        /* Ignore really long lines (> 1MB) */
655
        if (sock->recv_buf->len > 1024 * 1024 * 1) {
656
            CLOSE(sock->socket_id);
657
            sock->socket_id = -1;
658

                
659
            if (error_flag) {
660
                *error_flag = TRUE;
661
            }
662

                
663
            *ret_line = g_strdup("Too long line received from server. Disconnecting");
664

                
665
            return FALSE;
666
        }
667

                
668
        // No newline found, try to read new data from the socket
669
        do {
670
            FD_ZERO(&recv_fds);
671
            FD_SET(sock->socket_id, &recv_fds);
672

                
673
            tv.tv_sec = timeout;
674
            tv.tv_usec = 0;
675

                
676
            len = select(sock->socket_id + 1, &recv_fds, NULL, NULL, &tv);
677
            if (len == 0) {
678
                // Read timeout
679
                *ret_line = g_strdup("Read timeout");
680
                return FALSE;
681
            } else if (len == 1) {
682
                gboolean beenhere = FALSE;
683

                
684
                do {
685
                    if (beenhere) {
686
                        g_usleep(G_USEC_PER_SEC / 10);
687
                    } else {
688
                        beenhere = TRUE;
689
                    }
690

                
691
                    memset(&buf, 0, sizeof(buf));
692
                    len = recv(sock->socket_id, buf, sizeof(buf) - 1, 0);
693

                
694
                    if (len > 0) {
695
                        g_string_append_len(sock->recv_buf, buf, len);
696
                    }
697
                } while (len == -1 && errno == EAGAIN && stamp + timeout > time(NULL));
698
            }
699
        } while (len == -1 && errno == EINTR && stamp + timeout > time(NULL));
700

                
701
        if (len == -1) {
702
            if (errno == EAGAIN) {
703
                // Read timeout
704
                *ret_line = g_strdup("Read timeout");
705
                return FALSE;
706
            }
707

                
708
            // Error occured
709
g_print(__FILE__":%i Error occured: %s\n", __LINE__, strerror(errno));
710
            if (error_flag) {
711
                *error_flag = TRUE;
712
            }
713

                
714
            CLOSE(sock->socket_id);
715
            sock->socket_id = -1;
716

                
717
            *ret_line = g_strdup_printf("Unexpected error occured while performing read: %s", strerror(errno));
718

                
719
            return FALSE;
720
        }
721

                
722
        if (len == 0) {
723
            // EOF, disconnect
724
g_print(__FILE__":%i EOF detected\n", __LINE__);
725
            if (error_flag) {
726
                *error_flag = TRUE;
727
            }
728

                
729
            CLOSE(sock->socket_id);
730
            sock->socket_id = -1;
731

                
732
            *ret_line = g_strdup(_("NNTPGrab server has disconnected"));
733

                
734
            return FALSE;
735
        }
736
    } while (TRUE);
737

                
738
    g_assert_not_reached();
739

                
740
    return FALSE;
741
}
742

                
743
gboolean
744
write_line(Connection *sock, const char *format, ...)
745
{
746
    char *line;
747
    va_list ap;
748

                
749
    va_start(ap, format);
750
    g_vasprintf(&line, format, ap);
751
    va_end(ap);
752

                
753
    if (send(sock->socket_id, line, strlen(line), 0) == -1) {
754
        free(line);
755
        CLOSE(sock->socket_id);
756
        sock->socket_id = -1;
757

                
758
        return FALSE;
759
    }
760

                
761
    free(line);
762

                
763
    return TRUE;
764
}
765

                
766
static void
767
connect_to_server(Connection *sock, const char *hostname, int port, char **errmsg)
768
{
769
    struct addrinfo hints, *res, *ressave;
770
    int n;
771
    char *str_port;
772
    struct timeval tv;
773
#if 0 
774
    SSL *ssl;
775
#endif
776

                
777
    g_return_if_fail(sock != NULL);
778
    g_return_if_fail(hostname != NULL);
779
    g_return_if_fail(port > 0);
780
    g_return_if_fail(port < 65535);
781
    g_return_if_fail(errmsg != NULL);
782
    g_return_if_fail(*errmsg == NULL);
783

                
784
    if (sock->socket_id >= 0) {
785
        CLOSE(sock->socket_id);
786
    }
787

                
788
    sock->socket_id = -1;
789

                
790
    memset(&hints, 0, sizeof(struct addrinfo));
791

                
792
    hints.ai_family = AF_UNSPEC;
793
    hints.ai_socktype = SOCK_STREAM;
794

                
795
    str_port = g_strdup_printf("%i", port);
796
    n = getaddrinfo(hostname, str_port, &hints, &res);
797
    g_free(str_port);
798

                
799
    if (n != 0) {
800
        *errmsg = g_strdup(gai_strerror(n));
801

                
802
        return;
803
    }
804

                
805
    ressave = res;
806

                
807
    while (res) {
808
        sock->socket_id = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
809

                
810
#ifdef WIN32
811
        if ((sock->socket_id == INVALID_SOCKET)) {
812
#else
813
        if ((sock->socket_id == -1)) {
814
#endif
815
            // The socket couldn't be created
816
            // Save the errno and try the next item in the list
817
            res = res->ai_next;
818
            sock->socket_id = -1;
819

                
820
            if (*errmsg) {
821
                g_free(*errmsg);
822
            }
823

                
824
            *errmsg = g_strdup(strerror(errno));
825

                
826
            continue;
827
        }
828

                
829
        // Set the connection timeout on the socket
830
        tv.tv_sec = 5;
831
        tv.tv_usec = 0;
832
        setsockopt(sock->socket_id, SOL_SOCKET, SO_RCVTIMEO, (const void*) &tv, sizeof(tv));
833
        setsockopt(sock->socket_id, SOL_SOCKET, SO_SNDTIMEO, (const void*) &tv, sizeof(tv));
834

                
835
        if (connect(sock->socket_id, res->ai_addr, (int) res->ai_addrlen) == 0) {
836
            // Connection succesfull
837
            break;
838
        }
839

                
840
        // Connection could not be made
841
#ifndef WIN32
842
        if (errno == EINPROGRESS) {
843
            // The connection could not be established within the connect time limit.
844
            // This provides a more clear error message
845
            errno = ETIMEDOUT;
846
        }
847
#endif
848

                
849
        if (*errmsg) {
850
            g_free(*errmsg);
851
        }
852

                
853
#ifdef WIN32
854
        switch(WSAGetLastError()) {
855
            case WSAECONNREFUSED:
856
                *errmsg = g_strdup(_("Connection refused"));
857
                break;
858

                
859
            case WSAETIMEDOUT:
860
                *errmsg = g_strdup(_("Connection timed out"));
861
                break;
862

                
863
            default:
864
                *errmsg = g_strdup_printf(_("Unknown error occured, WSAGetLastError() = %i"), WSAGetLastError());
865
                break;
866
        }
867
#else
868
            *errmsg = g_strdup(strerror(errno));
869
#endif
870

                
871
        CLOSE(sock->socket_id);
872
        sock->socket_id = -1;
873

                
874
        res = res->ai_next;
875
    }
876

                
877
    if (sock->socket_id == -1) {
878
        freeaddrinfo(ressave);
879

                
880
        return;
881
    }
882

                
883
    freeaddrinfo(ressave);
884

                
885
#if 0 
886
    if (use_ssl) {
887
        if ((ssl = prepare_ssl_connection(*conn_id, errmsg)) == NULL) {
888
            CLOSE(*conn_id);
889
            return NNTP_ERROR_SSL_INITIALISE;
890
        }
891
    } else {
892
        ssl = NULL;
893
    }
894
#endif
895
}
896

                
897
NntpgrabCore *
898
get_core(void)
899
{
900
    return (NntpgrabCore*) glue;
901
}
902

                
903
gboolean
904
has_signal_handler_pending(int signal_id)
905
{
906
    if (glue->standalone_core && signal_id != CONNECTION_LOST_SIGNAL) {
907
        return g_signal_has_handler_pending(glue->standalone_core, signals[signal_id], 0, TRUE);
908
    } else {
909
        return g_signal_has_handler_pending(glue, signals[signal_id], 0, TRUE);
910
    }
911
}
912

                
913
static gboolean
914
do_emit_connection_lost(gpointer data)
915
{
916
    char *errmsg = (char *) data;
917

                
918
    if (!get_core()) {
919
        g_free(errmsg);
920
        return FALSE;
921
    }
922

                
923
    g_signal_emit_by_name(get_core(), "connection_lost", errmsg);
924
    g_free(errmsg);
925

                
926
    return FALSE;
927
}
928

                
929
static void
930
emit_connection_lost(const char *errmsg)
931
{
932
    if (!get_core()) {
933
        return;
934
    }
935

                
936
    g_idle_add(do_emit_connection_lost, (gpointer) g_strdup(errmsg));
937
}
938

                
939
static gpointer
940
callbacks_thread(gpointer data)
941
{
942
    NntpgrabGlue *core = data;
943

                
944
    do {
945
        gboolean error_flag;
946
        char *line = NULL;
947

                
948
        if (!read_line(&core->socket, &line, 1, &error_flag)) {
949
            if (error_flag) {
950
                // An error occured!
951
                char *msg = g_strdup_printf(__FILE__ ":%i Connection lost from NNTPGrab Server: %s", __LINE__, line);
952

                
953
                emit_connection_lost(msg);
954
                DEBUG(msg);
955

                
956
                g_free(line);
957
                g_free(msg);
958

                
959
                return NULL;
960
            }
961

                
962
            if (line) {
963
                g_free(line);
964
            }
965

                
966
            // No data received, sleep
967
            g_usleep(G_USEC_PER_SEC / 10);
968

                
969
            continue;
970
        }
971

                
972
        glue_process_jsonrpc_msg(line);
973

                
974
        g_free(line);
975
    } while (!abort_flag);
976

                
977
    return NULL;
978
}
979

                
980
/********************************* 
981
 Public functions
982
 *********************************/
983
NntpgrabGlue *
984
nntpgrab_glue_new(void)
985
{
986
    return g_object_new((GType) NNTPGRAB_TYPE_GLUE, NULL);
987
}
988

                
989
ngboolean
990
nntpgrab_glue_init(NntpgrabGlue *obj, int glue_version, char **err)
991
{
992
#ifdef WIN32
993
    WORD wVersionRequested;
994
    WSADATA wsaData;
995
    int ret;
996
#endif
997

                
998
    glue = NNTPGRAB_GLUE(obj);
999

                
1000
    g_return_val_if_fail(obj != NULL, FALSE);
1001
    g_return_val_if_fail(glue != NULL, FALSE);
1002

                
1003
    if (glue->is_initialized) {
1004
        if (err) {
1005
            *err = g_strdup_printf(_("NNTPGrab Core already initialized"));
1006
        }
1007
        return FALSE;
1008
    }
1009

                
1010
    // Check if the API version matches
1011
    if (glue_version != NNTPGRAB_GLUE_VERSION) {
1012
        if (err) {
1013
            *err = g_strdup_printf(_("NNTPGrab Glue API mismatch (Glue API version = %i, frontend's version = %i)"), NNTPGRAB_GLUE_VERSION, glue_version);
1014
        }
1015
        return FALSE;
1016
    }
1017

                
1018
#ifdef WIN32
1019
    // Initialise Winsock
1020
    wVersionRequested = MAKEWORD( 2, 2 );
1021

                
1022
    ret = WSAStartup( wVersionRequested, &wsaData );
1023
    if ( ret != 0 ) {
1024
        /* Tell the user that we could not find a usable */
1025
        /* WinSock DLL. */
1026
        if (err) {
1027
            *err = g_strdup_printf(_("Winsock could not be initialised"));
1028
        }
1029
        return FALSE;
1030
    }
1031

                
1032
    /* Confirm that the WinSock DLL supports 2.2.*/
1033
    /* Note that if the DLL supports versions greater */
1034
    /* than 2.2 in addition to 2.2, it will still return */
1035
    /* 2.2 in wVersion since that is the version we */
1036
    /* requested. */
1037

                
1038
    if ( LOBYTE( wsaData.wVersion ) != 2 ||
1039
         HIBYTE( wsaData.wVersion ) != 2 ) {
1040
        /* Tell the user that we could not find a usable */
1041
        /* WinSock DLL. */
1042
        WSACleanup( );
1043

                
1044
        if (err) {
1045
            *err = g_strdup_printf(_("Winsock 2.2 or higher is required for this program"));
1046
        }
1047

                
1048
        return FALSE;
1049
    }
1050
#endif
1051

                
1052
    glue->glue_version = glue_version;
1053
    glue->is_initialized = TRUE;
1054

                
1055
    return TRUE;
1056
}
1057

                
1058
static gboolean
1059
ensure_core_library_is_loaded(char **err)
1060
{
1061
    if (module) {
1062
        return TRUE;
1063
    }
1064

                
1065
#ifdef WIN32
1066
#define EXT "-0.dll"
1067
#elif DARWIN
1068
#define EXT ".0.dylib"
1069
#else
1070
#define EXT ".so.0"
1071
#endif
1072

                
1073
    module = g_module_open("libnntpgrab" EXT, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
1074
    if (!module) {
1075
        if (err) {
1076
            *err = g_strdup_printf(_("Error while loading NNTPGrab Core library:\n%s\n"), g_module_error());
1077
        } else {
1078
            g_error(_("Error while loading NNTPGrab Core library:\n%s\n"), g_module_error());
1079
        }
1080
        return FALSE;
1081
    }
1082

                
1083
    g_module_make_resident(module);
1084
    return TRUE;
1085
}
1086

                
1087
static void
1088
bind_func(const char *name, void **func, char **err)
1089
{
1090
    if (!ensure_core_library_is_loaded(err)) {
1091
        return;
1092
    }
1093

                
1094
    if (!(*func)) {
1095
        g_module_symbol(module, name, func);
1096
    }
1097

                
1098
    if (!(*func)) {
1099
        if (err) {
1100
            *err = g_strdup_printf(_("Unable to bind the function '%s'\n%s"), name, g_module_error());
1101
        } else {
1102
            g_critical(_("Unable to bind the function '%s'\n%s"), name, g_module_error());
1103
        }
1104
    }
1105
}
1106

                
1107
static ngboolean
1108
nntpgrab_core_new_and_init(NntpgrabGlue *glue, int version, char **err, char **warnings)
1109
{
1110
    static NntpgrabCore *(*new_func) (void) = NULL;
1111
    static ngboolean (*init_func) (NntpgrabCore *, int, char **, char **) = NULL;
1112

                
1113
    g_return_val_if_fail(glue != NULL, FALSE);
1114

                
1115
    if (!ensure_core_library_is_loaded(err)) {
1116
        return FALSE;
1117
    }
1118

                
1119
    bind_func("nntpgrab_core_new", (void**) &new_func, err);
1120
    g_return_val_if_fail(new_func != NULL, FALSE);
1121
    glue->standalone_core = new_func();
1122

                
1123
    bind_func("nntpgrab_core_init", (void**) &init_func, err);
1124
    g_return_val_if_fail(init_func != NULL, FALSE);
1125
    if (!init_func(glue->standalone_core, version, err, warnings)) {
1126
        return FALSE;
1127
    }
1128

                
1129
    return TRUE;
1130
}
1131

                
1132
ngboolean
1133
nntpgrab_glue_connect(NntpgrabGlue *obj, const char *hostname, int port, const char *username, const char *password, ngboolean use_ssl, char **err, char **warnings)
1134
{
1135
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1136
    int api_version = 0;
1137
    char *line = NULL;
1138

                
1139
    g_return_val_if_fail(glue != NULL, FALSE);
1140
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1141
    g_return_val_if_fail(err != NULL, FALSE);
1142
    g_return_val_if_fail(*err == NULL, FALSE);
1143
    g_return_val_if_fail(warnings != NULL, FALSE);
1144
    g_return_val_if_fail(*warnings == NULL, FALSE);
1145

                
1146
    if (!hostname || strlen(hostname) == 0) {
1147
        return nntpgrab_core_new_and_init(glue, NNTPGRAB_API_VERSION, err, warnings);
1148
    }
1149

                
1150
    connect_to_server(&glue->socket, hostname, port, err);
1151
    if (glue->socket.socket_id < 0) {
1152
        return FALSE;
1153
    }
1154

                
1155
    // API check
1156
    if (!write_line(&glue->socket, "NNTPGrab - API version %i\r\n\r\n", NNTPGRAB_PLUGIN_API_VERSION)) {
1157
        *err = g_strdup_printf(_("NNTPGrab Server API mismatch (Server API version = %i, frontend's version = %i)"), NNTPGRAB_PLUGIN_API_VERSION, api_version);
1158
        return FALSE;
1159
    }
1160

                
1161
    if (!read_line(&glue->socket, &line, READ_TIMEOUT_VALUE, NULL)) {
1162
        char msg[128];
1163

                
1164
        memset(&msg, 0, sizeof(msg));
1165
        snprintf(msg, sizeof(msg) - 1, __FILE__ ":%i Connection lost from NNTPGrab Server: %s\n", __LINE__, line);
1166
        DEBUG(msg);
1167

                
1168
        g_free(line);
1169
        return FALSE;
1170
    }
1171

                
1172
    if (strcmp(line, "OK")) {
1173
        char msg[128];
1174

                
1175
        memset(&msg, 0, sizeof(msg));
1176
        snprintf(msg, sizeof(msg) - 1, __FILE__ ":%i unknown response received: %s\n", __LINE__, (line ? line : ""));
1177
        DEBUG(msg);
1178

                
1179
        g_free(line);
1180
        return FALSE;
1181
    }
1182

                
1183
    g_free(line);
1184

                
1185
    thread_listener = g_thread_create(callbacks_thread, glue, TRUE, NULL);
1186

                
1187
    return TRUE;
1188
}
1189

                
1190
ngboolean
1191
nntpgrab_glue_get_is_connected(NntpgrabGlue *obj)
1192
{
1193
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1194

                
1195
    if (glue->socket.socket_id < 0) {
1196
        return FALSE;
1197
    }
1198

                
1199
    return TRUE;
1200
}
1201

                
1202
void
1203
nntpgrab_glue_destroy(NntpgrabGlue *obj)
1204
{
1205
    g_object_unref(obj);
1206
}
1207

                
1208
void
1209
nntpgrab_glue_kill_server(NntpgrabGlue *obj)
1210
{
1211
    nntpgrab_glue_internal_kill_server(obj);
1212
}
1213

                
1214
NGList *
1215
nntpgrab_glue_config_get_avail_servers(NntpgrabGlue *obj)
1216
{
1217
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1218
    static NGList *(*func) (NntpgrabCore *) = NULL;
1219

                
1220
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1221

                
1222
    if (glue->standalone_core) {
1223
        bind_func("nntpgrab_core_config_get_avail_servers", (void**) &func, NULL);
1224
        g_return_val_if_fail(func != NULL, NULL);
1225
        return func(glue->standalone_core);
1226
    } else {
1227
        return nntpgrab_glue_internal_config_get_avail_servers(glue);
1228
    }
1229
}
1230

                
1231
void
1232
nntpgrab_glue_config_free_avail_servers(NntpgrabGlue *obj, NGList *servers)
1233
{
1234
    NGList *list;
1235

                
1236
    list = servers;
1237
    while (list) {
1238
        g_free(list->data);
1239
        list = ng_list_next(list);
1240
    }
1241

                
1242
    g_list_free((GList*) servers);
1243
}
1244

                
1245
gboolean
1246
nntpgrab_glue_config_get_server_info(NntpgrabGlue *obj, const char *servername, NGConfigServer *ret)
1247
{
1248
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1249
    static gboolean (*func) (NntpgrabCore *, const char *, NGConfigServer *) = NULL;
1250

                
1251
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1252

                
1253
    if (glue->standalone_core) {
1254
        bind_func("nntpgrab_core_config_get_server_info", (void**) &func, NULL);
1255
        g_return_val_if_fail(func != NULL, FALSE);
1256
        return func(glue->standalone_core, servername, ret);
1257
    } else {
1258
        return nntpgrab_glue_internal_config_get_server_info(glue, servername, ret);
1259
    }
1260
}
1261

                
1262
gboolean
1263
nntpgrab_glue_config_add_server(NntpgrabGlue *obj, NGConfigServer new_server, char **errmsg)
1264
{
1265
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1266
    static gboolean (*func) (NntpgrabCore *, NGConfigServer, char **) = NULL;
1267

                
1268
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1269

                
1270
    if (glue->standalone_core) {
1271
        bind_func("nntpgrab_core_config_add_server", (void**) &func, NULL);
1272
        g_return_val_if_fail(func != NULL, FALSE);
1273
        return func(glue->standalone_core, new_server, errmsg);
1274
    } else {
1275
        return nntpgrab_glue_internal_config_add_server(glue, new_server, errmsg);
1276
    }
1277
}
1278

                
1279
gboolean
1280
nntpgrab_glue_config_del_server(NntpgrabGlue *obj, const char *servername, char **errmsg)
1281
{
1282
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1283
    static gboolean (*func) (NntpgrabCore *, const char *, char **) = NULL;
1284

                
1285
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1286

                
1287
    if (glue->standalone_core) {
1288
        bind_func("nntpgrab_core_config_del_server", (void**) &func, NULL);
1289
        g_return_val_if_fail(func != NULL, FALSE);
1290
        return func(glue->standalone_core, servername, errmsg);
1291
    } else {
1292
        return nntpgrab_glue_internal_config_del_server(glue, servername, errmsg);
1293
    }
1294
}
1295

                
1296
gboolean
1297
nntpgrab_glue_config_edit_server(NntpgrabGlue *obj, const char *servername, NGConfigServer new_server, char **errmsg)
1298
{
1299
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1300
    static gboolean (*func) (NntpgrabCore *, const char *, NGConfigServer, char **) = NULL;
1301

                
1302
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1303

                
1304
    if (glue->standalone_core) {
1305
        bind_func("nntpgrab_core_config_edit_server", (void**) &func, NULL);
1306
        g_return_val_if_fail(func != NULL, FALSE);
1307
        return func(glue->standalone_core, servername, new_server, errmsg);
1308
    } else {
1309
        return nntpgrab_glue_internal_config_edit_server(glue, servername, new_server, errmsg);
1310
    }
1311
}
1312

                
1313
NGConfigOpts
1314
nntpgrab_glue_config_get_opts(NntpgrabGlue *obj)
1315
{
1316
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1317
    static NGConfigOpts (*func) (NntpgrabCore *) = NULL;
1318
    NGConfigOpts dummy;
1319

                
1320
    memset(&dummy, 0, sizeof(NGConfigOpts));
1321
    g_return_val_if_fail(glue->is_initialized == TRUE, dummy);
1322

                
1323
    if (glue->standalone_core) {
1324
        bind_func("nntpgrab_core_config_get_opts", (void**) &func, NULL);
1325

                
1326
        g_return_val_if_fail(func != NULL, dummy);
1327

                
1328
        return func(glue->standalone_core);
1329
    } else {
1330
        NGConfigOpts ret;
1331

                
1332
        memset(&ret, 0, sizeof(NGConfigOpts));
1333

                
1334
        if (!nntpgrab_glue_internal_config_get_opts(glue, &ret)) {
1335
            return dummy;
1336
        } else {
1337
            return ret;
1338
        }
1339
    }
1340
}
1341

                
1342
void
1343
nntpgrab_glue_config_set_opts(NntpgrabGlue *obj, NGConfigOpts opts)
1344
{
1345
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1346
    static void (*func) (NntpgrabCore *, NGConfigOpts) = NULL;
1347

                
1348
    g_return_if_fail(glue->is_initialized == TRUE);
1349

                
1350
    if (glue->standalone_core) {
1351
        bind_func("nntpgrab_core_config_set_opts", (void**) &func, NULL);
1352
        g_return_if_fail(func != NULL);
1353
        func(glue->standalone_core, opts);
1354
    } else {
1355
        nntpgrab_glue_internal_config_set_opts(glue, opts);
1356
    }
1357
}
1358

                
1359
ngboolean
1360
nntpgrab_glue_config_get_folder_listing(NntpgrabGlue *obj, const char *parent, NGList **folders)
1361
{
1362
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1363

                
1364
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1365

                
1366
    if (glue->standalone_core) {
1367
        return nntpgrab_utils_get_folder_listing(parent, folders);
1368
    } else {
1369
        return nntpgrab_glue_internal_config_get_folder_listing(glue, parent, folders);
1370
    }
1371
}
1372

                
1373
void
1374
nntpgrab_glue_config_free_folder_listing(NntpgrabGlue *obj, NGList *folders)
1375
{
1376
    nntpgrab_utils_free_folder_listing(folders);
1377
}
1378

                
1379
gboolean
1380
nntpgrab_glue_schedular_start(NntpgrabGlue *obj)
1381
{
1382
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1383
    static gboolean (*func) (NntpgrabCore *) = NULL;
1384

                
1385
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1386

                
1387
    if (glue->standalone_core) {
1388
        bind_func("nntpgrab_core_schedular_start", (void**) &func, NULL);
1389
        g_return_val_if_fail(func != NULL, FALSE);
1390
        return func(glue->standalone_core);
1391
    } else {
1392
        return nntpgrab_glue_internal_schedular_start(glue);
1393
    }
1394
}
1395

                
1396
gboolean
1397
nntpgrab_glue_schedular_stop(NntpgrabGlue *obj, gboolean wait)
1398
{
1399
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1400
    static gboolean (*func) (NntpgrabCore *, gboolean) = NULL;
1401

                
1402
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1403

                
1404
    if (glue->standalone_core) {
1405
        bind_func("nntpgrab_core_schedular_stop", (void**) &func, NULL);
1406
        g_return_val_if_fail(func != NULL, FALSE);
1407
        return func(glue->standalone_core, wait);
1408
    } else {
1409
        return nntpgrab_glue_internal_schedular_stop(glue, wait);
1410
    }
1411
}
1412

                
1413
NGSchedularState
1414
nntpgrab_glue_schedular_get_state(NntpgrabGlue *obj)
1415
{
1416
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1417
    static NGSchedularState (*func) (NntpgrabCore *) = NULL;
1418

                
1419
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1420

                
1421
    if (glue->standalone_core) {
1422
        bind_func("nntpgrab_core_schedular_get_state", (void**) &func, NULL);
1423
        g_return_val_if_fail(func != NULL, SCHEDULAR_STATE_STOPPED);
1424
        return func(glue->standalone_core);
1425
    } else {
1426
        return nntpgrab_glue_internal_schedular_get_state(glue);
1427
    }
1428
}
1429

                
1430
ngboolean
1431
nntpgrab_glue_schedular_add_task_to_queue(NntpgrabGlue *obj, const char *collection_name, const char *subject, const char *poster, time_t stamp, nguint64 file_size, NGList *groups, NGList *parts, char **errmsg)
1432
{
1433
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1434
    static ngboolean (*func) (NntpgrabCore *, const char *, const char *, const char *, time_t, nguint64, NGList *, NGList *, char **) = NULL;
1435

                
1436
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1437

                
1438
    if (glue->standalone_core) {
1439
        bind_func("nntpgrab_core_schedular_add_task_to_queue", (void**) &func, NULL);
1440
        g_return_val_if_fail(func != NULL, FALSE);
1441
        return func(glue->standalone_core, collection_name, subject, poster, stamp, file_size, groups, parts, errmsg);
1442
    } else {
1443
        return nntpgrab_glue_internal_schedular_add_task_to_queue(glue, collection_name, subject, poster, stamp, file_size, groups, parts, errmsg);
1444
    }
1445
}
1446

                
1447
ngboolean
1448
nntpgrab_glue_schedular_del_task_from_queue(NntpgrabGlue *obj, const char *collection_name, const char *subject, char **errmsg)
1449
{
1450
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1451
    static ngboolean (*func) (NntpgrabCore *, const char *, const char *, char **) = NULL;
1452

                
1453
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1454

                
1455
    if (glue->standalone_core) {
1456
        bind_func("nntpgrab_core_schedular_del_task_from_queue", (void**) &func, NULL);
1457
        g_return_val_if_fail(func != NULL, FALSE);
1458
        return func(glue->standalone_core, collection_name, subject, errmsg);
1459
    } else {
1460
        return nntpgrab_glue_internal_schedular_del_task_from_queue(glue, collection_name, subject, errmsg);
1461
    }
1462
}
1463

                
1464
ngboolean
1465
nntpgrab_glue_schedular_restart_task(NntpgrabGlue *obj, const char *collection_name, const char *subject, char **errmsg)
1466
{
1467
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1468
    static ngboolean (*func) (NntpgrabCore *, const char *, const char *, char **) = NULL;
1469

                
1470
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1471

                
1472
    if (glue->standalone_core) {
1473
        bind_func("nntpgrab_core_schedular_restart_task", (void**) &func, NULL);
1474
        g_return_val_if_fail(func != NULL, FALSE);
1475
        return func(glue->standalone_core, collection_name, subject, errmsg);
1476
    } else {
1477
        return nntpgrab_glue_internal_schedular_restart_task(glue, collection_name, subject, errmsg);
1478
    }
1479
}
1480

                
1481
ngboolean
1482
nntpgrab_glue_schedular_save_queue(NntpgrabGlue *obj, char **errmsg)
1483
{
1484
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1485
    static ngboolean (*func) (NntpgrabCore *, char **) = NULL;
1486

                
1487
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1488

                
1489
    if (glue->standalone_core) {
1490
        bind_func("nntpgrab_core_schedular_save_queue", (void**) &func, NULL);
1491
        g_return_val_if_fail(func != NULL, FALSE);
1492
        return func(glue->standalone_core, errmsg);
1493
    } else {
1494
        return nntpgrab_glue_internal_schedular_save_queue(glue, errmsg);
1495
    }
1496
}
1497

                
1498
void
1499
nntpgrab_glue_schedular_foreach_task(NntpgrabGlue *obj, ForeachCollectionFunc collection_func, ForeachFileFunc file_func, ForeachGroupFunc group_func, void *data)
1500
{
1501
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1502
    static void (*func) (NntpgrabCore *, ForeachCollectionFunc, ForeachFileFunc, ForeachGroupFunc, void *) = NULL;
1503

                
1504
    g_return_if_fail(glue->is_initialized == TRUE);
1505

                
1506
    if (glue->standalone_core) {
1507
        bind_func("nntpgrab_core_schedular_foreach_task", (void**) &func, NULL);
1508
        g_return_if_fail(func != NULL);
1509
        func(glue->standalone_core, collection_func, file_func, group_func, data);
1510
    } else {
1511
        nntpgrab_glue_internal_schedular_foreach_task(glue, collection_func, file_func, group_func, data);
1512
    }
1513
}
1514

                
1515
ngboolean
1516
nntpgrab_glue_schedular_move_task(NntpgrabGlue *obj, const char *collection_name_src, const char *subject_src, const char *collection_name_dest, int position_dest)
1517
{
1518
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1519
    static ngboolean (*func) (NntpgrabCore *, const char *, const char *, const char *, int) = NULL;
1520

                
1521
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1522

                
1523
    if (glue->standalone_core) {
1524
        bind_func("nntpgrab_core_schedular_move_task", (void**) &func, NULL);
1525
        g_return_val_if_fail(func != NULL, FALSE);
1526
        return func(glue->standalone_core, collection_name_src, subject_src, collection_name_dest, position_dest);
1527
    } else {
1528
        return nntpgrab_glue_internal_schedular_move_task(glue, collection_name_src, subject_src, collection_name_dest, position_dest);
1529
    }
1530
}
1531

                
1532
ngboolean
1533
nntpgrab_glue_schedular_move_collection(NntpgrabGlue *obj, const char *collection_name, int new_position)
1534
{
1535
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1536
    static ngboolean (*func) (NntpgrabCore *, const char *, int) = NULL;
1537

                
1538
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1539

                
1540
    if (glue->standalone_core) {
1541
        bind_func("nntpgrab_core_schedular_move_collection", (void**) &func, NULL);
1542
        g_return_val_if_fail(func != NULL, FALSE);
1543
        return func(glue->standalone_core, collection_name, new_position);
1544
    } else {
1545
        return nntpgrab_glue_internal_schedular_move_collection(glue, collection_name, new_position);
1546
    }
1547
}
1548

                
1549
ngboolean
1550
nntpgrab_glue_schedular_mark_task_optional(NntpgrabGlue *obj, const char *collection_name, const char *subject, ngboolean is_optional)
1551
{
1552
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1553
    static ngboolean (*func) (NntpgrabCore *, const char *, const char *, ngboolean) = NULL;
1554

                
1555
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1556

                
1557
    if (glue->standalone_core) {
1558
        bind_func("nntpgrab_core_schedular_mark_task_optional", (void**) &func, NULL);
1559
        g_return_val_if_fail(func != NULL, FALSE);
1560
        return func(glue->standalone_core, collection_name, subject, is_optional);
1561
    } else {
1562
        return nntpgrab_glue_internal_schedular_mark_task_optional(glue, collection_name, subject, is_optional);
1563
    }
1564
}
1565

                
1566
NGList *
1567
nntpgrab_glue_plugins_get_avail_plugins(NntpgrabGlue *obj)
1568
{
1569
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1570
    static NGList *(*func) (NntpgrabCore *) = NULL;
1571

                
1572
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1573

                
1574
    if (glue->standalone_core) {
1575
        bind_func("nntpgrab_core_plugins_get_avail_plugins", (void**) &func, NULL);
1576
        g_return_val_if_fail(func != NULL, FALSE);
1577
        return func(glue->standalone_core);
1578
    } else {
1579
        return nntpgrab_glue_internal_plugins_get_avail_plugins(glue);
1580
    }
1581
}
1582

                
1583
void
1584
nntpgrab_glue_plugins_free_avail_plugins(NntpgrabGlue *obj, NGList *plugins)
1585
{
1586
    NGList *list;
1587

                
1588
    list = plugins;
1589
    while (list) {
1590
        g_free(list->data);
1591
        list = ng_list_next(list);
1592
    }
1593

                
1594
    g_list_free((GList*) plugins);
1595
}
1596

                
1597
ngboolean
1598
nntpgrab_glue_plugins_get_plugin_info(NntpgrabGlue *obj, const char *plugin_name, NNTPGrabPluginInfo *plugin_info)
1599
{
1600
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1601
    static ngboolean (*func) (NntpgrabCore *, const char *, NNTPGrabPluginInfo *) = NULL;
1602

                
1603
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1604

                
1605
    if (glue->standalone_core) {
1606
        bind_func("nntpgrab_core_plugins_get_plugin_info", (void**) &func, NULL);
1607
        g_return_val_if_fail(func != NULL, FALSE);
1608
        return func(glue->standalone_core, plugin_name, plugin_info);
1609
    } else {
1610
        return nntpgrab_glue_internal_plugins_get_plugin_info(glue, plugin_name, plugin_info);
1611
    }
1612
}
1613

                
1614
ngboolean
1615
nntpgrab_glue_plugins_load_plugin(NntpgrabGlue *obj, const char *plugin_name, char **errmsg)
1616
{
1617
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1618
    static ngboolean (*func) (NntpgrabCore *, const char *, char **) = NULL;
1619

                
1620
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1621

                
1622
    if (glue->standalone_core) {
1623
        bind_func("nntpgrab_core_plugins_load_plugin", (void**) &func, NULL);
1624
        g_return_val_if_fail(func != NULL, FALSE);
1625
        return func(glue->standalone_core, plugin_name, errmsg);
1626
    } else {
1627
        return nntpgrab_glue_internal_plugins_load_plugin(glue, plugin_name, errmsg);
1628
    }
1629
}
1630

                
1631
ngboolean
1632
nntpgrab_glue_plugins_unload_plugin(NntpgrabGlue *obj, const char *plugin_name, char **errmsg)
1633
{
1634
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1635
    static ngboolean (*func) (NntpgrabCore *, const char *, char **) = NULL;
1636

                
1637
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1638

                
1639
    if (glue->standalone_core) {
1640
        bind_func("nntpgrab_core_plugins_unload_plugin", (void**) &func, NULL);
1641
        g_return_val_if_fail(func != NULL, FALSE);
1642
        return func(glue->standalone_core, plugin_name, errmsg);
1643
    } else {
1644
        return nntpgrab_glue_internal_plugins_unload_plugin(glue, plugin_name, errmsg);
1645
    }
1646
}
1647

                
1648
ngboolean
1649
nntpgrab_glue_plugins_set_persistent(NntpgrabGlue *obj, const char *plugin_name, ngboolean persistent)
1650
{
1651
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1652
    static ngboolean (*func) (NntpgrabCore *, const char *, ngboolean) = NULL;
1653

                
1654
    g_return_val_if_fail(glue->is_initialized == TRUE, FALSE);
1655

                
1656
    if (glue->standalone_core) {
1657
        bind_func("nntpgrab_core_plugins_set_persistent", (void**) &func, NULL);
1658
        g_return_val_if_fail(func != NULL, FALSE);
1659
        return func(glue->standalone_core, plugin_name, persistent);
1660
    } else {
1661
        return nntpgrab_glue_internal_plugins_set_persistent(glue, plugin_name, persistent);
1662
    }
1663
}
1664

                
1665
ngboolean
1666
nntpgrab_glue_get_is_standalone(NntpgrabGlue *obj)
1667
{
1668
    g_return_val_if_fail(glue != NULL, FALSE);
1669

                
1670
    return (glue->standalone_core != NULL);
1671
}
1672

                
1673
void
1674
nntpgrab_glue_set_emit_log_messages(NntpgrabGlue *obj, ngboolean val)
1675
{
1676
    NntpgrabGlue *glue = NNTPGRAB_GLUE(obj);
1677
    static void (*func) (NntpgrabCore *, ngboolean) = NULL;
1678

                
1679
    g_return_if_fail(glue->is_initialized == TRUE);
1680

                
1681
    if (glue->standalone_core) {
1682
        bind_func("nntpgrab_core_set_emit_log_messages", (void**) &func, NULL);
1683
        g_return_if_fail(func != NULL);
1684
        func(glue->standalone_core, val);
1685
    } else {
1686
        nntpgrab_glue_internal_set_emit_log_messages(glue, val);
1687
    }
1688
}