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