00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 #include 
00020 #include 
00021 #include 
00022 #include 
00023 #include 
00024 
00025 #include "configuration.h"
00026 #include "schedular.h"
00027 #include "plugin_schedular.h"
00028 #include "nntpgrab_plugin_schedular.h"
00029 #include "nntpconnection.h"
00030 #include "decoder.h"
00031 #include "nntpgrab_internal.h"
00032 
00033 static PluginSchedularExportedFuncs plugin_funcs;
00034 static GModule *plugin = NULL;
00035 static Schedular *schedular = NULL;
00036 
00037 typedef struct SchedularClass SchedularClass;
00038 
00039 static GType schedular_get_type (void);
00040 
00041 static void task_added_callback(const NNTPCollection *collection, const NNTPFile *file);
00042 static void task_removed_callback(const char *collection_name, const char *subject, guint64 total_file_size, guint64 total_file_size_remaining);
00043 static void task_state_changed_callback(const char *collection_name, const char *subject, TaskState old_state, TaskState new_state);
00044 static void collection_added_callback(const char *collection_name);
00045 static void collection_removed_callback(const char *collection_name);
00046 static GList *config_get_avail_servers(void);
00047 static ConfigServer *config_get_server_info(const char *servername);
00048 static ConfigOpts config_get_opts (void);
00049 static gpointer nntp_connection_initialize (const char *servername, NNTPGrabErrCode *err);
00050 static void nntp_connection_destroy (gpointer obj);
00051 static NNTPGrabErrCode nntp_connection_get_part (gpointer obj, const char *collection_name, const NNTPFile *file, const NNTPPart *part, char **reason);
00052 static gboolean decode_file (const char *collection_name, const NNTPFile *file, int *saved_errno);
00053 static void notify_schedular_state_changed (SchedularState new_state, const char *reason);
00054 static void emit_fatal_error (const char *errmsg);
00055 static void emit_part_download_complete (const char *servername, gpointer connection, const char *collection_name, const char *subject, int partnum, int size);
00056 static void emit_part_download_failed (const char *servername, gpointer connection, const char *collection_name, const char *subject, int partnum, int size, gboolean all_servers_tried);
00057 static void emit_task_moved (const char *orig_collection_name, const char *subject, const char *new_collection_name, int old_position, int new_position);
00058 static void emit_collection_moved (const char *collection_name, int old_position, int new_position);
00059 static void emit_file_download_state_update (const char *collection_name, const char *subject, int num_parts_total, int num_parts_done, int num_parts_failed, guint64 file_size, guint64 file_size_remaining, guint64 total_file_size, guint64 total_file_size_remaining);
00060 static void config_changed_callback(Configuration *config, ConfigChangedFlag flag, gpointer data);
00061 
00062 struct Schedular
00063 {
00064     GObject parent;
00065 
00066     GStaticRWLock rwlock;
00067     Configuration *config;
00068     ConfigOpts opts;
00069     Decoder *decoder;
00070 };
00071 
00072 struct SchedularClass
00073 {
00074     GObjectClass parent;
00075 };
00076 
00077 G_DEFINE_TYPE(Schedular, schedular, G_TYPE_OBJECT);
00078 
00079 static void
00080 schedular_init (Schedular *obj)
00081 {
00082     g_static_rw_lock_init(&obj->rwlock);
00083 }
00084 
00085 static void
00086 schedular_finalize (GObject *obj)
00087 {
00088     Schedular *schedular = SCHEDULAR(obj);
00089 
00090     if (plugin_funcs.destroy) {
00091         plugin_funcs.destroy();
00092     }
00093 
00094     g_module_close(plugin);
00095 
00096     g_static_rw_lock_writer_lock(&schedular->rwlock);
00097 
00098     g_object_unref(schedular->config);
00099     decoder_destroy(schedular->decoder);
00100 
00101     g_static_rw_lock_writer_unlock(&schedular->rwlock);
00102 
00103     g_static_rw_lock_free(&schedular->rwlock);
00104 }
00105 
00106 static void
00107 schedular_class_init (SchedularClass *klass)
00108 {
00109     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
00110 
00111     gobject_class->finalize = schedular_finalize;
00112 }
00113 
00114 Schedular *
00115 schedular_new(Configuration *config, char **errmsg)
00116 {
00117     static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
00118 
00119     g_static_mutex_lock(&mutex);
00120 
00121     g_assert(schedular == NULL);
00122 
00123     if (!plugin) {
00124         char *msg;
00125         PluginSchedularImportedFuncs imported_funcs;
00126         plugin_schedular_init_func init_func;
00127         char *filename;
00128 
00129 #ifdef WIN32
00130 #define EXT "-0.dll"
00131 #else
00132 #define EXT ".so"
00133 #endif
00134 
00135        if (g_getenv("NNTPGRAB_LIBDIR")) {
00136             filename = g_strdup_printf("%s/libnntpgrab_plugin_schedular%s", g_getenv("NNTPGRAB_LIBDIR"), EXT);
00137        } else {
00138             filename = g_strdup_printf("%s/libnntpgrab_plugin_schedular%s", PLUGIN_DIR, EXT);
00139        }
00140 
00141         plugin = g_module_open(filename, G_MODULE_BIND_LOCAL);
00142 
00143         g_free(filename);
00144 
00145         if (!plugin) {
00146             if (errmsg) {
00147                 *errmsg = g_strdup(g_module_error());
00148             }
00149 
00150             return NULL;
00151         }
00152 
00153         imported_funcs.version = NNTPGRAB_PLUGIN_API_VERSION;
00154         imported_funcs.task_added = task_added_callback;
00155         imported_funcs.task_removed = task_removed_callback;
00156         imported_funcs.task_state_changed = task_state_changed_callback;
00157         imported_funcs.collection_added = collection_added_callback;
00158         imported_funcs.collection_removed = collection_removed_callback;
00159         imported_funcs.config_get_avail_servers = config_get_avail_servers;
00160         imported_funcs.config_get_server_info = config_get_server_info;
00161         imported_funcs.config_get_opts = config_get_opts;
00162         imported_funcs.nntp_connection_initialize = nntp_connection_initialize;
00163         imported_funcs.nntp_connection_destroy = nntp_connection_destroy;
00164         imported_funcs.nntp_connection_get_part = nntp_connection_get_part;
00165         imported_funcs.decode_file = decode_file;
00166         imported_funcs.notify_schedular_state_changed = notify_schedular_state_changed;
00167         imported_funcs.emit_fatal_error = emit_fatal_error;
00168         imported_funcs.emit_part_download_complete = emit_part_download_complete;
00169         imported_funcs.emit_part_download_failed = emit_part_download_failed;
00170         imported_funcs.emit_task_moved = emit_task_moved;
00171         imported_funcs.emit_collection_moved = emit_collection_moved;
00172         imported_funcs.emit_file_download_state_update = emit_file_download_state_update;
00173 
00174         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_get_version", (gpointer *) &plugin_funcs.get_version)) {
00175             if (errmsg) {
00176                 *errmsg = g_strdup(g_module_error());
00177             }
00178 
00179             return NULL;
00180         }
00181 
00182         
00183         if (plugin_funcs.get_version() != NNTPGRAB_PLUGIN_API_VERSION) {
00184             if (errmsg) {
00185                 *errmsg = g_strdup_printf(_("Schedular Plugin API mismatch (Plugin API version = %i, expected = %i)"), plugin_funcs.get_version(), NNTPGRAB_PLUGIN_API_VERSION);
00186             }
00187 
00188             return NULL;
00189         }
00190 
00191         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_initialize", (gpointer *) &init_func)) {
00192             if (errmsg) {
00193                 *errmsg = g_strdup(g_module_error());
00194             }
00195 
00196             return NULL;
00197         }
00198 
00199         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_destroy", (gpointer *) &plugin_funcs.destroy)) {
00200             if (errmsg) {
00201                 *errmsg = g_strdup(g_module_error());
00202             }
00203 
00204             return NULL;
00205         }
00206 
00207         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_start", (gpointer *) &plugin_funcs.start)) {
00208             if (errmsg) {
00209                 *errmsg = g_strdup(g_module_error());
00210             }
00211 
00212             return NULL;
00213         }
00214 
00215         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_stop", (gpointer *) &plugin_funcs.stop)) {
00216             if (errmsg) {
00217                 *errmsg = g_strdup(g_module_error());
00218             }
00219 
00220             return NULL;
00221         }
00222 
00223         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_get_state", (gpointer *) &plugin_funcs.get_state)) {
00224             if (errmsg) {
00225                 *errmsg = g_strdup(g_module_error());
00226             }
00227 
00228             return NULL;
00229         }
00230 
00231         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_add_task_to_queue", (gpointer *) &plugin_funcs.add_task_to_queue)) {
00232             if (errmsg) {
00233                 *errmsg = g_strdup(g_module_error());
00234             }
00235 
00236             return NULL;
00237         }
00238 
00239         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_del_task_from_queue", (gpointer *) &plugin_funcs.del_task_from_queue)) {
00240             if (errmsg) {
00241                 *errmsg = g_strdup(g_module_error());
00242             }
00243 
00244             return NULL;
00245         }
00246 
00247         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_restart_task", (gpointer *) &plugin_funcs.restart_task)) {
00248             if (errmsg) {
00249                 *errmsg = g_strdup(g_module_error());
00250             }
00251 
00252             return NULL;
00253         }
00254 
00255         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_save_queue", (gpointer *) &plugin_funcs.save_queue)) {
00256             if (errmsg) {
00257                 *errmsg = g_strdup(g_module_error());
00258             }
00259 
00260             return NULL;
00261         }
00262 
00263         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_foreach_task", (gpointer *) &plugin_funcs.foreach_task)) {
00264             if (errmsg) {
00265                 *errmsg = g_strdup(g_module_error());
00266             }
00267 
00268             return NULL;
00269         }
00270 
00271         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_move_task", (gpointer *) &plugin_funcs.move_task)) {
00272             if (errmsg) {
00273                 *errmsg = g_strdup(g_module_error());
00274             }
00275 
00276             return NULL;
00277         }
00278 
00279         if (!g_module_symbol(plugin, "nntpgrab_plugin_schedular_move_collection", (gpointer *) &plugin_funcs.move_collection)) {
00280             if (errmsg) {
00281                 *errmsg = g_strdup(g_module_error());
00282             }
00283 
00284             return NULL;
00285         }
00286 
00287         
00288         if (!init_func(imported_funcs, &msg)) {
00289             if (errmsg) {
00290                 *errmsg = g_strdup_printf(_("Schedular Plugin initialization failed!\n%s"), msg);
00291             }
00292 
00293             g_free(msg);
00294 
00295             return NULL;
00296         }
00297 
00298         nntpgrab_core_emit_debug_message(_("Schedular plugin initialized"));
00299     }
00300 
00301     g_object_ref(config);
00302 
00303     schedular = g_object_new(SCHEDULAR_TYPE_OBJECT, NULL);
00304     schedular->config = config;
00305     schedular->decoder = decoder_new(config);
00306     schedular->opts = configuration_get_opts(schedular->config);
00307 
00308     g_signal_connect(config, "config_changed", G_CALLBACK(config_changed_callback), NULL);
00309 
00310     g_static_mutex_unlock(&mutex);
00311 
00312     return schedular;
00313 }
00314 
00315 void
00316 schedular_destroy(Schedular *obj)
00317 {
00318     g_object_unref(obj);
00319 }
00320 
00321 gboolean
00322 schedular_start(Schedular *obj)
00323 {
00324     g_assert(plugin_funcs.start);
00325 
00326     return plugin_funcs.start();
00327 }
00328 
00329 gboolean
00330 schedular_stop(Schedular *obj)
00331 {
00332     g_assert(plugin_funcs.stop);
00333 
00334     return plugin_funcs.stop(NULL);
00335 }
00336 
00337 SchedularState
00338 schedular_get_state (Schedular *obj)
00339 {
00340     g_assert(plugin_funcs.get_state);
00341 
00342     return plugin_funcs.get_state();
00343 }
00344 
00345 gboolean
00346 schedular_add_task_to_queue(Schedular *obj, const char *collection_name, const NNTPFile *file, char **errmsg)
00347 {
00348     char *msg;
00349 
00350     g_assert(plugin_funcs.add_task_to_queue);
00351 
00352     msg = g_strdup_printf(_("New task added to queue, collection_name = '%s', subject = '%s'"), collection_name, file->subject);
00353     nntpgrab_core_emit_debug_message(msg);
00354     g_free(msg);
00355 
00356     return plugin_funcs.add_task_to_queue(collection_name, file, errmsg);
00357 }
00358 
00359 gboolean
00360 schedular_del_task_from_queue(Schedular *obj, const char *collection_name, const char *subject, char **errmsg)
00361 {
00362     char *msg;
00363 
00364     g_assert(plugin_funcs.del_task_from_queue);
00365 
00366     if (!subject) {
00367         msg = g_strdup_printf(_("Entire collection removed from queue, collection_name = '%s'"), collection_name);
00368     } else {
00369         msg = g_strdup_printf(_("Task removed from queue, collection_name = '%s', subject = '%s'"), collection_name, subject);
00370     }
00371     nntpgrab_core_emit_debug_message(msg);
00372     g_free(msg);
00373 
00374     return plugin_funcs.del_task_from_queue(collection_name, subject, errmsg);
00375 }
00376 
00377 gboolean
00378 schedular_restart_task(Schedular *obj, const char *collection_name, const char *subject, char **errmsg)
00379 {
00380     char *msg;
00381 
00382     g_assert(plugin_funcs.restart_task);
00383 
00384     if (!subject) {
00385         msg = g_strdup_printf(_("Entire collection restarted, collection_name = '%s'"), collection_name);
00386     } else {
00387         msg = g_strdup_printf(_("Task restarted, collection_name = '%s', subject = '%s'"), collection_name, subject);
00388     }
00389     nntpgrab_core_emit_debug_message(msg);
00390     g_free(msg);
00391 
00392     return plugin_funcs.restart_task(collection_name, subject, errmsg);
00393 }
00394 
00395 gboolean
00396 schedular_save_queue(Schedular *obj, char **errmsg)
00397 {
00398     g_assert(plugin_funcs.save_queue);
00399 
00400     return plugin_funcs.save_queue(errmsg);
00401 }
00402 
00403 struct _foreach_data
00404 {
00405     ForeachCollectionFunc collection_func;
00406     ForeachFileFunc file_func;
00407     ForeachGroupFunc group_func;
00408     gpointer data;
00409 };
00410 
00411 static void
00412 foreach_func(gpointer data, gpointer user_data)
00413 {
00414     struct _foreach_data *foreach_data = (struct _foreach_data *) user_data;
00415     NNTPCollection *collection = (NNTPCollection *) data;
00416     GList *list, *list2;
00417 
00418     if (foreach_data->collection_func) {
00419         foreach_data->collection_func(collection->collection_name, collection->total_size, collection->total_size_remaining, collection->position, foreach_data->data);
00420     }
00421 
00422     if (!foreach_data->group_func && !foreach_data->file_func) {
00423         return;
00424     }
00425 
00426     list = collection->files;
00427     while (list) {
00428         NNTPFile *file = (NNTPFile *) list->data;
00429 
00430         if (foreach_data->file_func) {
00431             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);
00432         }
00433 
00434         if (foreach_data->group_func) {
00435             list2 = file->groups;
00436             while (list2) {
00437                 const char *group = (const char *) list2->data;
00438 
00439                 foreach_data->group_func(collection->collection_name, file->subject, group, foreach_data->data);
00440 
00441                 list2 = g_list_next(list2);
00442             }
00443         }
00444 
00445         list = g_list_next(list);
00446     }
00447 }
00448 
00449 void
00450 schedular_foreach_task(Schedular *obj, ForeachCollectionFunc collection_func, ForeachFileFunc file_func, ForeachGroupFunc group_func, gpointer data)
00451 {
00452     struct _foreach_data foreach_data;
00453 
00454     g_assert(plugin_funcs.foreach_task);
00455 
00456     foreach_data.collection_func = collection_func;
00457     foreach_data.file_func = file_func;
00458     foreach_data.group_func = group_func;
00459     foreach_data.data = data;
00460 
00461     plugin_funcs.foreach_task(foreach_func, &foreach_data);
00462 }
00463 
00464 gboolean
00465 schedular_move_task(Schedular *obj, const char *collection_name_src, const char *subject_src, const char *collection_name_dest, int position_dest)
00466 {
00467     return plugin_funcs.move_task(collection_name_src, subject_src, collection_name_dest, position_dest);
00468 }
00469 
00470 gboolean
00471 schedular_move_collection(Schedular *obj, const char *collection_name, int new_position)
00472 {
00473     return plugin_funcs.move_collection(collection_name, new_position);
00474 }
00475 
00476 static void
00477 task_added_callback(const NNTPCollection *collection, const NNTPFile *file)
00478 {
00479     nntpgrab_core_emit_file_added(collection, file);
00480 }
00481 
00482 static void
00483 task_removed_callback(const char *collection_name, const char *subject, guint64 total_file_size, guint64 total_file_size_remaining)
00484 {
00485     nntpgrab_core_emit_file_removed(collection_name, subject, total_file_size, total_file_size_remaining);
00486 }
00487 
00488 static void
00489 task_state_changed_callback(const char *collection_name, const char *subject, TaskState old_state, TaskState new_state)
00490 {
00491     nntpgrab_core_emit_file_state_changed(collection_name, subject, old_state, new_state);
00492 }
00493 
00494 static void
00495 collection_added_callback(const char *collection_name)
00496 {
00497     nntpgrab_core_emit_collection_added(collection_name);
00498 }
00499 
00500 static void
00501 collection_removed_callback(const char *collection_name)
00502 {
00503     nntpgrab_core_emit_collection_removed(collection_name);
00504 }
00505 
00506 static GList *
00507 config_get_avail_servers(void)
00508 {
00509     g_assert(schedular);
00510 
00511     return configuration_get_avail_servers(schedular->config);
00512 }
00513 
00514 static ConfigServer *
00515 config_get_server_info(const char *servername)
00516 {
00517     g_assert(schedular);
00518 
00519     return configuration_get_server_info(schedular->config, servername);
00520 }
00521 
00522 static ConfigOpts
00523 config_get_opts (void)
00524 {
00525     g_assert(schedular);
00526 
00527     return configuration_get_opts(schedular->config);
00528 }
00529 
00530 static gpointer
00531 nntp_connection_initialize (const char *servername, NNTPGrabErrCode *err)
00532 {
00533     NNTPConnection *conn;
00534     ConfigServer *server;
00535 
00536     server = configuration_get_server_info(schedular->config, servername);
00537     if (!server) {
00538         return NULL;
00539     }
00540 
00541     conn = nntpconnection_new(schedular->config, *server);
00542     g_slice_free(ConfigServer, server);
00543 
00544     if ((*err = nntpconnection_connect(conn)) != NNTP_ERROR_NONE) {
00545         nntpconnection_destroy(conn);
00546         return NULL;
00547     }
00548 
00549     return (gpointer) conn;
00550 }
00551 
00552 static void
00553 nntp_connection_destroy (gpointer obj)
00554 {
00555     g_assert(obj != NULL);
00556 
00557     if (nntpconnection_get_is_connected(obj)) {
00558         nntpconnection_disconnect(obj);
00559     }
00560 
00561     nntpconnection_destroy(obj);
00562 }
00563 
00564 static NNTPGrabErrCode
00565 nntp_connection_get_part (gpointer obj, const char *collection_name, const NNTPFile *file, const NNTPPart *part, char **reason)
00566 {
00567     char *filename;
00568     NNTPGrabErrCode ret;
00569 
00570     g_assert(obj != NULL);
00571     g_assert(schedular != NULL);
00572 
00573     
00574     if (!nntpconnection_get_is_connected(obj)) {
00575         
00576         nntpgrab_core_emit_debug_message(_("Connection lost. Trying to reconnect"));
00577         if ((ret = nntpconnection_connect(obj)) != NNTP_ERROR_NONE) {
00578             nntpgrab_core_emit_debug_message(_("Reconnect failed"));
00579             nntpconnection_disconnect(obj);
00580             return ret;
00581         }
00582     }
00583 
00584     g_static_rw_lock_reader_lock(&schedular->rwlock);
00585     filename = g_strdup_printf("%s%s%s.%i", schedular->opts.temp_directory, G_DIR_SEPARATOR_S, file->tmp_filename, part->partnum);
00586     g_static_rw_lock_reader_unlock(&schedular->rwlock);
00587 
00588     if ((ret = nntpconnection_get_part(obj, collection_name, file->subject, part, filename)) != NNTP_ERROR_NONE) {
00589         if (reason) {
00590             switch (ret) {
00591                 case NNTP_ERROR_UNABLE_TO_SAVE_PART:
00592                     *reason = g_strdup_printf(_("Unable to save part to file '%s'"), filename);
00593                     break;
00594                 default:
00595                     *reason = NULL;
00596             }
00597         }
00598 
00599         g_free(filename);
00600         return ret;
00601     }
00602 
00603     g_free(filename);
00604 
00605     nntpgrab_core_emit_debug_message(_("Saving of part SUCCEEDED"));
00606 
00607     return NNTP_ERROR_NONE;
00608 }
00609 
00610 static gboolean
00611 decode_file (const char *collection_name, const NNTPFile *file, int *saved_errno)
00612 {
00613     return decoder_decode_file(schedular->decoder, collection_name, file, saved_errno);
00614 }
00615 
00616 static void
00617 notify_schedular_state_changed (SchedularState new_state, const char *reason)
00618 {
00619     nntpgrab_core_emit_schedular_state_changed(new_state, reason);
00620 }
00621 
00622 static void
00623 emit_fatal_error (const char *errmsg)
00624 {
00625     nntpgrab_core_emit_fatal_error(errmsg);
00626 }
00627 
00628 static void
00629 emit_part_download_complete (const char *servername, gpointer connection, const char *collection_name, const char *subject, int partnum, int size)
00630 {
00631     int conn_id = -1;
00632 
00633     if (connection) {
00634         conn_id = nntpconnection_get_conn_id((NNTPConnection*) connection);
00635     }
00636 
00637     nntpgrab_core_emit_part_done(servername, conn_id, collection_name, subject, partnum, size);
00638 }
00639 
00640 static void
00641 emit_part_download_failed (const char *servername, gpointer connection, const char *collection_name, const char *subject, int partnum, int size, gboolean all_servers_tried)
00642 {
00643     int conn_id = -1;
00644 
00645     if (connection) {
00646         conn_id = nntpconnection_get_conn_id((NNTPConnection*) connection);
00647     }
00648 
00649     nntpgrab_core_emit_part_failed(servername, conn_id, collection_name, subject, partnum, size, all_servers_tried);
00650 }
00651 
00652 static void
00653 emit_task_moved (const char *orig_collection_name, const char *subject, const char *new_collection_name, int old_position, int new_position)
00654 {
00655     nntpgrab_core_emit_task_moved(orig_collection_name, subject, new_collection_name, old_position, new_position);
00656 }
00657 
00658 static void
00659 emit_collection_moved (const char *collection_name, int old_position, int new_position)
00660 {
00661     nntpgrab_core_emit_collection_moved(collection_name, old_position, new_position);
00662 }
00663 
00664 static void
00665 emit_file_download_state_update (const char *collection_name, const char *subject, int num_parts_total, int num_parts_done, int num_parts_failed, guint64 file_size, guint64 file_size_remaining, guint64 total_file_size, guint64 total_file_size_remaining)
00666 {
00667     nntpgrab_core_emit_file_download_state_update(collection_name, subject, num_parts_total, num_parts_done, num_parts_failed, file_size, file_size_remaining, total_file_size, total_file_size_remaining);
00668 }
00669 
00670 static void
00671 config_changed_callback (Configuration *config, ConfigChangedFlag flag, gpointer data)
00672 {
00673     g_assert(schedular);
00674 
00675     nntpgrab_core_emit_debug_message(_("Schedular: Received config changed signal"));
00676 
00677     if (flag == CONFIG_CHANGED_OPTS_CHANGED) {
00678         g_static_rw_lock_writer_lock(&schedular->rwlock);
00679         schedular->opts = configuration_get_opts(config);
00680         g_static_rw_lock_writer_unlock(&schedular->rwlock);
00681     }
00682 
00683     if (flag == CONFIG_CHANGED_SERVER_ADDED || flag == CONFIG_CHANGED_SERVER_DELETED) {
00684         if (schedular_get_state(schedular) == SCHEDULAR_STATE_RUNNING) {
00685             
00686             schedular_stop(schedular);
00687             schedular_start(schedular);
00688         }
00689     }
00690 }