/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-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
#include
void message_display_parts (mu_message_t msg, int indent);
const char *from;
const char *subject;
const char *charset;
int print_attachments;
int indent_level = 4;
int debug = 0;
void
print_file (const char *fname, int indent)
{
char buf[128];
FILE *fp = fopen (fname, "r");
if (!fp)
{
fprintf (stderr, "can't open file %s: %s", fname, strerror (errno));
return;
}
while (fgets (buf, sizeof buf, fp))
printf ("%*.*s%s", indent, indent, "", buf);
fclose (fp);
unlink (fname);
}
struct mu_option options[] = {
{ "debug", 'd', NULL, MU_OPTION_DEFAULT,
"enable debugging", mu_c_bool, &debug },
{ "print-attachment", 'p', NULL, MU_OPTION_DEFAULT,
"print attachments", mu_c_bool, &print_attachments },
{ "indent", 'i', "N", MU_OPTION_DEFAULT,
"indentation level", mu_c_int, &indent_level },
{ "charset", 'c', NULL, MU_OPTION_DEFAULT,
"output character set", mu_c_string, &charset },
MU_OPTION_END
};
int
main (int argc, char **argv)
{
mu_mailbox_t mbox = NULL;
size_t i;
size_t count = 0;
char *mailbox_name;
mu_set_program_name (argv[0]);
mu_cli_simple (argc, argv,
MU_CLI_OPTION_OPTIONS, options,
MU_CLI_OPTION_PROG_DOC, "mime test tool",
MU_CLI_OPTION_PROG_ARGS, "MBOX",
MU_CLI_OPTION_RETURN_ARGC, &argc,
MU_CLI_OPTION_RETURN_ARGV, &argv,
MU_CLI_OPTION_END);
if (argc != 1)
{
mu_error ("exactly one argument required");
return 2;
}
mailbox_name = argv[0];
/* Registration. */
mu_registrar_record (mu_mbox_record);
mu_registrar_set_default_record (mu_mbox_record);
MU_ASSERT (mu_mailbox_create_default (&mbox, mailbox_name));
/* Debugging trace. */
if (debug)
{
mu_debug_set_category_level (MU_DEBCAT_MAILBOX,
MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
}
/* Open the mailbox for reading only. */
MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_READ));
/* Iterate through the entire message set. */
MU_ASSERT (mu_mailbox_messages_count (mbox, &count));
for (i = 1; i <= count; ++i)
{
mu_message_t msg;
mu_header_t hdr;
size_t nparts;
size_t msize, nlines;
MU_ASSERT (mu_mailbox_get_message (mbox, i, &msg));
MU_ASSERT (mu_message_size (msg, &msize));
MU_ASSERT (mu_message_lines (msg, &nlines));
MU_ASSERT (mu_message_get_header (msg, &hdr));
if (mu_header_sget_value (hdr, MU_HEADER_FROM, &from))
from = "";
if (mu_header_sget_value (hdr, MU_HEADER_SUBJECT, &subject))
subject = "";
printf ("Message:%lu\n", (unsigned long) i);
printf ("From:%s\n", from);
printf ("Subject:%s\n", subject);
MU_ASSERT (mu_message_get_num_parts (msg, &nparts));
printf ("Number of parts in message:%lu\n",
(unsigned long) nparts);
printf ("Total message size:%lu/%lu\n",
(unsigned long) msize, (unsigned long) nlines);
message_display_parts (msg, 0);
}
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
return 0;
}
char buf[2048];
static void
print_message_part_sizes (mu_message_t part, int indent)
{
mu_body_t body;
mu_header_t hdr;
size_t msize, mlines, hsize, hlines, bsize, blines;
MU_ASSERT (mu_message_size (part, &msize));
MU_ASSERT (mu_message_lines (part, &mlines));
MU_ASSERT (mu_message_get_header (part, &hdr));
MU_ASSERT (mu_header_size (hdr, &hsize));
MU_ASSERT (mu_header_lines (hdr, &hlines));
MU_ASSERT (mu_message_get_body (part, &body));
MU_ASSERT (mu_body_size (body, &bsize));
MU_ASSERT (mu_body_lines (body, &blines));
printf ("%*.*sMessage part size:%lu/%lu: %lu/%lu, %lu/%lu\n",
indent, indent, "",
(unsigned long) msize, (unsigned long) mlines,
(unsigned long) hsize, (unsigned long) hlines,
(unsigned long) bsize, (unsigned long) blines);
}
void
message_display_parts (mu_message_t msg, int indent)
{
int ret, j;
size_t nparts;
mu_message_t part;
mu_header_t hdr;
mu_stream_t str;
mu_body_t body;
int ismulti;
size_t nbytes;
/* How many parts does the message has? */
if ((ret = mu_message_get_num_parts (msg, &nparts)) != 0)
{
fprintf (stderr, "mu_message_get_num_parts - %s\n", mu_strerror (ret));
exit (2);
}
/* Iterate through all the parts.
Treat type "message/rfc822" differently, since it is a message of
its own that can have other subparts(recursive). */
for (j = 1; j <= nparts; j++)
{
int status;
const char *hvalue;
char *type = NULL;
const char *encoding = "";
MU_ASSERT (mu_message_get_part (msg, j, &part));
MU_ASSERT (mu_message_get_header (part, &hdr));
status = mu_header_sget_value (hdr, MU_HEADER_CONTENT_TYPE,
&hvalue);
if (status == MU_ERR_NOENT)
/* nothing */;
else if (status != 0)
mu_error ("Cannot get header value: %s", mu_strerror (status));
else
{
status = mu_mimehdr_aget_disp (hvalue, &type);
if (status)
mu_error ("Cannot extract content type field: %s",
mu_strerror (status));
}
printf ("%*.*sType of part %d:%s\n", indent, indent, "",
j, mu_prstr (type));
print_message_part_sizes (part, indent);
if (mu_header_sget_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING,
&encoding))
encoding = "";
ismulti = 0;
if ((type
&& mu_c_strcasecmp (type, "message/rfc822") == 0)
|| (mu_message_is_multipart (part, &ismulti) == 0 && ismulti))
{
if (!ismulti)
MU_ASSERT (mu_message_unencapsulate (part, &part, NULL));
MU_ASSERT (mu_message_get_header (part, &hdr));
if (mu_header_sget_value (hdr, MU_HEADER_FROM, &from))
from = "";
if (mu_header_sget_value (hdr, MU_HEADER_SUBJECT, &subject))
subject = "";
printf ("%*.*sEncapsulated message:\n",
indent, indent, "");
printf ("%*.*sFrom:%s\n", indent, indent, "", from);
printf ("%*.*sSubject:%s\n", indent, indent, "", subject);
printf ("%*.*sBegin\n", indent, indent, "");
message_display_parts (part, indent + indent_level);
mu_message_destroy (&part, NULL);
}
else if (!type
|| (mu_c_strcasecmp (type, "text/plain") == 0)
|| (mu_c_strcasecmp (type, "text/html")) == 0)
{
printf ("%*.*sText Message\n", indent, indent, "");
printf ("%*.*sBegin\n", indent, indent, "");
mu_message_get_body (part, &body);
mu_body_get_streamref (body, &str);
/* Make sure the original body stream is not closed when
str gets destroyed */
mu_filter_create (&str, str, encoding, MU_FILTER_DECODE,
MU_STREAM_READ);
while (mu_stream_readline (str, buf, sizeof (buf), &nbytes) == 0
&& nbytes)
{
printf ("%*.*s%s", indent, indent, "", buf);
}
mu_stream_destroy (&str);
}
else
{
/* Save the attachements. */
char *fname = NULL;
mu_message_aget_decoded_attachment_name (part, charset,
&fname, NULL);
if (fname == NULL)
fname = mu_tempname (NULL);
printf ("%*.*sAttachment - saving [%s]\n", indent, indent, "",
fname);
printf ("%*.*sBegin\n", indent, indent, "");
if (charset)
{
mu_mime_io_buffer_t info;
mu_mime_io_buffer_create (&info);
mu_mime_io_buffer_set_charset (info, charset);
MU_ASSERT (mu_message_save_attachment (part, NULL, info));
mu_mime_io_buffer_destroy (&info);
}
else
MU_ASSERT (mu_message_save_attachment (part, fname, NULL));
if (print_attachments)
print_file (fname, indent);
free (fname);
}
printf ("\n%*.*sEnd\n", indent, indent, "");
free (type);
}
}