serv_rssclient.c: use array instead of linked list to avoid crashy bug
authorArt Cancro <ajc@citadel.org>
Sat, 10 Jun 2023 23:28:47 +0000 (14:28 -0900)
committerArt Cancro <ajc@citadel.org>
Sat, 10 Jun 2023 23:28:47 +0000 (14:28 -0900)
citadel/server/modules/rssclient/serv_rssclient.c
libcitadel/lib/stringbuf.c

index 07ea2e8181da82f6c8620a59c2751f1b3e333ba2..ad15391b6aca901e369c579d015ab9571fae343e 100644 (file)
 #include "../../context.h"
 #include "../../internet_addressing.h"
 
-struct rssroom {
-       struct rssroom *next;
-       char *room;
-};
-
-struct rssurl {
-       struct rssurl *next;
-       char *url;
-       struct rssroom *rooms;
+struct rssfeed {
+       char url[SIZ];                  // string containing the URL of an RSS or Atom feed
+       char room[ROOMNAMELEN];         // the name of a room which is pulling this feed
 };
 
 struct rssparser {
+       char url[SIZ];
        StrBuf *CData;
        struct CtdlMessage *msg;
        char *link;
        char *description;
        char *item_id;
-       struct rssroom *rooms;
 };
 
+Array *feeds = NULL;
 time_t last_run = 0L;
-struct rssurl *rsstodo = NULL;
 
 
 // This handler is called whenever an XML tag opens.
@@ -99,6 +93,7 @@ void rss_start_element(void *data, const char *el, const char **attribute) {
 void rss_end_element(void *data, const char *el) {
        struct rssparser *r = (struct rssparser *)data;
        StrBuf *encoded_field;
+       long msgnum;
 
        if (server_shutting_down) return;                       // shunt the whole operation if we're exiting
 
@@ -169,17 +164,19 @@ void rss_end_element(void *data, const char *el) {
                                        CM_SetFieldLONG(r->msg, eTimestamp, time(NULL));
                                }
 
-                               // Save it to the room(s)
-                               struct rssroom *rr = NULL;
-                               long msgnum = (-1);
-                               for (rr=r->rooms; rr!=NULL; rr=rr->next) {
-                                       if (rr == r->rooms) {
-                                               msgnum = CtdlSubmitMsg(r->msg, NULL, rr->room);         // in first room, save msg
-                                       }
-                                       else {
-                                               CtdlSaveMsgPointerInRoom(rr->room, msgnum, 0, NULL);    // elsewhere, save a pointer
+                               msgnum = -1 ;
+                               for (int i=0; i<array_len(feeds); ++i) {
+                                       struct rssfeed *rf = (struct rssfeed *) array_get_element_at(feeds, i);
+                                       if (!strcmp(rf->url, r->url)) {
+                                               if (msgnum < 0) {
+                                                       // Save the item in a room
+                                                       msgnum = CtdlSubmitMsg(r->msg, NULL, rf->room);
+                                               }
+                                               else {
+                                                       // If the same item goes to multiple rooms, just save a pointer
+                                                       CtdlSaveMsgPointerInRoom(rf->room, msgnum, 0, NULL);
+                                               }
                                        }
-                                       syslog(LOG_DEBUG, "rssclient: saved message %ld to %s", msgnum, rr->room);
                                }
                        }
                        else {
@@ -289,11 +286,13 @@ void rss_handle_data(void *data, const char *content, int length) {
 
 
 // Feed has been downloaded, now parse it.
-void rss_parse_feed(StrBuf *Feed, struct rssroom *rooms) {
+// `Feed` is the actual RSS downloaded from the site.
+// `url` is a string containing the feed URL
+void rss_parse_feed(StrBuf *Feed, char *url) {
        struct rssparser r;
 
        memset(&r, 0, sizeof r);
-       r.rooms = rooms;
+       strcpy(r.url, url);
        XML_Parser p = XML_ParserCreate("UTF-8");
        XML_SetElementHandler(p, rss_start_element, rss_end_element);
        XML_SetCharacterDataHandler(p, rss_handle_data);
@@ -303,43 +302,12 @@ void rss_parse_feed(StrBuf *Feed, struct rssroom *rooms) {
 }
 
 
-// Add a feed/room pair into the todo list
-void rssclient_push_todo(char *rssurl, char *roomname) {
-       struct rssurl *r = NULL;
-       struct rssurl *thisone = NULL;
-       struct rssroom *newroom = NULL;
-
-       syslog(LOG_DEBUG, "rssclient: will fetch %s to %s", rssurl, roomname);
-
-       for (r=rsstodo; r!=NULL; r=r->next) {
-               if (!strcasecmp(r->url, rssurl)) {
-                       thisone = r;
-               }
-       }
-
-       if (thisone == NULL) {
-               thisone = malloc(sizeof(struct rssurl));
-               thisone->url = strdup(rssurl);
-               thisone->rooms = NULL;
-               thisone->next = rsstodo;
-               rsstodo = thisone;
-       }
-
-       newroom = malloc(sizeof(struct rssroom));
-       newroom->room = strdup(roomname);
-       newroom->next = thisone->rooms;
-       thisone->rooms = newroom;
-}
-
-
-// pull one feed (possibly multiple rooms)
-void rss_pull_one_feed(struct rssurl *url) {
+// pull the first feed in the list
+void rss_pull_one_feed(char *url) {
        CURL *curl;
        CURLcode res;
        StrBuf *Downloaded = NULL;
 
-       syslog(LOG_DEBUG, "rssclient: fetching %s", url->url);
-
        curl = curl_easy_init();
        if (!curl) {
                return;
@@ -347,7 +315,8 @@ void rss_pull_one_feed(struct rssurl *url) {
 
        Downloaded = NewStrBuf();
 
-       curl_easy_setopt(curl, CURLOPT_URL, url->url);
+       syslog(LOG_DEBUG, "rssclient: fetching %s", url);
+       curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);                     // Follow redirects
@@ -360,29 +329,24 @@ void rss_pull_one_feed(struct rssurl *url) {
        }
        curl_easy_cleanup(curl);
 
-       rss_parse_feed(Downloaded, url->rooms);                                 // parse the feed
+       rss_parse_feed(Downloaded, url);
        FreeStrBuf(&Downloaded);                                                // free the downloaded feed data
 }
 
 
 // We have a list, now download the feeds
 void rss_pull_feeds(void) {
-       struct rssurl *r;
-       struct rssroom *rr;
-
-       while ((rsstodo != NULL) && (!server_shutting_down)) {
-               rss_pull_one_feed(rsstodo);
-               r = rsstodo;
-               rsstodo = rsstodo->next;
-               while (r->rooms != NULL) {
-                       rr = r->rooms;
-                       r->rooms = r->rooms->next;
-                       free(rr->room);
-                       free(rr);
+       char url[SIZ];
+
+       while (array_len(feeds) > 0) {
+               struct rssfeed *r = (struct rssfeed *) array_get_element_at(feeds, 0);
+               strcpy(url, r->url);
+               rss_pull_one_feed(url);
+               while (r = array_get_element_at(feeds, 0), !strcmp(r->url, url)) {
+                       array_delete_element_at(feeds, 0);
                }
-               free(r->url);
-               free(r);
        }
+
 }
 
 
@@ -391,6 +355,7 @@ void rssclient_scan_room(struct ctdlroom *qrbuf, void *data) {
        char *serialized_config = NULL;
        int num_configs = 0;
        char cfgline[SIZ];
+       struct rssfeed one_feed;
        int i = 0;
 
        if (server_shutting_down) return;
@@ -409,7 +374,9 @@ void rssclient_scan_room(struct ctdlroom *qrbuf, void *data) {
                        if (vbar != NULL) {
                                *vbar = 0;
                        }
-                       rssclient_push_todo(cfgline, qrbuf->QRname);
+                       safestrncpy(one_feed.url, cfgline, SIZ);
+                       safestrncpy(one_feed.room, qrbuf->QRname, ROOMNAMELEN);
+                       array_append(feeds, &one_feed);
                }
        }
 
@@ -432,8 +399,15 @@ void rssclient_scan(void) {
        }
 
        syslog(LOG_DEBUG, "rssclient: started");
+       feeds = array_new(sizeof(struct rssfeed));
+       if (feeds == NULL) {
+               syslog(LOG_DEBUG, "rssclient: cannot allocate memory for feed list");
+               return;
+       }
        CtdlForEachRoom(rssclient_scan_room, NULL);
+       array_sort(feeds, (int (*)(const void *, const void *))strcmp);
        rss_pull_feeds();
+       array_free(feeds);
        syslog(LOG_DEBUG, "rssclient: ended");
        last_run = time(NULL);
        return;
index d31c227c53059edb6e74c4958b5c1b6d7e459a1e..b3421f060b650aba7c58328da0fdf5b91f1133b2 100644 (file)
@@ -65,18 +65,16 @@ const char HexList[256][3] = {
        "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"};
 
 
-/*
- * Private Structure for the Stringbuffer
- */
+// Private Structure for the Stringbuffer
 struct StrBuf {
-       char *buf;         /**< the pointer to the dynamic buffer */
-       long BufSize;      /**< how many spcae do we optain */
-       long BufUsed;      /**< StNumber of Chars used excluding the trailing \\0 */
-       int ConstBuf;      /**< are we just a wrapper arround a static buffer and musn't we be changed? */
+       char *buf;              // the pointer to the dynamic buffer
+       long BufSize;           // how many spcae do we optain
+       long BufUsed;           // Number of Chars used excluding the trailing \\0
+       int ConstBuf;           // are we just a wrapper arround a static buffer and musn't we be changed?
 #ifdef SIZE_DEBUG
-       long nIncreases;   /**< for profiling; cound how many times we needed more */
-       char bt [SIZ];     /**< Stacktrace of last increase */
-       char bt_lastinc [SIZ]; /**< How much did we increase last time? */
+       long nIncreases;        // for profiling; cound how many times we needed more
+       char bt [SIZ];          // Stacktrace of last increase
+       char bt_lastinc[SIZ];   // How much did we increase last time?
 #endif
 };
 
@@ -93,22 +91,24 @@ static void StrBufBacktrace(StrBuf *Buf, int which) {
        size_t size, i;
        char **strings;
 
-       if (which)
+       if (which) {
                pstart = pch = Buf->bt;
-       else
+       }
+       else {
                pstart = pch = Buf->bt_lastinc;
+       }
        size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
        strings = backtrace_symbols(stack_frames, size);
        for (i = 0; i < size; i++) {
-               if (strings != NULL)
+               if (strings != NULL) {
                        n = snprintf(pch, SIZ - (pch - pstart), "%s\\n", strings[i]);
-               else
+               }
+               else {
                        n = snprintf(pch, SIZ - (pch - pstart), "%p\\n", stack_frames[i]);
+               }
                pch += n;
        }
        free(strings);
-
-
 }
 #endif