sfeed

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

sfeed_mbox.c (raw) (4890B)


   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 			if (*(s + 1) == '\0')
  41 				break;
  42 			s++;
  43 			switch (*s) {
  44 			case 'n':
  45 				putc('\n', fp);
  46 				s++;
  47 				goto escapefrom;
  48 			case '\\': putc('\\', fp); break;
  49 			case 't':  putc('\t', fp); break;
  50 			}
  51 			break;
  52 		default:
  53 			putc(*s, fp); break;
  54 		}
  55 	}
  56 }
  57 
  58 static void
  59 printfeed(FILE *fp, const char *feedname)
  60 {
  61 	char *fields[FieldLast], timebuf[32];
  62 	struct tm parsedtm, *tm;
  63 	time_t parsedtime;
  64 	unsigned long long hash;
  65 	ssize_t linelen;
  66 	int ishtml;
  67 
  68 	while ((linelen = getline(&line, &linesize, fp)) > 0 &&
  69 	       !ferror(stdout)) {
  70 		if (line[linelen - 1] == '\n')
  71 			line[--linelen] = '\0';
  72 		hash = djb2((unsigned char *)line, 5381ULL);
  73 		parseline(line, fields);
  74 
  75 		/* mbox + mail header */
  76 		printf("From MAILER-DAEMON %s\n", mtimebuf);
  77 
  78 		parsedtime = 0;
  79 		if (!strtotime(fields[FieldUnixTimestamp], &parsedtime) &&
  80 		    (tm = gmtime_r(&parsedtime, &parsedtm)) &&
  81 		    strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S +0000", tm)) {
  82 			printf("Date: %s\n", timebuf);
  83 		} else {
  84 			printf("Date: %s\n", dtimebuf); /* invalid/missing: use current time */
  85 		}
  86 
  87 		printf("From: %s <anonymous@>\n", fields[FieldAuthor][0] ? fields[FieldAuthor] : feedname);
  88 		printf("To: %s <%s@%s>\n", user, user, host);
  89 		printf("Subject: %s\n", fields[FieldTitle]);
  90 		printf("Message-ID: <%s%s%llu@%s>\n",
  91 		       fields[FieldUnixTimestamp],
  92 		       fields[FieldUnixTimestamp][0] ? "." : "",
  93 		       hash, feedname);
  94 
  95 		ishtml = usecontent && !strcmp(fields[FieldContentType], "html");
  96 		if (ishtml)
  97 			fputs("Content-Type: text/html; charset=\"utf-8\"\n", stdout);
  98 		else
  99 			fputs("Content-Type: text/plain; charset=\"utf-8\"\n", stdout);
 100 		fputs("Content-Transfer-Encoding: binary\n", stdout);
 101 		printf("X-Feedname: %s\n", feedname);
 102 		fputs("\n", stdout);
 103 
 104 		if (ishtml) {
 105 			fputs("<p>\n", stdout);
 106 			if (fields[FieldLink][0]) {
 107 				fputs("Link: <a href=\"", stdout);
 108 				xmlencode(fields[FieldLink], stdout);
 109 				fputs("\">", stdout);
 110 				xmlencode(fields[FieldLink], stdout);
 111 				fputs("</a><br/>\n", stdout);
 112 			}
 113 			if (fields[FieldEnclosure][0]) {
 114 				fputs("Enclosure: <a href=\"", stdout);
 115 				xmlencode(fields[FieldEnclosure], stdout);
 116 				fputs("\">", stdout);
 117 				xmlencode(fields[FieldEnclosure], stdout);
 118 				fputs("</a><br/>\n", stdout);
 119 			}
 120 			fputs("</p>\n", stdout);
 121 		} else {
 122 			if (fields[FieldLink][0])
 123 				printf("Link:      %s\n", fields[FieldLink]);
 124 			if (fields[FieldEnclosure][0])
 125 				printf("Enclosure: %s\n", fields[FieldEnclosure]);
 126 		}
 127 		if (usecontent) {
 128 			fputs("\n", stdout);
 129 			if (ishtml && fields[FieldLink][0]) {
 130 				fputs("<base href=\"", stdout);
 131 				xmlencode(fields[FieldLink], stdout);
 132 				fputs("\"/>\n", stdout);
 133 			}
 134 			printcontent(fields[FieldContent], stdout);
 135 		}
 136 		fputs("\n\n", stdout);
 137 	}
 138 }
 139 
 140 int
 141 main(int argc, char *argv[])
 142 {
 143 	struct tm tmnow;
 144 	time_t now;
 145 	FILE *fp;
 146 	char *name, *tmp;
 147 	int i;
 148 
 149 	if (pledge(argc == 1 ? "stdio" : "stdio rpath", NULL) == -1)
 150 		err(1, "pledge");
 151 
 152 	if ((tmp = getenv("SFEED_MBOX_CONTENT")))
 153 		usecontent = !strcmp(tmp, "1");
 154 	if (!(user = getenv("USER")))
 155 		user = "you";
 156 	if (gethostname(host, sizeof(host)) == -1)
 157 		err(1, "gethostname");
 158 	if ((now = time(NULL)) == (time_t)-1)
 159 		errx(1, "time");
 160 	if (!gmtime_r(&now, &tmnow))
 161 		err(1, "gmtime_r: can't get current time");
 162 	if (!strftime(mtimebuf, sizeof(mtimebuf), "%a %b %d %H:%M:%S %Y", &tmnow))
 163 		errx(1, "strftime: can't format current time");
 164 	if (!strftime(dtimebuf, sizeof(dtimebuf), "%a, %d %b %Y %H:%M:%S +0000", &tmnow))
 165 		errx(1, "strftime: can't format current time");
 166 
 167 	if (argc == 1) {
 168 		printfeed(stdin, "");
 169 		checkfileerror(stdin, "<stdin>", 'r');
 170 	} else {
 171 		for (i = 1; i < argc; i++) {
 172 			if (!(fp = fopen(argv[i], "r")))
 173 				err(1, "fopen: %s", argv[i]);
 174 			name = ((name = strrchr(argv[i], '/'))) ? name + 1 : argv[i];
 175 			printfeed(fp, name);
 176 			checkfileerror(fp, argv[i], 'r');
 177 			checkfileerror(stdout, "<stdout>", 'w');
 178 			fclose(fp);
 179 		}
 180 	}
 181 
 182 	checkfileerror(stdout, "<stdout>", 'w');
 183 
 184 	return 0;
 185 }