commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-129-gdd8d091


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-129-gdd8d091
Date: Thu, 07 Oct 2010 10:34:51 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=dd8d091ba3cae58fd437c664478de8bcbdf25ac6

The branch, master has been updated
       via  dd8d091ba3cae58fd437c664478de8bcbdf25ac6 (commit)
       via  f24df125b4a5f7e29eee39e89127871a38856281 (commit)
      from  6b7badca005c9876033125407a3522831d80a820 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit dd8d091ba3cae58fd437c664478de8bcbdf25ac6
Author: Sergey Poznyakoff <address@hidden>
Date:   Thu Oct 7 13:23:45 2010 +0300

    Implement a filter for quoting ^From.  Use it for appending to UNIX 
mailboxes.
    
    * libmailutils/fromflt.c: New file.
    * libmailutils/Makefile.am (libmailutils_la_SOURCES): Add fromflt.c
    * libmailutils/tests/testsuite.at: Include fromflt.at.
    * include/mailutils/filter.h (mu_from_filter): New filter type.
    * libmailutils/filter.c (mu_filter_get_list): Register mu_from_filter.
    
    * libmailutils/fromflt.at: New file.
    * libmailutils/tests/Makefile.am (TESTSUITE_AT): Add fromflt.at.
    * libmailutils/tests/base64d.at: Mention `filter' in the keywords.
    * libmailutils/tests/base64e.at: Likewise.
    * libmailutils/tests/fltst.c (main): Fix argc check.
    
    * libproto/mbox/mbox.c (append_message_to_stream): Use "FROM" filter.

commit f24df125b4a5f7e29eee39e89127871a38856281
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Oct 6 23:47:56 2010 +0300

    Fixes in stream subsystem.  Rewrite and optimize maidag lmtp mode using 
streams.
    
    * libmailutils/file_stream.c (mu_fd_stream_create): Mark stream as
    open, do not call mu_stream_open explicitly.
    * libmailutils/message_stream.c (mu_stream_to_message): Bugfixes,
    wrong owner given to mu_envelope_set_ calls.
    * libmailutils/stream.c (_MU_STR_FLUSH_ALL)
    (_MU_STR_FLUSH_KEEP): New macros for _stream_flush_buffer.
    (_stream_flush_buffer): Change the meaning of the last argument.
    All callers updated.
    (mu_stream_seek): Fix operation with MU_SEEK_END.
    Call _mu_stream_cleareof on success.
    (mu_stream_read): Call _stream_flush_buffer in buffered mode.
    (mu_stream_getdelim, mu_stream_readdelim): Call _stream_flush_buffer.
    * libmailutils/streamcpy.c (mu_stream_copy): Reset size if mu_stream_seek
    fails.
    * libmailutils/temp_file_stream.c (mu_temp_file_stream_create): Set
    full buffering mode by default.
    
    * maidag/mailtmp.c: Remove.
    * maidag/Makefile.am (maidag_SOURCES): Remove mailtmp.c
    * po/POTFILES.in: Likewise.
    * maidag/deliver.c (make_tmp): Rewrite.  Return mu_mailbox_t.
    All callers changed.
    * maidag/lmtp.c (lmtp_transcript): Remove static.
    (lmpt_transcript): New function.
    (lmtp_reply): Use mu_stream_t instead of FILE.
    (xlatnl): Remove.  Superseded by mu_rtrim_cset and family.
    (mtmp, mbox): Remove globals.
    (mesg): New global.
    (cfun_unknown, cfun_mail_from, cfun_rcpt_to)
    (dot_temp_fail, dot_deliver, cfun_rset)
    (cfun_lhlo, cfun_quit, cfun_help): Use mu_stream_t instead of FILE.
    (cfun_data): Rewrite.
    (cfun_dot): Remove.
    (to_fgets): Rewrite using mu_stream_t.
    (lmtp_loop): Change signature. Rewrite using mu_stream_t.
    (lmtp_connection, maidag_lmtp_server): Update accordingly.
    * maidag/maidag.c (maidag_transcript): New global.
    (options, parse_opt): New option --transcript.
    * maidag/maidag.h (maidag_transcript): New extern.
    (mail_tmp_begin, mail_tmp_add_line, mail_tmp_finish)
    (mail_tmp_destroy): Remove.

-----------------------------------------------------------------------

Summary of changes:
 include/mailutils/filter.h      |    3 +-
 libmailutils/Makefile.am        |    1 +
 libmailutils/file_stream.c      |    8 +-
 libmailutils/filter.c           |    1 +
 libmailutils/fromflt.c          |  283 +++++++++++++++++++++++++++
 libmailutils/message_stream.c   |    4 +-
 libmailutils/stream.c           |   60 +++++--
 libmailutils/streamcpy.c        |    1 +
 libmailutils/temp_file_stream.c |    5 +-
 libmailutils/tests/Makefile.am  |    1 +
 libmailutils/tests/base64d.at   |    4 +-
 libmailutils/tests/base64e.at   |    4 +-
 libmailutils/tests/fltst.c      |    2 +-
 libmailutils/tests/fromflt.at   |   96 ++++++++++
 libmailutils/tests/testsuite.at |    1 +
 libproto/mbox/mbox.c            |   17 ++-
 maidag/Makefile.am              |    1 -
 maidag/deliver.c                |  116 ++++++++++--
 maidag/lmtp.c                   |  402 ++++++++++++++++++++++-----------------
 maidag/maidag.c                 |   38 +++--
 maidag/maidag.h                 |    7 +-
 maidag/mailtmp.c                |  187 ------------------
 po/POTFILES.in                  |    1 -
 23 files changed, 810 insertions(+), 433 deletions(-)
 create mode 100644 libmailutils/fromflt.c
 create mode 100644 libmailutils/tests/fromflt.at
 delete mode 100644 maidag/mailtmp.c

diff --git a/include/mailutils/filter.h b/include/mailutils/filter.h
index 120318d..d9c53ca 100644
--- a/include/mailutils/filter.h
+++ b/include/mailutils/filter.h
@@ -103,7 +103,8 @@ extern mu_filter_record_t mu_bit8_filter;
 extern mu_filter_record_t mu_bit7_filter;
 extern mu_filter_record_t mu_rfc_2047_Q_filter;
 extern mu_filter_record_t mu_rfc_2047_B_filter;
-  
+extern mu_filter_record_t mu_from_filter;
+
 enum mu_iconv_fallback_mode
   {
     mu_fallback_none,
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index 3f083e0..07a0a4e 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -83,6 +83,7 @@ libmailutils_la_SOURCES = \
  fltstream.c\
  folder.c\
  freeitem.c\
+ fromflt.c\
  gdebug.c\
  getpass.c\
  gocs.c\
diff --git a/libmailutils/file_stream.c b/libmailutils/file_stream.c
index 578f482..e6a6e67 100644
--- a/libmailutils/file_stream.c
+++ b/libmailutils/file_stream.c
@@ -390,16 +390,12 @@ mu_fd_stream_create (mu_stream_t *pstream, char 
*filename, int fd, int flags)
   struct _mu_file_stream *fstr;
   int rc = _mu_file_stream_create (&fstr,
                                   sizeof (struct _mu_file_stream),
-                                  filename, fd, flags);
+                                  filename, fd, flags|_MU_STR_OPEN);
   if (rc == 0)
     {
       mu_stream_t stream = (mu_stream_t) fstr;
       mu_stream_set_buffer (stream, mu_buffer_full, 0);
-      rc = mu_stream_open (stream);
-      if (rc)
-       mu_stream_unref (stream);
-      else
-       *pstream = stream;
+      *pstream = stream;
     }
   return rc;
 }
diff --git a/libmailutils/filter.c b/libmailutils/filter.c
index 8fdc25f..0008ba0 100644
--- a/libmailutils/filter.c
+++ b/libmailutils/filter.c
@@ -78,6 +78,7 @@ mu_filter_get_list (mu_list_t *plist)
       mu_list_append (filter_list, mu_dot_filter);
       mu_list_append (filter_list, mu_rfc_2047_Q_filter);
       mu_list_append (filter_list, mu_rfc_2047_B_filter);
+      mu_list_append (filter_list, mu_from_filter);
       /* FIXME: add the default encodings?  */
     }
   *plist = filter_list;
diff --git a/libmailutils/fromflt.c b/libmailutils/fromflt.c
new file mode 100644
index 0000000..d96d46d
--- /dev/null
+++ b/libmailutils/fromflt.c
@@ -0,0 +1,283 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2003, 2007, 2010 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, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/errno.h>
+#include <mailutils/filter.h>
+#include <mailutils/stream.h>
+
+enum from_decode_state
+  {
+    from_decode_init,
+    from_decode_nl,
+    from_decode_char
+  };
+
+#define GT_FROM_MARK_STR ">From "
+#define GT_FROM_MARK_LEN (sizeof (GT_FROM_MARK_STR) - 1)
+
+/* Move min(isize,osize) bytes from iptr to optr, replacing each '>From '
+   at the beginning of line with 'From '. */
+static enum mu_filter_result
+_from_decoder (void *xd,
+              enum mu_filter_command cmd,
+              struct mu_filter_io *iobuf)
+{
+  int *pstate = xd;
+  const unsigned char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+  enum from_decode_state state;
+  size_t i, j;
+
+  switch (cmd)
+    {
+    case mu_filter_init:
+      *pstate = from_decode_init;
+      return mu_filter_ok;
+      
+    case mu_filter_done:
+      return mu_filter_ok;
+      
+    default:
+      state = *pstate;
+      break;
+    }
+  
+  iptr = (const unsigned char *) iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  for (i = j = 0; i < isize && j < osize; i++)
+    {
+      unsigned char c = *iptr++;
+      
+      if (c == '\n')
+       state = from_decode_nl;
+      else if (state == from_decode_init || state == from_decode_nl)
+       {
+         size_t len = isize - i;
+
+         if (len < GT_FROM_MARK_LEN)
+           {
+             if (memcmp (iptr - 1, GT_FROM_MARK_STR, len) == 0)
+               {
+                 if (i == 0)
+                   {
+                     iobuf->isize = GT_FROM_MARK_LEN - len;
+                     return mu_filter_moreinput;
+                   }
+                 break;
+               }
+             else
+               state = from_decode_char;
+           }
+         else if (memcmp (iptr - 1, GT_FROM_MARK_STR, GT_FROM_MARK_LEN) == 0)
+           {
+             /* Skip > */
+             state = from_decode_char;
+             continue;
+           }
+       }         
+      optr[j++] = c;
+    }
+
+  *pstate = state;
+  iobuf->isize = i;
+  iobuf->osize = j;
+  return mu_filter_ok;
+}
+
+#define FROM_MARK_STR "From "
+#define FROM_MARK_LEN (sizeof (FROM_MARK_STR) - 1)
+
+enum from_encode_state
+  {
+    from_encode_init,
+    from_encode_nl,
+    from_encode_char,
+    from_encode_gt,
+    from_encode_f,
+    from_encode_r,
+    from_encode_o,
+    from_encode_m,
+    from_encode_sp
+  };
+
+static int length_to_state_tab[] = {
+  from_encode_gt,
+  from_encode_f,
+  from_encode_r,
+  from_encode_o,
+  from_encode_m,
+  from_encode_sp
+};
+
+static int state_to_length_tab[] = {
+  0, 0, 0,
+  GT_FROM_MARK_LEN,
+  GT_FROM_MARK_LEN-1,
+  GT_FROM_MARK_LEN-2,
+  GT_FROM_MARK_LEN-3,
+  GT_FROM_MARK_LEN-4,
+  GT_FROM_MARK_LEN-5
+};      
+
+/* Move min(isize,osize) bytes from iptr to optr, replacing each 'From '
+   at the beginning of line with '>From '. */
+
+static enum mu_filter_result
+_from_encoder (void *xd,
+              enum mu_filter_command cmd,
+              struct mu_filter_io *iobuf)
+{
+  int *pstate = xd;
+  const unsigned char *iptr;
+  size_t isize;
+  char *optr;
+  size_t osize;
+  enum from_encode_state state;
+  size_t i, j;
+  
+  switch (cmd)
+    {
+    case mu_filter_init:
+      *pstate = from_encode_init;
+      return mu_filter_ok;
+      
+    case mu_filter_done:
+      return mu_filter_ok;
+      
+    default:
+      state = *pstate;
+      switch (state)
+       {
+       case from_encode_init:
+       case from_encode_nl:
+       case from_encode_char:
+         break;
+
+       default:
+         osize = state_to_length_tab[state];
+         if (iobuf->osize < osize)
+           {
+             iobuf->osize = osize;
+             return mu_filter_moreoutput;
+           }
+         memcpy (iobuf->output, GT_FROM_MARK_STR + GT_FROM_MARK_LEN - osize,
+                 osize);
+         iobuf->osize = osize;
+         iobuf->isize = osize;
+         *pstate = from_encode_init;
+         return mu_filter_ok;
+       }
+      break;
+    }
+  
+  iptr = (const unsigned char *) iobuf->input;
+  isize = iobuf->isize;
+  optr = iobuf->output;
+  osize = iobuf->osize;
+
+  for (i = j = 0; i < isize && j < osize; i++)
+    {
+      unsigned char c = *iptr++;
+      
+      if (c == '\n')
+       state = from_encode_nl;
+      else if (state == from_encode_init || state == from_encode_nl)
+       {
+         size_t len = isize - i;
+
+         if (len < FROM_MARK_LEN)
+           {
+             if (memcmp (iptr - 1, FROM_MARK_STR, len) == 0)
+               {
+                 if (i == 0)
+                   {
+                     iobuf->isize = FROM_MARK_LEN;
+                     return mu_filter_moreinput;
+                   }
+                 break;
+               }
+             else
+               state = from_encode_char;
+           }
+         else if (memcmp (iptr - 1, FROM_MARK_STR, FROM_MARK_LEN) == 0)
+           {
+             size_t rest = osize - j;
+             
+             if (rest > GT_FROM_MARK_LEN)
+               rest = GT_FROM_MARK_LEN;
+             else if (rest < 2)
+               {
+                 if (i == 0)
+                   {
+                     iobuf->osize = GT_FROM_MARK_LEN;
+                     return mu_filter_moreoutput;
+                   }
+                 break;
+               }
+             
+             memcpy (optr + j, GT_FROM_MARK_STR, rest);
+             i += rest - 2;
+             iptr += rest - 2;
+             j += rest;
+             if (rest < GT_FROM_MARK_LEN)
+               state = length_to_state_tab[rest];
+             else
+               state = from_encode_char;
+             continue;
+           }
+         else
+           state = from_encode_char;
+       }
+      optr[j++] = c;
+    }
+  *pstate = state;
+  iobuf->isize = i;
+  iobuf->osize = j;
+  return mu_filter_ok;
+}
+
+static int
+_from_alloc_state (void **pret, int mode, void *data MU_ARG_UNUSED)
+{
+  *pret = malloc (sizeof (int));
+  if (!*pret)
+    return ENOMEM;
+  return 0;
+}
+
+static struct _mu_filter_record _from_filter = {
+  "FROM",
+  0,
+  _from_alloc_state,
+  _from_encoder,
+  _from_decoder
+};
+
+mu_filter_record_t mu_from_filter = &_from_filter;
+
diff --git a/libmailutils/message_stream.c b/libmailutils/message_stream.c
index 6bfdae5..9f590d9 100644
--- a/libmailutils/message_stream.c
+++ b/libmailutils/message_stream.c
@@ -414,8 +414,8 @@ mu_stream_to_message (mu_stream_t instream, mu_message_t 
*pmsg)
       return rc;
     }
   
-  mu_envelope_set_date (env, _env_msg_date, msg);
-  mu_envelope_set_sender (env, _env_msg_sender, msg);
+  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);
diff --git a/libmailutils/stream.c b/libmailutils/stream.c
index 2dfbc82..6084479 100644
--- a/libmailutils/stream.c
+++ b/libmailutils/stream.c
@@ -34,6 +34,9 @@
 
 size_t mu_stream_default_buffer_size = MU_STREAM_DEFBUFSIZ;
 
+#define _MU_STR_FLUSH_ALL  0x01
+#define _MU_STR_FLUSH_KEEP 0x02
+
 #define _stream_event(stream, code, n, p)                      \
   do                                                           \
     {                                                          \
@@ -167,12 +170,12 @@ _stream_buffer_full_p (struct _mu_stream *stream)
 }
 
 static int
-_stream_flush_buffer (struct _mu_stream *stream, int all)
+_stream_flush_buffer (struct _mu_stream *stream, int flags)
 {
   int rc;
   char *start, *end;
   size_t wrsize;
-  
+
   if (stream->flags & _MU_STR_DIRTY)
     {
       if ((stream->flags & MU_STREAM_SEEK) && stream->seek)
@@ -215,7 +218,8 @@ _stream_flush_buffer (struct _mu_stream *stream, int all)
              if (wrsize == 0)
                break;
            }
-         if ((all && wrsize) || wrsize == stream->level)
+         if (((flags & _MU_STR_FLUSH_ALL) && wrsize) ||
+             wrsize == stream->level)
            {
              rc = _stream_write_unbuffered (stream,
                                             stream->buffer,
@@ -234,10 +238,11 @@ _stream_flush_buffer (struct _mu_stream *stream, int all)
          stream->level = stream->pos = wrsize;
          return 0;
        }
+      _stream_clrflag (stream, _MU_STR_DIRTY);
     }
 
-  _stream_clrflag (stream, _MU_STR_DIRTY);
-  stream->pos = stream->level = 0;
+  if (!(flags & _MU_STR_FLUSH_KEEP))
+    stream->pos = stream->level = 0;
   return 0;
 }
 
@@ -400,8 +405,8 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int 
whence,
     case MU_SEEK_END:
       rc = mu_stream_size (stream, &size);
       if (rc)
-       return mu_stream_seterr (stream, rc, 1);
-      offset += size + stream->pos;
+       return rc;
+      offset += size;
       break;
 
     default:
@@ -414,7 +419,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int 
whence,
          || offset < stream->offset
          || offset > stream->offset + stream->level))
     {
-      if ((rc = _stream_flush_buffer (stream, 1)))
+      if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
        return rc;
       rc = stream->seek (stream, offset, &stream->offset);
       if (rc == ESPIPE)
@@ -425,7 +430,9 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int 
whence,
     }
   else if (stream->buftype != mu_buffer_none)
     stream->pos = offset - stream->offset;
-                           
+
+  _mu_stream_cleareof (stream);
+  
   if (pres)
     *pres = stream->offset + stream->pos;
   return 0;
@@ -469,7 +476,7 @@ _stream_skip_input_bytes (mu_stream_t stream, mu_off_t 
count, mu_off_t *pres)
        {
          for (pos = 0;;)
            {
-             if ((rc = _stream_flush_buffer (stream, 1)))
+             if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
                return rc;
              if (stream->pos == stream->level)
                {
@@ -693,10 +700,15 @@ mu_stream_read (mu_stream_t stream, void *buf, size_t 
size, size_t *pread)
     {
       char *bufp = buf;
       size_t nbytes = 0;
+      int rc;
+      
+      if ((rc = _stream_flush_buffer (stream,
+                                     _MU_STR_FLUSH_ALL|_MU_STR_FLUSH_KEEP)))
+       return rc;
+
       while (size)
        {
          size_t n;
-         int rc;
          
          if (stream->pos == stream->level)
            {
@@ -824,7 +836,12 @@ mu_stream_readdelim (mu_stream_t stream, char *buf, size_t 
size,
        rc = _stream_readdelim (stream, buf, size, delim, pread);
     }
   else
-    rc = _stream_scandelim (stream, buf, size, delim, pread);
+    {
+      if ((rc = _stream_flush_buffer (stream,
+                                     _MU_STR_FLUSH_ALL|_MU_STR_FLUSH_KEEP)))
+       return rc;
+      rc = _stream_scandelim (stream, buf, size, delim, pread);
+    }
   return rc;
 }
 
@@ -850,6 +867,10 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, 
size_t *psize,
       _stream_init (stream);
     }
 
+  if ((rc = _stream_flush_buffer (stream,
+                                 _MU_STR_FLUSH_ALL|_MU_STR_FLUSH_KEEP)))
+    return rc;
+  
   if (lineptr == NULL || n == 0)
     {
       char *new_lineptr;
@@ -997,7 +1018,7 @@ mu_stream_flush (mu_stream_t stream)
        return MU_ERR_NOT_OPEN;
       _stream_init (stream);
     }
-  rc = _stream_flush_buffer (stream, 1);
+  rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL);
   if (rc)
     return rc;
   if ((stream->flags & _MU_STR_WRT) && stream->flush)
@@ -1031,7 +1052,8 @@ int
 mu_stream_size (mu_stream_t stream, mu_off_t *psize)
 {
   int rc;
-    
+  mu_off_t size;
+  
   if (!(stream->flags & _MU_STR_OPEN))
     {
       if (stream->open)
@@ -1040,7 +1062,13 @@ mu_stream_size (mu_stream_t stream, mu_off_t *psize)
     }
   if (!stream->size)
     return mu_stream_seterr (stream, ENOSYS, 0);
-  rc = stream->size (stream, psize);
+  rc = stream->size (stream, &size);
+  if (rc == 0)
+    {
+      if (stream->buftype != mu_buffer_none && stream->offset == size)
+       size += stream->level;
+      *psize = size;
+    }
   return mu_stream_seterr (stream, rc, rc != 0);
 }
 
@@ -1118,7 +1146,7 @@ mu_stream_truncate (mu_stream_t stream, mu_off_t size)
     {
       int rc;
       
-      if ((rc = _stream_flush_buffer (stream, 1)))
+      if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
        return rc;
       return stream->truncate (stream, size);
     }
diff --git a/libmailutils/streamcpy.c b/libmailutils/streamcpy.c
index 13742e7..2020fad 100644
--- a/libmailutils/streamcpy.c
+++ b/libmailutils/streamcpy.c
@@ -72,6 +72,7 @@ mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t 
size,
            case EACCES:
              mu_stream_clearerr (src);
            case ENOSYS:
+             size = 0;
              break;
 
            default:
diff --git a/libmailutils/temp_file_stream.c b/libmailutils/temp_file_stream.c
index 857bada..fb178a5 100644
--- a/libmailutils/temp_file_stream.c
+++ b/libmailutils/temp_file_stream.c
@@ -66,7 +66,10 @@ mu_temp_file_stream_create (mu_stream_t *pstream, const char 
*dir)
       if (rc)
        mu_stream_unref (stream);
       else
-       *pstream = stream;
+       {
+         mu_stream_set_buffer (stream, mu_buffer_full, 0);
+         *pstream = stream;
+       }
     }
   return 0;
 }
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 7324e88..a8215fb 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -64,6 +64,7 @@ TESTSUITE_AT = \
  base64e.at\
  decode2047.at\
  encode2047.at\
+ fromflt.at\
  list.at\
  mailcap.at\
  testsuite.at\
diff --git a/libmailutils/tests/base64d.at b/libmailutils/tests/base64d.at
index b26c415..df1efd3 100644
--- a/libmailutils/tests/base64d.at
+++ b/libmailutils/tests/base64d.at
@@ -16,7 +16,7 @@
 # This file is part of Mailfromd testsuite. 
 
 AT_SETUP([base64 decoding (read)])
-AT_KEYWORDS([base64 base64d base64dr decode])
+AT_KEYWORDS([base64 base64d base64dr decode filter])
 
 AT_CHECK([
 cp $abs_top_srcdir/libmailutils/tests/Encode expout
@@ -28,7 +28,7 @@ AT_CLEANUP
 
 
 AT_SETUP([base64 decoding (write)])
-AT_KEYWORDS([base64 base64d base64dw decode])
+AT_KEYWORDS([base64 base64d base64dw decode filter])
 
 AT_CHECK([
 cp $abs_top_srcdir/libmailutils/tests/Encode expout
diff --git a/libmailutils/tests/base64e.at b/libmailutils/tests/base64e.at
index c753471..b94522e 100644
--- a/libmailutils/tests/base64e.at
+++ b/libmailutils/tests/base64e.at
@@ -16,7 +16,7 @@
 # This file is part of Mailfromd testsuite. 
 
 AT_SETUP([base64 encoding (read)])
-AT_KEYWORDS([base64 base64e base64er encode])
+AT_KEYWORDS([base64 base64e base64er encode filter])
 
 AT_CHECK([
 cp $abs_top_srcdir/libmailutils/tests/Decode expout
@@ -28,7 +28,7 @@ AT_CLEANUP
 
 
 AT_SETUP([base64 encoding (write)])
-AT_KEYWORDS([base64 base64e base64ew encode])
+AT_KEYWORDS([base64 base64e base64ew encode filter])
 
 AT_CHECK([
 cp $abs_top_srcdir/libmailutils/tests/Decode expout
diff --git a/libmailutils/tests/fltst.c b/libmailutils/tests/fltst.c
index 8597dd5..d62a02b 100644
--- a/libmailutils/tests/fltst.c
+++ b/libmailutils/tests/fltst.c
@@ -114,7 +114,7 @@ main (int argc, char * argv [])
   
   if (argc == 1)
     usage (NULL);
-  if (argc < 3)
+  if (argc < 4)
     usage ("not enough arguments");
   
   fltname = argv[1];
diff --git a/libmailutils/tests/fromflt.at b/libmailutils/tests/fromflt.at
new file mode 100644
index 0000000..a5b3313
--- /dev/null
+++ b/libmailutils/tests/fromflt.at
@@ -0,0 +1,96 @@
+# This file is part of GNU Mailutils. -*- Autotest -*-
+# Copyright (C) 2007, 2008, 2009, 2010 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.
+#
+# This program 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/>.
+# This file is part of Mailfromd testsuite. 
+
+# -------------------------------------------
+# Data for 'From' filter tests.
+# -------------------------------------------
+
+m4_define([from_plain_text],[From this time on
+from that source
+ From stdin
+and
+From them
+])
+
+m4_define([from_encoded_text],[>From this time on
+from that source
+ From stdin
+and
+>From them
+])
+
+# -------------------------------------------
+# Test 'From' encoding
+# -------------------------------------------
+
+# Test read mode
+
+AT_SETUP([from filter encoding (read)])
+AT_KEYWORDS([from frome fromer encode])
+
+AT_CHECK([
+AT_DATA([input],from_plain_text)
+fltst from encode read < input
+],
+[0],
+[from_encoded_text])
+
+AT_CLEANUP
+
+# The same, in write mode
+
+AT_SETUP([from filter encoding (write)])
+AT_KEYWORDS([from frome fromew encode])
+
+AT_CHECK([
+AT_DATA([input],from_plain_text)
+fltst from encode write < input
+],
+[0],
+[from_encoded_text])
+
+AT_CLEANUP
+
+# -------------------------------------------
+# Test '>From' decoding
+# -------------------------------------------
+
+AT_SETUP([from filter decoding (read)])
+AT_KEYWORDS([from fromd fromdr decode])
+
+AT_CHECK([
+AT_DATA([input],from_encoded_text)
+fltst from decode read < input
+],
+[0],
+[from_plain_text])
+
+AT_CLEANUP
+
+# The same, in write mode
+
+AT_SETUP([from filter decoding (write)])
+AT_KEYWORDS([from fromd fromdw decode])
+
+AT_CHECK([
+AT_DATA([input],from_encoded_text)
+fltst from decode write < input
+],
+[0],
+[from_plain_text])
+
+AT_CLEANUP
diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at
index 1de64b6..fbdc7c9 100644
--- a/libmailutils/tests/testsuite.at
+++ b/libmailutils/tests/testsuite.at
@@ -63,4 +63,5 @@ m4_include([base64e.at])
 m4_include([base64d.at])
 m4_include([decode2047.at])
 m4_include([encode2047.at])
+m4_include([fromflt.at])
 
diff --git a/libproto/mbox/mbox.c b/libproto/mbox/mbox.c
index 6250765..cc412ff 100644
--- a/libproto/mbox/mbox.c
+++ b/libproto/mbox/mbox.c
@@ -28,6 +28,7 @@
 #include <mbox0.h>
 #include <mailutils/cstr.h>
 #include <mailutils/io.h>
+#include <mailutils/filter.h>
 
 #define ATTRIBUTE_IS_DELETED(flag)        (flag & MU_ATTRIBUTE_DELETED)
 #define ATTRIBUTE_IS_EQUAL(flag1, flag2)  (flag1 == flag2)
@@ -1033,7 +1034,7 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t 
msg,
                          mbox_data_t mud, int flags)
 {
   int status;
-  mu_stream_t istr;
+  mu_stream_t istr, flt;
   
   status = msg_envelope_to_stream (ostr, msg);
   if (status)
@@ -1084,10 +1085,18 @@ append_message_to_stream (mu_stream_t ostr, 
mu_message_t msg,
       if (status)
        return status;
     }
-  status = mu_stream_copy (ostr, istr, 0, NULL);
-  mu_stream_destroy (&istr);
+
+  status = mu_filter_create (&flt, istr, "FROM",
+                            MU_FILTER_ENCODE, MU_STREAM_READ);
+  mu_stream_unref (istr);
   if (status == 0)
-    status = mu_stream_write (ostr, "\n", 1, NULL);
+    {
+      status = mu_stream_copy (ostr, flt, 0, NULL);
+      mu_stream_destroy (&flt);
+      if (status == 0)
+       status = mu_stream_write (ostr, "\n", 1, NULL);
+    }
+  
   return status;
 }
 
diff --git a/maidag/Makefile.am b/maidag/Makefile.am
index 0b28d93..835f895 100644
--- a/maidag/Makefile.am
+++ b/maidag/Makefile.am
@@ -26,7 +26,6 @@ maidag_SOURCES=\
  lmtp.c\
  maidag.c\
  maidag.h\
- mailtmp.c\
  mailquota.c\
  python.c\
  sieve.c\
diff --git a/maidag/deliver.c b/maidag/deliver.c
index 24e2f0c..d5bbc1f 100644
--- a/maidag/deliver.c
+++ b/maidag/deliver.c
@@ -19,26 +19,110 @@
 
 #include "maidag.h"
 
-void
-make_tmp (const char *from, mu_mailbox_t *mbox)
+static mu_mailbox_t
+make_tmp (const char *from)
 {
-  struct mail_tmp *mtmp;
-  char *buf = NULL;
-  size_t n = 0;
   int rc;
+  mu_stream_t in, out;
+  char *buf = NULL;
+  size_t size = 0, n;
+  mu_mailbox_t mbox;
+  
+  rc = mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_READ);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
+                      "MU_STDIN_FD", rc);
+      exit (EX_TEMPFAIL);
+    } 
+
+  rc = mu_temp_file_stream_create (&out, NULL);
+  if (rc)
+    {
+      maidag_error (_("unable to open temporary file: %s"), mu_strerror (rc));
+      exit (EX_TEMPFAIL);
+    }
 
-  if (mail_tmp_begin (&mtmp, from))
-    exit (EX_TEMPFAIL);
+  rc = mu_stream_getline (in, &buf, &size, &n);
+  if (rc)
+    {
+      maidag_error (_("read error: %s"), mu_strerror (rc));
+      mu_stream_destroy (&in);
+      mu_stream_destroy (&out);
+      exit (EX_TEMPFAIL);
+    }
+  if (n == 0)
+    {
+      maidag_error (_("unexpected EOF on input"));
+      mu_stream_destroy (&in);
+      mu_stream_destroy (&out);
+      exit (EX_TEMPFAIL);
+    } 
 
-  while (getline (&buf, &n, stdin) > 0)
-    if ((rc = mail_tmp_add_line (mtmp, buf, strlen (buf))))
-      break;
+  if (n >= 5 && memcmp (buf, "From ", 5))
+    {
+      struct mu_auth_data *auth = NULL;
+      if (!from)
+       {
+         auth = mu_get_auth_by_uid (getuid ());
+         if (auth)
+           from = auth->name;
+       }
+      if (from)
+       {
+         time_t t;
+         
+         time (&t);
+         mu_stream_printf (out, "From %s %s", from, ctime (&t));
+       }
+      else
+       {
+         maidag_error (_("cannot determine sender address"));
+         mu_stream_destroy (&in);
+         mu_stream_destroy (&out);
+         exit (EX_TEMPFAIL);
+       }
+      if (auth)
+       mu_auth_data_free (auth);
+    }
+
+  mu_stream_write (out, buf, n, NULL);
   free (buf);
-  if (rc == 0)
-    rc = mail_tmp_finish (mtmp, mbox);
-  mail_tmp_destroy (&mtmp);
+  
+  rc = mu_stream_copy (out, in, 0, NULL);
+  
+  mu_stream_destroy (&in);
   if (rc)
-    exit (EX_TEMPFAIL);
+    {
+      maidag_error (_("copy error: %s"), mu_strerror (rc));
+      mu_stream_destroy (&out);
+      exit (EX_TEMPFAIL);
+    }
+
+  mu_stream_flush (out);
+  if ((rc = mu_mailbox_create (&mbox, "mbox:/dev/null")) 
+      || (rc = mu_mailbox_open (mbox, MU_STREAM_READ))
+      || (rc = mu_mailbox_set_stream (mbox, out)))
+    {
+      maidag_error (_("error opening temporary file: %s"), 
+                    mu_strerror (rc));
+      mu_stream_destroy (&out);
+      exit (EX_TEMPFAIL);
+    }
+
+  rc = mu_mailbox_messages_count (mbox, &n);
+  if (rc)
+    {
+      errno = rc;
+      maidag_error (_("error creating temporary message: %s"),
+                   mu_strerror (rc));
+      mu_stream_destroy (&out);
+      exit (EX_TEMPFAIL);
+    }
+
+  /* FIXME: mu_stream_unref (out); But mu_mailbox_set_stream
+     steals the reference */
+  return mbox;
 }
 
 int
@@ -65,9 +149,7 @@ mda (mu_mailbox_t mbx, char *username)
 int
 maidag_stdio_delivery (int argc, char **argv)
 {
-  mu_mailbox_t mbox;
-
-  make_tmp (sender_address, &mbox);
+  mu_mailbox_t mbox = make_tmp (sender_address);
   
   if (multiple_delivery)
     multiple_delivery = argc > 1;
diff --git a/maidag/lmtp.c b/maidag/lmtp.c
index 4393291..726be15 100644
--- a/maidag/lmtp.c
+++ b/maidag/lmtp.c
@@ -26,10 +26,39 @@
 #include <mu_umaxtostr.h>
 
 mu_list_t lmtp_groups;
-static int lmtp_transcript;
+
+static mu_stream_t
+lmpt_transcript (mu_stream_t iostream)
+{
+  int rc;
+  mu_debug_t debug;
+  mu_stream_t dstr, xstr;
+      
+  mu_diag_get_debug (&debug);
+      
+  rc = mu_dbgstream_create (&dstr, debug, MU_DIAG_DEBUG, 0);
+  if (rc)
+    mu_error (_("cannot create debug stream; transcript disabled: %s"),
+             mu_strerror (rc));
+  else
+    {
+      rc = mu_xscript_stream_create (&xstr, iostream, dstr, NULL);
+      if (rc)
+       mu_error (_("cannot create transcript stream: %s"),
+                 mu_strerror (rc));
+      else
+       {
+         /* FIXME: Would do a mu_stream_unref (iostream) here,
+            however mu_xscript_stream_create *may* steal the reference.
+            This should be fixed in mu_xscript_stream_create. */
+         iostream = xstr;
+       }
+    }
+  return iostream;
+}
 
 void
-lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
+lmtp_reply (mu_stream_t iostr, char *code, char *enh, char *fmt, ...)
 {
   va_list ap;
   char *str;
@@ -38,14 +67,6 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
   vasprintf (&str, fmt, ap);
   va_end (ap);
 
-  if (lmtp_transcript)
-    {
-      if (enh)
-       mu_diag_output (MU_DIAG_INFO, "LMTP reply: %s %s %s", code, enh, str);
-      else
-       mu_diag_output (MU_DIAG_INFO, "LMTP reply: %s %s", code, str);
-    }
-  
   if (!str)
     {
       mu_error (_("not enough memory"));
@@ -59,39 +80,23 @@ lmtp_reply (FILE *fp, char *code, char *enh, char *fmt, ...)
       if (end)
        {
          size_t len = end - str;
-         fprintf (fp, "%s-", code);
+         mu_stream_printf (iostr, "%s-", code);
          if (enh)
-           fprintf (fp, "%s ", enh);
-         fprintf (fp, "%.*s\r\n", (int) len, str);
+           mu_stream_printf (iostr, "%s ", enh);
+         mu_stream_printf (iostr, "%.*s\r\n", (int) len, str);
          for (str = end; *str && *str == '\n'; str++);
        }
       else
        {
-         fprintf (fp, "%s ", code);
+         mu_stream_printf (iostr, "%s ", code);
          if (enh)
-           fprintf (fp, "%s ", enh);
-         fprintf (fp, "%s\r\n", str);
+           mu_stream_printf (iostr, "%s ", enh);
+         mu_stream_printf (iostr, "%s\r\n", str);
          str += strlen (str);
        }
     }
 }
 
-void
-xlatnl (char *arg)
-{
-  size_t len = strlen (arg);
-  if (len > 0 && arg[len-1] == '\n')
-    {
-      len--;
-      if (len > 0 && arg[len-1] == '\r')
-       {
-         arg[len-1] = '\n';
-         arg[len] = 0;
-       }
-    }
-}
-
-
 enum lmtp_state
   {
     state_none,
@@ -152,14 +157,13 @@ int transtab[NCMD][NSTATE] = {
 char *lhlo_domain;     /* Sender domain */
 char *mail_from;       /* Sender address */
 mu_list_t rcpt_list;   /* Recipient addresses */
-struct mail_tmp *mtmp; /* Temporary mail storage */
-mu_mailbox_t mbox;     /* Collected mail body */
+mu_message_t mesg;     /* Collected message */
 
 
 int
-cfun_unknown (FILE *out, char *arg)
+cfun_unknown (mu_stream_t iostr, char *arg)
 {
-  lmtp_reply (out, "500", "5.5.1", "Command unrecognized");
+  lmtp_reply (iostr, "500", "5.5.1", "Command unrecognized");
   return 0;
 }
 
@@ -242,46 +246,46 @@ check_address (char *arg, int with_domain, char **pret)
 
 
 int
-cfun_mail_from (FILE *out, char *arg)
+cfun_mail_from (mu_stream_t iostr, char *arg)
 {
   if (*arg == 0)
     {
-      lmtp_reply (out, "501", "5.5.2", "Syntax error");
+      lmtp_reply (iostr, "501", "5.5.2", "Syntax error");
       return 1;
     }
 
   if (check_address (arg, 1, &mail_from))
     {
-      lmtp_reply (out, "553", "5.1.8", "Address format error");
+      lmtp_reply (iostr, "553", "5.1.8", "Address format error");
       return 1;
     }
-  lmtp_reply (out, "250", "2.1.0", "Go ahead");
+  lmtp_reply (iostr, "250", "2.1.0", "Go ahead");
   return 0;
 }
 
 
 int
-cfun_rcpt_to (FILE *out, char *arg)
+cfun_rcpt_to (mu_stream_t iostr, char *arg)
 {
   char *user;
   struct mu_auth_data *auth;
   
   if (*arg == 0)
     {
-      lmtp_reply (out, "501", "5.5.2", "Syntax error");
+      lmtp_reply (iostr, "501", "5.5.2", "Syntax error");
       return 1;
     }
 
   /* FIXME: Check if domain is OK */
   if (check_address (arg, 0, &user))
     {
-      lmtp_reply (out, "553", "5.1.8", "Address format error");
+      lmtp_reply (iostr, "553", "5.1.8", "Address format error");
       return 1;
     }
   auth = mu_get_auth_by_name (user);
   if (!auth)
     {
-      lmtp_reply (out, "550", "5.1.1", "User unknown");
+      lmtp_reply (iostr, "550", "5.1.1", "User unknown");
       free (user);
       return 1;
     }
@@ -292,37 +296,17 @@ cfun_rcpt_to (FILE *out, char *arg)
       mu_list_set_destroy_item (rcpt_list, mu_list_free_item);
     }
   mu_list_append (rcpt_list, user);
-  lmtp_reply (out, "250", "2.1.5", "Go ahead");
+  lmtp_reply (iostr, "250", "2.1.5", "Go ahead");
   return 0;
 }  
 
 
 int
-cfun_data (FILE *out, char *arg)
-{
-  if (*arg)
-    {
-      lmtp_reply (out, "501", "5.5.2", "Syntax error");
-      return 1;
-    }
-
-  if (mail_tmp_begin (&mtmp, mail_from))
-    {
-      /* FIXME: codes */
-      lmtp_reply (out, "450", "4.1.0", "Temporary failure, try again later");
-      return 1;
-    }
-  lmtp_reply (out, "354", NULL, "Go ahead");
-  return 0;
-}
-
-
-int
 dot_temp_fail (void *item, void *cbdata)
 {
   char *name = item;
-  FILE *out = cbdata;
-  lmtp_reply (out, "450", "4.1.0", "%s: temporary failure", name);
+  mu_stream_t iostr = cbdata;
+  lmtp_reply (iostr, "450", "4.1.0", "%s: temporary failure", name);
   return 0;
 }
 
@@ -330,39 +314,27 @@ int
 dot_deliver (void *item, void *cbdata)
 {
   char *name = item;
-  FILE *out = cbdata;
+  mu_stream_t iostr = cbdata;
   char *errp = NULL;
-  mu_message_t msg;
-  int status;
   
-  if ((status = mu_mailbox_get_message (mbox, 1, &msg)) != 0)
-    {
-      mu_error (_("cannot get message from the temporary mailbox: %s"),
-               mu_strerror (status));
-      lmtp_reply (out, "450", "4.1.0",
-                 "%s: temporary failure, try again later",
-                 name);
-      return 0;
-    }
-
-  switch (deliver (msg, name, &errp))
+  switch (deliver (mesg, name, &errp))
     {
     case 0:
-      lmtp_reply (out, "250", "2.0.0", "%s: delivered", name);
+      lmtp_reply (iostr, "250", "2.0.0", "%s: delivered", name);
       break;
 
     case EX_UNAVAILABLE:
       if (errp)
-       lmtp_reply (out, "553", "5.1.8", "%s", errp);
+       lmtp_reply (iostr, "553", "5.1.8", "%s", errp);
       else
-       lmtp_reply (out, "553", "5.1.8", "%s: delivery failed", name);
+       lmtp_reply (iostr, "553", "5.1.8", "%s: delivery failed", name);
       break;
 
     default:
       if (errp)
-       lmtp_reply (out, "450", "4.1.0", "%s", errp);
+       lmtp_reply (iostr, "450", "4.1.0", "%s", errp);
       else
-       lmtp_reply (out, "450", "4.1.0",
+       lmtp_reply (iostr, "450", "4.1.0",
                    "%s: temporary failure, try again later",
                    name);
       break;
@@ -372,37 +344,103 @@ dot_deliver (void *item, void *cbdata)
 }
 
 int
-cfun_dot (FILE *out, char *arg)
+cfun_data (mu_stream_t iostr, char *arg)
 {
-  if (!mtmp)
-    mu_list_do (rcpt_list, dot_temp_fail, out);
-  else
+  int rc;
+  mu_stream_t flt, tempstr;
+  time_t t;
+  int xlev = MU_XSCRIPT_PAYLOAD, xlev_switch = 0, buf_switch = 0;
+  struct mu_buffer_query oldbuf;
+  
+  if (*arg)
     {
-      int rc = mail_tmp_finish (mtmp, &mbox);
-      if (rc)
-       mu_list_do (rcpt_list, dot_temp_fail, out);
-      else
-       {
-         mu_list_do (rcpt_list, dot_deliver, out);
-         mail_tmp_destroy (&mtmp);
-         mu_mailbox_destroy (&mbox);
-       }
+      lmtp_reply (iostr, "501", "5.5.2", "Syntax error");
+      return 1;
     }
-  free (mail_from);
-  mu_list_destroy (&rcpt_list);
+
+  rc = mu_filter_create (&flt, iostr, "CRLFDOT", MU_FILTER_DECODE,
+                        MU_STREAM_READ|MU_STREAM_WRTHRU);
+  if (rc)
+    {
+      maidag_error (_("unable to open filter: %s"),
+                   mu_strerror (rc));
+      lmtp_reply (iostr, "450", "4.1.0", "Temporary failure, try again later");
+      return 1;
+    }
+
+  rc = mu_temp_file_stream_create (&tempstr, NULL);
+  if (rc)
+    {
+      maidag_error (_("unable to open temporary file: %s"), mu_strerror (rc));
+      mu_stream_destroy (&flt);
+      return 1;
+    }
+
+  /* Write out envelope */
+  time (&t);
+  rc = mu_stream_printf (tempstr, "From %s %s", mail_from, ctime (&t));
+  if (rc)
+    {
+      maidag_error (_("copy error: %s"), mu_strerror (rc));
+      mu_stream_destroy (&flt);
+      mu_stream_destroy (&tempstr);
+      mu_list_do (rcpt_list, dot_temp_fail, iostr);
+    }
+
+  lmtp_reply (iostr, "354", NULL, "Go ahead");
+
+  if (mu_stream_ioctl (iostr, MU_IOCTL_GET_TRANSPORT_BUFFER, &oldbuf) == 0)
+    {
+      struct mu_buffer_query newbuf;
+
+      newbuf.type = MU_TRANSPORT_OUTPUT;
+      newbuf.buftype = mu_buffer_full;
+      newbuf.bufsize = 64*1024;
+      if (mu_stream_ioctl (iostr, MU_IOCTL_SET_TRANSPORT_BUFFER, &newbuf))
+       buf_switch = 1;
+    }
+
+  if (mu_stream_ioctl (iostr, MU_IOCTL_LEVEL, &xlev) == 0)
+    xlev_switch = 1;
+  rc = mu_stream_copy (tempstr, flt, 0, NULL);
+  mu_stream_destroy (&flt);
+  if (xlev_switch)
+    mu_stream_ioctl (iostr, MU_IOCTL_LEVEL, &xlev);
+  if (buf_switch)
+    mu_stream_ioctl (iostr, MU_IOCTL_SET_TRANSPORT_BUFFER, &oldbuf);
+  if (rc)
+    {
+      maidag_error (_("copy error: %s"), mu_strerror (rc));
+      mu_list_do (rcpt_list, dot_temp_fail, iostr);
+    }
+
+  rc = mu_stream_to_message (tempstr, &mesg);
+  if (rc)
+    {
+      maidag_error (_("error creating temporary message: %s"),
+                   mu_strerror (rc));
+      mu_list_do (rcpt_list, dot_temp_fail, iostr);
+    }
+  
+  rc = mu_list_do (rcpt_list, dot_deliver, iostr);
+
+  mu_stream_destroy (&tempstr);
+  mu_message_destroy (&mesg, mu_message_get_owner (mesg));
+  if (rc)
+    mu_list_do (rcpt_list, dot_temp_fail, iostr);
+
   return 0;
 }
-  
+
 
 int
-cfun_rset (FILE *out, char *arg)
+cfun_rset (mu_stream_t iostr, char *arg)
 {
   free (lhlo_domain);
   free (mail_from);
   mu_list_destroy (&rcpt_list);
-  mail_tmp_destroy (&mtmp);
-  mu_mailbox_destroy (&mbox);
-  lmtp_reply (out, "250", "2.0.0", "OK, forgotten");
+  mu_message_destroy (&mesg, mu_message_get_owner (mesg));
+  lmtp_reply (iostr, "250", "2.0.0", "OK, forgotten");
   return 0;
 }
 
@@ -413,32 +451,32 @@ PIPELINING\n\
 HELP";
 
 int
-cfun_lhlo (FILE *out, char *arg)
+cfun_lhlo (mu_stream_t iostr, char *arg)
 {
   if (*arg == 0)
     {
-      lmtp_reply (out, "501", "5.0.0", "Syntax error");
+      lmtp_reply (iostr, "501", "5.0.0", "Syntax error");
       return 1;
     }
   lhlo_domain = strdup (arg);
-  lmtp_reply (out, "250", NULL, "Hello\n");
-  lmtp_reply (out, "250", NULL, capa_str);
+  lmtp_reply (iostr, "250", NULL, "Hello\n");
+  lmtp_reply (iostr, "250", NULL, capa_str);
   return 0;
 }
 
 
 int
-cfun_quit (FILE *out, char *arg)
+cfun_quit (mu_stream_t iostr, char *arg)
 {
-  lmtp_reply (out, "221", "2.0.0", "Bye");
+  lmtp_reply (iostr, "221", "2.0.0", "Bye");
   return 0;
 }
 
 
 int
-cfun_help (FILE *out, char *arg)
+cfun_help (mu_stream_t iostr, char *arg)
 {
-  lmtp_reply (out, "200", "2.0.0", "Man, help yourself");
+  lmtp_reply (iostr, "200", "2.0.0", "Man, help yourself");
   return 0;
 }
 
@@ -448,7 +486,7 @@ struct command_tab
   char *cmd_verb;
   int cmd_len;
   enum lmtp_command cmd_code;
-  int (*cmd_fun) (FILE *, char *);
+  int (*cmd_fun) (mu_stream_t, char *);
 } command_tab[] = {
 #define S(s) #s, (sizeof #s - 1)
   { S(lhlo), cmd_lhlo, cfun_lhlo },
@@ -458,7 +496,6 @@ struct command_tab
   { S(quit), cmd_quit, cfun_quit },
   { S(rset), cmd_rset, cfun_rset },
   { S(help), cmd_help, cfun_help },
-  { S(.), cmd_dot, cfun_dot },
   { NULL, 0, cmd_unknown, cfun_unknown }
 };
 
@@ -479,72 +516,47 @@ getcmd (char *buf, char **sp)
   return cp;
 }
 
-static char *
-to_fgets (char *buf, size_t size, FILE *fp, unsigned int timeout)
+static int
+to_fgets (mu_stream_t iostr, char **pbuf, size_t *psize, size_t *pnread,
+         unsigned int timeout)
 {
-  char *p;
+  int rc;
+  
   alarm (timeout);
-  p = fgets (buf, size, fp);
+  rc = mu_stream_getline (iostr, pbuf, psize, pnread);
   alarm (0);
-  return p;
+  return rc;
 }
 
 int
-lmtp_loop (FILE *in, FILE *out, unsigned int timeout)
+lmtp_loop (mu_stream_t iostr, unsigned int timeout)
 {
-  char buf[1024];
+  size_t size = 0, n;
+  char *buf = NULL;
   enum lmtp_state state = state_init;
 
-  setvbuf (in, NULL, _IOLBF, 0);
-  setvbuf (out, NULL, _IOLBF, 0);
-
-  lmtp_reply (out, "220", NULL, "At your service");
-  while (to_fgets (buf, sizeof buf, in, timeout))
+  lmtp_reply (iostr, "220", NULL, "At your service");
+  while (to_fgets (iostr, &buf, &size, &n, timeout) == 0 && n)
     {
-      if (state == state_data
-         && !(buf[0] == '.'
-              && (buf[1] == '\n' || (buf[1] == '\r' && buf[2] == '\n'))))
-       {
-         /* This is a special case */
-         if (mtmp)
-           {
-             size_t len;
-             int rc;
+      char *sp;
+      struct command_tab *cp = getcmd (buf, &sp);
+      enum lmtp_command cmd = cp->cmd_code;
+      enum lmtp_state next_state = transtab[cmd][state];
 
-             xlatnl (buf);
-             len = strlen (buf);
-             if ((rc = mail_tmp_add_line (mtmp, buf, len)))
-               {
-                 mail_tmp_destroy (&mtmp);
-                 /* Wait the dot to report the error */
-               }
-           }
-       }
-      else
-       {
-         char *sp;
-         struct command_tab *cp = getcmd (buf, &sp);
-         enum lmtp_command cmd = cp->cmd_code;
-         enum lmtp_state next_state = transtab[cmd][state];
+      mu_rtrim_cset (sp, "\r\n");
 
-         mu_rtrim_cset (sp, "\r\n");
-
-         if (lmtp_transcript)
-           mu_diag_output (MU_DIAG_INFO, "LMTP receive: %s", buf);
-             
-         if (next_state != state_none)
+      if (next_state != state_none)
+       {
+         if (cp->cmd_fun)
            {
-             if (cp->cmd_fun)
-               {
-                 sp = mu_str_skip_class (sp, MU_CTYPE_SPACE);
-                 if (cp->cmd_fun (out, sp))
-                   continue;
-               }
-             state = next_state;
+             sp = mu_str_skip_class (sp, MU_CTYPE_SPACE);
+             if (cp->cmd_fun (iostr, sp))
+               continue;
            }
-         else
-           lmtp_reply (out, "503", "5.0.0", "Syntax error");
+         state = next_state;
        }
+      else
+       lmtp_reply (iostr, "503", "5.0.0", "Syntax error");
       
       if (state == state_end)
        break;
@@ -563,8 +575,22 @@ int
 lmtp_connection (int fd, struct sockaddr *sa, int salen, void *data,
                 mu_ip_server_t srv, time_t timeout, int transcript)
 {
-  lmtp_transcript = transcript;
-  lmtp_loop (fdopen (fd, "r"), fdopen (fd, "w"), timeout);
+  mu_stream_t str;
+  int rc;
+  
+  rc = mu_fd_stream_create (&str, NULL, fd,
+                           MU_STREAM_RDWR|MU_STREAM_AUTOCLOSE);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_fd_stream_create", NULL, rc);
+      return rc;
+    }
+  mu_stream_set_buffer (str, mu_buffer_line, 0);
+
+  if (transcript || maidag_transcript)
+    str = lmpt_transcript (str);
+  lmtp_loop (str, timeout);
+  mu_stream_destroy (&str);
   return 0;
 }
 
@@ -640,6 +666,40 @@ maidag_lmtp_server ()
       if (status)
        return EX_CONFIG;
     }
-  else 
-    return lmtp_loop (stdin, stdout, 0);
+  else
+    {
+      mu_stream_t str, istream, ostream;
+
+      rc = mu_stdio_stream_create (&istream, MU_STDIN_FD, MU_STREAM_READ);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
+                          "MU_STDIN_FD", rc);
+         return EX_UNAVAILABLE;
+       } 
+ 
+      rc = mu_stdio_stream_create (&ostream, MU_STDOUT_FD, MU_STREAM_WRITE);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
+                          "MU_STDOUT_FD", rc);
+         return 1;
+       } 
+
+      rc = mu_iostream_create (&str, istream, ostream);
+      mu_stream_unref (istream);
+      mu_stream_unref (ostream);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_iostream_create", NULL, rc);
+         return 1;
+       } 
+
+      if (maidag_transcript)
+       str = lmpt_transcript (str);
+
+      rc = lmtp_loop (str, 0);
+      mu_stream_destroy (&str);
+      return rc;
+    }
 }
diff --git a/maidag/maidag.c b/maidag/maidag.c
index 894fa61..ff5c34b 100644
--- a/maidag/maidag.c
+++ b/maidag/maidag.c
@@ -53,6 +53,7 @@ int lmtp_mode;
 int url_option;
 char *lmtp_url_string;
 int reuse_lmtp_address = 1;
+int maidag_transcript;
 
 const char *program_version = "maidag (" PACKAGE_STRING ")";
 static char doc[] =
@@ -72,6 +73,7 @@ static char args_doc[] = N_("[recipient...]");
 #define LMTP_OPTION 258
 #define FOREGROUND_OPTION 260
 #define URL_OPTION 261
+#define TRANSCRIPT_OPTION 262
 
 static struct argp_option options[] = 
 {
@@ -79,21 +81,23 @@ static struct argp_option options[] =
  { NULL, 0, NULL, 0,
    N_("General options"), GRID },
       
-  { "foreground", FOREGROUND_OPTION, 0, 0, N_("remain in foreground"),
-    GRID + 1 },
-  { "inetd",  'i', 0, 0, N_("run in inetd mode"), GRID + 1 },
-  { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
-    N_("runs in daemon mode with a maximum of NUMBER children"), GRID + 1 },
-  { "url", URL_OPTION, 0, 0, N_("deliver to given URLs"), GRID + 1 },
-  { "from", 'f', N_("EMAIL"), 0,
-    N_("specify the sender's name"), GRID + 1 },
-  { NULL, 'r', NULL, OPTION_ALIAS, NULL },
-  { "lmtp", LMTP_OPTION, N_("URL"), OPTION_ARG_OPTIONAL,
-    N_("operate in LMTP mode"), GRID + 1 },
-  { "debug", 'x', N_("FLAGS"), 0,
-    N_("enable debugging"), GRID + 1 },
-  { "stderr", STDERR_OPTION, NULL, 0,
-    N_("log to standard error"), GRID + 1 },
+ { "foreground", FOREGROUND_OPTION, 0, 0, N_("remain in foreground"),
+   GRID + 1 },
+ { "inetd",  'i', 0, 0, N_("run in inetd mode"), GRID + 1 },
+ { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
+   N_("runs in daemon mode with a maximum of NUMBER children"), GRID + 1 },
+ { "url", URL_OPTION, 0, 0, N_("deliver to given URLs"), GRID + 1 },
+ { "from", 'f', N_("EMAIL"), 0,
+   N_("specify the sender's name"), GRID + 1 },
+ { NULL, 'r', NULL, OPTION_ALIAS, NULL },
+ { "lmtp", LMTP_OPTION, N_("URL"), OPTION_ARG_OPTIONAL,
+   N_("operate in LMTP mode"), GRID + 1 },
+ { "debug", 'x', N_("FLAGS"), 0,
+   N_("enable debugging"), GRID + 1 },
+ { "stderr", STDERR_OPTION, NULL, 0,
+   N_("log to standard error"), GRID + 1 },
+ { "transcript", TRANSCRIPT_OPTION, NULL, 0,
+   N_("enable session transcript"), GRID + 1 },
 #undef GRID
 
 #define GRID 2
@@ -212,6 +216,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
        mu_argp_node_list_new (lst, "listen", arg);
       break;
 
+    case TRANSCRIPT_OPTION:
+      maidag_transcript = 1;
+      break;
+      
     case 'r':
     case 'f':
       if (sender_address != NULL)
diff --git a/maidag/maidag.h b/maidag/maidag.h
index 18ea2ec..aa2195f 100644
--- a/maidag/maidag.h
+++ b/maidag/maidag.h
@@ -142,6 +142,7 @@ extern char *lmtp_url_string;
 extern int reuse_lmtp_address;
 extern mu_list_t lmtp_groups;
 extern mu_acl_t maidag_acl;
+extern int maidag_transcript;
 
 void close_fds (void);
 int switch_user_id (struct mu_auth_data *auth, int user);
@@ -160,12 +161,6 @@ int deliver (mu_message_t msg, char *name, char **errp);
 int sieve_test (struct mu_auth_data *auth, mu_message_t msg);
 int check_quota (struct mu_auth_data *auth, mu_off_t size, mu_off_t *rest);
 
-struct mail_tmp;
-int mail_tmp_begin (struct mail_tmp **pmtmp, const char *from);
-int mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen);
-int mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox);
-void mail_tmp_destroy (struct mail_tmp **pmtmp);
-
 enum maidag_forward_result
   {
     maidag_forward_none,
diff --git a/maidag/mailtmp.c b/maidag/mailtmp.c
deleted file mode 100644
index d981673..0000000
--- a/maidag/mailtmp.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2009, 2010 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, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-   MA 02110-1301 USA */
-
-#include "maidag.h"
-
-struct mail_tmp
-{
-  mu_stream_t stream;
-  size_t line;
-  char *tempfile;
-  const char *from;
-  int had_nl;
-};  
-
-int
-mail_tmp_begin (struct mail_tmp **pmtmp, const char *from)
-{
-  int status;
-  struct mail_tmp *mtmp = malloc (sizeof *mtmp);
-  
-  if (!mtmp)
-    return ENOMEM;
-
-  memset (mtmp, 0, sizeof *mtmp);
-
-  mtmp->tempfile = mu_tempname (NULL);
-  if ((status = mu_file_stream_create (&mtmp->stream, mtmp->tempfile,
-                                      MU_STREAM_RDWR)))
-    {
-      free (mtmp);
-      maidag_error (_("unable to open temporary file: %s"),
-                   mu_strerror (status));
-      return status;
-    }
-
-  mtmp->from = from;
-  *pmtmp = mtmp;
-  return 0;
-}
-
-int
-mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen)
-{
-  int status = 0;
-  
-  mtmp->line++;
-  if (mtmp->line == 1)
-    {
-      const char *from = mtmp->from;
-      
-      if (buflen >= 5 && memcmp (buf, "From ", 5))
-       {
-         struct mu_auth_data *auth = NULL;
-         if (!from)
-           {
-             auth = mu_get_auth_by_uid (getuid ());
-             if (auth)
-               from = auth->name;
-           }
-         if (from)
-           {
-             time_t t;
-             char *envs;
-             
-             time (&t);
-             asprintf (&envs, "From %s %s", from, ctime (&t));
-             status = mu_stream_write (mtmp->stream, 
-                                       envs,
-                                       strlen (envs), NULL);
-             free (envs);
-           }
-         else
-           {
-             maidag_error (_("cannot determine sender address"));
-             return EINVAL;
-           }
-         if (auth)
-           mu_auth_data_free (auth);
-       }
-    }
-  else if (buflen >= 5 && !memcmp (buf, "From ", 5))
-    {
-      static char *escape = ">";
-      status = mu_stream_write (mtmp->stream, escape, 1, NULL);
-    }
-
-  if (!status)
-    status = mu_stream_write (mtmp->stream, buf, buflen, NULL);
-      
-  if (status)
-    {
-      maidag_error (_("error writing temporary file: %s"), 
-                    mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream);
-    }
-  mtmp->had_nl = buf[buflen-1] == '\n';
-  return status;
-}
-
-int
-mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox)
-{
-  int status;
-  static char *newline = "\n";
-  size_t n;
-  
-  if (!mtmp->had_nl)
-    status = mu_stream_write (mtmp->stream, newline, 1, NULL);
-
-  status = mu_stream_write (mtmp->stream, newline, 1, NULL);
-  unlink (mtmp->tempfile);
-  free (mtmp->tempfile);
-  mtmp->tempfile = NULL;
-  
-  if (status)
-    {
-      errno = status;
-      maidag_error (_("error writing temporary file: %s"), 
-                    mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream);
-      return status;
-    }
-
-  mu_stream_flush (mtmp->stream);
-  if ((status = mu_mailbox_create (mbox, "mbox:/dev/null")) 
-      || (status = mu_mailbox_open (*mbox, MU_STREAM_READ))
-      || (status = mu_mailbox_set_stream (*mbox, mtmp->stream)))
-    {
-      maidag_error (_("error opening temporary file: %s"), 
-                    mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream);
-      return status;
-    }
-
-  status = mu_mailbox_messages_count (*mbox, &n);
-  if (status)
-    {
-      errno = status;
-      maidag_error (_("error creating temporary message: %s"),
-                   mu_strerror (status));
-      mu_stream_destroy (&mtmp->stream);
-      return status;
-    }
-
-  mtmp->stream = NULL;
-  mtmp->line = 0;
-  
-  return status;
-  
-}
-
-void
-mail_tmp_destroy (struct mail_tmp **pmtmp)
-{
-  struct mail_tmp *mtmp = *pmtmp;
-
-  if (mtmp)
-    {
-      if (mtmp->tempfile)
-       {
-         unlink (mtmp->tempfile);
-         free (mtmp->tempfile);
-       }
-      mu_stream_destroy (&mtmp->stream);
-      free (*pmtmp);
-      *pmtmp = NULL;
-    }
-}
-
-
-  
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f600fe5..a189a7d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -90,7 +90,6 @@ maidag/deliver.c
 maidag/lmtp.c
 maidag/maidag.c
 maidag/mailquota.c
-maidag/mailtmp.c
 maidag/script.c
 
 mail/alias.c


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]