Fix segfault in mail folder (SF: 3007493)
[monky] / src / prss.c
index 84cc803..e562506 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
+ * vim: ts=4 sw=4 noet ai cindent syntax=c
  *
  * Copyright (c) 2007 Mikko Sysikaski <mikko.sysikaski@gmail.com>
  *                                       Toni Spets <toni.spets@gmail.com>
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * vim: ts=4 sw=4 noet ai cindent syntax=c
- *
  */
 
 #include "conky.h"
 #include "prss.h"
+#include "logging.h"
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
@@ -33,6 +33,7 @@ void prss_parse_doc(PRSS *result, xmlDocPtr doc);
 void prss_parse_data(void *result, const char *xml_data)
 {
        PRSS *data = (PRSS*)result;
+
        xmlDocPtr doc = xmlReadMemory(xml_data, strlen(xml_data), "", NULL,
                PARSE_OPTIONS);
 
@@ -41,22 +42,58 @@ void prss_parse_data(void *result, const char *xml_data)
        }
 
        prss_parse_doc(data, doc);
+       xmlFreeDoc(doc);
 }
 
-void prss_free(PRSS *data)
+void free_rss_items(PRSS *data)
 {
-       if (!data) {
-               return;
+       int i;
+
+       for (i = 0; i < data->item_count; i++) {
+#define CLEAR(a) if (data->items[i].a) { free(data->items[i].a); data->items[i].a = 0; }
+               CLEAR(title);
+               CLEAR(link);
+               CLEAR(description);
+               CLEAR(category);
+               CLEAR(pubDate);
+               CLEAR(guid);
+#undef CLEAR
        }
-       xmlFreeDoc(data->_data);
-       free(data->version);
        free(data->items);
+       data->item_count = 0;
+       data->items = 0;
 }
 
-static inline void prss_null(PRSS *p)
+void prss_free(PRSS *data)
 {
-       memset(p, 0, sizeof(PRSS));
+       if (!data) {
+               return;
+       }
+       if (data->version) {
+               free(data->version);
+               data->version = 0;
+       }
+       if (data->items) {
+               free_rss_items(data);
+       }
+       data->version = 0;
+       data->items = 0;
+#define CLEAR(a) if (data->a) { free(data->a); data->a = 0; }
+       CLEAR(title);
+       CLEAR(link);
+       CLEAR(description);
+       CLEAR(language);
+       CLEAR(pubDate);
+       CLEAR(lastBuildDate);
+       CLEAR(generator);
+       CLEAR(docs);
+       CLEAR(managingEditor);
+       CLEAR(webMaster);
+       CLEAR(copyright);
+       CLEAR(ttl);
+#undef CLEAR
 }
+
 static inline void prss_null_item(PRSS_Item *i)
 {
        memset(i, 0, sizeof(PRSS_Item));
@@ -66,10 +103,8 @@ static inline void read_item(PRSS_Item *res, xmlNodePtr data)
 {
        prss_null_item(res);
 
-       res->title = res->link = res->description = NULL;
        for (; data; data = data->next) {
                xmlNodePtr child;
-               const char *name;
 
                if (data->type != XML_ELEMENT_NODE) {
                        continue;
@@ -80,26 +115,23 @@ static inline void read_item(PRSS_Item *res, xmlNodePtr data)
                        continue;
                }
 
-               name = (const char *)data->name;
-               if (!strcasecmp(name, "title")) {
-                       res->title = (char *) child->content;
-               } else if (!strcasecmp(name, "link")) {
-                       res->link = (char *) child->content;
-               } else if (!strcasecmp(name, "description")) {
-                       res->description = (char *) child->content;
-               } else if (!strcasecmp(name, "category")) {
-                       res->category = (char *) child->content;
-               } else if (!strcasecmp(name, "pubDate")) {
-                       res->pubdate = (char *) child->content;
-               } else if (!strcasecmp(name, "guid")) {
-                       res->guid = (char *) child->content;
+#define ASSIGN(a) if (strcasecmp((const char*)data->name, #a) == EQUAL) { \
+                       if (res->a) free(res->a); \
+                       res->a = strdup((const char*)child->content); \
+                       continue; \
                }
+               ASSIGN(title);
+               ASSIGN(link);
+               ASSIGN(description);
+               ASSIGN(category);
+               ASSIGN(pubDate);
+               ASSIGN(guid);
+#undef ASSIGN
        }
 }
 static inline void read_element(PRSS *res, xmlNodePtr n)
 {
        xmlNodePtr child;
-       const char *name;
 
        if (n->type != XML_ELEMENT_NODE) {
                return;
@@ -110,32 +142,25 @@ static inline void read_element(PRSS *res, xmlNodePtr n)
                return;
        }
 
-       name = (const char *)n->name;
-       if (!strcasecmp(name, "title")) {
-               res->title = (char *) child->content;
-       } else if (!strcasecmp(name, "link")) {
-               res->link = (char *) child->content;
-       } else if (!strcasecmp(name, "description")) {
-               res->description = (char *) child->content;
-       } else if (!strcasecmp(name, "language")) {
-               res->language = (char *) child->content;
-       } else if (!strcasecmp(name, "pubDate")) {
-               res->pubdate = (char *) child->content;
-       } else if (!strcasecmp(name, "lastBuildDate")) {
-               res->lastbuilddate = (char *) child->content;
-       } else if (!strcasecmp(name, "generator")) {
-               res->generator = (char *) child->content;
-       } else if (!strcasecmp(name, "docs")) {
-               res->docs = (char *) child->content;
-       } else if (!strcasecmp(name, "managingEditor")) {
-               res->managingeditor = (char *) child->content;
-       } else if (!strcasecmp(name, "webMaster")) {
-               res->webmaster = (char *) child->content;
-       } else if (!strcasecmp(name, "copyright")) {
-               res->copyright = (char *) child->content;
-       } else if (!strcasecmp(name, "ttl")) {
-               res->ttl = (char *) child->content;
-       } else if (!strcasecmp(name, "item")) {
+#define ASSIGN(a) if (strcasecmp((const char*)n->name, #a) == EQUAL) { \
+               if (res->a) free(res->a); \
+               res->a = strdup((const char*)child->content); \
+               return; \
+       }
+       ASSIGN(title);
+       ASSIGN(link);
+       ASSIGN(description);
+       ASSIGN(language);
+       ASSIGN(pubDate);
+       ASSIGN(lastBuildDate);
+       ASSIGN(generator);
+       ASSIGN(docs);
+       ASSIGN(managingEditor);
+       ASSIGN(webMaster);
+       ASSIGN(copyright);
+       ASSIGN(ttl);
+#undef ASSIGN
+       if (!strcasecmp((const char*)n->name, "item")) {
                read_item(&res->items[res->item_count++], n->children);
        }
 }
@@ -146,8 +171,10 @@ static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root)
        xmlNodePtr n;
        int items = 0;
 
+       DBGP("parsing rss 2.0 or <1 doc");
+
        while (channel && (channel->type != XML_ELEMENT_NODE
-                       || strcmp((const char *) channel->name, "channel"))) {
+                               || strcmp((const char *) channel->name, "channel"))) {
                channel = channel->next;
        }
        if (!channel) {
@@ -161,8 +188,9 @@ static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root)
                }
        }
 
+       if (res->version) free(res->version);
        res->version = strndup("2.0", text_buffer_size);
-       if (res->items) free(res->items);
+       if (res->items) free_rss_items(res);
        res->items = malloc(items * sizeof(PRSS_Item));
        res->item_count = 0;
 
@@ -177,6 +205,8 @@ static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
        int items = 0;
        xmlNodePtr n;
 
+       DBGP("parsing rss 1.0 doc");
+
        for (n = root->children; n; n = n->next) {
                if (n->type == XML_ELEMENT_NODE) {
                        if (!strcmp((const char *) n->name, "item")) {
@@ -191,8 +221,9 @@ static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
                }
        }
 
+       if (res->version) free(res->version);
        res->version = strndup("1.0", text_buffer_size);
-       if (res->items) free(res->items);
+       if (res->items) free_rss_items(res);
        res->items = malloc(items * sizeof(PRSS_Item));
        res->item_count = 0;
 
@@ -205,21 +236,11 @@ static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
 
        return 1;
 }
-static inline int parse_rss_0_9x(PRSS *res, xmlNodePtr root)
-{
-       // almost same...
-       return parse_rss_2_0(res, root);
-}
 
 void prss_parse_doc(PRSS *result, xmlDocPtr doc)
 {
-       /* FIXME: doc shouldn't be freed after failure when called explicitly from
-        * program! */
-
        xmlNodePtr root = xmlDocGetRootElement(doc);
 
-       prss_null(result);
-       result->_data = doc;
        do {
                if (root->type == XML_ELEMENT_NODE) {
                        if (!strcmp((const char *) root->name, "RDF")) {