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