00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef _MSC_VER
00020 #include "config.h.win32"
00021 #else
00022 #include "config.h"
00023 #endif
00024
00025 #include
00026 #include
00027 #include
00028 #include
00029 #include
00030
00031 #include "nntpgrab_plugin_schedular.h"
00032 #include "nntpgrab_types.h"
00033
00034 #ifdef _MSC_VER
00035 #undef atoll
00036 #define atoll _atoi64
00037 #endif
00038
00039 static char *xml_parser_errmsg = NULL;
00040
00041 static void
00042 xml_parser_error_func (void *ctx, const char *msg, ...)
00043 {
00044 va_list args;
00045 char *orig = xml_parser_errmsg;
00046 char *tmp;
00047
00048 va_start(args, msg);
00049
00050 tmp = g_strdup_vprintf(msg, args);
00051 if (orig) {
00052 xml_parser_errmsg = g_strdup_printf("%s %s", orig, tmp);
00053 g_free(orig);
00054 g_free(tmp);
00055 } else {
00056 xml_parser_errmsg = tmp;
00057 }
00058
00059 va_end(args);
00060 }
00061
00062 static char *
00063 generate_filename(void)
00064 {
00065 return g_build_filename(g_get_user_config_dir(), "NNTPGrab", "download_queue.xml", NULL);
00066 }
00067
00068 static void
00069 parse_part(xmlDocPtr doc, xmlNodePtr cur, NNTPFile *file, NNTPPart *part)
00070 {
00071 while(cur != NULL) {
00072 if (!xmlStrcmp(cur->name, (const xmlChar *) "MessageID")) {
00073 xmlChar *message_id = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00074 if (message_id) {
00075 strncpy((char *) part->message_id, (const char *) message_id, (size_t) sizeof(part->message_id));
00076 xmlFree(message_id);
00077 }
00078 }
00079
00080 if (!xmlStrcmp(cur->name, (const xmlChar *) "Size")) {
00081 xmlChar *size = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00082 if (size) {
00083 part->size = atoi((const char *) size);
00084 xmlFree(size);
00085 }
00086 }
00087
00088 if (!xmlStrcmp(cur->name, (const xmlChar *) "Downloaded")) {
00089 xmlChar *downloaded = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00090 if (downloaded) {
00091 part->downloaded = atoi((const char *) downloaded);
00092 xmlFree(downloaded);
00093 }
00094 }
00095
00096 cur = cur->next;
00097 }
00098 }
00099
00100 static void
00101 parse_groups(xmlDocPtr doc, xmlNodePtr cur, NNTPFile *file)
00102 {
00103 while(cur != NULL) {
00104 if (!xmlStrcmp(cur->name, (const xmlChar *) "Group")) {
00105 xmlChar *group = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00106 if (group) {
00107 file->groups = g_list_append(file->groups, g_strdup((const gchar*) group));
00108 xmlFree(group);
00109 }
00110 }
00111
00112 cur = cur->next;
00113 }
00114 }
00115
00116 static void
00117 parse_parts(xmlDocPtr doc, xmlNodePtr cur, NNTPFile *file)
00118 {
00119 while(cur != NULL) {
00120 if (!xmlStrcmp(cur->name, (const xmlChar *) "Part")) {
00121 NNTPPart *part = g_slice_new0(NNTPPart);
00122 xmlChar *partnum;
00123
00124 partnum = xmlGetProp(cur, (const xmlChar *) "partnum");
00125 part->partnum = atoi((const char *) partnum);
00126 xmlFree(partnum);
00127
00128 file->parts = g_list_append(file->parts, part);
00129
00130 parse_part(doc, cur->xmlChildrenNode, file, part);
00131 }
00132
00133 cur = cur->next;
00134 }
00135
00136 file->numparts = g_list_length(file->parts);
00137 }
00138
00139 static void
00140 parse_file(xmlDocPtr doc, xmlNodePtr cur, NNTPCollection *collection, NNTPFile *file)
00141 {
00142
00143 file->num_parts_downloaded = -1;
00144 file->file_size_remaining = -1;
00145
00146 while(cur != NULL) {
00147 if (!xmlStrcmp(cur->name, (const xmlChar *) "Subject")) {
00148 xmlChar *subject = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00149 if (subject) {
00150 strncpy((char *) file->subject, (const char *) subject, (size_t) sizeof(file->subject));
00151 xmlFree(subject);
00152 }
00153 }
00154
00155 if (!xmlStrcmp(cur->name, (const xmlChar *) "Poster")) {
00156 xmlChar *poster = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00157 if (poster) {
00158 strncpy((char *) file->poster, (const char *) poster, (size_t) sizeof(file->poster));
00159 xmlFree(poster);
00160 }
00161 }
00162
00163 if (!xmlStrcmp(cur->name, (const xmlChar *) "Stamp")) {
00164 xmlChar *stamp = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00165 if (stamp) {
00166 file->stamp = atoi((const char *) stamp);
00167 xmlFree(stamp);
00168 }
00169 }
00170
00171 if (!xmlStrcmp(cur->name, (const xmlChar *) "FileSize")) {
00172 xmlChar *size = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00173 if (size) {
00174 file->file_size = atoll((const char *) size);
00175 xmlFree(size);
00176 }
00177 }
00178
00179 if (!xmlStrcmp(cur->name, (const xmlChar *) "NumPartsDownloaded")) {
00180 xmlChar *num_parts_downloaded = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00181 if (num_parts_downloaded) {
00182 file->num_parts_downloaded = atoi((const char *) num_parts_downloaded);
00183 xmlFree(num_parts_downloaded);
00184 }
00185 }
00186
00187 if (!xmlStrcmp(cur->name, (const xmlChar *) "FileIsDownloaded")) {
00188 xmlChar *file_is_downloaded = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00189 if (file_is_downloaded) {
00190 file->file_is_downloaded = atoi((const char *) file_is_downloaded);
00191 xmlFree(file_is_downloaded);
00192 }
00193 }
00194
00195 if (!xmlStrcmp(cur->name, (const xmlChar *) "Groups")) {
00196 parse_groups(doc, cur->xmlChildrenNode, file);
00197 }
00198
00199 if (!xmlStrcmp(cur->name, (const xmlChar *) "Parts")) {
00200 parse_parts(doc, cur->xmlChildrenNode, file);
00201 }
00202
00203 if (!xmlStrcmp(cur->name, (const xmlChar *) "TempFilename")) {
00204 xmlChar *tmp_filename = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00205 if (tmp_filename) {
00206 strncpy((char *) file->tmp_filename, (const char *) tmp_filename, (size_t) sizeof(file->tmp_filename));
00207 xmlFree(tmp_filename);
00208 }
00209 }
00210
00211 if (!xmlStrcmp(cur->name, (const xmlChar *) "RealFilename")) {
00212 xmlChar *real_filename = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00213 if (real_filename) {
00214 strncpy((char *) file->real_filename, (const char *) real_filename, (size_t) sizeof(file->real_filename));
00215 xmlFree(real_filename);
00216 }
00217 }
00218
00219 if (!xmlStrcmp(cur->name, (const xmlChar *) "Status")) {
00220 xmlChar *status = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00221 if (status) {
00222 file->status = atoi((const char *) status);
00223 xmlFree(status);
00224 }
00225 }
00226
00227 if (!xmlStrcmp(cur->name, (const xmlChar *) "FileType")) {
00228 xmlChar *file_type = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00229 if (file_type) {
00230 file->file_type = atoi((const char *) file_type);
00231 xmlFree(file_type);
00232 }
00233 }
00234
00235 if (!xmlStrcmp(cur->name, (const xmlChar *) "PAR2StartNum")) {
00236 xmlChar *par2_startnum = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00237 if (par2_startnum) {
00238 file->par2_startnum = atoi((const char *) par2_startnum);
00239 xmlFree(par2_startnum);
00240 }
00241 }
00242
00243 if (!xmlStrcmp(cur->name, (const xmlChar *) "PAR2EndNum")) {
00244 xmlChar *par2_endnum = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00245 if (par2_endnum) {
00246 file->par2_endnum = atoi((const char *) par2_endnum);
00247 xmlFree(par2_endnum);
00248 }
00249 }
00250
00251 if (!xmlStrcmp(cur->name, (const xmlChar *) "PAR2NumBlocks")) {
00252 xmlChar *par2_numblocks = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00253 if (par2_numblocks) {
00254 file->num_par2_blocks = atoi((const char *) par2_numblocks);
00255 xmlFree(par2_numblocks);
00256 }
00257 }
00258
00259 cur = cur->next;
00260 }
00261
00262
00263 if (file->num_parts_downloaded == -1) {
00264 file->num_parts_downloaded = g_list_length(file->parts);
00265 }
00266
00267 if (file->file_is_downloaded) {
00268 file->num_parts_failed = g_list_length(file->parts) - file->num_parts_downloaded;
00269 file->file_size_remaining = 0;
00270 } else {
00271 GList *list = file->parts;
00272
00273 file->file_size_remaining = 0;
00274
00275 while (list) {
00276 NNTPPart *part = list->data;
00277
00278 if (!part->downloaded) {
00279 file->file_size_remaining += part->size;
00280 }
00281
00282 list = g_list_next(list);
00283 }
00284 }
00285 }
00286
00287 static void
00288 parse_files(xmlDocPtr doc, xmlNodePtr cur, NNTPCollection *collection)
00289 {
00290 while(cur != NULL) {
00291 if (!xmlStrcmp(cur->name, (const xmlChar *) "File")) {
00292 NNTPFile *file = g_slice_new0(NNTPFile);
00293 xmlChar *pos;
00294
00295 collection->files = g_list_append(collection->files, file);
00296
00297 pos = xmlGetProp(cur, (const xmlChar *) "position");
00298 if (pos) {
00299 file->position = atoi((const char *) pos);
00300 xmlFree(pos);
00301 } else {
00302 file->position = g_list_length(collection->files);
00303 }
00304
00305 parse_file(doc, cur->xmlChildrenNode, collection, file);
00306
00307
00308 if (file->par2_startnum == 0) {
00309 file->par2_startnum = -1;
00310 }
00311
00312 if (file->par2_endnum == 0) {
00313 file->par2_endnum = -1;
00314 }
00315 }
00316
00317 cur = cur->next;
00318 }
00319 }
00320
00321 static NNTPCollection *
00322 parse_collection(xmlDocPtr doc, xmlNodePtr cur)
00323 {
00324 NNTPCollection *collection = g_slice_new0(NNTPCollection);
00325 GList *list;
00326
00327 while(cur != NULL) {
00328 if (!xmlStrcmp(cur->name, (const xmlChar *) "Name")) {
00329 xmlChar *name = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00330 if (name) {
00331 strncpy((char *) collection->collection_name, (const char *) name, (size_t) sizeof(collection->collection_name));
00332 xmlFree(name);
00333 }
00334 }
00335
00336 if (!xmlStrcmp(cur->name, (const xmlChar *) "TotalSize")) {
00337 xmlChar *size = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
00338 if (size) {
00339 collection->total_size = atoll((const char *) size);
00340 xmlFree(size);
00341 }
00342 }
00343
00344 if (!xmlStrcmp(cur->name, (const xmlChar *) "Files")) {
00345 parse_files(doc, cur->xmlChildrenNode, collection);
00346 }
00347
00348 cur = cur->next;
00349 }
00350
00351
00352 list = collection->files;
00353
00354 collection->total_size_remaining = 0;
00355 while (list) {
00356 NNTPFile *file = list->data;
00357
00358 collection->total_size_remaining += file->file_size_remaining;
00359
00360 list = g_list_next(list);
00361 }
00362
00363 return collection;
00364 }
00365
00366 static gboolean
00367 parse_xml_document(const char *contents, GList **ret, char **errmsg)
00368 {
00369 xmlDocPtr doc;
00370 xmlNodePtr cur;
00371
00372 g_assert(ret);
00373
00374 *ret = NULL;
00375
00376 xmlSetGenericErrorFunc(NULL, xml_parser_error_func);
00377
00378 if (xml_parser_errmsg) {
00379 g_free(xml_parser_errmsg);
00380 xml_parser_errmsg = NULL;
00381 }
00382
00383 doc = xmlParseMemory(contents, strlen(contents));
00384 if (doc == NULL) {
00385 if (errmsg) {
00386 if (xml_parser_errmsg) {
00387 *errmsg = g_strdup_printf(_("Invalid XML document:\n%s"), xml_parser_errmsg);
00388 } else {
00389 *errmsg = g_strdup(_("Invalid XML document"));
00390 }
00391 }
00392
00393 g_free(xml_parser_errmsg);
00394 xml_parser_errmsg = NULL;
00395
00396 xmlFreeDoc(doc);
00397 return FALSE;
00398 }
00399
00400 if ((cur = xmlDocGetRootElement(doc)) && xmlStrcmp(cur->name, (const xmlChar *) "NNTPGrab")) {
00401 if (errmsg) {
00402 *errmsg = g_strdup("parse_xml_document: document of the wrong type, root node != NNTPGrab");
00403 }
00404
00405 xmlFreeDoc(doc);
00406 return FALSE;
00407 }
00408
00409 cur = cur->xmlChildrenNode;
00410 if (!cur) {
00411 if (errmsg) {
00412 *errmsg = g_strdup("parse_xml_document: no children of root-node!");
00413 }
00414
00415 xmlFreeDoc(doc);
00416 return FALSE;
00417 }
00418
00419 cur = cur->next;
00420
00421 if (xmlStrcmp(cur->name, (const xmlChar *) "DownloadQueue")) {
00422 if (errmsg) {
00423 *errmsg = g_strdup("parse_xml_document: document of the wrong type, root node != NNTPGrab/DownloadQueue");
00424 }
00425
00426 xmlFreeDoc(doc);
00427 return FALSE;
00428 }
00429
00430 cur = cur->xmlChildrenNode;
00431 if (!cur) {
00432
00433 xmlFreeDoc(doc);
00434 return TRUE;
00435 }
00436
00437 do {
00438 if (!xmlStrcmp(cur->name, (const xmlChar *) "Collection")) {
00439 NNTPCollection *collection = parse_collection(doc, cur->xmlChildrenNode);
00440
00441 collection->position = g_list_length(*ret);
00442
00443 *ret = g_list_append(*ret, collection);
00444 }
00445 } while ((cur=cur->next));
00446
00447 xmlFreeDoc(doc);
00448 return TRUE;
00449 }
00450
00451 gboolean
00452 load_download_queue(GList **ret, char **errmsg)
00453 {
00454 char *filename;
00455 char *contents = NULL;
00456 GError *err = NULL;
00457 gboolean retval;
00458
00459 filename = generate_filename();
00460 if (!g_file_get_contents(filename, &contents, NULL, &err)) {
00461
00462 g_error_free(err);
00463 g_free(filename);
00464
00465 return TRUE;
00466 }
00467
00468 retval = parse_xml_document(contents, ret, errmsg);
00469
00470 g_free(filename);
00471 g_free(contents);
00472
00473 return retval;
00474 }
00475
00476 static void
00477 save_part(xmlDocPtr doc, xmlNodePtr parent, NNTPPart *part)
00478 {
00479 xmlNodePtr node, cdataNode;
00480 char *str;
00481
00482 node = xmlNewNode(NULL, (const xmlChar *) "MessageID");
00483 cdataNode = xmlNewCDataBlock(doc, (const xmlChar *) part->message_id, strlen(part->message_id));
00484 xmlAddChild(node, cdataNode);
00485 xmlAddChild(parent, node);
00486
00487 str = g_strdup_printf("%i", part->size);
00488 xmlNewTextChild(parent, NULL, (const xmlChar *) "Size", (const xmlChar *) str);
00489 g_free(str);
00490
00491 str = g_strdup_printf("%i", part->downloaded);
00492 xmlNewTextChild(parent, NULL, (const xmlChar *) "Downloaded", (const xmlChar *) str);
00493 g_free(str);
00494 }
00495
00496 static void
00497 save_file(xmlDocPtr doc, xmlNodePtr parent, NNTPFile *file)
00498 {
00499 xmlNodePtr node, cdataNode, parent2;
00500 char *str;
00501 GList *list;
00502
00503 if (file->file_size_remaining < 0) {
00504 if (file->file_is_downloaded) {
00505 file->file_size_remaining = 0;
00506 } else {
00507 GList *list = file->parts;
00508
00509 file->file_size_remaining = 0;
00510
00511 while (list) {
00512 NNTPPart *part = list->data;
00513
00514 if (!part->downloaded) {
00515 file->file_size_remaining += part->size;
00516 }
00517
00518 list = g_list_next(list);
00519 }
00520 }
00521 }
00522
00523 node = xmlNewNode(NULL, (const xmlChar *) "Subject");
00524 cdataNode = xmlNewCDataBlock(doc, (const xmlChar *) file->subject, strlen((const char *) file->subject));
00525 xmlAddChild(node, cdataNode);
00526 xmlAddChild(parent, node);
00527
00528 node = xmlNewNode(NULL, (const xmlChar *) "Poster");
00529 cdataNode = xmlNewCDataBlock(doc, (const xmlChar *) file->poster, strlen((const char *) file->poster));
00530 xmlAddChild(node, cdataNode);
00531 xmlAddChild(parent, node);
00532
00533 str = g_strdup_printf("%li", file->stamp);
00534 xmlNewTextChild(parent, NULL, (const xmlChar *) "Stamp", (const xmlChar *) str);
00535 g_free(str);
00536
00537 #if SIZEOF_LONG == 8
00538 str = g_strdup_printf("%li", file->file_size);
00539 #else
00540 str = g_strdup_printf("%lli", file->file_size);
00541 #endif
00542 xmlNewTextChild(parent, NULL, (const xmlChar *) "FileSize", (const xmlChar *) str);
00543 g_free(str);
00544
00545 str = g_strdup_printf("%i", file->file_is_downloaded);
00546 xmlNewTextChild(parent, NULL, (const xmlChar *) "FileIsDownloaded", (const xmlChar *) str);
00547 g_free(str);
00548
00549 str = g_strdup_printf("%i", file->num_parts_downloaded);
00550 xmlNewTextChild(parent, NULL, (const xmlChar *) "NumPartsDownloaded", (const xmlChar *) str);
00551 g_free(str);
00552
00553 node = xmlNewNode(NULL, (const xmlChar *) "TempFilename");
00554 cdataNode = xmlNewCDataBlock(doc, (const xmlChar *) file->tmp_filename, strlen((const char *) file->tmp_filename));
00555 xmlAddChild(node, cdataNode);
00556 xmlAddChild(parent, node);
00557
00558 node = xmlNewNode(NULL, (const xmlChar *) "RealFilename");
00559 cdataNode = xmlNewCDataBlock(doc, (const xmlChar *) file->real_filename, strlen((const char *) file->real_filename));
00560 xmlAddChild(node, cdataNode);
00561 xmlAddChild(parent, node);
00562
00563 str = g_strdup_printf("%i", file->status);
00564 xmlNewTextChild(parent, NULL, (const xmlChar *) "Status", (const xmlChar *) str);
00565 g_free(str);
00566
00567 str = g_strdup_printf("%i", file->file_type);
00568 xmlNewTextChild(parent, NULL, (const xmlChar *) "FileType", (const xmlChar *) str);
00569 g_free(str);
00570
00571 str = g_strdup_printf("%i", file->par2_startnum);
00572 xmlNewTextChild(parent, NULL, (const xmlChar *) "PAR2StartNum", (const xmlChar *) str);
00573 g_free(str);
00574
00575 str = g_strdup_printf("%i", file->par2_endnum);
00576 xmlNewTextChild(parent, NULL, (const xmlChar *) "PAR2EndNum", (const xmlChar *) str);
00577 g_free(str);
00578
00579 str = g_strdup_printf("%i", file->num_par2_blocks);
00580 xmlNewTextChild(parent, NULL, (const xmlChar *) "PAR2NumBlocks", (const xmlChar *) str);
00581 g_free(str);
00582
00583 node = xmlNewNode(NULL, BAD_CAST "Groups");
00584 xmlAddChild(parent, node);
00585
00586 parent2 = node;
00587
00588 list = file->groups;
00589 while (list) {
00590 char *group = (char *) list->data;
00591
00592 node = xmlNewNode(NULL, (const xmlChar *) "Group");
00593 cdataNode = xmlNewCDataBlock(doc, (const xmlChar *) group, strlen(group));
00594 xmlAddChild(node, cdataNode);
00595 xmlAddChild(parent2, node);
00596
00597 list = g_list_next(list);
00598 }
00599
00600 node = xmlNewNode(NULL, BAD_CAST "Parts");
00601 xmlAddChild(parent, node);
00602
00603 parent2 = node;
00604
00605 list = file->parts;
00606 while (list) {
00607 NNTPPart *part = (NNTPPart *) list->data;
00608
00609 node = xmlNewNode(NULL, BAD_CAST "Part");
00610 xmlAddChild(parent2, node);
00611
00612 str = g_strdup_printf("%i", part->partnum);
00613 xmlNewProp(node, (const xmlChar *) "partnum", (const xmlChar *) str);
00614 g_free(str);
00615
00616 save_part(doc, node, part);
00617
00618 list = g_list_next(list);
00619 }
00620 }
00621
00622 static void
00623 save_collection(xmlDocPtr doc, xmlNodePtr parent, NNTPCollection *collection)
00624 {
00625 xmlNodePtr node, cdataNode;
00626 char *str;
00627 GList *list;
00628 int i;
00629
00630 node = xmlNewNode(NULL, (const xmlChar *) "Name");
00631 cdataNode = xmlNewCDataBlock(doc, (const xmlChar *) collection->collection_name, strlen(collection->collection_name));
00632 xmlAddChild(node, cdataNode);
00633 xmlAddChild(parent, node);
00634
00635 #if SIZEOF_LONG == 8
00636 str = g_strdup_printf("%li", collection->total_size);
00637 #else
00638 str = g_strdup_printf("%lli", collection->total_size);
00639 #endif
00640 xmlNewTextChild(parent, NULL, (const xmlChar *) "TotalSize", (const xmlChar *) str);
00641 g_free(str);
00642
00643 node = xmlNewNode(NULL, BAD_CAST "Files");
00644 xmlAddChild(parent, node);
00645
00646 parent = node;
00647
00648 list = collection->files;
00649 i = 0;
00650 while (list) {
00651 NNTPFile *file = (NNTPFile *) list->data;
00652
00653 node = xmlNewNode(NULL, BAD_CAST "File");
00654 xmlAddChild(parent, node);
00655
00656 i++;
00657 str = g_strdup_printf("%i", i);
00658 xmlNewProp(node, (const xmlChar *) "position", (const xmlChar *) str);
00659 g_free(str);
00660
00661 save_file(doc, node, file);
00662
00663 list = g_list_next(list);
00664 }
00665 }
00666
00667 gboolean
00668 save_download_queue(GList *queue, char **errmsg)
00669 {
00670 xmlDocPtr doc;
00671 xmlNodePtr node, parent;
00672 GList *list;
00673 char *filename;
00674 char *dirname;
00675
00676 doc = xmlNewDoc(BAD_CAST "1.0");
00677 node = xmlNewNode(NULL, BAD_CAST "NNTPGrab");
00678 xmlDocSetRootElement(doc, node);
00679
00680 parent = node;
00681 node = xmlNewNode(NULL, BAD_CAST "DownloadQueue");
00682 xmlAddChild(parent, node);
00683
00684 parent = node;
00685
00686 list = queue;
00687 while (list) {
00688 NNTPCollection *collection = (NNTPCollection *) list->data;
00689
00690 node = xmlNewNode(NULL, BAD_CAST "Collection");
00691 xmlAddChild(parent, node);
00692
00693 save_collection(doc, node, collection);
00694
00695 list = g_list_next(list);
00696 }
00697
00698
00699 filename = generate_filename();
00700 dirname = g_path_get_dirname(filename);
00701 g_mkdir_with_parents(dirname, 0700);
00702 g_free(dirname);
00703
00704 if (xmlSaveFormatFile(filename, doc, 1) == -1) {
00705
00706 if (errmsg) {
00707 *errmsg = g_strdup_printf(_("Error while saving XML document '%s'"), filename);
00708 }
00709
00710 g_free(filename);
00711 xmlFreeDoc(doc);
00712
00713 return FALSE;
00714 }
00715
00716 g_free(filename);
00717 xmlFreeDoc(doc);
00718
00719 return TRUE;
00720 }
00721
00722 void
00723 free_download_queue(GList *queue)
00724 {
00725 GList *list;
00726
00727 list = queue;
00728 while (list) {
00729 GList *list2;
00730 NNTPCollection *collection = (NNTPCollection *) list->data;
00731
00732 list2 = collection->files;
00733 while (list2) {
00734 GList *list3;
00735 NNTPFile *file = (NNTPFile *) list2->data;
00736
00737 list3 = file->groups;
00738 while (list3) {
00739 g_free(list3->data);
00740 list3 = g_list_next(list3);
00741 }
00742
00743 g_list_free(file->groups);
00744
00745 list3 = file->parts;
00746 while (list3) {
00747 g_slice_free(NNTPPart, list3->data);
00748 list3 = g_list_next(list3);
00749 }
00750
00751 g_list_free(file->parts);
00752
00753 g_slice_free(NNTPFile, file);
00754
00755 list2 = g_list_next(list2);
00756 }
00757
00758 g_slice_free(NNTPCollection, collection);
00759
00760 list = g_list_next(list);
00761 }
00762
00763 g_list_free(queue);
00764 }
00765