rohrpost

A commandline mail client to change the world as we see it.
git clone git://r-36.net/rohrpost
Log | Files | Refs | 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