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 }