Commit e218f1ec e218f1ec00749701a00c074c4574a75a6f156d2b by Sergey Poznyakoff

Implement imap (client) bodystructure and envelope.

* libmailutils/string/wordsplit.c (alloc_space): Fix reallocation
calculations.

* imap4d/fetch.c (bodystructure): Output number of lines for any
TEXT part, not only TEXT/PLAIN.

* include/mailutils/header.h (MU_HEADER_CONTENT_LOCATION): New define.
* include/mailutils/imap.h (mu_imap_fetch_bodystructure): Implement.
(mu_imap_fetch_envelope): Replace data fields with a single pointer
to struct mu_imapenvelope.
* include/mailutils/message.h: Include datetime.h
(mu_imapenvelope, mu_bodystructure): New structs.
(mu_message_type): New type.
(mu_message_get_imapenvelope,mu_message_imapenvelope_free)
(mu_message_set_imapenvelope)
(mu_bodystructure_free,mu_list_free_bodystructure)
(mu_message_get_bodystructure)
(mu_message_set_bodystructure): New protos.
* include/mailutils/mime.h (mu_mime_param_assoc_create)
(mu_mime_param_assoc_add): New protos.
* include/mailutils/sys/message.h (_mu_message)<_imapenvelope>
<_bodystructure>: New methods.
* libmailutils/mailbox/bodystruct.c: New file.
* libmailutils/mailbox/imapenv.c: New file.
* libmailutils/mailbox/Makefile.am (libmailbox_la_SOURCES): Add new
sources.

* libproto/imap/fetch.c: Implement bodystructure.
* mu/imap.c: Likewise.

* testsuite/bs.c: New file.
* testsuite/Makefile.am (noinst_PROGRAMS): Add bs.
1 parent 690b1bf8
......@@ -372,8 +372,9 @@ bodystructure (mu_message_t msg, int extension)
if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
{
struct mu_wordsplit ws;
char *s, *p;
char *p;
size_t len;
ws.ws_delim = " \t\r\n;=";
ws.ws_alloc_die = imap4d_ws_alloc_die;
if (mu_wordsplit (buffer, &ws, IMAP4D_WS_FLAGS))
......@@ -383,18 +384,17 @@ bodystructure (mu_message_t msg, int extension)
return RESP_BAD; /* FIXME: a better error handling, maybe? */
}
len = strcspn (ws.ws_wordv[0], "/");
if (mu_c_strcasecmp (ws.ws_wordv[0], "MESSAGE/RFC822") == 0)
message_rfc822 = 1;
else if (mu_c_strcasecmp (ws.ws_wordv[0], "TEXT/PLAIN") == 0)
else if (mu_c_strncasecmp (ws.ws_wordv[0], "TEXT", len) == 0)
text_plain = 1;
s = strchr (ws.ws_wordv[0], '/');
if (s)
*s++ = 0;
ws.ws_wordv[0][len++] = 0;
p = ws.ws_wordv[0];
io_send_qstring (p);
io_sendf (" ");
io_send_qstring (s);
io_send_qstring (ws.ws_wordv[0] + len);
/* body parameter parenthesized list: Content-type attributes */
if (ws.ws_wordc > 1)
......
......@@ -59,6 +59,7 @@ extern "C" {
#define MU_HEADER_CONTENT_DESCRIPTION "Content-Description"
#define MU_HEADER_CONTENT_DISPOSITION "Content-Disposition"
#define MU_HEADER_CONTENT_MD5 "Content-MD5"
#define MU_HEADER_CONTENT_LOCATION "Content-Location"
#define MU_HEADER_MIME_VERSION "MIME-Version"
#define MU_HEADER_X_MAILER "X-Mailer"
#define MU_HEADER_X_UIDL "X-UIDL"
......
......@@ -236,23 +236,13 @@ struct mu_imap_fetch_body
struct mu_imap_fetch_bodystructure
{
int type;
//FIXME?
struct mu_bodystructure *bs;
};
struct mu_imap_fetch_envelope
{
int type;
struct tm date;
struct mu_timezone tz;
char *subject;
mu_address_t from;
mu_address_t sender;
mu_address_t reply_to;
mu_address_t to;
mu_address_t cc;
mu_address_t bcc;
char *in_reply_to;
char *message_id;
struct mu_imapenvelope *imapenvelope;
};
struct mu_imap_fetch_flags
......
......@@ -20,6 +20,7 @@
#define _MAILUTILS_MESSAGE_H
#include <mailutils/types.h>
#include <mailutils/datetime.h>
#ifdef __cplusplus
extern "C" {
......@@ -28,6 +29,64 @@ extern "C" {
#define MU_SCAN_SEEK 0x01
#define MU_SCAN_SIZE 0x02
struct mu_imapenvelope
{
struct tm date;
struct mu_timezone tz;
char *subject;
mu_address_t from;
mu_address_t sender;
mu_address_t reply_to;
mu_address_t to;
mu_address_t cc;
mu_address_t bcc;
char *in_reply_to;
char *message_id;
};
enum mu_message_type
{
mu_message_other,
mu_message_text, /* text/plain */
mu_message_rfc822, /* message/rfc822 */
mu_message_multipart /* multipart/mixed */
};
struct mu_bodystructure
{
enum mu_message_type body_message_type;
char *body_type;
char *body_subtype;
mu_assoc_t body_param;
char *body_id;
char *body_descr;
char *body_encoding;
size_t body_size;
/* Optional */
char *body_md5;
char *body_disposition;
mu_assoc_t body_disp_param;
char *body_language;
char *body_location;
union
{
struct
{
size_t body_lines;
} text;
struct
{
struct mu_imapenvelope *body_env;
struct mu_bodystructure *body_struct;
size_t body_lines;
} rfc822;
struct
{
mu_list_t body_parts;
} multipart;
} v;
};
struct mu_message_scan
{
int flags;
......@@ -137,6 +196,21 @@ extern int mu_message_set_qid (mu_message_t,
int (*_get_qid) (mu_message_t,
mu_message_qid_t *),
void *owner);
extern int mu_message_get_imapenvelope (mu_message_t, struct mu_imapenvelope **);
extern void mu_message_imapenvelope_free (struct mu_imapenvelope *);
extern int mu_message_set_imapenvelope (mu_message_t,
int (*_imapenvelope) (mu_message_t, struct mu_imapenvelope **),
void *owner);
extern void mu_bodystructure_free (struct mu_bodystructure *);
extern void mu_list_free_bodystructure (void *item);
extern int mu_message_get_bodystructure (mu_message_t,
struct mu_bodystructure **);
extern int mu_message_set_bodystructure (mu_message_t msg,
int (*_bodystructure) (mu_message_t, struct mu_bodystructure **),
void *owner);
/* misc functions */
extern int mu_message_create_attachment (const char *content_type,
......@@ -190,7 +264,6 @@ extern int mu_message_from_stream_with_envelope (mu_message_t *pmsg,
mu_envelope_t env);
extern int mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg);
#ifdef __cplusplus
}
#endif
......
......@@ -66,6 +66,9 @@ int mu_base64_decode (const unsigned char *input, size_t input_len,
unsigned char **output, size_t * output_len);
int mu_mime_param_assoc_create (mu_assoc_t *passoc);
int mu_mime_param_assoc_add (mu_assoc_t assoc, const char *name);
int mu_mime_header_parse (const char *text, char *charset, char **pvalue,
mu_assoc_t *paramtab);
int mu_mime_header_parse_subset (const char *text, const char *charset,
......
......@@ -61,6 +61,8 @@ struct _mu_message
int (*_get_qid) (mu_message_t, mu_message_qid_t *);
int (*_get_num_parts) (mu_message_t, size_t *);
int (*_get_part) (mu_message_t, size_t, mu_message_t *);
int (*_imapenvelope) (mu_message_t, struct mu_imapenvelope **);
int (*_bodystructure) (mu_message_t, struct mu_bodystructure **);
int (*_is_multipart) (mu_message_t, int *);
int (*_lines) (mu_message_t, size_t *, int);
int (*_size) (mu_message_t, size_t *);
......
......@@ -23,12 +23,14 @@ libmailbox_la_SOURCES = \
mbxitr.c\
attribute.c\
body.c\
bodystruct.c\
envelope.c\
folder.c\
fsfolder.c\
hdrfirst.c\
hdritr.c\
header.c\
imapenv.c\
msgcpy.c\
msgattr.c\
msgbody.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/assoc.h>
#include <mailutils/list.h>
#include <mailutils/message.h>
#include <mailutils/mime.h>
#include <mailutils/header.h>
#include <mailutils/sys/message.h>
#include <mailutils/errno.h>
#include <mailutils/debug.h>
#include <mailutils/nls.h>
#include <mailutils/cstr.h>
#include <mailutils/body.h>
void
mu_list_free_bodystructure (void *item)
{
mu_bodystructure_free (item);
}
void
mu_bodystructure_free (struct mu_bodystructure *bs)
{
if (!bs)
return;
free (bs->body_type);
free (bs->body_subtype);
mu_assoc_destroy (&bs->body_param);
free (bs->body_id);
free (bs->body_descr);
free (bs->body_encoding);
free (bs->body_md5);
free (bs->body_disposition);
mu_assoc_destroy (&bs->body_disp_param);
free (bs->body_language);
free (bs->body_location);
switch (bs->body_message_type)
{
case mu_message_other:
case mu_message_text:
break;
case mu_message_rfc822:
mu_message_imapenvelope_free (bs->v.rfc822.body_env);
mu_bodystructure_free (bs->v.rfc822.body_struct);
break;
case mu_message_multipart:
mu_list_destroy (&bs->v.multipart.body_parts);
}
free (bs);
}
static int bodystructure_fill (mu_message_t msg,
struct mu_bodystructure *bs);
static int
bodystructure_init (mu_message_t msg, struct mu_bodystructure **pbs)
{
int rc;
struct mu_bodystructure *bs = calloc (1, sizeof (*bs));
if (!bs)
return ENOMEM;
rc = bodystructure_fill (msg, bs);
if (rc)
mu_bodystructure_free (bs);
else
*pbs = bs;
return rc;
}
static int
bodystructure_fill (mu_message_t msg, struct mu_bodystructure *bs)
{
mu_header_t header = NULL;
const char *buffer = NULL;
mu_body_t body = NULL;
int rc;
int is_multipart = 0;
rc = mu_message_get_header (msg, &header);
if (rc)
return rc;
if (mu_header_sget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
{
char *value;
char *p;
size_t len;
rc = mu_mime_header_parse (buffer, "UTF-8", &value, &bs->body_param);
if (rc)
return rc;
len = strcspn (value, "/");
if (mu_c_strcasecmp (value, "MESSAGE/RFC822") == 0)
bs->body_message_type = mu_message_rfc822;
else if (mu_c_strncasecmp (value, "TEXT", len) == 0)
bs->body_message_type = mu_message_text;
p = malloc (len + 1);
if (!p)
return ENOMEM;
memcpy (p, value, len);
p[len] = 0;
bs->body_type = p;
mu_strupper (bs->body_type);
if (value[len])
{
bs->body_subtype = strdup (value + len + 1);
if (!bs->body_subtype)
return ENOMEM;
mu_strupper (bs->body_subtype);
}
/* body parameter parenthesized list: Content-type attributes */
rc = mu_message_is_multipart (msg, &is_multipart);
if (rc)
return rc;
if (is_multipart)
bs->body_message_type = mu_message_multipart;
}
else
{
struct mu_mime_param param;
/* Default? If Content-Type is not present consider as text/plain. */
bs->body_type = strdup ("TEXT");
if (!bs->body_type)
return ENOMEM;
bs->body_subtype = strdup ("PLAIN");
if (!bs->body_subtype)
return ENOMEM;
rc = mu_mime_param_assoc_create (&bs->body_param);
if (rc)
return rc;
memset (&param, 0, sizeof (param));
param.value = strdup ("US-ASCII");
rc = mu_assoc_install (bs->body_param, "CHARSET", &param);
if (rc)
{
free (param.value);
return rc;
}
bs->body_message_type = mu_message_text;
}
if (is_multipart)
{
size_t i, nparts;
rc = mu_message_get_num_parts (msg, &nparts);
if (rc)
return rc;
rc = mu_list_create (&bs->v.multipart.body_parts);
if (rc)
return rc;
mu_list_set_destroy_item (bs->v.multipart.body_parts,
mu_list_free_bodystructure);
for (i = 1; i <= nparts; i++)
{
mu_message_t partmsg;
struct mu_bodystructure *partbs;
rc = mu_message_get_part (msg, i, &partmsg);
if (rc)
return rc;
rc = bodystructure_init (partmsg, &partbs);
if (rc)
return rc;
rc = mu_list_append (bs->v.multipart.body_parts, partbs);
if (rc)
{
mu_bodystructure_free (partbs);
return rc;
}
}
}
else
{
/* body id: Content-ID. */
rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_ID,
&bs->body_id);
if (rc && rc != MU_ERR_NOENT)
return rc;
/* body description: Content-Description. */
rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_DESCRIPTION,
&bs->body_descr);
if (rc && rc != MU_ERR_NOENT)
return rc;
/* body encoding: Content-Transfer-Encoding. */
rc = mu_header_aget_value_unfold (header,
MU_HEADER_CONTENT_TRANSFER_ENCODING,
&bs->body_encoding);
if (rc == MU_ERR_NOENT)
{
bs->body_encoding = strdup ("7BIT");
if (!bs->body_encoding)
return ENOMEM;
}
else if (rc)
return rc;
/* body size RFC822 format. */
rc = mu_message_get_body (msg, &body);
if (rc)
return rc;
rc = mu_body_size (body, &bs->body_size);
if (rc)
return rc;
/* If the mime type was text. */
if (bs->body_message_type == mu_message_text)
{
rc = mu_body_lines (body, &bs->v.text.body_lines);
if (rc)
return rc;
}
else if (bs->body_message_type == mu_message_rfc822)
{
mu_message_t emsg = NULL;
/* Add envelope structure of the encapsulated message. */
rc = mu_message_unencapsulate (msg, &emsg, NULL);
if (rc)
return rc;
rc = mu_message_get_imapenvelope (emsg, &bs->v.rfc822.body_env);
if (rc)
return rc;
/* Add body structure of the encapsulated message. */
rc = bodystructure_init (emsg, &bs->v.rfc822.body_struct);
if (rc)
return rc;
/* Size in text lines of the encapsulated message. */
rc = mu_message_lines (emsg, &bs->v.rfc822.body_lines);
mu_message_destroy (&emsg, NULL);
}
}
/* body MD5: Content-MD5. */
rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_MD5,
&bs->body_md5);
if (rc && rc != MU_ERR_NOENT)
return rc;
/* body disposition: Content-Disposition. */
rc = mu_header_sget_value (header, MU_HEADER_CONTENT_DISPOSITION,
&buffer);
if (rc == 0)
{
rc = mu_mime_header_parse (buffer, "UTF-8", &bs->body_disposition,
&bs->body_disp_param);
if (rc)
return rc;
}
else if (rc != MU_ERR_NOENT)
return rc;
/* body language: Content-Language. */
rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_LANGUAGE,
&bs->body_language);
if (rc && rc != MU_ERR_NOENT)
return rc;
rc = mu_header_aget_value_unfold (header, MU_HEADER_CONTENT_LOCATION,
&bs->body_location);
if (rc && rc != MU_ERR_NOENT)
return rc;
return 0;
}
int
mu_message_get_bodystructure (mu_message_t msg,
struct mu_bodystructure **pbs)
{
if (msg == NULL)
return EINVAL;
if (pbs == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->_bodystructure)
return msg->_bodystructure (msg, pbs);
return bodystructure_init (msg, pbs);
}
int
mu_message_set_bodystructure (mu_message_t msg,
int (*_bodystructure) (mu_message_t, struct mu_bodystructure **),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_bodystructure = _bodystructure;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/header.h>
#include <mailutils/envelope.h>
#include <mailutils/address.h>
#include <mailutils/message.h>
#include <mailutils/sys/message.h>
#include <mailutils/errno.h>
void
mu_message_imapenvelope_free (struct mu_imapenvelope *env)
{
if (!env)
return;
free (env->subject);
mu_address_destroy (&env->from);
mu_address_destroy (&env->sender);
mu_address_destroy (&env->reply_to);
mu_address_destroy (&env->to);
mu_address_destroy (&env->cc);
mu_address_destroy (&env->bcc);
free (env->in_reply_to);
free (env->message_id);
free (env);
}
int
mu_message_get_imapenvelope (mu_message_t msg, struct mu_imapenvelope **pimapenvelope)
{
struct mu_imapenvelope *imapenvelope;
int rc;
if (msg == NULL)
return EINVAL;
if (imapenvelope == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->_imapenvelope)
return msg->_imapenvelope (msg, pimapenvelope);
imapenvelope = calloc (1, sizeof (imapenvelope[0]));
if (!imapenvelope)
return ENOMEM;
do
{
mu_header_t hdr;
mu_envelope_t env;
const char *s;
if ((rc = mu_message_get_envelope (msg, &env)))
break;
if ((rc = mu_envelope_sget_date (env, &s)))
break;
if ((rc = mu_scan_datetime (s, MU_DATETIME_FROM,
&imapenvelope->date, &imapenvelope->tz,
NULL)))
break;
if ((rc = mu_message_get_header (msg, &hdr)))
break;
rc = mu_header_get_address (hdr, MU_HEADER_FROM, &imapenvelope->from);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_get_address (hdr, MU_HEADER_SENDER, &imapenvelope->sender);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_get_address (hdr, MU_HEADER_REPLY_TO, &imapenvelope->reply_to);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_get_address (hdr, MU_HEADER_TO, &imapenvelope->to);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_get_address (hdr, MU_HEADER_CC, &imapenvelope->cc);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_get_address (hdr, MU_HEADER_BCC, &imapenvelope->bcc);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_aget_value_unfold (hdr, MU_HEADER_SUBJECT,
&imapenvelope->subject);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_aget_value_unfold (hdr, MU_HEADER_IN_REPLY_TO,
&imapenvelope->in_reply_to);
if (rc && rc != MU_ERR_NOENT)
break;
rc = mu_header_aget_value_unfold (hdr, MU_HEADER_MESSAGE_ID,
&imapenvelope->message_id);
}
while (0);
if (rc)
mu_message_imapenvelope_free (imapenvelope);
else
*pimapenvelope = imapenvelope;
return rc;
}
int
mu_message_set_imapenvelope (mu_message_t msg,
int (*_imapenvelope) (mu_message_t,
struct mu_imapenvelope **),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_imapenvelope = _imapenvelope;
return 0;
}
......@@ -184,7 +184,7 @@ alloc_space (struct mu_wordsplit *wsp, size_t count)
else if (wsp->ws_wordn < offs + wsp->ws_wordc + count)
{
newalloc = offs + wsp->ws_wordc +
count > ALLOC_INCR ? count : ALLOC_INCR;
(count > ALLOC_INCR ? count : ALLOC_INCR);
ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0]));
}
else
......
......@@ -297,4 +297,13 @@ _mu_imap_list_nth_element_is_string (mu_list_t list, size_t n,
strcmp (elt->v.string, str) == 0;
}
int
_mu_imap_list_nth_element_is_string_ci (mu_list_t list, size_t n,
const char *str)
{
struct imap_list_element *elt = _mu_imap_list_at (list, n);
return elt && elt->type == imap_eltype_string &&
mu_c_strcasecmp (elt->v.string, str) == 0;
}
......
......@@ -225,7 +225,143 @@ format_date (mu_stream_t str, char *name,
}
mu_stream_printf (str, "\n");
}
#define S(str) ((str) ? (str) : "")
static void
print_param (mu_stream_t ostr, const char *prefix, mu_assoc_t assoc,
int indent)
{
mu_iterator_t itr;
int i;
mu_stream_printf (ostr, "%*s%s:\n", indent, "", prefix);
indent += 4;
if (mu_assoc_get_iterator (assoc, &itr))
return;
for (i = 0, mu_iterator_first (itr);
!mu_iterator_is_done (itr);
i++, mu_iterator_next (itr))
{
const char *name;
struct mu_mime_param *p;
mu_iterator_current_kv (itr, (const void **)&name, (void**)&p);
mu_stream_printf (ostr, "%*s%d: %s=%s\n", indent, "", i, name, p->value);
}
mu_iterator_destroy (&itr);
}
struct print_data
{
mu_stream_t ostr;
int num;
int level;
};
static void print_bs (mu_stream_t ostr,
struct mu_bodystructure *bs, int level);
static int
print_item (void *item, void *data)
{
struct mu_bodystructure *bs = item;
struct print_data *pd = data;
mu_stream_printf (pd->ostr, "%*sPart #%d\n", (pd->level-1) << 2, "",
pd->num);
print_bs (pd->ostr, bs, pd->level);
++pd->num;
return 0;
}
static void
print_address (mu_stream_t ostr, const char *title, mu_address_t addr,
int indent)
{
mu_stream_printf (ostr, "%*s%s: ", indent, "", title);
mu_stream_format_address (mu_strout, addr);
mu_stream_printf (ostr, "\n");
}
static void
print_imapenvelope (mu_stream_t ostr, struct mu_imapenvelope *env, int level)
{
int indent = (level << 2);
mu_stream_printf (ostr, "%*sEnvelope:\n", indent, "");
indent += 4;
mu_stream_printf (ostr, "%*sTime: ", indent, "");
mu_c_streamftime (mu_strout, "%c%n", &env->date, &env->tz);
mu_stream_printf (ostr, "%*sSubject: %s\n", indent, "", S(env->subject));
print_address (ostr, "From", env->from, indent);
print_address (ostr, "Sender", env->sender, indent);
print_address (ostr, "Reply-to", env->reply_to, indent);
print_address (ostr, "To", env->to, indent);
print_address (ostr, "Cc", env->cc, indent);
print_address (ostr, "Bcc", env->bcc, indent);
mu_stream_printf (ostr, "%*sIn-Reply-To: %s\n", indent, "",
S(env->in_reply_to));
mu_stream_printf (ostr, "%*sMessage-ID: %s\n", indent, "",
S(env->message_id));
}
static void
print_bs (mu_stream_t ostr, struct mu_bodystructure *bs, int level)
{
int indent = level << 2;
mu_stream_printf (ostr, "%*sbody_type=%s\n", indent, "", S(bs->body_type));
mu_stream_printf (ostr, "%*sbody_subtype=%s\n", indent, "",
S(bs->body_subtype));
print_param (ostr, "Parameters", bs->body_param, indent);
mu_stream_printf (ostr, "%*sbody_id=%s\n", indent, "", S(bs->body_id));
mu_stream_printf (ostr, "%*sbody_descr=%s\n", indent, "", S(bs->body_descr));
mu_stream_printf (ostr, "%*sbody_encoding=%s\n", indent, "",
S(bs->body_encoding));
mu_stream_printf (ostr, "%*sbody_size=%lu\n", indent, "",
(unsigned long) bs->body_size);
/* Optional */
mu_stream_printf (ostr, "%*sbody_md5=%s\n", indent, "", S(bs->body_md5));
mu_stream_printf (ostr, "%*sbody_disposition=%s\n", indent, "",
S(bs->body_disposition));
print_param (ostr, "Disposition Parameters", bs->body_disp_param, indent);
mu_stream_printf (ostr, "%*sbody_language=%s\n", indent, "",
S(bs->body_language));
mu_stream_printf (ostr, "%*sbody_location=%s\n", indent, "",
S(bs->body_location));
mu_stream_printf (ostr, "%*sType ", indent, "");
switch (bs->body_message_type)
{
case mu_message_other:
mu_stream_printf (ostr, "mu_message_other\n");
break;
case mu_message_text:
mu_stream_printf (ostr, "mu_message_text:\n%*sbody_lines=%lu\n",
indent + 4, "",
(unsigned long) bs->v.text.body_lines);
break;
case mu_message_rfc822:
mu_stream_printf (ostr, "mu_message_rfc822:\n%*sbody_lines=%lu\n",
indent + 4, "",
(unsigned long) bs->v.rfc822.body_lines);
print_imapenvelope (ostr, bs->v.rfc822.body_env, level + 1);
print_bs (ostr, bs->v.rfc822.body_struct, level + 1);
break;
case mu_message_multipart:
{
struct print_data pd;
pd.ostr = ostr;
pd.num = 0;
pd.level = level + 1;
mu_stream_printf (ostr, "mu_message_multipart:\n");
mu_list_foreach (bs->v.multipart.body_parts, print_item, &pd);
}
}
}
static int
fetch_response_printer (void *item, void *data)
{
......@@ -252,31 +388,35 @@ fetch_response_printer (void *item, void *data)
case MU_IMAP_FETCH_BODYSTRUCTURE:
/* FIXME */
mu_stream_printf (str, "BODYSTRUCTURE (not yet implemented)\n");
mu_stream_printf (str, "BODYSTRUCTURE:\nBEGIN\n");
print_bs (str, resp->bodystructure.bs, 0);
mu_stream_printf (str, "END\n");
break;
case MU_IMAP_FETCH_ENVELOPE:
{
struct mu_imapenvelope *env = resp->envelope.imapenvelope;
mu_stream_printf (str, "ENVELOPE:\n");
format_date (str, "date", &resp->envelope.date, &resp->envelope.tz);
format_date (str, "date", &env->date, &env->tz);
mu_stream_printf (str, " subject = %s\n",
resp->envelope.subject ?
resp->envelope.subject : "NIL");
env->subject ?
env->subject : "NIL");
format_email (str, "from", resp->envelope.from);
format_email (str, "sender", resp->envelope.sender);
format_email (str, "reply-to", resp->envelope.reply_to);
format_email (str, "to", resp->envelope.to);
format_email (str, "cc", resp->envelope.cc);
format_email (str, "bcc", resp->envelope.bcc);
format_email (str, "from", env->from);
format_email (str, "sender", env->sender);
format_email (str, "reply-to", env->reply_to);
format_email (str, "to", env->to);
format_email (str, "cc", env->cc);
format_email (str, "bcc", env->bcc);
mu_stream_printf (str, " in-reply-to = %s\n",
resp->envelope.in_reply_to ?
resp->envelope.in_reply_to : "NIL");
env->in_reply_to ?
env->in_reply_to : "NIL");
mu_stream_printf (str, " message-id = %s\n",
resp->envelope.message_id ?
resp->envelope.message_id : "NIL");
env->message_id ?
env->message_id : "NIL");
}
break;
......
......@@ -50,6 +50,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
bs\
fldel\
lstuid\
mbdel\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <mailutils/mailutils.h>
#define S(str) ((str) ? (str) : "")
static void
print_param (const char *prefix, mu_assoc_t assoc, int indent)
{
mu_iterator_t itr;
int i;
mu_printf ("%*s%s:\n", indent, "", prefix);
if (!assoc)
return;
indent += 4;
MU_ASSERT (mu_assoc_get_iterator (assoc, &itr));
for (i = 0, mu_iterator_first (itr);
!mu_iterator_is_done (itr);
i++, mu_iterator_next (itr))
{
const char *name;
struct mu_mime_param *p;
mu_iterator_current_kv (itr, (const void **)&name, (void**)&p);
mu_printf ("%*s%d: %s=%s\n", indent, "", i, name, p->value);
}
mu_iterator_destroy (&itr);
}
struct print_data
{
int num;
int level;
};
static void print_bs (struct mu_bodystructure *bs, int level);
static int
print_item (void *item, void *data)
{
struct mu_bodystructure *bs = item;
struct print_data *pd = data;
mu_printf ("%*sPart #%d\n", (pd->level-1) << 2, "", pd->num);
print_bs (bs, pd->level);
++pd->num;
return 0;
}
static void
print_address (const char *title, mu_address_t addr, int indent)
{
mu_printf ("%*s%s: ", indent, "", title);
mu_stream_format_address (mu_strout, addr);
mu_printf ("\n");
}
static void
print_imapenvelope (struct mu_imapenvelope *env, int level)
{
int indent = (level << 2);
mu_printf ("%*sEnvelope:\n", indent, "");
indent += 4;
mu_printf ("%*sTime: ", indent, "");
mu_c_streamftime (mu_strout, "%c%n", &env->date, &env->tz);
mu_printf ("%*sSubject: %s\n", indent, "", S(env->subject));
print_address ("From", env->from, indent);
print_address ("Sender", env->sender, indent);
print_address ("Reply-to", env->reply_to, indent);
print_address ("To", env->to, indent);
print_address ("Cc", env->cc, indent);
print_address ("Bcc", env->bcc, indent);
mu_printf ("%*sIn-Reply-To: %s\n", indent, "", S(env->in_reply_to));
mu_printf ("%*sMessage-ID: %s\n", indent, "", S(env->message_id));
}
static void
print_bs (struct mu_bodystructure *bs, int level)
{
int indent = level << 2;
mu_printf ("%*sbody_type=%s\n", indent, "", S(bs->body_type));
mu_printf ("%*sbody_subtype=%s\n", indent, "", S(bs->body_subtype));
print_param ("Parameters", bs->body_param, indent);
mu_printf ("%*sbody_id=%s\n", indent, "", S(bs->body_id));
mu_printf ("%*sbody_descr=%s\n", indent, "", S(bs->body_descr));
mu_printf ("%*sbody_encoding=%s\n", indent, "", S(bs->body_encoding));
mu_printf ("%*sbody_size=%lu\n", indent, "", (unsigned long) bs->body_size);
/* Optional */
mu_printf ("%*sbody_md5=%s\n", indent, "", S(bs->body_md5));
mu_printf ("%*sbody_disposition=%s\n", indent, "", S(bs->body_disposition));
print_param ("Disposition Parameters", bs->body_disp_param, indent);
mu_printf ("%*sbody_language=%s\n", indent, "", S(bs->body_language));
mu_printf ("%*sbody_location=%s\n", indent, "", S(bs->body_location));
mu_printf ("%*sType ", indent, "");
switch (bs->body_message_type)
{
case mu_message_other:
mu_printf ("mu_message_other\n");
break;
case mu_message_text:
mu_printf ("mu_message_text:\n%*sbody_lines=%lu\n", indent + 4, "",
(unsigned long) bs->v.text.body_lines);
break;
case mu_message_rfc822:
mu_printf ("mu_message_rfc822:\n%*sbody_lines=%lu\n", indent + 4, "",
(unsigned long) bs->v.rfc822.body_lines);
print_imapenvelope (bs->v.rfc822.body_env, level + 1);
print_bs (bs->v.rfc822.body_struct, level + 1);
break;
case mu_message_multipart:
{
struct print_data pd;
pd.num = 0;
pd.level = level + 1;
mu_printf ("mu_message_multipart:\n");
mu_list_foreach (bs->v.multipart.body_parts, print_item, &pd);
}
}
}
int
main (int argc, char **argv)
{
mu_mailbox_t mbox;
mu_message_t mesg;
struct mu_bodystructure *bs;
if (argc != 3)
{
fprintf (stderr, "usage: %s URL NUM\n", argv[0]);
return 1;
}
mu_register_all_mbox_formats ();
MU_ASSERT (mu_mailbox_create (&mbox, argv[1]));
MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_READ));
MU_ASSERT (mu_mailbox_get_message (mbox, atoi (argv[2]), &mesg));
MU_ASSERT (mu_message_get_bodystructure (mesg, &bs));
print_bs (bs, 0);
mu_bodystructure_free (bs);
return 0;
}