Commit 6301266f 6301266fabab03f0e1dfcab76e7b6fc1e6eda1c6 by Sergey Poznyakoff

imap client: implement CREATE and APPEND. Fix APPEND in imap4d.

* imap4d/append.c (imap4d_append0): Use
mu_message_from_stream_with_envelope with crafted envelope.  The effect is
that the envelope of the message always reflects the actual sender, as
deduced from the header (X-Envelope-Sender, Sender, From, in that order)
and the date given with the APPEND command (or current date/time, if not
given).
* imap4d/tests/append00.at: Reflect changes in the envelope.
* imap4d/tests/append01.at: Likewise.
* imap4d/io.c (io_format_completion_response): Call imap4d_sync to
emit eventual non-tagged responses before the tagged one.

* include/mailutils/envelope.h (mu_envelope_set_destroy): New proto.
* include/mailutils/header.h (MU_HEADER_SENDER): Remove duplicate define.
* include/mailutils/imap.h (mu_imap_mailbox_create)
(mu_imap_append_stream_size,mu_imap_append_stream)
(mu_imap_append_message,mu_imapio_send_flags)
(mu_imapio_send_time): New protos.
* include/mailutils/imapio.h (mu_imapio_send_literal): Remove proto.
(mu_imapio_send_literal_string)
(mu_imapio_send_literal_stream): New protos.
* include/mailutils/message.h
(mu_message_from_stream_with_envelope): New proto.
* include/mailutils/sys/imap.h (MU_IMAP_CLIENT_APPEND_RX): New state.
* include/mailutils/sys/message_stream.h (_mu_message_stream)
<envelope>: Rename to envelope_string.
<construct_envelope>: New member.

* libmailutils/imapio/literal.c: Remove.
* libmailutils/imapio/litstream.c: New file.
* libmailutils/imapio/litstring.c: New file.
* libmailutils/imapio/time.c: New file.
* libmailutils/imapio/Makefile.am: Add new files.
* libmailutils/imapio/flags.c (mu_imapio_send_flags): New function.
* libmailutils/imapio/qstring.c (mu_imapio_send_qstring_unfold): Use
mu_imapio_send_literal_string.

* libmailutils/mailbox/envelope.c (mu_envelope_set_destroy): New
function.
* libmailutils/stream/message_stream.c
(mu_message_from_stream_with_envelope): New function.
(mu_stream_to_message): Rewrite as an alternative entry point to the
above.

* libproto/imap/Makefile.am: Add new files.
* libproto/imap/appmsg.c: New file.
* libproto/imap/appstr.c: New file.
* libproto/imap/appstrsiz.c: New file.
* libproto/imap/mbcreate.c: New file.

* mu/imap.c: Implement create and append.
1 parent 5357fe73
......@@ -17,46 +17,68 @@
#include "imap4d.h"
struct _temp_envelope
{
struct tm tm;
mu_timezone tz;
char *sender;
};
static int
_append_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite)
_temp_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
{
mu_message_t msg = mu_envelope_get_owner (envelope);
size_t size;
struct _temp_envelope *tenv = mu_envelope_get_owner (envelope);
int rc;
mu_stream_t str;
mu_stream_stat_buffer stat;
if (!buf)
size = MU_ENVELOPE_DATE_LENGTH;
{
if (!pnwrite)
return MU_ERR_OUT_PTR_NULL;
rc = mu_nullstream_create (&str, MU_STREAM_WRITE);
}
else
rc = mu_fixed_memory_stream_create (&str, buf, len, MU_STREAM_WRITE);
if (rc)
return rc;
mu_stream_set_stat (str, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT), stat);
rc = mu_c_streamftime (str, MU_DATETIME_FROM, &tenv->tm, &tenv->tz);
if (rc == 0)
{
struct tm **tm = mu_message_get_owner (msg);
size = mu_strftime (buf, len, "%a %b %d %H:%M:%S %Y", *tm);
mu_stream_flush (str);
if (pnwrite)
*pnwrite = stat[MU_STREAM_STAT_OUT];
rc = mu_stream_write (str, "", 1, NULL);
}
if (pnwrite)
*pnwrite = size;
mu_stream_unref (str);
if (rc)
return rc;
return 0;
}
static int
_append_sender (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite)
_temp_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
{
size_t n = mu_cpystr (buf, "GNU-imap4d", len);
struct _temp_envelope *tenv = mu_envelope_get_owner (envelope);
size_t n = mu_cpystr (buf, tenv->sender, len);
if (pnwrite)
*pnwrite = n;
*pnwrite = n;
return 0;
}
/* FIXME: Why not use mu_message_size instead? */
static int
_append_size (mu_message_t msg, size_t *psize)
_temp_envelope_destroy (mu_envelope_t envelope)
{
mu_stream_t str;
int status = mu_message_get_stream (msg, &str);
if (status == 0)
{
mu_off_t size;
status = mu_stream_size (str, &size);
if (status == 0 && psize)
*psize = size;
}
return status;
struct _temp_envelope *tenv = mu_envelope_get_owner (envelope);
free (tenv->sender);
return 0;
}
int
......@@ -66,65 +88,84 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
mu_stream_t stream;
int rc = 0;
mu_message_t msg = 0;
struct tm *tm;
time_t t;
mu_envelope_t env;
mu_envelope_t env = NULL;
size_t size;
if (mu_message_create (&msg, &tm))
return 1;
struct _temp_envelope tenv;
memset (&tenv, 0, sizeof (tenv));
text = mu_str_skip_class (text, MU_CTYPE_BLANK);
size = strlen (text);
rc = quota_check (size);
if (rc != RESP_OK)
{
*err_text = rc == RESP_NO ?
"Mailbox quota exceeded" : "Operation failed";
return 1;
}
/* If a date_time is specified, the internal date SHOULD be set in the
resulting message; otherwise, the internal date of the resulting
message is set to the current date and time by default. */
if (date_time)
{
if (util_parse_internal_date (date_time, &t, datetime_default))
if (mu_scan_datetime (date_time, MU_DATETIME_INTERNALDATE, &tenv.tm,
&tenv.tz, NULL))
{
*err_text = "Invalid date/time format";
return 1;
}
rc = mu_envelope_create (&env, &tenv);
if (rc)
return rc;
mu_envelope_set_date (env, _temp_envelope_date, &tenv);
mu_envelope_set_sender (env, _temp_envelope_sender, &tenv);
mu_envelope_set_destroy (env, _temp_envelope_destroy, &tenv);
}
else
time (&t);
tm = gmtime (&t);
text = mu_str_skip_class (text, MU_CTYPE_BLANK);
if (mu_static_memory_stream_create (&stream, text, strlen (text)))
if (mu_static_memory_stream_create (&stream, text, size))
{
mu_message_destroy (&msg, &tm);
if (env)
mu_envelope_destroy (&env, mu_envelope_get_owner (env));
return 1;
}
rc = mu_message_from_stream_with_envelope (&msg, stream, env);
mu_stream_unref (stream);
mu_message_set_stream (msg, stream, &tm);
mu_message_set_size (msg, _append_size, &tm);
mu_envelope_create (&env, msg);
mu_envelope_set_date (env, _append_date, msg);
mu_envelope_set_sender (env, _append_sender, msg);
mu_message_set_envelope (msg, env, &tm);
rc = _append_size (msg, &size);
if (rc)
{
mu_diag_output (MU_DIAG_NOTICE,
_("cannot compute size of the message being appended; "
"using estimated value: %s"),
mu_strerror (rc));
/* raw estimate */
size = strlen (text);
}
rc = quota_check (size);
if (rc != RESP_OK)
{
*err_text = rc == RESP_NO ?
"Mailbox quota exceeded" : "Operation failed";
mu_message_destroy (&msg, &tm);
if (env)
mu_envelope_destroy (&env, mu_envelope_get_owner (env));
return 1;
}
if (env)
{
/* Restore sender */
mu_header_t hdr = NULL;
char *val;
mu_message_get_header (msg, &hdr);
if (mu_header_aget_value_unfold (hdr, MU_HEADER_ENV_SENDER, &val) == 0 ||
mu_header_aget_value_unfold (hdr, MU_HEADER_SENDER, &val) == 0 ||
mu_header_aget_value_unfold (hdr, MU_HEADER_FROM, &val) == 0)
{
mu_address_t addr;
rc = mu_address_create (&addr, val);
free (val);
if (rc == 0)
{
mu_address_aget_email (addr, 1, &tenv.sender);
mu_address_destroy (&addr);
}
}
if (!tenv.sender)
tenv.sender = strdup ("GNU-imap4d");
}
imap4d_enter_critical ();
rc = mu_mailbox_append_message (mbox, msg);
if (rc == 0)
......@@ -143,7 +184,10 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
}
imap4d_leave_critical ();
mu_message_destroy (&msg, &tm);
mu_message_unref (msg);
if (env)
mu_envelope_destroy (&env, mu_envelope_get_owner (env));
return rc;
}
......
......@@ -235,6 +235,8 @@ io_format_completion_response (mu_stream_t str,
int status = 0;
const char *sc = sc2string (rc);
imap4d_sync ();
mu_stream_printf (str, "%s %s%s ",
command->tag, sc, command->name);
mu_stream_vprintf (str, format, ap);
......
......@@ -44,7 +44,7 @@ awk 'NR==1 {print "1:",$1,$2; next} NF==0 {print NR":"; next} {print NR":",$0}'
* BYE Session terminating.
X OK LOGOUT Completed
==
1: From GNU-imap4d
1: From foobar@Blurdybloop.COM
2: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
3: From: Fred Foobar <foobar@Blurdybloop.COM>
4: Subject: afternoon meeting
......
......@@ -44,7 +44,7 @@ awk 'NF==0 {print NR":"; next} {print NR":",$0}' mbox
* BYE Session terminating.
X OK LOGOUT Completed
==
1: From GNU-imap4d Sun Aug 25 16:00:00 2002
1: From foobar@Blurdybloop.COM Sun Aug 25 18:00:00 2002
2: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
3: From: Fred Foobar <foobar@Blurdybloop.COM>
4: Subject: afternoon meeting again
......
......@@ -47,6 +47,9 @@ int mu_envelope_set_date (mu_envelope_t,
int (*_date) (mu_envelope_t, char *, size_t ,
size_t *),
void *);
int mu_envelope_set_destroy (mu_envelope_t envelope,
int (*_destroy) (mu_envelope_t),
void *owner);
/* mu_strftime format for envelope dates */
#define MU_ENVELOPE_DATE_FORMAT "%a %b %d %H:%M:%S %Y"
......
......@@ -34,7 +34,6 @@ extern "C" {
#define MU_HEADER_SENDER "Sender"
#define MU_HEADER_RESENT_FROM "Resent-From"
#define MU_HEADER_SUBJECT "Subject"
#define MU_HEADER_SENDER "Sender"
#define MU_HEADER_RESENT_SENDER "Resent-Sender"
#define MU_HEADER_TO "To"
#define MU_HEADER_RESENT_TO "Resent-To"
......
......@@ -87,6 +87,18 @@ int mu_imap_close (mu_imap_t imap);
int mu_imap_unselect (mu_imap_t imap);
int mu_imap_expunge (mu_imap_t imap);
int mu_imap_mailbox_create (mu_imap_t imap, const char *mailbox);
int mu_imap_append_stream_size (mu_imap_t imap, const char *mailbox, int flags,
struct tm *tm, struct mu_timezone *tz,
mu_stream_t stream, mu_off_t size);
int mu_imap_append_stream (mu_imap_t imap, const char *mailbox, int flags,
struct tm *tm, struct mu_timezone *tz,
mu_stream_t stream);
int mu_imap_append_message (mu_imap_t imap, const char *mailbox, int flags,
struct tm *tm, struct mu_timezone *tz,
mu_message_t msg);
int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier);
int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier);
......
......@@ -22,6 +22,8 @@ extern "C" {
#endif
# include <mailutils/types.h>
# include <mailutils/util.h>
# include <time.h>
#define MU_IMAPIO_CLIENT 0
#define MU_IMAPIO_SERVER 1
......@@ -36,11 +38,17 @@ int mu_imapio_get_words (mu_imapio_t io, size_t *pwc, char ***pwv);
int mu_imapio_send (mu_imapio_t io, const char *buf, size_t bytes);
int mu_imapio_printf (mu_imapio_t io, const char *fmt, ...);
int mu_imapio_send_literal (struct _mu_imapio *io, const char *buffer);
int mu_imapio_send_literal_string (struct _mu_imapio *io, const char *buffer);
int mu_imapio_send_literal_stream (struct _mu_imapio *io, mu_stream_t stream,
mu_off_t size);
int mu_imapio_send_qstring (struct _mu_imapio *io, const char *buffer);
int mu_imapio_send_qstring_unfold (struct _mu_imapio *io, const char *buffer,
int unfold);
int mu_imapio_send_flags (struct _mu_imapio *io, int flags);
int mu_imapio_send_time (struct _mu_imapio *io, struct tm *tm,
struct mu_timezone *tz);
int mu_imapio_trace_enable (mu_imapio_t io);
int mu_imapio_trace_disable (mu_imapio_t io);
int mu_imapio_get_trace (mu_imapio_t io);
......
......@@ -196,6 +196,9 @@ extern int mu_message_save_to_mailbox (mu_message_t msg, const char *toname,
int perms);
extern int mu_message_from_stream_with_envelope (mu_message_t *pmsg,
mu_stream_t instream,
mu_envelope_t env);
extern int mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg);
......
......@@ -65,6 +65,7 @@ enum mu_imap_client_state
MU_IMAP_CLIENT_CHECK_RX,
MU_IMAP_CLIENT_COPY_RX,
MU_IMAP_CLIENT_EXPUNGE_RX,
MU_IMAP_CLIENT_APPEND_RX,
MU_IMAP_CLIENT_CLOSING
};
......
......@@ -25,7 +25,8 @@ struct _mu_message_stream
mu_stream_t transport; /* Actual stream */
mu_off_t offset;
char *envelope;
int construct_envelope;
char *envelope_string;
size_t envelope_length;
char *from;
char *date;
......
......@@ -21,11 +21,13 @@ libimapio_la_SOURCES = \
create.c\
flags.c\
getline.c\
literal.c\
litstream.c\
litstring.c\
printf.c\
qstring.c\
replstr.c\
send.c\
time.c\
trace.c\
words.c\
xscript.c
......
......@@ -83,3 +83,17 @@ mu_imap_format_flags (mu_stream_t str, int flags)
return 0;
}
int
mu_imapio_send_flags (struct _mu_imapio *io, int flags)
{
int rc;
rc = mu_stream_write (io->_imap_stream, "(", 1, NULL);
if (rc)
return rc;
rc = mu_imap_format_flags (io->_imap_stream, flags);
if (rc == 0)
rc = mu_stream_write (io->_imap_stream, ")", 1, NULL);
return rc;
}
......
/* 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/>. */
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imapio.h>
#include <mailutils/stream.h>
int
mu_imapio_send_literal_stream (struct _mu_imapio *io, mu_stream_t stream,
mu_off_t len)
{
mu_stream_printf (io->_imap_stream, "{%lu}\r\n", (unsigned long) len);
if (!io->_imap_server)
{
int rc = mu_imapio_getline (io);
if (rc)
return rc;
if (!(io->_imap_reply_ready && io->_imap_ws.ws_wordv[0][0] == '+'))
return MU_ERR_BADREPLY;
}
return mu_stream_copy (io->_imap_stream, stream, len, NULL);
}
......@@ -24,11 +24,11 @@
#include <mailutils/stream.h>
int
mu_imapio_send_literal (struct _mu_imapio *io, const char *buffer)
mu_imapio_send_literal_string (struct _mu_imapio *io, const char *buffer)
{
size_t len = strlen (buffer);
mu_stream_printf (io->_imap_stream, "{%lu}\n", (unsigned long) len);
mu_stream_printf (io->_imap_stream, "{%lu}\r\n", (unsigned long) len);
if (!io->_imap_server)
{
......
......@@ -60,7 +60,7 @@ mu_imapio_send_qstring_unfold (struct _mu_imapio *io, const char *buffer,
}
}
else
return mu_imapio_send_literal (io, buffer);
return mu_imapio_send_literal_string (io, buffer);
}
return mu_imapio_printf (io, "\"%s\"", buffer);
}
......
/* 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/stream.h>
#include <mailutils/errno.h>
#include <mailutils/sys/imapio.h>
#include <mailutils/util.h>
int
mu_imapio_send_time (struct _mu_imapio *io, struct tm *tm,
struct mu_timezone *tz)
{
return mu_c_streamftime (io->_imap_stream,
"\"" MU_DATETIME_INTERNALDATE "\"", tm, tz);
}
......@@ -91,6 +91,19 @@ mu_envelope_set_date (mu_envelope_t envelope,
return 0;
}
int
mu_envelope_set_destroy (mu_envelope_t envelope,
int (*_destroy) (mu_envelope_t),
void *owner)
{
if (envelope == NULL)
return EINVAL;
if (envelope->owner != owner)
return EACCES;
envelope->_destroy = _destroy;
return 0;
}
/* General accessors: */
#define AC2(a,b) a ## b
......
......@@ -187,30 +187,33 @@ _message_open (mu_stream_t stream)
{
if (offset == 0 && memcmp (buffer, "From ", 5) == 0)
{
char *s, *p;
str->envelope_length = len;
str->envelope = mu_strdup (buffer);
if (!str->envelope)
return ENOMEM;
str->envelope[len - 1] = 0;
s = str->envelope + 5;
p = strchr (s, ' ');
if (p)
if (str->construct_envelope)
{
size_t n = p - s;
env_from = mu_alloc (n + 1);
if (!env_from)
char *s, *p;
str->envelope_string = mu_strdup (buffer);
if (!str->envelope_string)
return ENOMEM;
memcpy (env_from, s, n);
env_from[n] = 0;
env_date = mu_strdup (p + 1);
if (!env_date)
str->envelope_string[len - 1] = 0;
s = str->envelope_string + 5;
p = strchr (s, ' ');
if (p)
{
free (env_from);
return ENOMEM;
size_t n = p - s;
env_from = mu_alloc (n + 1);
if (!env_from)
return ENOMEM;
memcpy (env_from, s, n);
env_from[n] = 0;
env_date = mu_strdup (p + 1);
if (!env_date)
{
free (env_from);
return ENOMEM;
}
}
}
}
......@@ -233,7 +236,7 @@ _message_open (mu_stream_t stream)
return MU_ERR_INVALID_EMAIL;
}
has_headers = 1;
if (!env_from || !env_date)
if (str->construct_envelope && (!env_from || !env_date))
{
if (!from && mu_c_strncasecmp (buffer, MU_HEADER_FROM,
sizeof (MU_HEADER_FROM) - 1) == 0)
......@@ -263,40 +266,43 @@ _message_open (mu_stream_t stream)
if (rc)
return rc;
if (!env_from)
if (str->construct_envelope)
{
if (from)
if (!env_from)
{
mu_address_t addr;
mu_address_create (&addr, from);
if (addr)
if (from)
{
mu_address_aget_email (addr, 1, &env_from);
mu_address_destroy (&addr);
mu_address_t addr;
mu_address_create (&addr, from);
if (addr)
{
mu_address_aget_email (addr, 1, &env_from);
mu_address_destroy (&addr);
}
}
}
if (!env_from)
env_from = mu_get_user_email (NULL);
if (!env_from)
env_from = mu_get_user_email (NULL);
}
free (from);
if (!env_date)
{
struct tm *tm;
time_t t;
char date[80]; /* FIXME: This size is way too big */
time(&t);
tm = gmtime(&t);
mu_strftime (date, sizeof (date), "%a %b %e %H:%M:%S %Y", tm);
env_date = strdup (date);
}
str->from = env_from;
str->date = env_date;
}
free (from);
if (!env_date)
{
struct tm *tm;
time_t t;
char date[80]; /* FIXME: This size is way too big */
time(&t);
tm = gmtime(&t);
mu_strftime (date, sizeof (date), "%a %b %e %H:%M:%S %Y", tm);
env_date = strdup (date);
}
str->from = env_from;
str->date = env_date;
str->body_start = body_start;
str->body_end = body_end - 1;
......@@ -315,7 +321,7 @@ _message_done (mu_stream_t stream)
{
struct _mu_message_stream *s = (struct _mu_message_stream*) stream;
free (s->envelope);
free (s->envelope_string);
free (s->date);
free (s->from);
mu_stream_destroy (&s->transport);
......@@ -342,8 +348,9 @@ _message_error_string (struct _mu_stream *stream, int rc)
return mu_stream_strerror (str->transport, rc);
}
int
mu_message_stream_create (mu_stream_t *pstream, mu_stream_t src, int flags)
static int
mu_message_stream_create (mu_stream_t *pstream, mu_stream_t src, int flags,
int construct_envelope)
{
struct _mu_message_stream *s;
int sflag;
......@@ -368,6 +375,7 @@ mu_message_stream_create (mu_stream_t *pstream, mu_stream_t src, int flags)
free (s);
return rc;
}
s->construct_envelope = construct_envelope;
s->stream.open = _message_open;
s->stream.close = _message_close;
s->stream.done = _message_done;
......@@ -400,13 +408,12 @@ _body_obj_size (mu_body_t body, size_t *size)
*size = str->body_end - str->body_start + 1;
return 0;
}
int
mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg)
mu_message_from_stream_with_envelope (mu_message_t *pmsg,
mu_stream_t instream,
mu_envelope_t env)
{
mu_envelope_t env;
mu_message_t msg;
mu_body_t body;
mu_stream_t bstream;
......@@ -415,7 +422,7 @@ mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg)
struct _mu_message_stream *sp;
/* FIXME: Perhaps MU_STREAM_NO_CLOSE is needed */
if ((rc = mu_message_stream_create (&draftstream, instream, 0)))
if ((rc = mu_message_stream_create (&draftstream, instream, 0, !env)))
return rc;
if ((rc = mu_message_create (&msg, draftstream)))
......@@ -425,16 +432,19 @@ mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg)
}
mu_message_set_stream (msg, draftstream, draftstream);
if ((rc = mu_envelope_create (&env, draftstream)))
if (!env)
{
mu_message_destroy (&msg, draftstream);
mu_stream_destroy (&draftstream);
return rc;
}
if ((rc = mu_envelope_create (&env, draftstream)))
{
mu_message_destroy (&msg, draftstream);
mu_stream_destroy (&draftstream);
return rc;
}
mu_envelope_set_date (env, _env_msg_date, draftstream);
mu_envelope_set_sender (env, _env_msg_sender, draftstream);
mu_envelope_set_date (env, _env_msg_date, draftstream);
mu_envelope_set_sender (env, _env_msg_sender, draftstream);
}
mu_message_set_envelope (msg, env, draftstream);
mu_body_create (&body, msg);
......@@ -457,3 +467,9 @@ mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg)
*pmsg = msg;
return 0;
}
int
mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg)
{
return mu_message_from_stream_with_envelope (pmsg, instream, NULL);
}
......
......@@ -27,6 +27,9 @@ libmu_imap_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
# mbox.c\
# url.c
libmu_imap_la_SOURCES = \
appmsg.c\
appstr.c\
appstrsiz.c\
fake-folder.c\
fetch.c\
gencom.c\
......@@ -47,6 +50,7 @@ libmu_imap_la_SOURCES = \
id.c\
login.c\
logout.c\
mbcreate.c\
noop.c\
rename.c\
resplist.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/message.h>
#include <mailutils/stream.h>
#include <mailutils/errno.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
int
mu_imap_append_message (mu_imap_t imap, const char *mailbox, int flags,
struct tm *tm, struct mu_timezone *tz,
mu_message_t msg)
{
mu_stream_t str;
int rc;
rc = mu_message_get_streamref (msg, &str);
if (rc)
{
rc = mu_imap_append_stream (imap, mailbox, flags, tm, tz, str);
mu_stream_unref (str);
}
return rc;
}
/* 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/stream.h>
#include <mailutils/errno.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
int
mu_imap_append_stream (mu_imap_t imap, const char *mailbox, int flags,
struct tm *tm, struct mu_timezone *tz,
mu_stream_t stream)
{
mu_off_t size;
int rc;
rc = mu_stream_size (stream, &size);
if (rc == 0)
rc = mu_imap_append_stream_size (imap, mailbox, flags, tm, tz, stream,
size);
return rc;
}
/* 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/stream.h>
#include <mailutils/filter.h>
#include <mailutils/errno.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
static int
get_crlf_stream_size (mu_stream_t str, mu_off_t size, mu_off_t *prealsize)
{
mu_stream_t null, flt;
mu_stream_stat_buffer stat;
int rc;
mu_off_t needle;
rc = mu_nullstream_create (&null, MU_STREAM_WRITE);
if (rc)
return rc;
mu_stream_set_stat (null, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT), stat);
rc = mu_filter_create (&flt, null, "CRLF", MU_FILTER_ENCODE,
MU_STREAM_WRITE);
mu_stream_unref (null);
if (rc)
return rc;
rc = mu_stream_seek (str, 0, MU_SEEK_CUR, &needle);
if (rc)
return rc;
rc = mu_stream_copy (flt, str, size, NULL);
if (rc == 0)
rc = mu_stream_seek (str, 0, MU_SEEK_SET, NULL);
mu_stream_unref (flt);
if (rc == 0)
*prealsize = stat[MU_STREAM_STAT_OUT];
return rc;
}
int
mu_imap_append_stream_size (mu_imap_t imap, const char *mailbox, int flags,
struct tm *tm, struct mu_timezone *tz,
mu_stream_t stream, mu_off_t size)
{
int status;
mu_off_t realsize;
if (imap == NULL || !mailbox || !stream || size == 0)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->session_state < MU_IMAP_SESSION_AUTH)
return MU_ERR_SEQ;
switch (imap->client_state)
{
case MU_IMAP_CLIENT_READY:
status = get_crlf_stream_size (stream, size, &realsize);
if (status)
return status;
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s APPEND %s",
imap->tag_str, mailbox);
MU_IMAP_CHECK_ERROR (imap, status);
if (flags)
{
status = mu_imapio_send (imap->io, " ", 1);
if (status == 0)
status = mu_imapio_send_flags (imap->io, flags);
MU_IMAP_CHECK_ERROR (imap, status);
}
if (tm)
{
status = mu_imapio_send (imap->io, " ", 1);
if (status == 0)
status = mu_imapio_send_time (imap->io, tm, tz);
MU_IMAP_CHECK_ERROR (imap, status);
}
status = mu_imapio_send (imap->io, " ", 1);
if (status == 0)
{
mu_stream_t flt;
status = mu_filter_create (&flt, stream, "CRLF", MU_FILTER_ENCODE,
MU_STREAM_READ);
if (status == 0)
{
status = mu_imapio_send_literal_stream (imap->io, flt, realsize);
mu_stream_unref (flt);
}
}
MU_IMAP_CHECK_ERROR (imap, status);
status = mu_imapio_send (imap->io, "\r\n", 2);
MU_IMAP_CHECK_ERROR (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->client_state = MU_IMAP_CLIENT_APPEND_RX;
case MU_IMAP_CLIENT_APPEND_RX:
status = _mu_imap_response (imap, NULL, NULL);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
{
case MU_IMAP_OK:
status = 0;
break;
case MU_IMAP_NO:
status = MU_ERR_FAILURE;
break;
case MU_IMAP_BAD:
status = MU_ERR_BADREPLY;
break;
}
imap->client_state = MU_IMAP_CLIENT_READY;
break;
default:
status = EINPROGRESS;
}
return status;
}
/* 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 <string.h>
#include <mailutils/errno.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
int
mu_imap_mailbox_create (mu_imap_t imap, const char *mailbox)
{
char const *argv[2];
static struct imap_command com;
argv[0] = "CREATE";
argv[1] = mailbox;
com.session_state = MU_IMAP_SESSION_AUTH;
com.capa = NULL;
com.rx_state = MU_IMAP_CLIENT_DELETE_RX;
com.uid = 0;
com.argc = 2;
com.argv = argv;
com.handler = NULL;
return mu_imap_gencom (imap, &com);
}
......@@ -808,6 +808,93 @@ com_expunge (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
return 0;
}
static int
com_create (int argc, char **argv)
{
int status = mu_imap_mailbox_create (imap, argv[1]);
if (status)
report_failure ("create", status);
return 0;
}
static int
com_append (int argc, char **argv)
{
struct tm tmbuf, *tm = NULL;
struct mu_timezone tzbuf, *tz = NULL;
int flags = 0;
mu_stream_t stream;
int rc, i;
for (i = 1; i < argc; i++)
{
if (strcmp (argv[i], "-time") == 0)
{
char *p;
if (++i == argc)
{
mu_error (_("-time requires argument"));
return 0;
}
rc = mu_scan_datetime (argv[i], MU_DATETIME_INTERNALDATE,
&tmbuf, &tzbuf, &p);
if (rc || *p)
{
mu_error (_("cannot parse time"));
return 0;
}
tm = &tmbuf;
tz = &tzbuf;
}
else if (strcmp (argv[i], "-flag") == 0)
{
if (++i == argc)
{
mu_error (_("-flag requires argument"));
return 0;
}
if (mu_imap_flag_to_attribute (argv[i], &flags))
{
mu_error (_("unrecognized flag: %s"), argv[i]);
return 0;
}
}
else if (strcmp (argv[i], "--") == 0)
{
i++;
break;
}
else if (argv[i][0] == '-')
{
mu_error (_("unrecognized option: %s"), argv[i]);
return 0;
}
else
break;
}
if (argc - i != 2)
{
mu_error (_("wrong number of arguments"));
return 0;
}
rc = mu_file_stream_create (&stream, argv[i + 1],
MU_STREAM_READ|MU_STREAM_SEEK);
if (rc)
{
mu_error (_("cannot open file %s: %s"), argv[i + 1], mu_strerror (rc));
return 0;
}
rc = mu_imap_append_stream (imap, argv[i], flags, tm, tz, stream);
mu_stream_unref (stream);
if (rc)
report_failure ("append", rc);
return 0;
}
struct mutool_command imap_comtab[] = {
{ "capability", 1, -1, 0,
com_capability,
......@@ -887,6 +974,14 @@ struct mutool_command imap_comtab[] = {
com_expunge,
NULL,
N_("permanently remove messages marked for deletion") },
{ "create", 2, 2, 0,
com_create,
N_("MAILBOX"),
N_("create new mailbox") },
{ "append", 3, -1, 0,
com_append,
N_("[-time DATETIME] [-flag FLAG] MAILBOX FILE"),
N_("append message text from FILE to MAILBOX") },
{ "quit", 1, 1, 0,
com_logout,
NULL,
......