sfeed

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

sfeed_mbox.c (raw) (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 }