view.c - rohrpost - A commandline mail client to change the world as we see it.
(HTM) git clone git://r-36.net/rohrpost
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
view.c (9292B)
---
1 /*
2 * Copy me if you can.
3 * by 20h
4 */
5
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <time.h>
10 #include <strings.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <signal.h>
14 #include <string.h>
15
16 #include "ind.h"
17 #include "arg.h"
18 #include "cfg.h"
19 #include "llist.h"
20 #include "folder.h"
21 #include "imap.h"
22 #include "pager.h"
23 #include "mime.h"
24 #include "scan.h"
25 #include "mark.h"
26
27 enum {
28 PRINT_HEADER = 0x01,
29 PRINT_BODY = 0x02,
30 PRINT_VALUE = 0x04,
31 PRINT_NOMIME = 0x08,
32 IS_SUBPART = 0x10
33 };
34
35 void
36 view_printpartheader(mime_t *mime)
37 {
38 printf("--MIME-Part %s [%s] (%d Bytes)\n", mime->partid,
39 mime->ct, mime->bodylen);
40 }
41
42 void
43 view_printtextplain(mime_t *mime)
44 {
45 char *hvalue;
46 int plen;
47
48 plen = 0;
49 hvalue = mime_decodepart(mime, &plen);
50 if (hvalue != NULL) {
51 printf("%s\n", hvalue);
52 free(hvalue);
53 }
54 }
55
56 void
57 view_printtexthtml(mime_t *mime)
58 {
59 int infd, outfd, pid, plen;
60 char *hvalue, *decbuf, *lstr;
61
62 plen = 0;
63 hvalue = mime_decodepartencoding(mime, &plen);
64 if (hvalue == NULL)
65 return;
66
67 lstr = smprintf("lynx -dump -stdin -nomargins "
68 "-display_charset=\"utf-8\" "
69 "-image_links "
70 "-assume_charset=\"%s\"", mime->charset);
71 pid = runcmd(lstr, &infd, &outfd, NULL, 0);
72 free(lstr);
73 if (pid < 0) {
74 printf("Could not run lynx.\n");
75 printf("%s\n", hvalue);
76 free(hvalue);
77 return;
78 }
79
80 writeallfd(infd, hvalue, plen);
81 close(infd);
82 decbuf = readtoeoffd(outfd, &plen);
83 if (decbuf == NULL) {
84 printf("Lynx did not output anything.\n");
85 printf("%s\n", hvalue);
86 free(hvalue);
87
88 goto killlynx;
89 }
90
91 printf("%s\n", decbuf);
92
93 free(decbuf);
94 free(hvalue);
95 killlynx:
96 kill(pid, SIGTERM);
97 waitpid(pid, NULL, 0);
98 }
99
100 void
101 view_printtext(mime_t *mime, int options)
102 {
103 if (!(options & PRINT_NOMIME))
104 view_printpartheader(mime);
105
106 if (!strncasecmp(mime->ct+5, "plain", 5)) {
107 view_printtextplain(mime);
108 return;
109 } else if (!strncasecmp(mime->ct+5, "html", 4)) {
110 view_printtexthtml(mime);
111 return;
112 }
113 }
114
115 void
116 view_printpartname(char *id, mime_t *mime)
117 {
118 char *filename;
119
120 filename = mime_mkfilename(id, mime);
121 printf("--MIME-Part %s [%s] %s (%d Bytes)\n", mime->partid,
122 mime->ct, filename, mime->bodylen);
123 free(filename);
124 }
125
126 void
127 view_printpart(char *id, mime_t *mime, llist_t *dhdrs, llist_t *partl,
128 int options)
129 {
130 llistelem_t *delem, *helem, *part;
131 char *hvalue, *textplainid, *texthtmlid;
132 int didprint, inpartl;
133 llist_t *alpartl, *hlist;
134
135 inpartl = 0;
136 if (partl != NULL && llist_get(partl, mime->partid))
137 inpartl = 1;
138
139 if (dhdrs != NULL && !(options & PRINT_BODY) &&
140 (partl == NULL || inpartl) &&
141 !(options & IS_SUBPART)) {
142 didprint = 0;
143 if (!strcasecmp(dhdrs->first->key, "all")) {
144 forllist(mime->hdrs, helem) {
145 hvalue = mime_guessheader((char *)helem->data);
146 if (hvalue == NULL)
147 continue;
148 if (options & PRINT_VALUE) {
149 printf("%s\n", hvalue);
150 } else {
151 printf("%s: %s\n", helem->key, hvalue);
152 }
153 free(hvalue);
154 didprint = 1;
155 }
156 } else {
157 forllist(dhdrs, delem) {
158 hlist = llist_cifind(mime->hdrs, delem->key);
159 if (hlist != NULL) {
160 forllist(hlist, helem) {
161 hvalue = mime_guessheader(
162 (char *)helem->data);
163 if (hvalue == NULL)
164 continue;
165 if (options & PRINT_VALUE) {
166 printf("%s\n", hvalue);
167 } else {
168 printf("%s: %s\n", helem->key,
169 hvalue);
170 }
171 free(hvalue);
172 didprint = 1;
173 }
174 }
175 }
176 }
177 if (didprint && !(options & PRINT_HEADER))
178 printf("\n");
179 }
180
181 if (mime->parts->len > 0) {
182 alpartl = NULL;
183 options |= IS_SUBPART;
184
185 if (!strncasecmp(mime->ct, "multipart/alternative", 21) &&
186 (partl == NULL || inpartl)) {
187 texthtmlid = textplainid = NULL;
188 forllist(mime->parts, part) {
189 if (!strncasecmp(((mime_t *)part->data)->ct,
190 "text/plain", 10)
191 && (((mime_t *)part->data)->bodylen > 0)) {
192 textplainid =
193 ((mime_t *)part->data)->partid;
194 }
195 if (!strncasecmp(((mime_t *)part->data)->ct,
196 "text/html", 9)
197 && (((mime_t *)part->data)->bodylen > 0)) {
198 texthtmlid =
199 ((mime_t *)part->data)->partid;
200 }
201 }
202 if (textplainid == NULL && texthtmlid != NULL)
203 textplainid = texthtmlid;
204
205 alpartl = llist_new();
206 if (textplainid != NULL) {
207 llist_add(alpartl, textplainid, NULL, 0);
208 } else {
209 llist_add(alpartl, (char *)((mime_t *)mime->\
210 parts->first->data)->partid,
211 NULL, 0);
212 }
213 }
214
215 forllist(mime->parts, part) {
216 if (alpartl != NULL || inpartl) {
217 view_printpart(id, (mime_t *)part->data,
218 dhdrs, alpartl, options);
219 } else {
220 view_printpart(id, (mime_t *)part->data,
221 dhdrs, partl, options);
222 }
223 }
224
225 if (alpartl != NULL)
226 llist_free(alpartl);
227 return;
228 }
229
230 if (options & PRINT_HEADER)
231 return;
232
233 if (partl) {
234 if (inpartl) {
235 view_printtext(mime, options);
236 } else {
237 if (!(options & PRINT_NOMIME))
238 view_printpartname(id, mime);
239 }
240 return;
241 }
242
243 hvalue = mime_filename(mime);
244 if (hvalue != NULL) {
245 if (!(options & PRINT_NOMIME))
246 view_printpartname(id, mime);
247 free(hvalue);
248 return;
249 }
250
251 if (!strncasecmp(mime->ct, "text/", 5)) {
252 view_printtext(mime, options);
253 return;
254 }
255
256 if (!(options & PRINT_NOMIME))
257 view_printpartname(id, mime);
258 }
259
260 void
261 view_print(char *id, mime_t *mime, llist_t *dhdrs, llist_t *partl,
262 int options)
263 {
264 if (id != NULL && !(options & (PRINT_HEADER|PRINT_BODY)))
265 printf("--- %s ---\n", id);
266
267 view_printpart(id, mime, dhdrs, partl, options);
268
269 if (!(options & (PRINT_HEADER|PRINT_BODY)))
270 printf("\f\n");
271 }
272
273 void
274 viewusage(char *argv0)
275 {
276 die("usage: %s [-hbdnrv] [-c cfg] [-e headers] [-m folder]"
277 " [-p parts] msgs\n", argv0);
278 }
279
280 int
281 viewmain(int argc, char *argv[])
282 {
283 config_t *cfg;
284 imap_t *imap;
285 int status, filelen, printopts, dodebug;
286 char *user, *pass, *netspec, *selected, *mfilter, *parts, *filec,
287 *headers, *cfgn, *id, *argv0;
288 llist_t *ids, *msgs, *dhdrs, *partl;
289 llistelem_t *elem, *msg, *ide;
290 mime_t *mime;
291 mark_t *marks;
292
293 enum {
294 PRINTRAW = 0x01,
295 NOMIME = 0x02,
296 DODEBUG = 0x04,
297
298 NOARGS = 0x08
299 };
300
301 status = 0;
302 parts = NULL;
303 selected = NULL;
304 headers = NULL;
305 printopts = 0;
306 dodebug = 0;
307 cfgn = NULL;
308
309 ARGBEGIN(argv0) {
310 case 'b':
311 printopts |= PRINT_BODY;
312 break;
313 case 'c':
314 cfgn = EARGF(viewusage(argv0));
315 break;
316 case 'd':
317 dodebug = 1;
318 break;
319 case 'e':
320 headers = EARGF(viewusage(argv0));
321 break;
322 case 'm':
323 selected = EARGF(viewusage(argv0));
324 break;
325 case 'n':
326 printopts |= PRINT_NOMIME;
327 break;
328 case 'p':
329 parts = EARGF(viewusage(argv0));
330 break;
331 case 'r':
332 status |= PRINTRAW;
333 break;
334 case 'v':
335 printopts |= PRINT_VALUE;
336 break;
337 default:
338 viewusage(argv0);
339 } ARGEND;
340
341 filelen = 0;
342 if (argc < 1) {
343 filec = readtoeoffd(0, &filelen);
344 if (filec == NULL)
345 edie("readtoeoffd");
346 } else {
347 filec = NULL;
348 }
349
350 cfg = config_init(cfgn);
351 if (filec == NULL) {
352 user = config_checkgetstr(cfg, "imapuser");
353 pass = config_checkgetstr(cfg, "imappass");
354 netspec = config_checkgetstr(cfg, "imapnet");
355 if (selected == NULL) {
356 selected = config_checkgetstr(cfg, "selected");
357 } else {
358 selected = memdups(selected);
359 }
360 }
361 if (cfg->name != NULL) {
362 cfgn = memdups(cfg->name);
363 } else {
364 cfgn = memdups(cfgn);
365 }
366
367 if (headers == NULL) {
368 mfilter = config_checkgetstr(cfg, "view_msgfilter");
369 dhdrs = llist_splitstr(mfilter, " ,");
370 free(mfilter);
371 } else {
372 printopts |= PRINT_HEADER;
373 dhdrs = llist_splitstr(headers, " ,");
374 }
375
376 config_free(cfg);
377
378 partl = NULL;
379 if (parts != NULL)
380 partl = llist_splitstr(parts, " ,");
381
382 /*
383 * Stdin handling.
384 */
385 if (filec != NULL) {
386 if (status & PRINTRAW) {
387 printf("%s", filec);
388 free(filec);
389 goto viewcleanup;
390 }
391
392 mime = mime_parsebuf(filec, filelen);
393 free(filec);
394 if (mime == NULL)
395 die("Given input does not seem to be valid MIME.\n");
396
397 if (dodebug)
398 mime_print(mime);
399 view_print(NULL, mime, dhdrs, partl, printopts);
400 mime_free(mime);
401
402 goto viewcleanup;
403 }
404
405 ids = imap_argv2ids(cfgn, selected, argc, argv);
406 if (ids == NULL)
407 die("No msgids selected. Aborting.\n");
408
409 imap = imap_new(netspec, user, pass);
410 free(user);
411 free(pass);
412 free(netspec);
413
414 if (imap_init(imap))
415 imap_die(imap, "imap_init");
416 if (imap_select(imap, selected))
417 imap_die(imap, "imap_select");
418
419 msgs = imap_fetchraw(imap, ids);
420 if (msgs == NULL)
421 imap_die(imap, "imap_fetchheaders");
422 forllist(msgs, msg) {
423 elem = llist_get((llist_t *)msg->data, "literal");
424 if (elem == NULL)
425 continue;
426
427 if ((status & PRINTRAW)) {
428 printf("%s", (char *)elem->data);
429 continue;
430 }
431
432 ide = llist_get((llist_t *)msg->data, "id");
433 if (ide == NULL)
434 continue;
435
436 mime = mime_parsebuf((char *)elem->data, elem->datalen);
437 if (mime == NULL)
438 continue;
439
440 if (dodebug)
441 mime_print(mime);
442
443 id = smprintf("rp:/%s/%s/%s",
444 ((!strcmp(cfgn, "default"))? "" : cfgn),
445 selected,
446 (char *)ide->data);
447
448 view_print(id, mime, dhdrs, partl, printopts);
449
450 free(id);
451 mime_free(mime);
452 }
453 if (ids->last != NULL) {
454 marks = mark_init(cfgn, selected);
455 mark_set(marks, "cur", ids->last->key);
456 mark_stop(marks);
457 }
458
459 llist_free(ids);
460 llist_efree(msgs);
461
462 viewcleanup:
463 free(cfgn);
464 llist_free(dhdrs);
465
466 if (partl != NULL)
467 llist_free(partl);
468
469 if (filec == NULL) {
470 free(selected);
471 imap_close(imap);
472 imap_free(imap);
473 }
474 return 0;
475 }
476