Commit 217ae7a2 217ae7a2228c6f7054b4e8e1731ec5e17f0a86a4 by Sergey Poznyakoff

Split ibmailutils/mailbox/message.c into logically separated and

easily manageable parts.
1 parent 1ae9bae2
......@@ -28,7 +28,27 @@ libmailbox_la_SOURCES = \
hdrfirst.c\
hdritr.c\
header.c\
message.c\
msgscan.c
msgcpy.c\
msgattr.c\
msgbody.c\
msgcreat.c\
msgheader.c\
msgenv.c\
msglines.c\
msgmbx.c\
msgmod.c\
msgmulti.c\
msgnumparts.c\
msgobs.c\
msgpart.c\
msgqid.c\
msgqlines.c\
msgref.c\
msgsave.c\
msgscan.c\
msgsize.c\
msgstream.c\
msguid.c\
msguidl.c
INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
#include <mailutils/cctype.h>
#include <mailutils/address.h>
#include <mailutils/attribute.h>
#include <mailutils/auth.h>
#include <mailutils/body.h>
#include <mailutils/debug.h>
#include <mailutils/envelope.h>
#include <mailutils/errno.h>
#include <mailutils/folder.h>
#include <mailutils/header.h>
#include <mailutils/mailbox.h>
#include <mailutils/util.h>
#include <mailutils/observer.h>
#include <mailutils/stream.h>
#include <mailutils/mu_auth.h>
#include <mailutils/nls.h>
#include <mailutils/md5.h>
#include <mailutils/io.h>
#include <mailutils/sys/message.h>
#include <mailutils/sys/stream.h>
/* Message stream */
enum _message_stream_state
{
_mss_init,
_mss_header,
_mss_body,
_mss_eof
};
struct _mu_message_stream
{
struct _mu_stream stream;
mu_message_t msg;
enum _message_stream_state state;
mu_stream_t transport;
mu_off_t limit;
};
static int
_check_stream_state (struct _mu_message_stream *str)
{
int rc = 0;
if (str->transport && mu_stream_eof (str->transport))
mu_stream_destroy (&str->transport);
switch (str->state)
{
case _mss_init:
if (!str->transport)
{
rc = mu_header_get_streamref (str->msg->header, &str->transport);
if (rc == 0)
{
str->state = _mss_header;
rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
}
}
break;
case _mss_header:
if (!str->transport)
{
rc = mu_body_get_streamref (str->msg->body, &str->transport);
if (rc == 0)
{
str->state = _mss_body;
rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
}
}
break;
case _mss_body:
if (!str->transport)
str->state = _mss_eof;
case _mss_eof:
break;
}
return rc;
}
static void
_message_stream_done (struct _mu_stream *str)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
mu_stream_destroy (&sp->transport);
}
static int
_message_stream_flush (struct _mu_stream *str)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
int rc = _check_stream_state (sp);
if (rc)
return rc;
return mu_stream_flush (sp->transport);
}
static int
_message_stream_size (struct _mu_stream *str, mu_off_t *psize)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t hsize, bsize;
mu_header_size (sp->msg->header, &hsize);
mu_body_size (sp->msg->body, &bsize);
if (psize)
*psize = hsize + bsize;
return 0;
}
static int
_message_stream_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t hsize, size;
int rc;
rc = _check_stream_state (sp);
if (rc)
return rc;
mu_header_size (sp->msg->header, &hsize);
mu_body_size (sp->msg->body, &size);
if (off < 0 || off >= size + hsize)
return ESPIPE;
switch (sp->state)
{
case _mss_eof:
sp->state = _mss_init;
rc = _check_stream_state (sp);
if (rc)
return rc;
/* fall through */
case _mss_header:
if (off < hsize)
break;
mu_stream_destroy (&sp->transport);
rc = _check_stream_state (sp);
if (rc)
return rc;
/* fall through */
case _mss_body:
if (off > hsize)
off -= hsize;
else
{
mu_stream_destroy (&sp->transport);
sp->state = _mss_init;
rc = _check_stream_state (sp);
if (rc)
return rc;
}
break;
default:
break;
}
rc = mu_stream_seek (sp->transport, off, MU_SEEK_SET, &off);
if (rc == 0)
{
if (sp->state == _mss_body)
off += hsize;
*ppos = off;
}
return rc;
}
static int
_message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize,
size_t *pnread)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t nread = 0;
int rc;
while (bufsize)
{
size_t n;
rc = _check_stream_state (sp);
if (rc)
break;
if (sp->state == _mss_eof)
break;
rc = mu_stream_read (sp->transport, buf, bufsize, &n);
if (rc)
break;
if (n == 0)
continue;
nread += n;
buf += n;
bufsize -= n;
}
*pnread = nread;
return rc;
}
static int
_message_stream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
int delim, size_t *pnread)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t nread = 0;
int rc;
while (bufsize)
{
size_t n;
rc = _check_stream_state (sp);
if (rc)
break;
if (sp->state == _mss_eof)
break;
rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &n);
if (rc)
break;
if (n == 0)
continue;
nread += n;
if (buf[n-1] == delim)
break;
buf += n;
bufsize -= n;
}
*pnread = nread;
return rc;
}
#if 0
static int
_message_stream_write (struct _mu_stream *str,
const char *buf, size_t bufsize,
size_t *pnwritten)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
/* FIXME */
}
#endif
static int
_message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags)
{
struct _mu_message_stream *sp;
sp = (struct _mu_message_stream *) _mu_stream_create (sizeof (*sp),
flags |
MU_STREAM_SEEK |
_MU_STR_OPEN);
if (!sp)
return ENOMEM;
sp->stream.read = _message_stream_read;
sp->stream.readdelim = _message_stream_readdelim;
/* FIXME: Write is not defined */
/* sp->stream.write = _message_stream_write;*/
sp->stream.done = _message_stream_done;
sp->stream.flush = _message_stream_flush;
sp->stream.seek = _message_stream_seek;
sp->stream.size = _message_stream_size;
sp->state = _mss_init;
sp->msg = msg;
*pmsg = (mu_stream_t) sp;
return 0;
}
enum eoh_state
{
eoh_no,
eoh_maybe,
eoh_yes
};
/* Message header stuff */
static enum eoh_state
string_find_eoh (enum eoh_state eoh, const char *str, size_t len,
size_t *ppos)
{
size_t pos;
if (eoh == eoh_maybe && *str == '\n')
{
*ppos = 0;
return eoh_yes;
}
for (pos = 0; pos < len - 1; pos++)
if (str[pos] == '\n' && str[pos + 1] == '\n')
{
*ppos = pos + 1;
return eoh_yes;
}
*ppos = pos + 1;
return str[pos] == '\n' ? eoh_maybe : eoh_no;
}
#define MIN_HEADER_BUF_SIZE 2048
static int
_header_fill (mu_stream_t stream, char **pbuf, size_t *plen)
{
int status = 0;
char *buffer = NULL;
size_t bufsize = 0;
char inbuf[MIN_HEADER_BUF_SIZE];
size_t nread;
enum eoh_state eoh = eoh_no;
status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (status)
return status;
while (eoh != eoh_yes
&& (status = mu_stream_read (stream, inbuf, sizeof (inbuf), &nread))
== 0
&& nread)
{
char *nbuf;
size_t len;
eoh = string_find_eoh (eoh, inbuf, nread, &len);
nbuf = realloc (buffer, bufsize + len);
if (!nbuf)
{
status = ENOMEM;
break;
}
memcpy (nbuf + bufsize, inbuf, len);
buffer = nbuf;
bufsize += len;
}
if (status)
free (buffer);
else
{
*pbuf = buffer;
*plen = bufsize;
}
return status;
}
static int
message_header_fill (void *data, char **pbuf, size_t *plen)
{
int status = 0;
mu_message_t msg = data;
mu_stream_t stream;
status = mu_message_get_streamref (msg, &stream);
if (status == 0)
{
status = _header_fill (stream, pbuf, plen);
mu_stream_destroy (&stream);
}
return status;
}
/* Message envelope */
static int
message_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
{
mu_message_t msg = mu_envelope_get_owner (envelope);
time_t t;
size_t n;
if (msg == NULL)
return EINVAL;
/* FIXME: extract the time from "Date:". */
if (buf == NULL || len == 0)
{
n = MU_ENVELOPE_DATE_LENGTH;
}
else
{
char tmpbuf[MU_ENVELOPE_DATE_LENGTH+1];
t = time (NULL);
n = mu_strftime (tmpbuf, sizeof tmpbuf,
MU_ENVELOPE_DATE_FORMAT, localtime (&t));
n = mu_cpystr (buf, tmpbuf, len);
}
if (pnwrite)
*pnwrite = n;
return 0;
}
static int
message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
{
mu_message_t msg = mu_envelope_get_owner (envelope);
mu_header_t header;
int status;
const char *sender;
struct mu_auth_data *auth = NULL;
static char *hdrnames[] = {
"X-Envelope-Sender",
"X-Envelope-From",
"X-Original-Sender",
"From",
NULL
};
mu_address_t address = NULL;
if (msg == NULL)
return EINVAL;
/* First, try the header */
status = mu_message_get_header (msg, &header);
if (status)
return status;
status = mu_header_sget_firstof (header, hdrnames, &sender, NULL);
if (status)
{
auth = mu_get_auth_by_uid (getuid ());
if (!auth)
return MU_ERR_NOENT;
sender = auth->name;
}
status = mu_address_create (&address, sender);
if (status == 0)
{
status = mu_address_sget_email (address, 1, &sender);
if (status == 0)
{
size_t n = strlen (sender);
if (buf && len > 0)
{
len--; /* One for the null. */
n = (n < len) ? n : len;
memcpy (buf, sender, n);
buf[n] = '\0';
}
if (pnwrite)
*pnwrite = n;
}
mu_address_destroy (&address);
}
if (auth)
mu_auth_data_free (auth);
return status;
}
/* Allocate ressources for the mu_message_t. */
int
mu_message_create (mu_message_t *pmsg, void *owner)
{
mu_message_t msg;
int status;
if (pmsg == NULL)
return MU_ERR_OUT_PTR_NULL;
msg = calloc (1, sizeof (*msg));
if (msg == NULL)
return ENOMEM;
status = mu_monitor_create (&msg->monitor, 0, msg);
if (status != 0)
{
free (msg);
return status;
}
msg->owner = owner;
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_unref (mu_message_t msg)
{
if (msg)
{
mu_monitor_t monitor = msg->monitor;
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_count > 0)
msg->ref_count--;
if (msg->ref_count == 0)
{
_mu_message_free (msg);
mu_monitor_unlock (monitor);
mu_monitor_destroy (&monitor, msg);
}
else
mu_monitor_unlock (monitor);
}
}
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);
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);
}
}
int
mu_message_create_copy (mu_message_t *to, mu_message_t from)
{
int status = 0;
mu_stream_t fromstr = NULL;
mu_stream_t tmp = NULL;
if (!to)
return MU_ERR_OUT_PTR_NULL;
if (!from)
return EINVAL;
status = mu_memory_stream_create (&tmp, MU_STREAM_RDWR|MU_STREAM_SEEK);
if (status)
return status;
status = mu_message_get_streamref (from, &fromstr);
if (status)
{
mu_stream_destroy (&tmp);
return status;
}
status = mu_stream_copy (tmp, fromstr, 0, NULL);
if (status == 0)
{
status = mu_message_create (to, NULL);
if (status == 0)
mu_message_set_stream (*to, tmp, NULL);
}
if (status)
mu_stream_destroy (&tmp);
mu_stream_destroy (&fromstr);
return status;
}
void
mu_message_ref (mu_message_t msg)
{
if (msg)
{
mu_monitor_wrlock (msg->monitor);
msg->ref_count++;
mu_monitor_unlock (msg->monitor);
}
}
void *
mu_message_get_owner (mu_message_t msg)
{
return (msg == NULL) ? NULL : msg->owner;
}
int
mu_message_is_modified (mu_message_t msg)
{
int mod = 0;
if (msg)
{
if (mu_header_is_modified (msg->header))
mod |= MU_MSG_HEADER_MODIFIED;
if (mu_attribute_is_modified (msg->attribute))
mod |= MU_MSG_ATTRIBUTE_MODIFIED;
if (mu_body_is_modified (msg->body))
mod |= MU_MSG_BODY_MODIFIED;
if (msg->flags & MESSAGE_MODIFIED)
mod |= MU_MSG_BODY_MODIFIED | MU_MSG_HEADER_MODIFIED;
}
return mod;
}
int
mu_message_clear_modified (mu_message_t msg)
{
if (msg)
{
if (msg->header)
mu_header_clear_modified (msg->header);
if (msg->attribute)
mu_attribute_clear_modified (msg->attribute);
if (msg->body)
mu_body_clear_modified (msg->body);
msg->flags &= ~MESSAGE_MODIFIED;
}
return 0;
}
int
mu_message_get_mailbox (mu_message_t msg, mu_mailbox_t *pmailbox)
{
if (msg == NULL)
return EINVAL;
if (pmailbox == NULL)
return MU_ERR_OUT_PTR_NULL;
*pmailbox = msg->mailbox;
return 0;
}
int
mu_message_set_mailbox (mu_message_t msg, mu_mailbox_t mailbox, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->mailbox = mailbox;
return 0;
}
int
mu_message_get_header (mu_message_t msg, mu_header_t *phdr)
{
if (msg == NULL)
return EINVAL;
if (phdr == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->header == NULL)
{
mu_header_t header;
int status = mu_header_create (&header, NULL, 0);
if (status != 0)
return status;
if (msg->stream)
mu_header_set_fill (header, message_header_fill, msg);
status = mu_header_size (header, &msg->orig_header_size);
if (status)
return status;
msg->header = header;
}
*phdr = msg->header;
return 0;
}
/* Note: mu_message_set_header steals the reference to hdr */
int
mu_message_set_header (mu_message_t msg, mu_header_t hdr, void *owner)
{
if (msg == NULL )
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->header)
mu_header_destroy (&msg->header);
msg->header = hdr;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
int
mu_message_get_body (mu_message_t msg, mu_body_t *pbody)
{
if (msg == NULL)
return EINVAL;
if (pbody == NULL)
return MU_ERR_OUT_PTR_NULL;
/* Is it a floating mesg. */
if (msg->body == NULL)
{
mu_body_t body;
int status = mu_body_create (&body, msg);
if (status != 0)
return status;
/* If a stream is already set, use it to create the body stream. */
/* FIXME: I'm not sure if the second condition is really needed */
if (msg->stream/* && (msg->flags & MESSAGE_INTERNAL_STREAM)*/)
{
mu_stream_t stream;
int flags = 0;
/* FIXME: The actual mu_header_size cannot be used as offset,
because the headers might have been modified in between. */
mu_stream_get_flags (msg->stream, &flags);
status = mu_streamref_create_abridged (&stream, msg->stream,
msg->orig_header_size, 0);
if (status)
{
mu_body_destroy (&body, msg);
return status;
}
mu_body_set_stream (body, stream, msg);
}
msg->body = body;
}
*pbody = msg->body;
return 0;
}
int
mu_message_set_body (mu_message_t msg, mu_body_t body, void *owner)
{
if (msg == NULL )
return EINVAL;
if (msg->owner != owner)
return EACCES;
/* Make sure we destroy the old if it was owned by the mesg. */
/* FIXME: I do not know if somebody has already a ref on this ? */
if (msg->body)
mu_body_destroy (&msg->body, msg);
msg->body = body;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
int
mu_message_set_stream (mu_message_t msg, mu_stream_t stream, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->stream)
mu_stream_destroy (&msg->stream);
msg->stream = stream;
msg->flags |= MESSAGE_MODIFIED;
msg->flags &= ~MESSAGE_INTERNAL_STREAM;
return 0;
}
static int
_message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
{
int status;
if (msg == NULL)
return EINVAL;
if (pstream == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->stream == NULL)
{
if (msg->_get_stream)
{
status = msg->_get_stream (msg, &msg->stream);
if (status)
return status;
}
else
{
mu_header_t hdr;
mu_body_t body;
/* FIXME: Kind of a kludge: make sure the message has header
and body initialized. */
status = mu_message_get_header (msg, &hdr);
if (status)
return status;
status = mu_message_get_body (msg, &body);
if (status)
return status;
status = _message_stream_create (&msg->stream, msg, MU_STREAM_RDWR);
if (status)
return status;
msg->flags |= MESSAGE_INTERNAL_STREAM;
}
}
if (!ref)
{
*pstream = msg->stream;
return 0;
}
return mu_streamref_create (pstream, msg->stream);
}
int
mu_message_get_stream (mu_message_t msg, mu_stream_t *pstream)
{
/* FIXME: Deprecation warning */
return _message_get_stream (msg, pstream, 0);
}
int
mu_message_get_streamref (mu_message_t msg, mu_stream_t *pstream)
{
return _message_get_stream (msg, pstream, 1);
}
int
mu_message_set_get_stream (mu_message_t msg,
int (*_getstr) (mu_message_t, mu_stream_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_stream = _getstr;
return 0;
}
int
mu_message_set_lines (mu_message_t msg, int (*_lines)
(mu_message_t, size_t *, int), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_lines = _lines;
return 0;
}
int
mu_message_lines (mu_message_t msg, size_t *plines)
{
size_t hlines, blines;
int ret = 0;
if (msg == NULL)
return EINVAL;
/* Overload. */
if (msg->_lines)
return msg->_lines (msg, plines, 0);
if (plines)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hlines = blines = 0;
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;
}
/* Return the number of lines in the message, without going into
excess trouble for calculating it. If obtaining the result
means downloading the entire message (as is the case for POP3,
for example), return MU_ERR_INFO_UNAVAILABLE. */
int
mu_message_quick_lines (mu_message_t msg, size_t *plines)
{
size_t hlines, blines;
int rc;
if (msg == NULL)
return EINVAL;
/* Overload. */
if (msg->_lines)
{
int rc = msg->_lines (msg, plines, 1);
if (rc != ENOSYS)
return rc;
}
if (plines)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hlines = blines = 0;
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;
}
return rc;
}
int
mu_message_set_size (mu_message_t msg, int (*_size)
(mu_message_t, size_t *), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_size = _size;
return 0;
}
int
mu_message_size (mu_message_t msg, size_t *psize)
{
size_t hsize, bsize;
int ret = 0;
if (msg == NULL)
return EINVAL;
/* Overload ? */
if (msg->_size)
return msg->_size (msg, psize);
if (psize)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hsize = bsize = 0;
mu_message_get_header (msg, &hdr);
mu_message_get_body (msg, &body);
if ( ( ret = mu_header_size (hdr, &hsize) ) == 0 )
ret = mu_body_size (body, &bsize);
*psize = hsize + bsize;
}
return ret;
}
int
mu_message_get_envelope (mu_message_t msg, mu_envelope_t *penvelope)
{
if (msg == NULL)
return EINVAL;
if (penvelope == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->envelope == NULL)
{
mu_envelope_t envelope;
int status = mu_envelope_create (&envelope, msg);
if (status != 0)
return status;
mu_envelope_set_sender (envelope, message_envelope_sender, msg);
mu_envelope_set_date (envelope, message_envelope_date, msg);
msg->envelope = envelope;
}
*penvelope = msg->envelope;
return 0;
}
int
mu_message_set_envelope (mu_message_t msg, mu_envelope_t envelope, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->envelope)
mu_envelope_destroy (&msg->envelope, msg);
msg->envelope = envelope;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
int
mu_message_get_attribute (mu_message_t msg, mu_attribute_t *pattribute)
{
if (msg == NULL)
return EINVAL;
if (pattribute == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->attribute == NULL)
{
mu_attribute_t attribute;
int status = mu_attribute_create (&attribute, msg);
if (status != 0)
return status;
msg->attribute = attribute;
}
*pattribute = msg->attribute;
return 0;
}
int
mu_message_set_attribute (mu_message_t msg, mu_attribute_t attribute, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->attribute)
mu_attribute_destroy (&msg->attribute, owner);
msg->attribute = attribute;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
int
mu_message_get_uid (mu_message_t msg, size_t *puid)
{
if (msg == NULL)
return EINVAL;
if (msg->_get_uid)
return msg->_get_uid (msg, puid);
*puid = 0;
return 0;
}
int
mu_message_get_uidl (mu_message_t msg, char *buffer, size_t buflen,
size_t *pwriten)
{
mu_header_t header = NULL;
size_t n = 0;
int status;
if (msg == NULL || buffer == NULL || buflen == 0)
return EINVAL;
buffer[0] = '\0';
/* Try the function overload if error fallback. */
if (msg->_get_uidl)
{
status = msg->_get_uidl (msg, buffer, buflen, pwriten);
if (status == 0)
return status;
}
/* Be compatible with Qpopper ? qppoper saves the UIDL in "X-UIDL".
We generate a chksum and save it in the header. */
mu_message_get_header (msg, &header);
status = mu_header_get_value_unfold (header, "X-UIDL", buffer, buflen, &n);
if (status != 0 || n == 0)
{
size_t uid = 0;
struct mu_md5_ctx md5context;
mu_stream_t stream = NULL;
char buf[1024];
unsigned char md5digest[16];
char *tmp;
n = 0;
mu_message_get_uid (msg, &uid);
mu_message_get_streamref (msg, &stream);
mu_md5_init_ctx (&md5context);
status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (status == 0)
{
while (mu_stream_read (stream, buf, sizeof (buf), &n) == 0
&& n > 0)
mu_md5_process_bytes (buf, n, &md5context);
mu_md5_finish_ctx (&md5context, md5digest);
tmp = buf;
for (n = 0; n < 16; n++, tmp += 2)
sprintf (tmp, "%02x", md5digest[n]);
*tmp = '\0';
/* POP3 rfc says that an UID should not be longer than 70. */
snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL),
(unsigned long) uid);
mu_header_set_value (header, "X-UIDL", buf, 1);
buflen--; /* leave space for the NULL. */
strncpy (buffer, buf, buflen)[buflen] = '\0';
}
mu_stream_destroy (&stream);
}
return status;
}
int
mu_message_get_qid (mu_message_t msg, mu_message_qid_t *pqid)
{
if (msg == NULL)
return EINVAL;
if (!msg->_get_qid)
return ENOSYS;
return msg->_get_qid (msg, pqid);
}
int
mu_message_set_qid (mu_message_t msg,
int (*_get_qid) (mu_message_t, mu_message_qid_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_qid = _get_qid;
return 0;
}
int
mu_message_set_uid (mu_message_t msg, int (*_get_uid) (mu_message_t, size_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_uid = _get_uid;
return 0;
}
int
mu_message_set_uidl (mu_message_t msg,
int (* _get_uidl) (mu_message_t, char *, size_t, size_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_uidl = _get_uidl;
return 0;
}
int
mu_message_set_is_multipart (mu_message_t msg,
int (*_is_multipart) (mu_message_t, int *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_is_multipart = _is_multipart;
return 0;
}
int
mu_message_is_multipart (mu_message_t msg, int *pmulti)
{
if (msg && pmulti)
{
if (msg->_is_multipart)
return msg->_is_multipart (msg, pmulti);
if (msg->mime == NULL)
{
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);
}
return 0;
}
int
mu_message_get_num_parts (mu_message_t msg, size_t *pparts)
{
if (msg == NULL || pparts == NULL)
return EINVAL;
if (msg->_get_num_parts)
return msg->_get_num_parts (msg, pparts);
if (msg->mime == NULL)
{
int status = mu_mime_create (&msg->mime, msg, 0);
if (status != 0)
return status;
}
return mu_mime_get_num_parts (msg->mime, pparts);
}
int
mu_message_set_get_num_parts (mu_message_t msg,
int (*_get_num_parts) (mu_message_t, size_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_num_parts = _get_num_parts;
return 0;
}
int
mu_message_get_part (mu_message_t msg, size_t part, mu_message_t *pmsg)
{
if (msg == NULL || pmsg == NULL)
return EINVAL;
/* Overload. */
if (msg->_get_part)
return msg->_get_part (msg, part, pmsg);
if (msg->mime == NULL)
{
int status = mu_mime_create (&msg->mime, msg, 0);
if (status != 0)
return status;
}
return mu_mime_get_part (msg->mime, part, pmsg);
}
int
mu_message_set_get_part (mu_message_t msg, int (*_get_part)
(mu_message_t, size_t, mu_message_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_part = _get_part;
return 0;
}
int
mu_message_get_observable (mu_message_t msg, mu_observable_t *pobservable)
{
if (msg == NULL || pobservable == NULL)
return EINVAL;
if (msg->observable == NULL)
{
int status = mu_observable_create (&msg->observable, msg);
if (status != 0)
return status;
}
*pobservable = msg->observable;
return 0;
}
int
mu_message_save_to_mailbox (mu_message_t msg, const char *toname, int perms)
{
int rc = 0;
mu_mailbox_t to = 0;
if ((rc = mu_mailbox_create_default (&to, toname)))
{
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_create_default (%s) failed: %s\n", toname,
mu_strerror (rc)));
goto end;
}
if ((rc = mu_mailbox_open (to,
MU_STREAM_WRITE | MU_STREAM_CREAT
| (perms & MU_STREAM_IMASK))))
{
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_open (%s) failed: %s", toname,
mu_strerror (rc)));
goto end;
}
if ((rc = mu_mailbox_append_message (to, msg)))
{
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_append_message (%s) failed: %s", toname,
mu_strerror (rc)));
goto end;
}
end:
if (!rc)
{
if ((rc = mu_mailbox_close (to)))
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_close (%s) failed: %s", toname,
mu_strerror (rc)));
}
else
mu_mailbox_close (to);
mu_mailbox_destroy (&to);
return rc;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/attribute.h>
#include <mailutils/sys/message.h>
int
mu_message_get_attribute (mu_message_t msg, mu_attribute_t *pattribute)
{
if (msg == NULL)
return EINVAL;
if (pattribute == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->attribute == NULL)
{
mu_attribute_t attribute;
int status = mu_attribute_create (&attribute, msg);
if (status != 0)
return status;
msg->attribute = attribute;
}
*pattribute = msg->attribute;
return 0;
}
int
mu_message_set_attribute (mu_message_t msg, mu_attribute_t attribute, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->attribute)
mu_attribute_destroy (&msg->attribute, owner);
msg->attribute = attribute;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/stream.h>
#include <mailutils/sys/message.h>
int
mu_message_get_body (mu_message_t msg, mu_body_t *pbody)
{
if (msg == NULL)
return EINVAL;
if (pbody == NULL)
return MU_ERR_OUT_PTR_NULL;
/* Is it a floating mesg. */
if (msg->body == NULL)
{
mu_body_t body;
int status = mu_body_create (&body, msg);
if (status != 0)
return status;
/* If a stream is already set, use it to create the body stream. */
/* FIXME: I'm not sure if the second condition is really needed */
if (msg->stream/* && (msg->flags & MESSAGE_INTERNAL_STREAM)*/)
{
mu_stream_t stream;
int flags = 0;
/* FIXME: The actual mu_header_size cannot be used as offset,
because the headers might have been modified in between. */
mu_stream_get_flags (msg->stream, &flags);
status = mu_streamref_create_abridged (&stream, msg->stream,
msg->orig_header_size, 0);
if (status)
{
mu_body_destroy (&body, msg);
return status;
}
mu_body_set_stream (body, stream, msg);
}
msg->body = body;
}
*pbody = msg->body;
return 0;
}
int
mu_message_set_body (mu_message_t msg, mu_body_t body, void *owner)
{
if (msg == NULL )
return EINVAL;
if (msg->owner != owner)
return EACCES;
/* Make sure we destroy the old if it was owned by the mesg. */
/* FIXME: I do not know if somebody has already a ref on this ? */
if (msg->body)
mu_body_destroy (&msg->body, msg);
msg->body = body;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/sys/message.h>
int
mu_message_create_copy (mu_message_t *to, mu_message_t from)
{
int status = 0;
mu_stream_t fromstr = NULL;
mu_stream_t tmp = NULL;
if (!to)
return MU_ERR_OUT_PTR_NULL;
if (!from)
return EINVAL;
status = mu_memory_stream_create (&tmp, MU_STREAM_RDWR|MU_STREAM_SEEK);
if (status)
return status;
status = mu_message_get_streamref (from, &fromstr);
if (status)
{
mu_stream_destroy (&tmp);
return status;
}
status = mu_stream_copy (tmp, fromstr, 0, NULL);
if (status == 0)
{
status = mu_message_create (to, NULL);
if (status == 0)
mu_message_set_stream (*to, tmp, NULL);
}
if (status)
mu_stream_destroy (&tmp);
mu_stream_destroy (&fromstr);
return status;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/sys/message.h>
/* Allocate ressources for the mu_message_t. */
int
mu_message_create (mu_message_t *pmsg, void *owner)
{
mu_message_t msg;
int status;
if (pmsg == NULL)
return MU_ERR_OUT_PTR_NULL;
msg = calloc (1, sizeof (*msg));
if (msg == NULL)
return ENOMEM;
status = mu_monitor_create (&msg->monitor, 0, msg);
if (status != 0)
{
free (msg);
return status;
}
msg->owner = owner;
msg->ref_count = 1;
*pmsg = msg;
return 0;
}
void *
mu_message_get_owner (mu_message_t msg)
{
return (msg == NULL) ? NULL : msg->owner;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/envelope.h>
#include <mailutils/util.h>
#include <mailutils/header.h>
#include <mailutils/mu_auth.h>
#include <mailutils/address.h>
#include <mailutils/sys/message.h>
/* Message envelope */
static int
message_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
{
mu_message_t msg = mu_envelope_get_owner (envelope);
time_t t;
size_t n;
if (msg == NULL)
return EINVAL;
/* FIXME: extract the time from "Date:". */
if (buf == NULL || len == 0)
{
n = MU_ENVELOPE_DATE_LENGTH;
}
else
{
char tmpbuf[MU_ENVELOPE_DATE_LENGTH+1];
t = time (NULL);
n = mu_strftime (tmpbuf, sizeof tmpbuf,
MU_ENVELOPE_DATE_FORMAT, localtime (&t));
n = mu_cpystr (buf, tmpbuf, len);
}
if (pnwrite)
*pnwrite = n;
return 0;
}
static int
message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
{
mu_message_t msg = mu_envelope_get_owner (envelope);
mu_header_t header;
int status;
const char *sender;
struct mu_auth_data *auth = NULL;
static char *hdrnames[] = {
"X-Envelope-Sender",
"X-Envelope-From",
"X-Original-Sender",
"From",
NULL
};
mu_address_t address = NULL;
if (msg == NULL)
return EINVAL;
/* First, try the header */
status = mu_message_get_header (msg, &header);
if (status)
return status;
status = mu_header_sget_firstof (header, hdrnames, &sender, NULL);
if (status)
{
auth = mu_get_auth_by_uid (getuid ());
if (!auth)
return MU_ERR_NOENT;
sender = auth->name;
}
status = mu_address_create (&address, sender);
if (status == 0)
{
status = mu_address_sget_email (address, 1, &sender);
if (status == 0)
{
size_t n = strlen (sender);
if (buf && len > 0)
{
len--; /* One for the null. */
n = (n < len) ? n : len;
memcpy (buf, sender, n);
buf[n] = '\0';
}
if (pnwrite)
*pnwrite = n;
}
mu_address_destroy (&address);
}
if (auth)
mu_auth_data_free (auth);
return status;
}
int
mu_message_get_envelope (mu_message_t msg, mu_envelope_t *penvelope)
{
if (msg == NULL)
return EINVAL;
if (penvelope == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->envelope == NULL)
{
mu_envelope_t envelope;
int status = mu_envelope_create (&envelope, msg);
if (status != 0)
return status;
mu_envelope_set_sender (envelope, message_envelope_sender, msg);
mu_envelope_set_date (envelope, message_envelope_date, msg);
msg->envelope = envelope;
}
*penvelope = msg->envelope;
return 0;
}
int
mu_message_set_envelope (mu_message_t msg, mu_envelope_t envelope, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->envelope)
mu_envelope_destroy (&msg->envelope, msg);
msg->envelope = envelope;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/stream.h>
#include <mailutils/sys/message.h>
enum eoh_state
{
eoh_no,
eoh_maybe,
eoh_yes
};
/* Message header stuff */
static enum eoh_state
string_find_eoh (enum eoh_state eoh, const char *str, size_t len,
size_t *ppos)
{
size_t pos;
if (eoh == eoh_maybe && *str == '\n')
{
*ppos = 0;
return eoh_yes;
}
for (pos = 0; pos < len - 1; pos++)
if (str[pos] == '\n' && str[pos + 1] == '\n')
{
*ppos = pos + 1;
return eoh_yes;
}
*ppos = pos + 1;
return str[pos] == '\n' ? eoh_maybe : eoh_no;
}
#define MIN_HEADER_BUF_SIZE 2048
static int
_header_fill (mu_stream_t stream, char **pbuf, size_t *plen)
{
int status = 0;
char *buffer = NULL;
size_t bufsize = 0;
char inbuf[MIN_HEADER_BUF_SIZE];
size_t nread;
enum eoh_state eoh = eoh_no;
status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (status)
return status;
while (eoh != eoh_yes
&& (status = mu_stream_read (stream, inbuf, sizeof (inbuf), &nread))
== 0
&& nread)
{
char *nbuf;
size_t len;
eoh = string_find_eoh (eoh, inbuf, nread, &len);
nbuf = realloc (buffer, bufsize + len);
if (!nbuf)
{
status = ENOMEM;
break;
}
memcpy (nbuf + bufsize, inbuf, len);
buffer = nbuf;
bufsize += len;
}
if (status)
free (buffer);
else
{
*pbuf = buffer;
*plen = bufsize;
}
return status;
}
static int
message_header_fill (void *data, char **pbuf, size_t *plen)
{
int status = 0;
mu_message_t msg = data;
mu_stream_t stream;
status = mu_message_get_streamref (msg, &stream);
if (status == 0)
{
status = _header_fill (stream, pbuf, plen);
mu_stream_destroy (&stream);
}
return status;
}
int
mu_message_get_header (mu_message_t msg, mu_header_t *phdr)
{
if (msg == NULL)
return EINVAL;
if (phdr == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->header == NULL)
{
mu_header_t header;
int status = mu_header_create (&header, NULL, 0);
if (status != 0)
return status;
if (msg->stream)
mu_header_set_fill (header, message_header_fill, msg);
status = mu_header_size (header, &msg->orig_header_size);
if (status)
return status;
msg->header = header;
}
*phdr = msg->header;
return 0;
}
/* Note: mu_message_set_header steals the reference to hdr */
int
mu_message_set_header (mu_message_t msg, mu_header_t hdr, void *owner)
{
if (msg == NULL )
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->header)
mu_header_destroy (&msg->header);
msg->header = hdr;
msg->flags |= MESSAGE_MODIFIED;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/sys/message.h>
int
mu_message_lines (mu_message_t msg, size_t *plines)
{
size_t hlines, blines;
int ret = 0;
if (msg == NULL)
return EINVAL;
/* Overload. */
if (msg->_lines)
return msg->_lines (msg, plines, 0);
if (plines)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hlines = blines = 0;
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;
}
int
mu_message_set_lines (mu_message_t msg, int (*_lines)
(mu_message_t, size_t *, int), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_lines = _lines;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/sys/message.h>
int
mu_message_get_mailbox (mu_message_t msg, mu_mailbox_t *pmailbox)
{
if (msg == NULL)
return EINVAL;
if (pmailbox == NULL)
return MU_ERR_OUT_PTR_NULL;
*pmailbox = msg->mailbox;
return 0;
}
int
mu_message_set_mailbox (mu_message_t msg, mu_mailbox_t mailbox, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->mailbox = mailbox;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/attribute.h>
#include <mailutils/body.h>
#include <mailutils/sys/message.h>
int
mu_message_is_modified (mu_message_t msg)
{
int mod = 0;
if (msg)
{
if (mu_header_is_modified (msg->header))
mod |= MU_MSG_HEADER_MODIFIED;
if (mu_attribute_is_modified (msg->attribute))
mod |= MU_MSG_ATTRIBUTE_MODIFIED;
if (mu_body_is_modified (msg->body))
mod |= MU_MSG_BODY_MODIFIED;
if (msg->flags & MESSAGE_MODIFIED)
mod |= MU_MSG_BODY_MODIFIED | MU_MSG_HEADER_MODIFIED;
}
return mod;
}
int
mu_message_clear_modified (mu_message_t msg)
{
if (msg)
{
if (msg->header)
mu_header_clear_modified (msg->header);
if (msg->attribute)
mu_attribute_clear_modified (msg->attribute);
if (msg->body)
mu_body_clear_modified (msg->body);
msg->flags &= ~MESSAGE_MODIFIED;
}
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/mime.h>
#include <mailutils/errno.h>
#include <mailutils/sys/message.h>
int
mu_message_is_multipart (mu_message_t msg, int *pmulti)
{
if (msg && pmulti)
{
if (msg->_is_multipart)
return msg->_is_multipart (msg, pmulti);
if (msg->mime == NULL)
{
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);
}
return 0;
}
int
mu_message_set_is_multipart (mu_message_t msg,
int (*_is_multipart) (mu_message_t, int *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_is_multipart = _is_multipart;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/mime.h>
#include <mailutils/errno.h>
#include <mailutils/sys/message.h>
int
mu_message_get_num_parts (mu_message_t msg, size_t *pparts)
{
if (msg == NULL || pparts == NULL)
return EINVAL;
if (msg->_get_num_parts)
return msg->_get_num_parts (msg, pparts);
if (msg->mime == NULL)
{
int status = mu_mime_create (&msg->mime, msg, 0);
if (status != 0)
return status;
}
return mu_mime_get_num_parts (msg->mime, pparts);
}
int
mu_message_set_get_num_parts (mu_message_t msg,
int (*_get_num_parts) (mu_message_t, size_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_num_parts = _get_num_parts;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/observer.h>
#include <mailutils/sys/message.h>
int
mu_message_get_observable (mu_message_t msg, mu_observable_t *pobservable)
{
if (msg == NULL || pobservable == NULL)
return EINVAL;
if (msg->observable == NULL)
{
int status = mu_observable_create (&msg->observable, msg);
if (status != 0)
return status;
}
*pobservable = msg->observable;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/sys/message.h>
int
mu_message_get_part (mu_message_t msg, size_t part, mu_message_t *pmsg)
{
if (msg == NULL || pmsg == NULL)
return EINVAL;
/* Overload. */
if (msg->_get_part)
return msg->_get_part (msg, part, pmsg);
if (msg->mime == NULL)
{
int status = mu_mime_create (&msg->mime, msg, 0);
if (status != 0)
return status;
}
return mu_mime_get_part (msg->mime, part, pmsg);
}
int
mu_message_set_get_part (mu_message_t msg, int (*_get_part)
(mu_message_t, size_t, mu_message_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_part = _get_part;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/sys/message.h>
int
mu_message_get_qid (mu_message_t msg, mu_message_qid_t *pqid)
{
if (msg == NULL)
return EINVAL;
if (!msg->_get_qid)
return ENOSYS;
return msg->_get_qid (msg, pqid);
}
int
mu_message_set_qid (mu_message_t msg,
int (*_get_qid) (mu_message_t, mu_message_qid_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_qid = _get_qid;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/sys/message.h>
/* Return the number of lines in the message, without going into
excess trouble for calculating it. If obtaining the result
means downloading the entire message (as is the case for POP3,
for example), return MU_ERR_INFO_UNAVAILABLE. */
int
mu_message_quick_lines (mu_message_t msg, size_t *plines)
{
size_t hlines, blines;
int rc;
if (msg == NULL)
return EINVAL;
/* Overload. */
if (msg->_lines)
{
int rc = msg->_lines (msg, plines, 1);
if (rc != ENOSYS)
return rc;
}
if (plines)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hlines = blines = 0;
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;
}
return rc;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/monitor.h>
#include <mailutils/observer.h>
#include <mailutils/envelope.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/attribute.h>
#include <mailutils/stream.h>
#include <mailutils/sys/message.h>
void
mu_message_ref (mu_message_t msg)
{
if (msg)
{
mu_monitor_wrlock (msg->monitor);
msg->ref_count++;
mu_monitor_unlock (msg->monitor);
}
}
/* 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_unref (mu_message_t msg)
{
if (msg)
{
mu_monitor_t monitor = msg->monitor;
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_count > 0)
msg->ref_count--;
if (msg->ref_count == 0)
{
_mu_message_free (msg);
mu_monitor_unlock (monitor);
mu_monitor_destroy (&monitor, msg);
}
else
mu_monitor_unlock (monitor);
}
}
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);
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);
}
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <mailutils/types.h>
#include <mailutils/diag.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/mailbox.h>
#include <mailutils/message.h>
#include <mailutils/stream.h>
int
mu_message_save_to_mailbox (mu_message_t msg, const char *toname, int perms)
{
int rc = 0;
mu_mailbox_t to = 0;
if ((rc = mu_mailbox_create_default (&to, toname)))
{
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_create_default (%s) failed: %s\n", toname,
mu_strerror (rc)));
goto end;
}
if ((rc = mu_mailbox_open (to,
MU_STREAM_WRITE | MU_STREAM_CREAT
| (perms & MU_STREAM_IMASK))))
{
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_open (%s) failed: %s", toname,
mu_strerror (rc)));
goto end;
}
if ((rc = mu_mailbox_append_message (to, msg)))
{
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_append_message (%s) failed: %s", toname,
mu_strerror (rc)));
goto end;
}
end:
if (!rc)
{
if ((rc = mu_mailbox_close (to)))
mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
("mu_mailbox_close (%s) failed: %s", toname,
mu_strerror (rc)));
}
else
mu_mailbox_close (to);
mu_mailbox_destroy (&to);
return rc;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/sys/message.h>
int
mu_message_size (mu_message_t msg, size_t *psize)
{
size_t hsize, bsize;
int ret = 0;
if (msg == NULL)
return EINVAL;
/* Overload ? */
if (msg->_size)
return msg->_size (msg, psize);
if (psize)
{
mu_header_t hdr = NULL;
mu_body_t body = NULL;
hsize = bsize = 0;
mu_message_get_header (msg, &hdr);
mu_message_get_body (msg, &body);
if ( ( ret = mu_header_size (hdr, &hsize) ) == 0 )
ret = mu_body_size (body, &bsize);
*psize = hsize + bsize;
}
return ret;
}
int
mu_message_set_size (mu_message_t msg, int (*_size)
(mu_message_t, size_t *), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_size = _size;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/header.h>
#include <mailutils/body.h>
#include <mailutils/sys/message.h>
#include <mailutils/sys/stream.h>
/* Message stream */
enum _message_stream_state
{
_mss_init,
_mss_header,
_mss_body,
_mss_eof
};
struct _mu_message_stream
{
struct _mu_stream stream;
mu_message_t msg;
enum _message_stream_state state;
mu_stream_t transport;
mu_off_t limit;
};
static int
_check_stream_state (struct _mu_message_stream *str)
{
int rc = 0;
if (str->transport && mu_stream_eof (str->transport))
mu_stream_destroy (&str->transport);
switch (str->state)
{
case _mss_init:
if (!str->transport)
{
rc = mu_header_get_streamref (str->msg->header, &str->transport);
if (rc == 0)
{
str->state = _mss_header;
rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
}
}
break;
case _mss_header:
if (!str->transport)
{
rc = mu_body_get_streamref (str->msg->body, &str->transport);
if (rc == 0)
{
str->state = _mss_body;
rc = mu_stream_seek (str->transport, 0, MU_SEEK_SET, NULL);
}
}
break;
case _mss_body:
if (!str->transport)
str->state = _mss_eof;
case _mss_eof:
break;
}
return rc;
}
static void
_message_stream_done (struct _mu_stream *str)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
mu_stream_destroy (&sp->transport);
}
static int
_message_stream_flush (struct _mu_stream *str)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
int rc = _check_stream_state (sp);
if (rc)
return rc;
return mu_stream_flush (sp->transport);
}
static int
_message_stream_size (struct _mu_stream *str, mu_off_t *psize)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t hsize, bsize;
mu_header_size (sp->msg->header, &hsize);
mu_body_size (sp->msg->body, &bsize);
if (psize)
*psize = hsize + bsize;
return 0;
}
static int
_message_stream_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t hsize, size;
int rc;
rc = _check_stream_state (sp);
if (rc)
return rc;
mu_header_size (sp->msg->header, &hsize);
mu_body_size (sp->msg->body, &size);
if (off < 0 || off >= size + hsize)
return ESPIPE;
switch (sp->state)
{
case _mss_eof:
sp->state = _mss_init;
rc = _check_stream_state (sp);
if (rc)
return rc;
/* fall through */
case _mss_header:
if (off < hsize)
break;
mu_stream_destroy (&sp->transport);
rc = _check_stream_state (sp);
if (rc)
return rc;
/* fall through */
case _mss_body:
if (off > hsize)
off -= hsize;
else
{
mu_stream_destroy (&sp->transport);
sp->state = _mss_init;
rc = _check_stream_state (sp);
if (rc)
return rc;
}
break;
default:
break;
}
rc = mu_stream_seek (sp->transport, off, MU_SEEK_SET, &off);
if (rc == 0)
{
if (sp->state == _mss_body)
off += hsize;
*ppos = off;
}
return rc;
}
static int
_message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize,
size_t *pnread)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t nread = 0;
int rc;
while (bufsize)
{
size_t n;
rc = _check_stream_state (sp);
if (rc)
break;
if (sp->state == _mss_eof)
break;
rc = mu_stream_read (sp->transport, buf, bufsize, &n);
if (rc)
break;
if (n == 0)
continue;
nread += n;
buf += n;
bufsize -= n;
}
*pnread = nread;
return rc;
}
static int
_message_stream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
int delim, size_t *pnread)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
size_t nread = 0;
int rc;
while (bufsize)
{
size_t n;
rc = _check_stream_state (sp);
if (rc)
break;
if (sp->state == _mss_eof)
break;
rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &n);
if (rc)
break;
if (n == 0)
continue;
nread += n;
if (buf[n-1] == delim)
break;
buf += n;
bufsize -= n;
}
*pnread = nread;
return rc;
}
#if 0
static int
_message_stream_write (struct _mu_stream *str,
const char *buf, size_t bufsize,
size_t *pnwritten)
{
struct _mu_message_stream *sp = (struct _mu_message_stream *)str;
/* FIXME */
}
#endif
static int
_message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags)
{
struct _mu_message_stream *sp;
sp = (struct _mu_message_stream *) _mu_stream_create (sizeof (*sp),
flags |
MU_STREAM_SEEK |
_MU_STR_OPEN);
if (!sp)
return ENOMEM;
sp->stream.read = _message_stream_read;
sp->stream.readdelim = _message_stream_readdelim;
/* FIXME: Write is not defined */
/* sp->stream.write = _message_stream_write;*/
sp->stream.done = _message_stream_done;
sp->stream.flush = _message_stream_flush;
sp->stream.seek = _message_stream_seek;
sp->stream.size = _message_stream_size;
sp->state = _mss_init;
sp->msg = msg;
*pmsg = (mu_stream_t) sp;
return 0;
}
int
mu_message_set_stream (mu_message_t msg, mu_stream_t stream, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
if (msg->stream)
mu_stream_destroy (&msg->stream);
msg->stream = stream;
msg->flags |= MESSAGE_MODIFIED;
msg->flags &= ~MESSAGE_INTERNAL_STREAM;
return 0;
}
static int
_message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
{
int status;
if (msg == NULL)
return EINVAL;
if (pstream == NULL)
return MU_ERR_OUT_PTR_NULL;
if (msg->stream == NULL)
{
if (msg->_get_stream)
{
status = msg->_get_stream (msg, &msg->stream);
if (status)
return status;
}
else
{
mu_header_t hdr;
mu_body_t body;
/* FIXME: Kind of a kludge: make sure the message has header
and body initialized. */
status = mu_message_get_header (msg, &hdr);
if (status)
return status;
status = mu_message_get_body (msg, &body);
if (status)
return status;
status = _message_stream_create (&msg->stream, msg, MU_STREAM_RDWR);
if (status)
return status;
msg->flags |= MESSAGE_INTERNAL_STREAM;
}
}
if (!ref)
{
*pstream = msg->stream;
return 0;
}
return mu_streamref_create (pstream, msg->stream);
}
int
mu_message_get_stream (mu_message_t msg, mu_stream_t *pstream)
{
/* FIXME: Deprecation warning */
return _message_get_stream (msg, pstream, 0);
}
int
mu_message_get_streamref (mu_message_t msg, mu_stream_t *pstream)
{
return _message_get_stream (msg, pstream, 1);
}
int
mu_message_set_get_stream (mu_message_t msg,
int (*_getstr) (mu_message_t, mu_stream_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_stream = _getstr;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/sys/message.h>
int
mu_message_get_uid (mu_message_t msg, size_t *puid)
{
if (msg == NULL)
return EINVAL;
if (msg->_get_uid)
return msg->_get_uid (msg, puid);
*puid = 0;
return 0;
}
int
mu_message_set_uid (mu_message_t msg, int (*_get_uid) (mu_message_t, size_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_uid = _get_uid;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2009,
2010, 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/>. */
#include <config.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <mailutils/types.h>
#include <mailutils/message.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/stream.h>
#include <mailutils/md5.h>
#include <mailutils/sys/message.h>
int
mu_message_get_uidl (mu_message_t msg, char *buffer, size_t buflen,
size_t *pwriten)
{
mu_header_t header = NULL;
size_t n = 0;
int status;
if (msg == NULL || buffer == NULL || buflen == 0)
return EINVAL;
buffer[0] = '\0';
/* Try the function overload if error fallback. */
if (msg->_get_uidl)
{
status = msg->_get_uidl (msg, buffer, buflen, pwriten);
if (status == 0)
return status;
}
/* Be compatible with Qpopper ? qppoper saves the UIDL in "X-UIDL".
We generate a chksum and save it in the header. */
mu_message_get_header (msg, &header);
status = mu_header_get_value_unfold (header, "X-UIDL", buffer, buflen, &n);
if (status != 0 || n == 0)
{
size_t uid = 0;
struct mu_md5_ctx md5context;
mu_stream_t stream = NULL;
char buf[1024];
unsigned char md5digest[16];
char *tmp;
n = 0;
mu_message_get_uid (msg, &uid);
mu_message_get_streamref (msg, &stream);
mu_md5_init_ctx (&md5context);
status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (status == 0)
{
while (mu_stream_read (stream, buf, sizeof (buf), &n) == 0
&& n > 0)
mu_md5_process_bytes (buf, n, &md5context);
mu_md5_finish_ctx (&md5context, md5digest);
tmp = buf;
for (n = 0; n < 16; n++, tmp += 2)
sprintf (tmp, "%02x", md5digest[n]);
*tmp = '\0';
/* POP3 rfc says that an UID should not be longer than 70. */
snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL),
(unsigned long) uid);
mu_header_set_value (header, "X-UIDL", buf, 1);
buflen--; /* leave space for the NULL. */
strncpy (buffer, buf, buflen)[buflen] = '\0';
}
mu_stream_destroy (&stream);
}
return status;
}
int
mu_message_set_uidl (mu_message_t msg,
int (* _get_uidl) (mu_message_t, char *, size_t, size_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_uidl = _get_uidl;
return 0;
}