From: Ken Hornstein Date: Wed, 9 Apr 2014 15:29:32 +0000 (-0400) Subject: Now only display text and inline content by default. X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/f62ff135add5529166b3cbd8ab9347f0db7048bb?hp=-c Now only display text and inline content by default. Use mh-format(5) to display marker text for skipped content. --- f62ff135add5529166b3cbd8ab9347f0db7048bb diff --git a/h/fmt_scan.h b/h/fmt_scan.h index 4d768b7b..d50dc441 100644 --- a/h/fmt_scan.h +++ b/h/fmt_scan.h @@ -267,6 +267,25 @@ int fmt_addcomptext(char *component, char *text); void fmt_appendcomp(int bucket, char *component, char *text); +/* + * Iterate over the complete hash table of component structures. + * + * Arguments are: + * + * comp - Pointer to the current component structure. The next + * component in the hash table after this component. To + * start (or restart) the iteration of the hash table + * this argument should be NULL. + * bucket - Pointer to hash bucket. Will be managed by this function, + * the caller should not modify this value. + * + * Returns the next component in the hash table. This value should be + * passed into the next call to fmt_nextcomp(). Returns NULL at the end + * of the hash table. + */ + +struct comp *fmt_nextcomp(struct comp *comp, unsigned int *bucket); + /* * The implementation of the %(formataddr) function. This is available for * programs to provide their own local implementation if they wish to do diff --git a/h/mhparse.h b/h/mhparse.h index c2ba18a2..3685dd9e 100644 --- a/h/mhparse.h +++ b/h/mhparse.h @@ -495,7 +495,11 @@ char *get_param_value(PM pm, char replace); * inlineonly - If true, only display MIME parts that are marked with * a disposition of "inline" (includes parts that lack a * Content-Disposition header). + * markerform - A file of mh-format(5) code used to display info about + * MIME parts. + * markerformat - mh-format(5) code used to display info about MIME parts. */ -void show_all_messages(CT *cts, int concat, int textonly, int inlineonly); +void show_all_messages(CT *cts, int concat, int textonly, int inlineonly, + char *markerform, char *markerformat); extern int checksw; /* Add Content-MD5 field */ diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 970e71e5..3f170f31 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -1087,6 +1087,25 @@ fmt_appendcomp(int bucket, char *component, char *text) } } +/* + * Iterate over our component hash table + */ + +struct comp * +fmt_nextcomp(struct comp *comp, unsigned int *bucket) +{ + if (comp == NULL) + *bucket = 0; + else + comp = comp->c_next; + + while (comp == NULL && *bucket < sizeof(wantcomp)/sizeof(wantcomp[0])) { + comp = wantcomp[(*bucket)++]; + } + + return comp; +} + /* * Free and reset our component hash table */ diff --git a/uip/mhn.c b/uip/mhn.c index 8a4ab318..28f499bb 100644 --- a/uip/mhn.c +++ b/uip/mhn.c @@ -552,7 +552,7 @@ do_cache: * Show the message content */ if (showsw) - show_all_messages (cts, 0, 0, 0); + show_all_messages (cts, 0, 0, 0, NULL, NULL); /* Now free all the structures for the content */ for (ctp = cts; *ctp; ctp++) diff --git a/uip/mhshow.c b/uip/mhshow.c index ab589551..97048b08 100644 --- a/uip/mhshow.c +++ b/uip/mhshow.c @@ -388,7 +388,7 @@ do_cache: /* * Show the message content */ - show_all_messages (cts, concatsw, textonly, inlineonly); + show_all_messages (cts, concatsw, textonly, inlineonly, NULL, NULL); /* Now free all the structures for the content */ for (ctp = cts; *ctp; ctp++) diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index 9ca34192..72ef1584 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #ifdef HAVE_ICONV # include @@ -46,32 +47,56 @@ int show_content_aux (CT, int, char *, char *); /* * static prototypes */ -static void show_single_message (CT, char *, int, int, int); +static void show_single_message (CT, char *, int, int, int, struct format *); static void DisplayMsgHeader (CT, char *, int); -static int show_switch (CT, int, int, int, int); -static int show_content (CT, int); +static int show_switch (CT, int, int, int, int, struct format *); +static int show_content (CT, int, int, int, struct format *fmt); static int show_content_aux2 (CT, int, char *, char *, int, int, int); static int show_text (CT, int, int); -static int show_multi (CT, int, int, int, int); -static int show_multi_internal (CT, int, int, int, int); +static int show_multi (CT, int, int, int, int, struct format *); +static int show_multi_internal (CT, int, int, int, int, struct format *fmt); static int show_multi_aux (CT, int, char *); static int show_message_rfc822 (CT, int); static int show_partial (CT, int); -static int show_external (CT, int, int, int, int); +static int show_external (CT, int, int, int, int, struct format *); static int parse_display_string (CT, char *, int *, int *, char *, char *, size_t, int multipart); static int convert_content_charset (CT, char **); +static struct format *compile_marker(char *, char *); +static void output_marker (CT, struct format *); +static void free_markercomps (void); static int pidcheck(int); +/* + * Components (and list of parameters/components) we care about for the + * content marker display. + */ + +static struct comp *part_comp = NULL; +static struct comp *ctype_comp = NULL; +static struct comp *description_comp = NULL; +static struct comp *dispo_comp = NULL; + +struct param_comp_list { + char *param; + struct comp *comp; + struct param_comp_list *next; +}; + +static struct param_comp_list *ctype_pc_list = NULL; +static struct param_comp_list *dispo_pc_list = NULL; + /* * Top level entry point to show/display a group of messages */ void -show_all_messages (CT *cts, int concat, int textonly, int inlineonly) +show_all_messages (CT *cts, int concat, int textonly, int inlineonly, + char *markerform, char *markerformat) { CT ct, *ctp; + struct format *fmt; /* * If form is not specified, then get default form @@ -80,6 +105,11 @@ show_all_messages (CT *cts, int concat, int textonly, int inlineonly) if (!formsw) formsw = getcpy (etcpath ("mhl.headers")); + /* + * Compile the content marker format line + */ + fmt = compile_marker(markerform, markerformat); + /* * If form is "mhl.null", suppress display of header. */ @@ -91,8 +121,11 @@ show_all_messages (CT *cts, int concat, int textonly, int inlineonly) /* if top-level type is ok, then display message */ if (type_ok (ct, 1)) - show_single_message (ct, formsw, concat, textonly, inlineonly); + show_single_message (ct, formsw, concat, textonly, inlineonly, fmt); } + + free_markercomps(); + fmt_free(fmt, 1); } @@ -102,7 +135,7 @@ show_all_messages (CT *cts, int concat, int textonly, int inlineonly) static void show_single_message (CT ct, char *form, int concat, int textonly, - int inlineonly) + int inlineonly, struct format *fmt) { sigset_t set, oset; @@ -120,7 +153,7 @@ show_single_message (CT ct, char *form, int concat, int textonly, DisplayMsgHeader(ct, form, concat); /* Show the body of the message */ - show_switch (ct, 0, concat, textonly, inlineonly); + show_switch (ct, 0, concat, textonly, inlineonly, fmt); if (ct->c_fp) { fclose (ct->c_fp); @@ -211,11 +244,13 @@ DisplayMsgHeader (CT ct, char *form, int concat) */ static int -show_switch (CT ct, int alternate, int concat, int textonly, int inlineonly) +show_switch (CT ct, int alternate, int concat, int textonly, int inlineonly, + struct format *fmt) { switch (ct->c_type) { case CT_MULTIPART: - return show_multi (ct, alternate, concat, textonly, inlineonly); + return show_multi (ct, alternate, concat, textonly, + inlineonly, fmt); case CT_MESSAGE: switch (ct->c_subtype) { @@ -224,7 +259,7 @@ show_switch (CT ct, int alternate, int concat, int textonly, int inlineonly) case MESSAGE_EXTERNAL: return show_external (ct, alternate, concat, textonly, - inlineonly); + inlineonly, fmt); case MESSAGE_RFC822: default: @@ -238,7 +273,7 @@ show_switch (CT ct, int alternate, int concat, int textonly, int inlineonly) case CT_IMAGE: case CT_VIDEO: case CT_APPLICATION: - return show_content (ct, alternate); + return show_content (ct, alternate, textonly, inlineonly, fmt); default: adios (NULL, "unknown content type %d", ct->c_type); @@ -253,11 +288,22 @@ show_switch (CT ct, int alternate, int concat, int textonly, int inlineonly) */ static int -show_content (CT ct, int alternate) +show_content (CT ct, int alternate, int textonly, int inlineonly, + struct format *fmt) { char *cp, buffer[BUFSIZ]; CI ci = &ct->c_ctinfo; + /* + * If we're here, we are not a text type. So we don't need to check + * the content-type. + */ + + if (textonly || (inlineonly && is_inline(ct))) { + output_marker(ct, fmt); + return OK; + } + /* Check for invo_name-show-type/subtype */ snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", invo_name, ci->ci_type, ci->ci_subtype); @@ -479,7 +525,8 @@ show_text (CT ct, int alternate, int concat) */ static int -show_multi (CT ct, int alternate, int concat, int textonly, int inlineonly) +show_multi (CT ct, int alternate, int concat, int textonly, int inlineonly, + struct format *fmt) { char *cp, buffer[BUFSIZ]; CI ci = &ct->c_ctinfo; @@ -503,7 +550,8 @@ show_multi (CT ct, int alternate, int concat, int textonly, int inlineonly) * unknown types are displayable, since they're treated as mixed * per RFC 2046. */ - return show_multi_internal (ct, alternate, concat, textonly, inlineonly); + return show_multi_internal (ct, alternate, concat, textonly, + inlineonly, fmt); } @@ -514,7 +562,7 @@ show_multi (CT ct, int alternate, int concat, int textonly, int inlineonly) static int show_multi_internal (CT ct, int alternate, int concat, int textonly, - int inlineonly) + int inlineonly, struct format *fmt) { int alternating, nowalternate, result; struct multipart *m = (struct multipart *) ct->c_ctparams; @@ -539,12 +587,11 @@ show_multi_internal (CT ct, int alternate, int concat, int textonly, for (part = m->mp_parts; part; part = part->mp_next) { p = part->mp_part; - if (part_ok (p, 1) && type_ok (p, 1) && - (!inlineonly || is_inline(ct))) { + if (part_ok (p, 1) && type_ok (p, 1)) { int inneresult; inneresult = show_switch (p, nowalternate, concat, textonly, - inlineonly); + inlineonly, fmt); switch (inneresult) { case NOTOK: if (alternate && !alternating) { @@ -690,15 +737,16 @@ show_partial (CT ct, int alternate) */ static int -show_external (CT ct, int alternate, int concat, int textonly, int inlineonly) +show_external (CT ct, int alternate, int concat, int textonly, int inlineonly, + struct format *fmt) { struct exbody *e = (struct exbody *) ct->c_ctparams; CT p = e->eb_content; - if (!type_ok (p, 0) || (inlineonly && !is_inline(p))) + if (!type_ok (p, 0)) return OK; - return show_switch (p, alternate, concat, textonly, inlineonly); + return show_switch (p, alternate, concat, textonly, inlineonly, fmt); } @@ -1150,6 +1198,146 @@ convert_content_charset (CT ct, char **file) { return OK; } +/* + * Compile our format string and save any parameters we care about. + */ + +#define DEFAULT_MARKER "[ part %{part} - %{content-type} - %<{description}" \ + "%{description}%?{cdispo-filename}%{cdispo-filename}" \ + "%|%{ctype-name}%> ]" + +static struct format * +compile_marker(char *markerform, char *markerformat) +{ + struct format *fmt; + char *fmtstring; + struct comp *comp = NULL; + unsigned int bucket; + struct param_comp_list *pc_entry; + + fmtstring = new_fs(markerform, markerformat, DEFAULT_MARKER); + + (void) fmt_compile(fmtstring, &fmt, 1); + free(fmtstring); + + /* + * Things we care about: + * + * part - Part name (e.g., 1.1) + * content-type - Content-Type + * description - Content-Description + * disposition - Content-Disposition (inline, attachment) + * ctype- - Content-Type parameter + * cdispo- - Content-Disposition parameter + */ + + while ((comp = fmt_nextcomp(comp, &bucket)) != NULL) { + if (strcasecmp(comp->c_name, "part") == 0) { + part_comp = comp; + } else if (strcasecmp(comp->c_name, "content-type") == 0) { + ctype_comp = comp; + } else if (strcasecmp(comp->c_name, "description") == 0) { + description_comp = comp; + } else if (strcasecmp(comp->c_name, "disposition") == 0) { + dispo_comp = comp; + } else if (strncasecmp(comp->c_name, "ctype-", 6) == 0 && + strlen(comp->c_name) > 6) { + pc_entry = mh_xmalloc(sizeof(*pc_entry)); + pc_entry->param = getcpy(comp->c_name + 6); + pc_entry->comp = comp; + pc_entry->next = ctype_pc_list; + ctype_pc_list = pc_entry; + } else if (strncasecmp(comp->c_name, "cdispo-", 7) == 0 && + strlen(comp->c_name) > 7) { + pc_entry = mh_xmalloc(sizeof(*pc_entry)); + pc_entry->param = getcpy(comp->c_name + 7); + pc_entry->comp = comp; + pc_entry->next = dispo_pc_list; + dispo_pc_list = pc_entry; + } + } + + return fmt; +} + +/* + * Output on stdout an appropriate marker for this content, using mh-format + */ + +static void +output_marker(CT ct, struct format *fmt) +{ + char outbuf[BUFSIZ]; + struct param_comp_list *pcentry; + int dat[5]; + + /* + * Grab any items we care about. + */ + + if (ctype_comp && ct->c_ctinfo.ci_type) { + ctype_comp->c_text = concat(ct->c_ctinfo.ci_type, "/", + ct->c_ctinfo.ci_subtype, NULL); + } + + if (part_comp && ct->c_partno) { + part_comp->c_text = getcpy(ct->c_partno); + } + + if (description_comp && ct->c_descr) { + description_comp->c_text = getcpy(ct->c_descr); + } + + if (dispo_comp && ct->c_dispo_type) { + dispo_comp->c_text = getcpy(ct->c_dispo_type); + } + + for (pcentry = ctype_pc_list; pcentry != NULL; pcentry = pcentry->next) { + pcentry->comp->c_text = get_param(ct->c_ctinfo.ci_first_pm, + pcentry->param, '?', 0); + } + + for (pcentry = dispo_pc_list; pcentry != NULL; pcentry = pcentry->next) { + pcentry->comp->c_text = get_param(ct->c_dispo_first, + pcentry->param, '?', 0); + } + + fmt_scan(fmt, outbuf, sizeof(outbuf), sizeof(outbuf), dat, NULL); + + fputs(outbuf, stdout); + + fmt_freecomptext(); +} + +/* + * Reset (and free) any of the saved marker text + */ + +static void +free_markercomps(void) +{ + struct param_comp_list *pc_entry, *pc2; + + part_comp = NULL; + ctype_comp = NULL; + description_comp = NULL; + dispo_comp = NULL; + + for (pc_entry = ctype_pc_list; pc_entry != NULL; ) { + free(pc_entry->param); + pc2 = pc_entry->next; + free(pc_entry); + pc_entry = pc2; + } + + for (pc_entry = dispo_pc_list; pc_entry != NULL; ) { + free(pc_entry->param); + pc2 = pc_entry->next; + free(pc_entry); + pc_entry = pc2; + } +} + /* * Exit if the display process returned with a nonzero exit code, or terminated * with a SIGQUIT signal.