summaryrefslogtreecommitdiff
path: root/readmsg/readmsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'readmsg/readmsg.c')
-rw-r--r--readmsg/readmsg.c276
1 files changed, 257 insertions, 19 deletions
diff --git a/readmsg/readmsg.c b/readmsg/readmsg.c
index d37d87fa9..c4f7b4b6f 100644
--- a/readmsg/readmsg.c
+++ b/readmsg/readmsg.c
@@ -1,5 +1,5 @@
/* GNU Mailutils -- a suite of utilities for electronic mail
- Copyright (C) 1999-2019 Free Software Foundation, Inc.
+ Copyright (C) 1999-2024 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
@@ -19,15 +19,19 @@
#endif
#include "readmsg.h"
+#include <fnmatch.h>
+#include <regex.h>
#include "mailutils/cli.h"
#include "mailutils/mu_auth.h"
+#include "mailutils/alloc.h"
#include "mu_umaxtostr.h"
+#include "muaux.h"
#define WEEDLIST_SEPARATOR " :,"
static void print_unix_header (mu_message_t);
static void print_header (mu_message_t, int, int, char **);
-static void print_body (mu_message_t);
+static void print_body (mu_message_t, int);
static int string_starts_with (const char * s1, const char *s2);
int dbug = 0;
@@ -37,6 +41,131 @@ int no_header = 0;
int all_header = 0;
int form_feed = 0;
int show_all = 0;
+int mime_decode = 0;
+char *charset;
+
+enum
+ {
+ PAT_EXACT,
+ PAT_GLOB,
+ PAT_REGEX
+ };
+
+int pattern_type = PAT_EXACT;
+int pattern_ci = 0;
+
+static void *
+generic_init (char const *pattern)
+{
+ char *res;
+ if (pattern_ci)
+ unistr_downcase (pattern, &res);
+ else
+ res = mu_strdup (pattern);
+ return res;
+}
+
+static void
+generic_free (void *p)
+{
+ free (p);
+}
+
+static int
+pat_exact_match (void *pat, char const *text)
+{
+ return (pattern_ci ? unistr_is_substring_dn : unistr_is_substring)
+ (text, pat);
+}
+
+static int
+pat_glob_match (void *pat, char const *text)
+{
+ return fnmatch (pat, text, 0) == 0;
+}
+
+static void *
+pat_regex_init (char const *pattern)
+{
+ regex_t *rx = mu_alloc (sizeof (*rx));
+ int rc = regcomp (rx, pattern, REG_EXTENDED|REG_NOSUB
+ |(pattern_ci ? REG_ICASE : 0));
+ if (rc)
+ {
+ char errbuf[512];
+ regerror (rc, rx, errbuf, sizeof errbuf);
+ mu_error ("%s: %s", pattern, errbuf);
+ return NULL;
+ }
+ return rx;
+}
+
+static void
+pat_regex_free (void *p)
+{
+ regex_t *rx = p;
+ regfree (rx);
+ free (rx);
+}
+
+static int
+pat_regex_match (void *pat, char const *str)
+{
+ regex_t *rx = pat;
+ return regexec (rx, str, 0, NULL, 0) == 0;
+}
+
+static struct pattern_match_fun
+{
+ void *(*pat_init) (char const *pattern);
+ int (*pat_match) (void *pat, char const *str);
+ void (*pat_free) (void *);
+} pattern_match_tab[] = {
+ { generic_init, pat_exact_match, generic_free },
+ { generic_init, pat_glob_match, generic_free },
+ { pat_regex_init, pat_regex_match, pat_regex_free }
+};
+
+void *
+pattern_init (char const *pattern)
+{
+ return pattern_match_tab[pattern_type].pat_init (pattern);
+}
+
+int
+pattern_match (void *pat, char const *str)
+{
+ return pattern_match_tab[pattern_type].pat_match (pat, str);
+}
+
+void
+pattern_free (void *pat)
+{
+ return pattern_match_tab[pattern_type].pat_free (pat);
+}
+
+static void
+cli_pattern_match (struct mu_parseopt *po, struct mu_option *opt,
+ char const *arg)
+{
+ switch (opt->opt_short)
+ {
+ case 'e':
+ pattern_type = PAT_EXACT;
+ break;
+
+ case 'g':
+ pattern_type = PAT_GLOB;
+ break;
+
+ case 'r':
+ pattern_type = PAT_REGEX;
+ break;
+
+ case 'i':
+ pattern_ci = 1;
+ }
+}
static struct mu_option readmsg_options[] =
{
@@ -60,6 +189,21 @@ static struct mu_option readmsg_options[] =
{ "show-all-match", 'a', NULL, MU_OPTION_DEFAULT,
N_("print all messages matching pattern, not only the first"),
mu_c_bool, &show_all },
+ { "exact", 'e', NULL, MU_OPTION_DEFAULT,
+ N_("match exact string (default)"),
+ mu_c_int, NULL, cli_pattern_match },
+ { "glob", 'g', NULL, MU_OPTION_DEFAULT,
+ N_("match using globbing pattern"),
+ mu_c_int, NULL, cli_pattern_match },
+ { "regex", 'r', NULL, MU_OPTION_DEFAULT,
+ N_("match using POSIX regular expressions"),
+ mu_c_int, NULL, cli_pattern_match },
+ { "ignorecase", 'i', NULL, MU_OPTION_DEFAULT,
+ N_("case-insensitive matching"),
+ mu_c_int, NULL, cli_pattern_match },
+ { "mime", 'm', NULL, MU_OPTION_DEFAULT,
+ N_("decode MIME messages on output"),
+ mu_c_bool, &mime_decode },
MU_OPTION_END
}, *options[] = { readmsg_options, NULL };
@@ -146,7 +290,27 @@ print_unix_header (mu_message_t message)
if (size > 1 && buf[size-1] != '\n')
mu_printf ("\n");
}
-
+
+static void
+print_header_field (const char *name, const char *value)
+{
+ if (mime_decode)
+ {
+ int rc;
+ char *s;
+
+ rc = mu_rfc2047_decode (charset, value, &s);
+ if (rc == 0)
+ {
+ mu_printf ("%s: %s\n", name, s);
+ free (s);
+ }
+ }
+ else
+ mu_printf ("%s: %s\n", name, value);
+}
+
+
static void
print_header (mu_message_t message, int unix_header, int weedc, char **weedv)
{
@@ -191,11 +355,10 @@ print_header (mu_message_t message, int unix_header, int weedc, char **weedv)
if (string_starts_with (name, weedv[j]+1))
break;
}
- else if (string_starts_with (name, weedv[j]))
+ else if (strcmp (weedv[j], "*") == 0 ||
+ string_starts_with (name, weedv[j]))
{
- /* Check if mu_header_sget_value returns an empty string. */
- if (value && *value)
- mu_printf ("%s: %s\n", name, value);
+ print_header_field (name, value);
}
}
}
@@ -204,11 +367,12 @@ print_header (mu_message_t message, int unix_header, int weedc, char **weedv)
}
static void
-print_body (mu_message_t message)
+print_body_simple (mu_message_t message, int unix_header)
{
int status;
mu_body_t body = NULL;
mu_stream_t stream = NULL;
+
mu_message_get_body (message, &body);
status = mu_body_get_streamref (body, &stream);
@@ -221,6 +385,77 @@ print_body (mu_message_t message)
mu_stream_destroy (&stream);
}
+static void
+print_body_decode (mu_message_t message, int unix_header)
+{
+ int rc;
+ mu_iterator_t itr;
+
+ rc = mu_message_get_iterator (message, &itr);
+ if (rc)
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_iterator", NULL, rc);
+ exit (2);
+ }
+
+ for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
+ mu_iterator_next (itr))
+ {
+ mu_message_t partmsg;
+ mu_stream_t str;
+ mu_coord_t crd;
+
+ rc = mu_iterator_current_kv (itr, (const void**)&crd, (void**)&partmsg);
+ if (rc)
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_iterator_current", NULL, rc);
+ continue;
+ }
+
+ rc = message_body_stream (partmsg, unix_header, charset, &str);
+ if (rc == 0)
+ {
+ mu_stream_copy (mu_strout, str, 0, NULL);
+ mu_stream_destroy (&str);
+ }
+ else if (rc == MU_ERR_USER0)
+ {
+ char *s = mu_coord_string (crd);
+ mu_stream_printf (mu_strout,
+ "[part %s is a binary attachment: not shown]\n",
+ s);
+ free (s);
+ }
+ }
+ mu_iterator_destroy (&itr);
+}
+
+static void
+print_body (mu_message_t message, int unix_header)
+{
+ if (mime_decode)
+ print_body_decode (message, unix_header);
+ else
+ print_body_simple (message, unix_header);
+}
+
+static void
+define_charset (void)
+{
+ struct mu_lc_all lc_all = { .flags = 0 };
+ char *ep = getenv ("LC_ALL");
+ if (!ep)
+ ep = getenv ("LANG");
+
+ if (ep && mu_parse_lc_all (ep, &lc_all, MU_LC_CSET) == 0)
+ {
+ charset = mu_strdup (lc_all.charset);
+ mu_lc_all_free (&lc_all);
+ }
+ else
+ charset = mu_strdup ("us-ascii");
+}
+
int
main (int argc, char **argv)
{
@@ -231,7 +466,7 @@ main (int argc, char **argv)
mu_mailbox_t mbox = NULL;
struct mu_wordsplit ws;
char **weedv;
- int weedc;
+ int weedc = 0;
int unix_header = 0;
/* Native Language Support */
@@ -251,6 +486,8 @@ main (int argc, char **argv)
exit (1);
}
+ define_charset ();
+
status = mu_mailbox_create_default (&mbox, mailbox_name);
if (status != 0)
{
@@ -264,7 +501,7 @@ main (int argc, char **argv)
exit (2);
}
- /* Debuging Trace. */
+ /* Debugging Trace. */
if (dbug)
{
mu_debug_set_category_level (MU_DEBCAT_MAILBOX,
@@ -282,7 +519,15 @@ main (int argc, char **argv)
exit (2);
}
- if (weedlist == NULL)
+ if (all_header)
+ {
+ unix_header = 1;
+ if (mime_decode)
+ weedlist = "!MIME-Version !Content- *";
+ else
+ weedlist = "";
+ }
+ else if (weedlist == NULL)
weedlist = "Date To Cc Subject From Apparently-";
ws.ws_delim = WEEDLIST_SEPARATOR;
@@ -313,13 +558,6 @@ main (int argc, char **argv)
weedv = ws.ws_wordv;
}
- if (all_header)
- {
- unix_header = 1;
- weedc = 0;
- weedv = NULL;
- }
-
/* Build an array containing the message number. */
msglist (mbox, show_all, argc, argv, &set, &n);
@@ -341,7 +579,7 @@ main (int argc, char **argv)
if (!no_header)
print_header (msg, unix_header, weedc, weedv);
- print_body (msg);
+ print_body (msg, unix_header);
mu_printf (form_feed ? "\f" : "\n");
}

Return to:

Send suggestions and report system problems to the System administrator.