Commit a71c4b6b a71c4b6be03d60b9db1d878a912f23a3864c548a by Sergey Poznyakoff

Improve mime support, introduce ref/unref functions for mu_message_t and mu_mime_t.

* include/mailutils/message.h (mu_message_ref): Change proto.
(mu_message_unref): New proto (instead of macro).
* include/mailutils/mime.h (mu_mime_ref)
(mu_mime_unref, mu_mime_to_message): New protos.
* include/mailutils/sys/message.h (MESSAGE_MODIFIED)
(MESSAGE_INTERNAL_STREAM): New constants (from mime.c)
(MESSAGE_MIME_OWNER): New constant.
(_mu_message) <ref_count>: Rename from ref.
* include/mailutils/sys/mime.h (MIME_SEEK_ACTIVE): New constant.
(_mu_mime) <ref_count>: New member.
* libmailutils/mailbox/message.c (MESSAGE_MODIFIED)
(MESSAGE_INTERNAL_STREAM): Removed (see above).
* libmailutils/mailer/mailer.c (mu_message_unref): New function.
(mu_message_destroy): Rewrite.
(mu_message_ref): Returns void.
(mu_message_lines): Don't access header and body directly to
give virtual functions a chance to initialize them.
(mu_message_quick_lines): likewise.
* libmailutils/mailer/mailer.c (send_fragments): Use mu_mime_to_message
instead of mu_message_unref.
* libmailutils/mime/mime.c (_mime_append_part): Set offset only if
mime->stream is not null.
(_mime_body_stream_seek): Implement (albeit inefficiently).
(mu_mime_create): Set ref_count.
(mu_mime_ref, mu_mime_unref): New functions.
(mu_mime_destroy): Reimplement as a wrapper over _mu_mime_free.
(mu_mime_get_message): Increase refcount of the message being returned.
(mu_mime_to_message): New function.
* libmailutils/stream/message_stream.c (_message_open): Handle arbitrary
text as RFC822 without headers.

* libmu_sieve/actions.c: Unref the message returned by mu_mime_get_message.
* libmu_sieve/extensions/vacation.c: Likewise.
* mh/mhn.c: Likewise.

* libmailutils/stream/stream.c (mu_stream_seek) <MU_SEEK_CUR>: Bugfix.
1 parent bdf3c6cf
......@@ -58,8 +58,8 @@ extern int mu_message_clear_modified (mu_message_t);
extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *);
extern int mu_message_set_mailbox (mu_message_t, mu_mailbox_t, void *);
extern int mu_message_ref (mu_message_t);
#define mu_message_unref(msg) mu_message_destroy (&msg, NULL)
extern void mu_message_ref (mu_message_t);
extern void mu_message_unref (mu_message_t);
extern int mu_message_get_envelope (mu_message_t, mu_envelope_t *);
extern int mu_message_set_envelope (mu_message_t, mu_envelope_t, void *);
......
......@@ -31,6 +31,9 @@ extern "C" {
int mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags);
void mu_mime_destroy (mu_mime_t *pmime);
void mu_mime_ref (mu_mime_t mime);
void mu_mime_unref (mu_mime_t mime);
int mu_mime_is_multipart (mu_mime_t mime);
int mu_mime_get_num_parts (mu_mime_t mime, size_t *nparts);
......@@ -39,6 +42,7 @@ int mu_mime_get_part (mu_mime_t mime, size_t part, mu_message_t *msg);
int mu_mime_add_part (mu_mime_t mime, mu_message_t msg);
int mu_mime_get_message (mu_mime_t mime, mu_message_t *msg);
int mu_mime_to_message (mu_mime_t mime, mu_message_t *msg);
int mu_rfc2047_decode (const char *tocode, const char *fromstr,
char **ptostr);
......
......@@ -30,8 +30,15 @@
extern "C" {
#endif
#define MESSAGE_MODIFIED 0x10000
#define MESSAGE_INTERNAL_STREAM 0x20000
#define MESSAGE_MIME_OWNER 0x40000
struct _mu_message
{
/* Reference count. */
int ref_count;
/* Who is the owner. */
void *owner;
......@@ -48,9 +55,6 @@ struct _mu_message
mu_mailbox_t mailbox;
size_t orig_header_size;
/* Reference count. */
int ref;
int (*_get_stream) (mu_message_t, mu_stream_t *);
int (*_get_uidl) (mu_message_t, char *, size_t, size_t *);
int (*_get_uid) (mu_message_t, size_t *);
......
......@@ -44,9 +44,11 @@ extern "C" {
#define MIME_ADDED_MULTIPART_CT 0x08000000
#define MIME_INSERT_BOUNDARY 0x04000000
#define MIME_ADDING_BOUNDARY 0x02000000
#define MIME_SEEK_ACTIVE 0x01000000
struct _mu_mime
{
int ref_count;
mu_message_t msg;
mu_header_t hdrs;
mu_stream_t stream;
......
......@@ -52,9 +52,6 @@
#include <mailutils/sys/message.h>
#include <mailutils/sys/stream.h>
#define MESSAGE_MODIFIED 0x10000
#define MESSAGE_INTERNAL_STREAM 0x20000
/* Message stream */
......@@ -512,78 +509,100 @@ mu_message_create (mu_message_t *pmsg, void *owner)
return status;
}
msg->owner = owner;
msg->ref = 1;
msg->ref_count = 1;
*pmsg = msg;
return 0;
}
/* Free the message and all associated stuff */
static void
_mu_message_free (mu_message_t msg)
{
/* Notify the listeners. */
/* FIXME: to be removed since we do not support this event. */
if (msg->observable)
{
mu_observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY, msg);
mu_observable_destroy (&msg->observable, msg);
}
/* Envelope. */
if (msg->envelope)
mu_envelope_destroy (&msg->envelope, msg);
/* Header. */
if (msg->header)
mu_header_destroy (&msg->header);
/* Body. */
if (msg->body)
mu_body_destroy (&msg->body, msg);
/* Attribute. */
if (msg->attribute)
mu_attribute_destroy (&msg->attribute, msg);
/* Stream. */
if (msg->stream)
mu_stream_destroy (&msg->stream);
/* Mime. */
if (msg->flags & MESSAGE_MIME_OWNER)
mu_mime_destroy (&msg->mime);
/* Loose the owner. */
msg->owner = NULL;
free (msg);
}
void
mu_message_destroy (mu_message_t *pmsg, void *owner)
mu_message_unref (mu_message_t msg)
{
if (pmsg && *pmsg)
if (msg)
{
mu_message_t msg = *pmsg;
mu_monitor_t monitor = msg->monitor;
int destroy_lock = 0;
mu_monitor_wrlock (monitor);
/* Note: msg->ref may be incremented by mu_message_ref without
additional checking for its owner, therefore decrementing
it must also occur independently of the owner checking. Due
to this inconsistency ref may reach negative values, which
is very unfortunate.
The `owner' stuff is a leftover from older mailutils versions.
We are heading to removing it altogether. */
if (msg->ref > 0)
msg->ref--;
if ((msg->owner && msg->owner == owner)
|| (msg->owner == NULL && msg->ref <= 0))
if (msg->ref_count > 0)
msg->ref_count--;
if (msg->ref_count == 0)
{
destroy_lock = 1;
/* Notify the listeners. */
/* FIXME: to be removed since we do not support this event. */
if (msg->observable)
{
mu_observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY,
msg);
mu_observable_destroy (&msg->observable, msg);
}
/* Envelope. */
if (msg->envelope)
mu_envelope_destroy (&msg->envelope, msg);
/* Header. */
if (msg->header)
mu_header_destroy (&msg->header);
/* Body. */
if (msg->body)
mu_body_destroy (&msg->body, msg);
/* Attribute. */
if (msg->attribute)
mu_attribute_destroy (&msg->attribute, msg);
/* Stream. */
if (msg->stream)
mu_stream_destroy (&msg->stream);
/* Mime. */
if (msg->mime)
mu_mime_destroy (&msg->mime);
_mu_message_free (msg);
mu_monitor_unlock (monitor);
mu_monitor_destroy (&monitor, msg);
}
else
mu_monitor_unlock (monitor);
}
}
/* Loose the owner. */
msg->owner = NULL;
void
mu_message_destroy (mu_message_t *pmsg, void *owner)
{
if (pmsg && *pmsg)
{
mu_message_t msg = *pmsg;
mu_monitor_t monitor = msg->monitor;
mu_monitor_wrlock (monitor);
free (msg);
if (msg->owner && msg->owner == owner)
{
_mu_message_free (msg);
mu_monitor_unlock (monitor);
mu_monitor_destroy (&monitor, msg);
*pmsg = NULL;
return;
}
mu_monitor_unlock (monitor);
if (destroy_lock)
mu_monitor_destroy (&monitor, msg);
/* Loose the link */
*pmsg = NULL;
}
}
......@@ -625,16 +644,15 @@ mu_message_create_copy (mu_message_t *to, mu_message_t from)
return status;
}
int
void
mu_message_ref (mu_message_t msg)
{
if (msg)
{
mu_monitor_wrlock (msg->monitor);
msg->ref++;
msg->ref_count++;
mu_monitor_unlock (msg->monitor);
}
return 0;
}
void *
......@@ -905,9 +923,14 @@ mu_message_lines (mu_message_t msg, size_t *plines)
return msg->_lines (msg, plines, 0);
if (plines)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hlines = blines = 0;
if ( ( ret = mu_header_lines (msg->header, &hlines) ) == 0 )
ret = mu_body_lines (msg->body, &blines);
mu_message_get_header (msg, &hdr);
mu_message_get_body (msg, &body);
if ( ( ret = mu_header_lines (hdr, &hlines) ) == 0 )
ret = mu_body_lines (body, &blines);
*plines = hlines + blines;
}
return ret;
......@@ -934,9 +957,14 @@ mu_message_quick_lines (mu_message_t msg, size_t *plines)
}
if (plines)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hlines = blines = 0;
if ((rc = mu_header_lines (msg->header, &hlines)) == 0)
rc = mu_body_lines (msg->body, &blines);
mu_message_get_header (msg, &hdr);
mu_message_get_body (msg, &body);
if ((rc = mu_header_lines (hdr, &hlines)) == 0)
rc = mu_body_lines (body, &blines);
if (rc == 0)
*plines = hlines + blines;
}
......@@ -945,7 +973,7 @@ mu_message_quick_lines (mu_message_t msg, size_t *plines)
int
mu_message_set_size (mu_message_t msg, int (*_size)
(mu_message_t, size_t *), void *owner)
(mu_message_t, size_t *), void *owner)
{
if (msg == NULL)
return EINVAL;
......@@ -1194,6 +1222,7 @@ mu_message_is_multipart (mu_message_t msg, int *pmulti)
int status = mu_mime_create (&msg->mime, msg, 0);
if (status != 0)
return 0;
msg->flags |= MESSAGE_MIME_OWNER;
}
*pmulti = mu_mime_is_multipart(msg->mime);
}
......
......@@ -629,11 +629,11 @@ send_fragments (mu_mailer_t mailer,
if (status)
break;
mu_mime_get_message (mime, &newmsg);
mu_mime_to_message (mime, &newmsg);
merge_headers (newmsg, hdr);
status = mailer->_send_message (mailer, newmsg, from, to);
mu_mime_destroy (&mime);
mu_message_unref (newmsg);
if (status)
break;
if (delay)
......
......@@ -40,6 +40,7 @@
#include <mailutils/util.h>
#include <mailutils/sys/mime.h>
#include <mailutils/sys/message.h>
#include <mailutils/sys/stream.h>
#ifndef TRUE
......@@ -71,7 +72,7 @@ _mime_append_part (mu_mime_t mime, mu_message_t msg,
struct _mime_part *mime_part, **part_arr;
int ret;
size_t size;
mu_header_t hdr;
mu_header_t hdr;
if ((mime_part = calloc (1, sizeof (*mime_part))) == NULL)
return ENOMEM;
......@@ -129,7 +130,7 @@ _mime_append_part (mu_mime_t mime, mu_message_t msg,
mu_message_ref (msg);
mu_message_size (msg, &mime_part->len);
mu_message_lines (msg, &mime_part->lines);
if (mime->nmtp_parts > 1)
if (mime->stream && mime->nmtp_parts > 1)
mime_part->offset = mime->mtp_parts[mime->nmtp_parts - 2]->len;
mime_part->msg = msg;
}
......@@ -613,7 +614,27 @@ _mime_body_stream_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
mime_reset_state (mime);
if (off != mime->cur_offset)
return ESPIPE;
{
int rc;
mu_stream_t nullstr;
if (mime->flags & MIME_SEEK_ACTIVE)
return ESPIPE;
mime->flags |= MIME_SEEK_ACTIVE;
rc = mu_nullstream_create (&nullstr, MU_STREAM_WRITE);
if (rc == 0)
{
mu_off_t total;
rc = mu_stream_copy (nullstr, stream, off, &total);
mu_stream_destroy (&nullstr);
if (rc == 0 && total != off)
rc = ESPIPE;
}
mime->flags &= ~MIME_SEEK_ACTIVE;
if (rc)
return rc;
}
*presult = off;
return 0;
}
......@@ -912,49 +933,64 @@ mu_mime_create (mu_mime_t *pmime, mu_message_t msg, int flags)
else
{
mime->flags |= (flags & MIME_FLAG_MASK);
mime->ref_count = 1;
*pmime = mime;
}
return ret;
}
void
mu_mime_destroy (mu_mime_t *pmime)
mu_mime_ref (mu_mime_t mime)
{
mime->ref_count++;
}
static void
_mu_mime_free (mu_mime_t mime)
{
mu_mime_t mime;
struct _mime_part *mime_part;
int i;
int i;
if (pmime && *pmime)
if (mime->mtp_parts)
{
mime = *pmime;
if (mime->mtp_parts != NULL)
for (i = 0; i < mime->nmtp_parts; i++)
{
for (i = 0; i < mime->nmtp_parts; i++)
{
mime_part = mime->mtp_parts[i];
if (mime_part->msg && mime->flags & MIME_NEW_MESSAGE)
mu_message_unref (mime_part->msg);
else
mu_message_destroy (&mime_part->msg, mime_part);
free (mime_part);
}
free (mime->mtp_parts);
mime_part = mime->mtp_parts[i];
mu_message_unref (mime_part->msg);
free (mime_part);
}
mu_stream_destroy (&mime->stream);
mu_stream_destroy (&mime->part_stream);
if (mime->msg && mime->flags & MIME_NEW_MESSAGE)
mu_message_destroy (&mime->msg, mime);
if (mime->content_type)
free (mime->content_type);
if (mime->cur_buf)
free (mime->cur_buf);
if (mime->cur_line)
free (mime->cur_line);
if (mime->boundary)
free (mime->boundary);
if (mime->header_buf)
free (mime->header_buf);
free (mime);
free (mime->mtp_parts);
}
mu_stream_destroy (&mime->stream);
mu_stream_destroy (&mime->part_stream);
if (mime->msg && mime->flags & MIME_NEW_MESSAGE)
mu_message_destroy (&mime->msg, mime);
if (mime->content_type)
free (mime->content_type);
if (mime->cur_buf)
free (mime->cur_buf);
if (mime->cur_line)
free (mime->cur_line);
if (mime->boundary)
free (mime->boundary);
if (mime->header_buf)
free (mime->header_buf);
free (mime);
}
void
mu_mime_unref (mu_mime_t mime)
{
if (--mime->ref_count == 0)
_mu_mime_free (mime);
}
void
mu_mime_destroy (mu_mime_t *pmime)
{
if (pmime && *pmime)
{
mu_mime_unref (*pmime);
*pmime = NULL;
}
}
......@@ -1043,7 +1079,7 @@ mu_mime_get_message (mu_mime_t mime, mu_message_t *msg)
{
mu_stream_t body_stream;
mu_body_t body;
int ret = 0;
int ret = 0;
if (mime == NULL || msg == NULL)
return EINVAL;
......@@ -1069,6 +1105,8 @@ mu_mime_get_message (mu_mime_t mime, mu_message_t *msg)
if (ret == 0)
{
mu_body_set_stream (body, body_stream, mime->msg);
mime->msg->mime = mime;
mu_message_ref (mime->msg);
*msg = mime->msg;
return 0;
}
......@@ -1080,10 +1118,30 @@ mu_mime_get_message (mu_mime_t mime, mu_message_t *msg)
}
}
if (ret == 0)
*msg = mime->msg;
{
mu_message_ref (mime->msg);
*msg = mime->msg;
}
return ret;
}
int
mu_mime_to_message (mu_mime_t mime, mu_message_t *pmsg)
{
mu_message_t msg;
int rc = mu_mime_get_message (mime, &msg);
if (rc == 0)
{
mu_message_unref (msg);
msg->flags |= MESSAGE_MIME_OWNER;
mime->msg = NULL;
mu_mime_ref (mime);
*pmsg = msg;
}
return rc;
}
int
mu_mime_is_multipart (mu_mime_t mime)
{
......
......@@ -143,7 +143,26 @@ copy_trimmed_value (const char *str)
p[len] = 0;
return p;
}
static int
is_header_start (const char *buf)
{
for (; *buf; buf++)
{
if (mu_isalnum (*buf) || *buf == '-' || *buf == '_')
continue;
if (*buf == ':')
return 1;
}
return 0;
}
static int
is_header_cont (const char *buf)
{
return mu_isblank (*buf);
}
static int
_message_open (mu_stream_t stream)
{
......@@ -157,6 +176,7 @@ _message_open (mu_stream_t stream)
size_t offset, len;
mu_off_t body_start, body_end;
mu_stream_t transport = str->transport;
int has_headers = 0;
rc = mu_stream_seek (transport, 0, MU_SEEK_SET, NULL);
if (rc)
......@@ -197,25 +217,45 @@ _message_open (mu_stream_t stream)
else if (mu_mh_delim (buffer))
{
str->mark_offset = offset;
str->mark_length = len - 1; /* do not count the terminating newline */
str->mark_length = len - 1; /* do not count the terminating
newline */
break;
}
else if (!env_from || !env_date)
else
{
if (!from && mu_c_strncasecmp (buffer, MU_HEADER_FROM,
sizeof (MU_HEADER_FROM) - 1) == 0)
if (!is_header_start (buffer))
{
if (has_headers && is_header_cont (buffer))
{
offset += len;
continue;
}
rc = mu_stream_seek (transport, - (mu_off_t) len,
MU_SEEK_CUR, &offset);
if (rc)
return rc;
str->mark_offset = offset;
str->mark_length = 0;
break;
}
has_headers = 1;
if (!env_from || !env_date)
{
if (!from && mu_c_strncasecmp (buffer, MU_HEADER_FROM,
sizeof (MU_HEADER_FROM) - 1) == 0)
from = copy_trimmed_value (buffer + sizeof (MU_HEADER_FROM));
else if (!env_from
&& mu_c_strncasecmp (buffer, MU_HEADER_ENV_SENDER,
sizeof (MU_HEADER_ENV_SENDER) - 1) == 0)
env_from = copy_trimmed_value (buffer +
sizeof (MU_HEADER_ENV_SENDER));
else if (!env_date
&& mu_c_strncasecmp (buffer, MU_HEADER_ENV_DATE,
sizeof (MU_HEADER_ENV_DATE) - 1) == 0)
env_date = copy_trimmed_value (buffer +
sizeof (MU_HEADER_ENV_DATE));
from = copy_trimmed_value (buffer + sizeof (MU_HEADER_FROM));
else if (!env_from
&& mu_c_strncasecmp (buffer, MU_HEADER_ENV_SENDER,
sizeof (MU_HEADER_ENV_SENDER) - 1) == 0)
env_from = copy_trimmed_value (buffer +
sizeof (MU_HEADER_ENV_SENDER));
else if (!env_date
&& mu_c_strncasecmp (buffer, MU_HEADER_ENV_DATE,
sizeof (MU_HEADER_ENV_DATE) - 1) == 0)
env_date = copy_trimmed_value (buffer +
sizeof (MU_HEADER_ENV_DATE));
}
}
offset += len;
}
......
......@@ -423,7 +423,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
*pres = stream->offset + stream->pos;
return 0;
}
offset += stream->offset;
offset += stream->offset + stream->pos;
break;
case MU_SEEK_END:
......
......@@ -306,7 +306,7 @@ sieve_action_reject (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
rc = build_mime (&mime, mach->msg, val->v.string);
mu_mime_get_message (mime, &newmsg);
mu_message_unref (newmsg);
mu_sieve_get_message_sender (mach->msg, &addrtext);
mu_message_get_header (newmsg, &hdr);
mu_header_prepend (hdr, MU_HEADER_TO, addrtext);
......
......@@ -563,6 +563,7 @@ vacation_reply (mu_sieve_machine_t mach, mu_list_t tags, mu_message_t msg,
if (build_mime (mach, tags, &mime, msg, text))
return -1;
mu_mime_get_message (mime, &newmsg);
mu_message_unref (newmsg);
mu_message_get_header (newmsg, &newhdr);
}
......
......@@ -2408,6 +2408,7 @@ edit_forw (char *cmd, struct compose_env *env, mu_message_t *pmsg, int level)
}
mu_mime_get_message (mime, &msg);
mu_message_unref (msg);
mu_message_get_header (msg, &hdr);
if (npart > 2)
......@@ -2669,7 +2670,6 @@ mhn_edit (struct compose_env *env, int level)
{
mu_mime_get_message (new_env.mime, &new_msg);
mu_mime_add_part (env->mime, new_msg);
mu_message_unref (new_msg);
}
}
else if (strcmp (tok, "#end") == 0)
......@@ -2876,7 +2876,8 @@ mhn_compose ()
return rc;
mu_mime_get_message (mime, &msg);
mu_message_unref (msg);
p = strrchr (input_file, '/');
/* Prepare file names */
if (p)
......@@ -2900,6 +2901,7 @@ mhn_compose ()
mu_error (_("cannot create output stream (file %s): %s"),
name, mu_strerror (rc));
free (name);
mu_mime_unref (mime);
return rc;
}
......@@ -2916,7 +2918,7 @@ mhn_compose ()
rename (name, input_file);
free (name);
mu_mime_unref (mime);
return 0;
}
......