/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2005-2021 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 . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "mailutils/cli.h" #include "mailutils/argcv.h" #include "mailcap.h" static int dry_run; /* Dry run mode */ static int lint; /* Syntax check mode */ static int identify; /* Print only the file's type */ static char *metamail; /* Name of metamail program, if requested */ static char *mimetypes_config = DEFAULT_CUPS_CONFDIR; static char *no_ask_types; /* List of MIME types for which no questions should be asked */ static int interactive = -1; char const *mimeview_file; /* Name of the file to view */ mu_stream_t mimeview_stream; /* The corresponding stream */ static void cli_no_ask (struct mu_parseopt *po, struct mu_option *opt, char const *arg) { no_ask_types = mu_strdup (arg ? arg : "*"); setenv ("MM_NOASK", arg, 1); /* In case we are given --metamail option */ } static void cli_no_interactive (struct mu_parseopt *po, struct mu_option *opt, char const *arg) { interactive = 0; } static void cli_debug (struct mu_parseopt *po, struct mu_option *opt, char const *arg) { mu_debug_level_t lev; if (!arg) lev = MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE2); else { mu_debug_get_category_level (MU_DEBCAT_APP, &lev); for (; *arg; arg++) { switch (*arg) { case 'l': lev |= MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE4); break; case 'g': lev |= MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE3); break; default: if (mu_isdigit (*arg)) lev |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE0 + *arg - '0'); else mu_parseopt_error (po, _("ignoring invalid debug flag: %c"), *arg); } } } mu_debug_set_category_level (MU_DEBCAT_APP, lev); } static void cli_metamail (struct mu_parseopt *po, struct mu_option *opt, char const *arg) { if (!arg) arg = "metamail"; metamail = mu_strdup (arg); } static struct mu_option mimeview_options[] = { { "no-ask", 'a', N_("TYPE-LIST"), MU_OPTION_ARG_OPTIONAL, N_("do not ask for confirmation before displaying files, or, if TYPE-LIST is given, do not ask for confirmation before displaying such files whose MIME type matches one of the patterns from TYPE-LIST"), mu_c_string, NULL, cli_no_ask }, { "no-interactive", 'h', NULL, MU_OPTION_DEFAULT, N_("disable interactive mode"), mu_c_string, NULL, cli_no_interactive }, { "print", 0, NULL, MU_OPTION_ALIAS }, { "debug", 'd', N_("FLAGS"), MU_OPTION_ARG_OPTIONAL, N_("enable debugging output"), mu_c_string, NULL, cli_debug }, { "mimetypes", 'f', N_("FILE"), MU_OPTION_DEFAULT, N_("use this mime.types file"), mu_c_string, &mimetypes_config }, { "dry-run", 'n', NULL, MU_OPTION_DEFAULT, N_("do nothing, just print what would have been done"), mu_c_bool, &dry_run }, { "lint", 't', NULL, MU_OPTION_DEFAULT, N_("test mime.types syntax and exit"), mu_c_bool, &lint }, { "identify", 'i', NULL, MU_OPTION_DEFAULT, N_("identify MIME type of each file"), mu_c_bool, &identify }, { "metamail", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL, N_("use metamail to display files"), mu_c_string, NULL, cli_metamail }, MU_OPTION_END }, *options[] = { mimeview_options, NULL }; struct mu_cfg_param mimeview_cfg_param[] = { { "mimetypes", mu_c_string, &mimetypes_config, 0, NULL, N_("Use this mime.types file."), N_("file") }, { "metamail", mu_c_string, &metamail, 0, NULL, N_("Use this program to display files."), N_("prog") }, { NULL } }; struct mu_cli_setup cli = { options, mimeview_cfg_param, N_("GNU mimeview -- display files, using mailcap mechanism."), N_("FILE [FILE ...]"), NULL, N_("Debug flags are:\n\ g - Mime.types parser traces\n\ l - Mime.types lexical analyzer traces\n\ 0-9 - Set debugging level\n") }; static char *capa[] = { "debug", NULL }; static int open_file (char const *name) { int rc; struct stat st; if (stat (name, &st)) { mu_error (_("cannot stat `%s': %s"), name, mu_strerror (errno)); return -1; } if (!S_ISREG (st.st_mode) && !S_ISLNK (st.st_mode)) { mu_error (_("not a regular file or symbolic link: `%s'"), name); return -1; } mimeview_file = name; rc = mu_file_stream_create (&mimeview_stream, mimeview_file, MU_STREAM_READ); if (rc) { mu_error (_("Cannot open `%s': %s"), name, mu_strerror (rc)); return -1; } return 0; } void close_file () { mu_stream_close (mimeview_stream); } void display_file (const char *file, const char *type) { int status; if (identify) { printf ("%s: %s\n", file, type ? type : "unknown"); return; } if (!type) return; if (metamail) { char *argv[7]; argv[0] = "metamail"; argv[1] = "-b"; argv[2] = interactive ? "-p" : "-h"; argv[3] = "-c"; argv[4] = (char*) type; argv[5] = (char*) mimeview_file; argv[6] = NULL; if (mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE0)) { char *string; mu_argcv_string (6, argv, &string); mu_debug (MU_DEBCAT_APP, MU_DEBUG_TRACE0, (_("executing %s...\n"), string)); free (string); } if (!dry_run) mu_spawnvp (metamail, argv, &status); } else { mu_header_t hdr; char *text; mu_asprintf (&text, "Content-Type: %s\n", type); status = mu_header_create (&hdr, text, strlen (text)); if (status) mu_error (_("cannot create header: %s"), mu_strerror (status)); else { display_stream_mailcap (mimeview_file, mimeview_stream, hdr, no_ask_types, interactive, dry_run, MU_DEBCAT_APP); mu_header_destroy (&hdr); } } } int main (int argc, char **argv) { MU_APP_INIT_NLS (); interactive = isatty (fileno (stdin)); mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv); if (dry_run) { mu_debug_level_t lev; mu_debug_get_category_level (MU_DEBCAT_APP, &lev); lev |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE2); mu_debug_set_category_level (MU_DEBCAT_APP, lev); } if (argc == 0 && !lint) { mu_error (_("no files given")); return 1; } if (mimetypes_parse (mimetypes_config)) return 1; if (lint) return 0; while (argc--) { const char *type; char const *file = *argv++; if (open_file (file)) continue; type = get_file_type (); display_file (file, type); close_file (); } return 0; }