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