queue.c

Go to the documentation of this file.
00001 /*
00002  Copyright (C) 2005-2007 Erik van Pienbroek
00003 
00004  This program is free software; you can redistribute it and/or modify
00005  it under the terms of the GNU General Public License as published by
00006  the Free Software Foundation; either version 2 of the License, or
00007  (at your option) any later version.
00008 
00009  This program is distributed in the hope that it will be useful,
00010  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00012  GNU General Public License for more details.
00013 
00014  You should have received a copy of the GNU General Public License
00015  along with this program; if not, write to the Free Software
00016  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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     // backwards compatibility with version 0.1 and 0.2
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     // backwards compatibility (continued)
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             // Backwards compatibility
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     // calculate the remaining size of the collection
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         // Nothing in the queue
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         // File not found, looks like this is the first time NNTPGrab is ever started, ignore
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 /* SIZEOF_LONG == 4 */
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 /* SIZEOF_LONG == 4 */
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     // Generate the folder ~/.config/NNTPGrab in case it didn't exist yet
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         // TODO: Proper error message
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 

Generated on Sun Oct 12 01:45:30 2008 for NNTPGrab by  1.5.4