sfeed

simple feed reader - forked from git.codemadness.org/sfeed
git clone git://src.gearsix.net/sfeed
Log | Files | Refs | Atom | README | LICENSE

sfeed_mbox.c (4850B)


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