]> code.citadel.org Git - citadel.git/blobdiff - citadel/server/modules/rssclient/serv_rssclient.c
citadel.h is now citadel_defs.h
[citadel.git] / citadel / server / modules / rssclient / serv_rssclient.c
index 8021ebdba484e34e7836b84423d322c5a04e3374..07ea2e8181da82f6c8620a59c2751f1b3e333ba2 100644 (file)
@@ -1,18 +1,11 @@
-/*
- * Bring external RSS and/or Atom feeds into rooms.  This module implements a
- * very loose parser that scrapes both kinds of feeds and is not picky about
- * the standards compliance of the source data.
- *
- * Copyright (c) 2007-2022 by the citadel.org team
- *
- * This program is open source software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+// Bring external RSS and/or Atom feeds into rooms.  This module implements a
+// very loose parser that scrapes both kinds of feeds and is not picky about
+// the standards compliance of the source data.
+//
+// Copyright (c) 2007-2023 by the citadel.org team
+//
+// This program is open source software.  Use, duplication, or disclosure
+// is subject to the terms of the GNU General Public License, version 3.
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -26,7 +19,7 @@
 #include <expat.h>
 #include <curl/curl.h>
 #include <libcitadel.h>
-#include "../../citadel.h"
+#include "../../citadel_defs.h"
 #include "../../server.h"
 #include "../../citserver.h"
 #include "../../support.h"
@@ -65,7 +58,6 @@ struct rssurl *rsstodo = NULL;
 
 
 // This handler is called whenever an XML tag opens.
-//
 void rss_start_element(void *data, const char *el, const char **attribute) {
        struct rssparser *r = (struct rssparser *)data;
        int i;
@@ -104,7 +96,6 @@ void rss_start_element(void *data, const char *el, const char **attribute) {
 
 
 // This handler is called whenever an XML tag closes.
-//
 void rss_end_element(void *data, const char *el) {
        struct rssparser *r = (struct rssparser *)data;
        StrBuf *encoded_field;
@@ -135,37 +126,49 @@ void rss_end_element(void *data, const char *el) {
                        if (already_seen == 0) {
 
                                // Compose the message text
+
                                StrBuf *TheMessage = NewStrBuf();
-                               StrBufAppendPrintf(TheMessage,
-                                       "Content-type: text/html\n\n"
-                                       "\n\n"
-                                       "<html><head></head><body>"
-                               );
-               
+                               StrBufAppendPrintf(TheMessage, "<html><head></head><body>");
+
                                if (r->description != NULL) {
                                        StrBufAppendPrintf(TheMessage, "%s<br><br>\r\n", r->description);
                                        free(r->description);
                                        r->description = NULL;
                                }
-               
+
                                if (r->link != NULL) {
                                        StrBufAppendPrintf(TheMessage, "<a href=\"%s\">%s</a>\r\n", r->link, r->link);
                                        free(r->link);
                                        r->link = NULL;
                                }
-       
+
                                StrBufAppendPrintf(TheMessage, "</body></html>\r\n");
+
+                               // Quoted-Printable encode the HTML message, because RSS and Atom make no guarantee of line length limits.
+                               StrBuf *TheMessage_Encoded = StrBufQuotedPrintableEncode(TheMessage);
+
+                               // Now we reuse TheMessage -- this time it will contain the MIME headers concatenated with the encoded message.
+                               FlushStrBuf(TheMessage);
+                               StrBufAppendBufPlain(TheMessage, HKEY(
+                                       "Content-type: text/html; charset=UTF-8\r\n"
+                                       "Content-Transfer-Encoding: quoted-printable\r\n"
+                                       "\r\n"
+                                       ), 0
+                               );
+                               StrBufAppendBuf(TheMessage, TheMessage_Encoded, 0);
+                               FreeStrBuf(&TheMessage_Encoded);
+
                                CM_SetField(r->msg, eMesageText, ChrPtr(TheMessage), StrLength(TheMessage));
                                FreeStrBuf(&TheMessage);
-       
+
                                if (CM_IsEmpty(r->msg, eAuthor)) {
                                        CM_SetField(r->msg, eAuthor, HKEY("rss"));
                                }
-       
+
                                if (CM_IsEmpty(r->msg, eTimestamp)) {
                                        CM_SetFieldLONG(r->msg, eTimestamp, time(NULL));
                                }
-       
+
                                // Save it to the room(s)
                                struct rssroom *rr = NULL;
                                long msgnum = (-1);
@@ -182,7 +185,7 @@ void rss_end_element(void *data, const char *el) {
                        else {
                                syslog(LOG_DEBUG, "rssclient: already seen %s", r->item_id);
                        }
-       
+
                        CM_Free(r->msg);
                        r->msg = NULL;
                }
@@ -274,9 +277,7 @@ void rss_end_element(void *data, const char *el) {
 
 
 // This handler is called whenever data appears between opening and closing tags.
-//
-void rss_handle_data(void *data, const char *content, int length)
-{
+void rss_handle_data(void *data, const char *content, int length) {
        struct rssparser *r = (struct rssparser *)data;
 
        if (r->CData == NULL) {
@@ -288,9 +289,7 @@ 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)
-{
+void rss_parse_feed(StrBuf *Feed, struct rssroom *rooms) {
        struct rssparser r;
 
        memset(&r, 0, sizeof r);
@@ -305,9 +304,7 @@ 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)
-{
+void rssclient_push_todo(char *rssurl, char *roomname) {
        struct rssurl *r = NULL;
        struct rssurl *thisone = NULL;
        struct rssroom *newroom = NULL;
@@ -336,9 +333,7 @@ void rssclient_push_todo(char *rssurl, char *roomname)
 
 
 // pull one feed (possibly multiple rooms)
-//
-void rss_pull_one_feed(struct rssurl *url)
-{
+void rss_pull_one_feed(struct rssurl *url) {
        CURL *curl;
        CURLcode res;
        StrBuf *Downloaded = NULL;
@@ -371,9 +366,7 @@ void rss_pull_one_feed(struct rssurl *url)
 
 
 // We have a list, now download the feeds
-//
-void rss_pull_feeds(void)
-{
+void rss_pull_feeds(void) {
        struct rssurl *r;
        struct rssroom *rr;
 
@@ -394,9 +387,7 @@ void rss_pull_feeds(void)
 
 
 // Scan a room's netconfig looking for RSS feed parsing requests
-//
-void rssclient_scan_room(struct ctdlroom *qrbuf, void *data)
-{
+void rssclient_scan_room(struct ctdlroom *qrbuf, void *data) {
        char *serialized_config = NULL;
        int num_configs = 0;
        char cfgline[SIZ];
@@ -426,13 +417,11 @@ void rssclient_scan_room(struct ctdlroom *qrbuf, void *data)
 }
 
 
-/*
- * Scan for rooms that have RSS client requests configured
- */
+// Scan for rooms that have RSS client requests configured
 void rssclient_scan(void) {
        time_t now = time(NULL);
 
-       /* Run no more than once every 15 minutes. */
+       // Run no more than once every 15 minutes.
        if ((now - last_run) < 900) {
                syslog(LOG_DEBUG,
                        "rssclient: polling interval not yet reached; last run was %ldm%lds ago",