sfeed_mbox.c (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 9static char *line; 10static size_t linesize; 11static char host[256], *user, dtimebuf[32], mtimebuf[32]; 12static int usecontent = 0; /* env variable: $SFEED_MBOX_CONTENT */ 13 14static unsigned long long 15djb2(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 >). */ 27static void 28printcontent(const char *s, FILE *fp) 29{ 30escapefrom: 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 58static void 59printfeed(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 140int 141main(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}