sfeed_mbox.c - sfeed - RSS and Atom parser
 (HTM) git clone git://git.codemadness.org/sfeed
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       sfeed_mbox.c (5467B)
       ---
            1 #include <stdio.h>
            2 #include <stdlib.h>
            3 #include <string.h>
            4 #include <time.h>
            5 
            6 #include "util.h"
            7 
            8 static char *line;
            9 static size_t linesize;
           10 static char dtimebuf[32], mtimebuf[32];
           11 
           12 /* env variables: $SFEED_MBOX_FROM and $SFEED_MBOX_TO */
           13 static char *from = "<anonymous@localhost>", *to = "<anonymous@localhost>";
           14 /* env variable: $SFEED_MBOX_CONTENT */
           15 static int usecontent = 0;
           16 
           17 static unsigned long long
           18 djb2(unsigned char *s, unsigned long long hash)
           19 {
           20         int c;
           21 
           22         while ((c = *s++))
           23                 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
           24         return hash;
           25 }
           26 
           27 static void
           28 printtags(const char *s)
           29 {
           30         for (; *s; s++) {
           31                 if (*s == '|')
           32                         putchar(',');
           33                 else
           34                         putchar(*s);
           35         }
           36 }
           37 
           38 /* Unescape / decode fields printed by string_print_encoded()
           39  * "\\" to "\", "\t", to TAB, "\n" to newline. Other escape sequences are
           40  * ignored: "\z" etc. Mangle "From " in mboxrd style (always prefix >). */
           41 static void
           42 printcontent(const char *s)
           43 {
           44 escapefrom:
           45         for (; *s == '>'; s++)
           46                 putchar('>');
           47         /* escape "From ", mboxrd-style. */
           48         if (!strncmp(s, "From ", 5))
           49                 putchar('>');
           50 
           51         for (; *s; s++) {
           52                 switch (*s) {
           53                 case '\\':
           54                         if (*(s + 1) == '\0')
           55                                 break;
           56                         s++;
           57                         switch (*s) {
           58                         case 'n':
           59                                 putchar('\n');
           60                                 s++;
           61                                 goto escapefrom;
           62                         case '\\': putchar('\\'); break;
           63                         case 't':  putchar('\t'); break;
           64                         }
           65                         break;
           66                 default:
           67                         putchar(*s); break;
           68                 }
           69         }
           70 }
           71 
           72 static void
           73 printfeed(FILE *fp, const char *feedname)
           74 {
           75         char *fields[FieldLast], timebuf[32];
           76         struct tm parsedtm, *tm;
           77         time_t parsedtime;
           78         unsigned long long hash;
           79         ssize_t linelen;
           80         int ishtml;
           81 
           82         while ((linelen = getline(&line, &linesize, fp)) > 0 &&
           83                !ferror(stdout)) {
           84                 if (line[linelen - 1] == '\n')
           85                         line[--linelen] = '\0';
           86                 hash = djb2((unsigned char *)line, 5381ULL);
           87                 parseline(line, fields);
           88 
           89                 /* mbox + mail header */
           90                 printf("From MAILER-DAEMON %s\n", mtimebuf);
           91 
           92                 parsedtime = 0;
           93                 if (!strtotime(fields[FieldUnixTimestamp], &parsedtime) &&
           94                     (tm = gmtime_r(&parsedtime, &parsedtm)) &&
           95                     strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S +0000", tm)) {
           96                         printf("Date: %s\n", timebuf);
           97                 } else {
           98                         printf("Date: %s\n", dtimebuf); /* invalid/missing: use current time */
           99                 }
          100 
          101                 printf("From: %s\n", from);
          102                 printf("To: %s\n", to);
          103                 printf("Subject: %s\n", fields[FieldTitle]);
          104                 printf("Message-ID: <%s%s%llu@newsfeed.local>\n",
          105                        fields[FieldUnixTimestamp],
          106                        fields[FieldUnixTimestamp][0] ? "." : "",
          107                        hash);
          108 
          109                 ishtml = usecontent && !strcmp(fields[FieldContentType], "html");
          110                 if (ishtml)
          111                         fputs("Content-Type: text/html; charset=\"utf-8\"\n", stdout);
          112                 else
          113                         fputs("Content-Type: text/plain; charset=\"utf-8\"\n", stdout);
          114                 fputs("Content-Transfer-Encoding: binary\n", stdout);
          115                 if (feedname[0])
          116                         printf("X-Feedname: %s\n", feedname);
          117                 if (fields[FieldAuthor][0])
          118                         printf("X-RSS-Author: %s\n", fields[FieldAuthor]);
          119                 if (fields[FieldEnclosure][0])
          120                         printf("X-RSS-Enclosure: %s\n", fields[FieldEnclosure]);
          121                 if (fields[FieldId][0])
          122                         printf("X-RSS-ID: %s\n", fields[FieldId]);
          123                 if (fields[FieldCategory][0]) {
          124                         fputs("X-RSS-TAGS: ", stdout);
          125                         printtags(fields[FieldCategory]);
          126                         fputs("\n", stdout);
          127                 }
          128                 if (fields[FieldLink][0])
          129                         printf("X-RSS-URL: %s\n", fields[FieldLink]);
          130                 fputs("\n", stdout);
          131 
          132                 if (ishtml) {
          133                         fputs("<p>\n", stdout);
          134                         if (fields[FieldLink][0]) {
          135                                 fputs("Link: <a href=\"", stdout);
          136                                 xmlencode(fields[FieldLink], stdout);
          137                                 fputs("\">", stdout);
          138                                 xmlencode(fields[FieldLink], stdout);
          139                                 fputs("</a><br/>\n", stdout);
          140                         }
          141                         if (fields[FieldEnclosure][0]) {
          142                                 fputs("Enclosure: <a href=\"", stdout);
          143                                 xmlencode(fields[FieldEnclosure], stdout);
          144                                 fputs("\">", stdout);
          145                                 xmlencode(fields[FieldEnclosure], stdout);
          146                                 fputs("</a><br/>\n", stdout);
          147                         }
          148                         fputs("</p>\n", stdout);
          149                 } else {
          150                         if (fields[FieldLink][0])
          151                                 printf("Link:      %s\n", fields[FieldLink]);
          152                         if (fields[FieldEnclosure][0])
          153                                 printf("Enclosure: %s\n", fields[FieldEnclosure]);
          154                 }
          155                 if (usecontent) {
          156                         fputs("\n", stdout);
          157                         if (ishtml && fields[FieldLink][0]) {
          158                                 fputs("<base href=\"", stdout);
          159                                 xmlencode(fields[FieldLink], stdout);
          160                                 fputs("\"/>\n", stdout);
          161                         }
          162                         printcontent(fields[FieldContent]);
          163                 }
          164                 fputs("\n\n", stdout);
          165         }
          166 }
          167 
          168 int
          169 main(int argc, char *argv[])
          170 {
          171         struct tm tmnow;
          172         time_t now;
          173         FILE *fp;
          174         char *name, *tmp;
          175         int i;
          176 
          177         if (pledge(argc <= 1 ? "stdio" : "stdio rpath", NULL) == -1)
          178                 err(1, "pledge");
          179 
          180         if ((tmp = getenv("SFEED_MBOX_CONTENT")))
          181                 usecontent = !strcmp(tmp, "1");
          182         if ((tmp = getenv("SFEED_MBOX_FROM")))
          183                 from = tmp;
          184         if ((tmp = getenv("SFEED_MBOX_TO")))
          185                 to = tmp;
          186 
          187         if ((now = time(NULL)) == (time_t)-1)
          188                 errx(1, "time");
          189         if (!gmtime_r(&now, &tmnow))
          190                 err(1, "gmtime_r: can't get current time");
          191         if (!strftime(mtimebuf, sizeof(mtimebuf), "%a %b %d %H:%M:%S %Y", &tmnow))
          192                 errx(1, "strftime: can't format current time");
          193         if (!strftime(dtimebuf, sizeof(dtimebuf), "%a, %d %b %Y %H:%M:%S +0000", &tmnow))
          194                 errx(1, "strftime: can't format current time");
          195 
          196         if (argc <= 1) {
          197                 printfeed(stdin, "");
          198                 checkfileerror(stdin, "<stdin>", 'r');
          199         } else {
          200                 for (i = 1; i < argc; i++) {
          201                         if (!(fp = fopen(argv[i], "r")))
          202                                 err(1, "fopen: %s", argv[i]);
          203                         name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
          204                         printfeed(fp, name);
          205                         checkfileerror(fp, argv[i], 'r');
          206                         checkfileerror(stdout, "<stdout>", 'w');
          207                         fclose(fp);
          208                 }
          209         }
          210 
          211         checkfileerror(stdout, "<stdout>", 'w');
          212 
          213         return 0;
          214 }