/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2002-2019 Free Software Foundation, Inc. GNU Mailutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Mailutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Mailutils. If not, see . */ /* MH show command */ #include static char prog_doc[] = N_("Display GNU MH messages"); static char args_doc[] = N_("[MSGLIST]"); int use_draft; int use_showproc = 1; int header_option = 1; char *file; const char *showproc; char **showargv; size_t showargc; size_t showargmax; const char *mhnproc; static void addarg (const char *arg) { if (showargc == showargmax) showargv = mu_2nrealloc (showargv, &showargmax, sizeof showargv[0]); showargv[showargc++] = (char*) arg; } static void insarg (char *arg) { addarg (arg); if (showargc > 2) { char *p = showargv[showargc-1]; memmove (showargv + 2, showargv + 1, sizeof (showargv[0]) * (showargc - 2)); showargv[1] = p; } } static void finisarg (void) { struct mu_wordsplit ws; char *p; mu_wordsplit (showproc, &ws, MU_WRDSF_DEFFLAGS); if (ws.ws_wordc > 1) { size_t i; if (showargc + ws.ws_wordc > showargmax) { showargmax = showargc + ws.ws_wordc; showargv = mu_realloc (showargv, showargmax * sizeof showargv[0]); } memmove (showargv + ws.ws_wordc, showargv + 1, sizeof (showargv[0]) * (showargc - 1)); for (i = 1; i < ws.ws_wordc; i++) showargv[i] = ws.ws_wordv[i]; showargc += ws.ws_wordc - 1; showproc = ws.ws_wordv[0]; } p = strrchr (showproc, '/'); showargv[0] = (char*) (p ? p + 1 : showproc); addarg (NULL); } static void set_draft (struct mu_parseopt *po, struct mu_option *opt, char const *arg) { if (use_draft || file) { mu_parseopt_error (po, _("only one file at a time!")); exit (po->po_exit_error); } use_draft = 1; } static void set_file (struct mu_parseopt *po, struct mu_option *opt, char const *arg) { if (use_draft || file) { mu_parseopt_error (po, _("only one file at a time!")); exit (po->po_exit_error); } file = mh_expand_name (NULL, arg, NAME_FILE); } static void add_show_arg (struct mu_parseopt *po, struct mu_option *opt, char const *arg) { char *name = mu_alloc (strlen (opt->opt_long) + 2); name[0] = '-'; strcpy (name + 1, opt->opt_long); addarg (name); if (arg) addarg (arg); } static struct mu_option options[] = { { "draft", 0, NULL, MU_OPTION_DEFAULT, N_("show the draft file"), mu_c_string, NULL, set_draft }, { "file", 0, N_("FILE"), MU_OPTION_DEFAULT, N_("show this file"), mu_c_string, NULL, set_file }, { "header", 0, NULL, MU_OPTION_DEFAULT, N_("display a description of the message before the message itself"), mu_c_bool, &header_option }, { "showproc", 0, N_("PROGRAM"), MU_OPTION_DEFAULT, N_("use PROGRAM to show messages"), mu_c_string, &showproc }, { "noshowproc", 0, NULL, MU_OPTION_DEFAULT, N_("disable the use of the \"showproc:\" profile component"), mu_c_int, &use_showproc, NULL, "0" }, { "form", 0, N_("FILE"), MU_OPTION_DEFAULT, N_("read format from given file"), mu_c_string, NULL, add_show_arg }, { "moreproc", 0, N_("PROG"), MU_OPTION_DEFAULT, N_("use this PROG as pager"), mu_c_string, NULL, add_show_arg }, { "nomoreproc", 0, NULL, MU_OPTION_DEFAULT, N_("disable the use of moreproc"), mu_c_string, NULL, add_show_arg }, { "length", 0, N_("NUMBER"), MU_OPTION_DEFAULT, N_("set output screen length"), mu_c_string, NULL, add_show_arg }, { "width", 0, N_("NUMBER"), MU_OPTION_DEFAULT, N_("set output width"), mu_c_string, NULL, add_show_arg }, MU_OPTION_END }; static int resolve_mime (size_t num, mu_message_t msg, void *data) { int *ismime = data; mu_message_is_multipart (msg, ismime); return *ismime; } static int resolve_msg (size_t num, mu_message_t msg, void *data) { char *path = data; mh_message_number (msg, &num); addarg (mh_safe_make_file_name (path, mu_umaxtostr (0, num))); return 0; } static int adduid (size_t num, void *data) { addarg (mu_umaxtostr (0, num)); return 0; } static int printheader (size_t num, void *data) { mu_printf ("(Message %s:%lu)\n", (char*) data, (unsigned long)num); return 1; } static void checkfile (char *file) { int ismime = 0; if (!showproc) { mu_message_t msg = mh_file_to_message (NULL, file); mu_message_is_multipart (msg, &ismime); mu_message_unref (msg); } if (ismime) { showproc = mhnproc; insarg ("-show"); addarg ("-file"); } addarg (file); } int main (int argc, char **argv) { mu_mailbox_t mbox; mu_msgset_t msgset = NULL; const char *p; const char *mode = "cur"; showargmax = 2; showargc = 1; showargv = mu_calloc (showargmax, sizeof showargv[0]); mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER, args_doc, prog_doc, NULL); if (strcmp (mu_program_name, "next") == 0 || strcmp (mu_program_name, "prev") == 0) mode = mu_program_name; mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR); if (use_draft || file) { if (argc) { mu_error (_("only one file at a time!")); exit (1); } } else mh_msgset_parse (&msgset, mbox, argc, argv, mode); /* 1. If !use_showproc set showproc to /bin/cat and go to X. 2. If -file or -draft is given 2.a. If showproc is set, go to 2.c 2.b. If the file is a multipart one, set showproc to mhn with -file and -show options and go to X 2.c. Add file to the argument list and go to X. 3. Scan all messages to see if there are MIME ones. If so, set showproc to mhn with the -show option, transfer message UIDs to showproc arguments, and go to X 4. Otherwise set showproc from the showproc variable in .mh_profile X. If showproc is not set, set it to PAGER ("/usr/bin/more" by default). Y. Execute showproc with the collected argument list. */ if (!use_showproc) showproc = "/bin/cat"; else showproc = mh_global_profile_get ("showproc", NULL); mhnproc = mh_global_profile_get ("mhnproc", "mhn"); if (use_draft || file) { if (file) checkfile (file); else { const char *dfolder = mh_global_profile_get ("Draft-Folder", NULL); if (dfolder) { int ismime = 0; mu_mailbox_close (mbox); mu_mailbox_destroy (&mbox); mbox = mh_open_folder (dfolder, MU_STREAM_RDWR); mh_msgset_parse (&msgset, mbox, 0, NULL, mode); mu_msgset_foreach_message (msgset, resolve_mime, &ismime); if (ismime) { showproc = mhnproc; insarg ("-show"); addarg ("-file"); } mu_msgset_foreach_message (msgset, resolve_msg, (void *) dfolder); } else checkfile (mh_expand_name (mu_folder_directory (), "draft", NAME_ANY)); } } else { mu_url_t url; size_t n; int ismime = 0; const char *path; mu_mailbox_get_url (mbox, &url); mu_url_sget_path (url, &path); if (!showproc) { mu_msgset_foreach_message (msgset, resolve_mime, &ismime); if (ismime) { showproc = mhnproc; insarg ("-show"); } } if (ismime) mu_msgset_foreach_msguid (msgset, adduid, NULL); else mu_msgset_foreach_message (msgset, resolve_msg, (void*) path); p = mh_global_profile_get ("Unseen-Sequence", NULL); if (p) { mh_seq_delete (mbox, p, msgset, 0); mh_global_save_state (); } if (header_option && mu_msgset_count (msgset, &n) == 0 && n == 1) mu_msgset_foreach_msguid (msgset, printheader, (void*) path); } if (!mu_msgset_is_empty (msgset)) mh_mailbox_set_cur (mbox, mh_msgset_last (msgset, RET_UID)); mu_mailbox_close (mbox); mu_mailbox_destroy (&mbox); mu_stream_flush (mu_strout); if (!showproc) { showproc = getenv ("PAGER"); if (!showproc) showproc = "/usr/bin/more"; } finisarg (); execvp (showproc, showargv); mu_error (_("unable to exec %s: %s"), showargv[0], mu_strerror (errno)); return 1; }