commit-mailutils
[Top][All Lists]
Advanced

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

[SCM] GNU Mailutils branch, stream-cleanup, updated. rel-2_1-126-g0b457b


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, stream-cleanup, updated. rel-2_1-126-g0b457bd
Date: Sun, 05 Sep 2010 20:58:30 +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=0b457bda897eb23a0e47e77101cda048a529b7f5

The branch, stream-cleanup has been updated
       via  0b457bda897eb23a0e47e77101cda048a529b7f5 (commit)
       via  bec42149a6b0fed88c6f8830f3fd8b8f9182baf9 (commit)
       via  2acce23b595b13b09458fa57d8919f3f81170424 (commit)
       via  084fa368c2e22216c5fcca8afeb2ee145948caaa (commit)
      from  a08bf28c50373eb68b18f7537d8eac8746da4097 (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 0b457bda897eb23a0e47e77101cda048a529b7f5
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 23:49:54 2010 +0300

    Begin rewriting pop3 mailbox support. Several bugfixes.
    
    * examples/pop3client.c (com_capa): Call mu_pop3_capa_test.
    (com_stat): Count is size_t.
    
    * include/mailutils/opool.h (mu_opool_copy): New proto.
    * mailbox/opool.c (mu_opool_copy): New function.
    * mailbox/xscript-stream.c (_xscript_ctl)
    <MU_IOCTL_SWAP_STREAM>: Avoid coredumping if sp->transport
    is NULL.
    
    * include/mailutils/pop3.h (pop3_capa_test): Rename to
    mu_pop3_capa_test.
    (mu_pop3_stat): Third argument is a pointer to mu_off_t.
    * libproto/pop/pop3_capatst.c (pop3_capa_test): Rename to
    mu_pop3_capa_test.
    * libproto/pop/pop3_stat.c (mu_pop3_stat): Third argument is
    a pointer to mu_off_t.
    
    * libproto/pop/Makefile.am (libmu_pop_la_SOURCES): Put back
    folder.c, url.c and mbox.c.
    * libproto/pop/mbox.c: Begin rewriting.

commit bec42149a6b0fed88c6f8830f3fd8b8f9182baf9
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 20:14:53 2010 +0300

    Minor change in stream API.  Improve POP3 client interface.
    
    * include/mailutils/sys/stream.h (_MU_STR_EVENT_SET)
    (_MU_STR_EVENT_CLR): New defines.
    (_mu_stream) <event_cb, event_mask>: New members.
    * mailbox/stream.c (_stream_setflag, _stream_clrflag): New static
    functions.
    All functions use these instead of setting/clearing flags directly.
    (_mu_stream_cleareof, _mu_stream_seteof): New extern functions.
    (_stream_cleareof): Remove define, use _mu_stream_cleareof instead.
    (_stream_fill_buffer): Set EOF marker when end of stream is reached.
    
    * mailbox/fltstream.c (filter_read): Call _mu_stream_seteof to set
    EOF flag.
    
    * include/mailutils/pop3.h: Get rid of the superfluous "extern" in
    front of function prototypes.
    Add new prototypes.
    Remove extra whitespace.
    
    * libproto/pop/pop3_capatst.c: New file.
    * libproto/pop/pop3_list_cmd.c: New file.
    * libproto/pop/pop3_listas.c: New file.
    * libproto/pop/pop3_rdlist.c: New file.
    * libproto/pop/pop3_uidl_cmd.c: New file.
    * libproto/pop/pop3_uidlas.c: New file.
    * libproto/pop/Makefile.am: Add new files.
    * libproto/pop/pop3_capa.c (_mu_pop3_fill_list): Remove.
    Use mu_pop3_read_list instead.
    (capa_comp): New comparator for capa lists.
    * libproto/pop/pop3_list.c (mu_pop3_list): Fix format specifier.
    * libproto/pop/pop3_lista.c (mu_pop3_list_all): Rewrite.
    * libproto/pop/pop3_retr.c (mu_pop3_retr) <MU_POP3_RETR_RX>: do not
    reset state, this is done by the EOF event callback.
    * libproto/pop/pop3_top.c (mu_pop3_top) <MU_POP3_TOP_RX>: Likewise.
    * libproto/pop/pop3_stream.c (pop3_decode_state): New state pds_char.
    Change semantics of pds_init.
    (newstate, _pop3_decoder): Handle .\r\n in the initial state.
    (_pop3_event_cb): New event callback.
    (mu_pop3_filter_create): Set event callback on the filter stream.
    * libproto/pop/pop3_uidla.c (mu_pop3_uidl_all): Rewrite.
    
    * examples/Makefile.am (pop3client_CPPFLAGS): Add MU_APP_COMMON_INCLUDES.
    * examples/pop3client.c: Rewrite command parser.

commit 2acce23b595b13b09458fa57d8919f3f81170424
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 12:38:39 2010 +0300

    Further fixes in pop3.
    
    * libproto/pop/pop3_create.c (_mu_pop3_init): Fix return value.
    * libproto/pop/pop3_destroy.c: Add missing includes.
    * libproto/pop/pop3_stream.c (_pop3_decoder): Remove the final
    .\r\n altogether.
    * mailbox/fltstream.c (filter_read): Remove the hack for supporting
    buggy filters.

commit 084fa368c2e22216c5fcca8afeb2ee145948caaa
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Sep 5 12:38:20 2010 +0300

    Fix TLS support in smtp.
    
    * include/mailutils/tls.h (mu_tls_readline_fn)
    (mu_tls_writeline_fn, mu_tls_stream_ctl_fn): Remove typedefs.
    (mu_tls_begin): Remove prototype.
    * libmu_auth/tls.c (mu_tls_begin): Remove function.
    * libproto/mailer/smtp.c: Revamp STARTTLS support.

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

Summary of changes:
 examples/Makefile.am                              |    1 +
 examples/pop3client.c                             |  649 +++---
 include/mailutils/opool.h                         |    4 +
 include/mailutils/pop3.h                          |   90 +-
 include/mailutils/sys/stream.h                    |    9 +
 include/mailutils/tls.h                           |   13 -
 libmu_auth/tls.c                                  |   88 -
 libproto/mailer/smtp.c                            |   62 +-
 libproto/pop/Makefile.am                          |   12 +-
 libproto/pop/mbox.c                               | 2503 ++++-----------------
 libproto/pop/pop3_capa.c                          |   40 +-
 mailbox/freeitem.c => libproto/pop/pop3_capatst.c |   18 +-
 libproto/pop/pop3_create.c                        |    2 +
 libproto/pop/pop3_destroy.c                       |    1 +
 libproto/pop/pop3_list.c                          |    2 +-
 libproto/pop/{pop3_lista.c => pop3_list_cmd.c}    |    9 +-
 libproto/pop/pop3_lista.c                         |   44 +-
 mailbox/dbgsyslog.c => libproto/pop/pop3_listas.c |   19 +-
 libproto/pop/{pop3_quit.c => pop3_rdlist.c}       |   56 +-
 libproto/pop/pop3_retr.c                          |    5 +-
 libproto/pop/pop3_stat.c                          |    7 +-
 libproto/pop/pop3_stream.c                        |   55 +-
 libproto/pop/pop3_top.c                           |    5 +-
 libproto/pop/{pop3_uidla.c => pop3_uidl_cmd.c}    |   10 +-
 libproto/pop/pop3_uidla.c                         |   45 +-
 mailbox/dbgsyslog.c => libproto/pop/pop3_uidlas.c |   20 +-
 mailbox/fltstream.c                               |   11 +-
 mailbox/opool.c                                   |   19 +
 mailbox/stream.c                                  |   55 +-
 mailbox/xscript-stream.c                          |    5 +-
 30 files changed, 1109 insertions(+), 2750 deletions(-)
 copy mailbox/freeitem.c => libproto/pop/pop3_capatst.c (71%)
 copy libproto/pop/{pop3_lista.c => pop3_list_cmd.c} (86%)
 copy mailbox/dbgsyslog.c => libproto/pop/pop3_listas.c (70%)
 copy libproto/pop/{pop3_quit.c => pop3_rdlist.c} (53%)
 copy libproto/pop/{pop3_uidla.c => pop3_uidl_cmd.c} (82%)
 copy mailbox/dbgsyslog.c => libproto/pop/pop3_uidlas.c (69%)

diff --git a/examples/Makefile.am b/examples/Makefile.am
index 1ba0b87..f3fe13b 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -110,6 +110,7 @@ sfrom_LDADD =\
  @address@hidden
  ${MU_LIB_MAILUTILS}
 
+pop3client_CPPFLAGS = @MU_APP_COMMON_INCLUDES@
 pop3client_LDADD = \
  ../lib/libmuaux.la\
  ${MU_LIB_POP}\
diff --git a/examples/pop3client.c b/examples/pop3client.c
index 3751c0a..d3085eb 100644
--- a/examples/pop3client.c
+++ b/examples/pop3client.c
@@ -34,6 +34,7 @@
 #include <stdlib.h>
 #include <termios.h>
 #include <signal.h>
+#include <xalloc.h>
 
 #ifdef WITH_READLINE
 # include <readline/readline.h>
@@ -56,64 +57,81 @@
 typedef struct
 {
   const char *name;            /* User printable name of the function. */
-  int (*func) (char *);                /* Function to call to do the job. */
+  int argmin;
+  int argmax;
+  int (*func) (int, char **);  /* Function to call to do the job. */
   const char *doc;             /* Documentation for this function.  */
 }
 COMMAND;
 
 /* The names of functions that actually do the manipulation. */
-int com_apop (char *);
-int com_capa (char *);
-int com_disconnect (char *);
-int com_dele (char *);
-int com_exit (char *);
-int com_help (char *);
-int com_list (char *);
-int com_noop (char *);
-int com_connect (char *);
-int com_pass (char *);
-int com_quit (char *);
-int com_retr (char *);
-int com_rset (char *);
-int com_stat (char *);
-int com_top (char *);
-int com_uidl (char *);
-int com_user (char *);
-int com_verbose (char *);
-int com_prompt (char *);
-int com_stls (char *);
-
-void initialize_readline (void);
-COMMAND *find_command (char *);
-char *dupstr (const char *);
-int execute_line (char *);
-int valid_argument (const char *, char *);
+int com_apop (int, char **);
+int com_capa (int, char **);
+int com_disconnect (int, char **);
+int com_dele (int, char **);
+int com_exit (int, char **);
+int com_help (int, char **);
+int com_list (int, char **);
+int com_noop (int, char **);
+int com_connect (int, char **);
+int com_pass (int, char **);
+int com_quit (int, char **);
+int com_retr (int, char **);
+int com_rset (int, char **);
+int com_stat (int, char **);
+int com_top (int, char **);
+int com_uidl (int, char **);
+int com_user (int, char **);
+int com_verbose (int, char **);
+int com_prompt (int, char **);
+int com_stls (int, char **);
 
-void sig_int (int);
+COMMAND *find_command (char *);
 
 COMMAND commands[] = {
-  { "apop", com_apop, "Authenticate with APOP: APOP user secret" },
-  { "capa", com_capa, "List capabilities: capa" },
-  { "disconnect", com_disconnect, "Close connection: disconnect" },
-  { "dele", com_dele, "Mark message: DELE msgno" },
-  { "exit", com_exit, "exit program" },
-  { "help", com_help, "Display this text" },
-  { "?", com_help, "Synonym for `help'" },
-  { "list", com_list, "List messages: LIST [msgno]" },
-  { "noop", com_noop, "Send no operation: NOOP" },
-  { "pass", com_pass, "Send passwd: PASS [passwd]" },
-  { "prompt", com_prompt, "Set command prompt" },
-  { "connect", com_connect, "Open connection: connect hostname [port]" },
-  { "quit", com_quit, "Go to Update state : QUIT" },
-  { "retr", com_retr, "Dowload message: RETR msgno" },
-  { "rset", com_rset, "Unmark all messages: RSET" },
-  { "stat", com_stat, "Get the size and count of mailbox : STAT [msgno]" },
-  { "stls", com_stls, "Start TLS negotiation" },
-  { "top", com_top, "Get the header of message: TOP msgno [lines]" },
-  { "uidl", com_uidl, "Get the unique id of message: UIDL [msgno]" },
-  { "user", com_user, "send login: USER user" },
-  { "verbose", com_verbose, "Enable Protocol tracing: verbose [on|off]" },
-  { NULL, NULL, NULL }
+  { "apop",       3,  3, com_apop,
+    "Authenticate with APOP: APOP user secret" },
+  { "capa",       1, -1, com_capa,
+    "List capabilities: capa [-reread] [names...]" },
+  { "disconnect", 1, 1,
+    com_disconnect, "Close connection: disconnect" },
+  { "dele",       2, 2, com_dele,
+    "Mark message: DELE msgno" },
+  { "exit",       1, 1, com_exit,
+    "exit program" },
+  { "help",       1, 1, com_help,
+    "Display this text" },
+  { "?",          1, 1, com_help,
+    "Synonym for `help'" },
+  { "list",       1, 2, com_list,
+    "List messages: LIST [msgno]" },
+  { "noop",       1, 1, com_noop,
+    "Send no operation: NOOP" },
+  { "pass",       1, 2, com_pass,
+    "Send passwd: PASS [passwd]" },
+  { "prompt",     -1, -1, com_prompt,
+    "Set command prompt" },
+  { "connect",    1, 4, com_connect,
+    "Open connection: connect [-tls] hostname port" },
+  { "quit",       1, 1, com_quit,
+    "Go to Update state : QUIT" },
+  { "retr",       2, 2, com_retr,
+    "Dowload message: RETR msgno" },
+  { "rset",       1, 1, com_rset,
+    "Unmark all messages: RSET" },
+  { "stat",       1, 1, com_stat,
+    "Get the size and count of mailbox : STAT" },
+  { "stls",       1, 1, com_stls,
+    "Start TLS negotiation" },
+  { "top",        2, 3, com_top,
+    "Get the header of message: TOP msgno [lines]" },
+  { "uidl",       1, 2, com_uidl,
+    "Get the unique id of message: UIDL [msgno]" },
+  { "user",       2, 2, com_user,
+    "send login: USER user" },
+  { "verbose",    1, 2, com_verbose,
+    "Enable Protocol tracing: verbose [on|off]" },
+  { NULL }
 };
 
 /* Global handle for pop3.  */
@@ -189,20 +207,6 @@ expand_prompt ()
   return str;
 }
 
-char *
-dupstr (const char *s)
-{
-  char *r;
-
-  r = malloc (strlen (s) + 1);
-  if (!r)
-    {
-      mu_error ("Memory exhausted");
-      exit (1);
-    }
-  strcpy (r, s);
-  return r;
-}
 
 
 #ifdef WITH_READLINE
@@ -269,7 +273,7 @@ command_generator (const char *text, int state)
       list_index++;
 
       if (strncmp (name, text, len) == 0)
-       return (dupstr (name));
+       return xstrdup (name);
     }
 
   /* If no names matched, then return NULL. */
@@ -304,73 +308,103 @@ add_history (const char *s MU_ARG_UNUSED)
 }
 #endif
 
+int
+get_bool (const char *str, int *pb)
+{
+  if (mu_c_strcasecmp (str, "yes") == 0
+      || mu_c_strcasecmp (str, "on") == 0
+      || mu_c_strcasecmp (str, "true") == 0)
+    *pb = 1;
+  else if (mu_c_strcasecmp (str, "no") == 0
+      || mu_c_strcasecmp (str, "off") == 0
+      || mu_c_strcasecmp (str, "false") == 0)
+    *pb = 0;
+  else
+    {
+      mu_error ("not a boolean: %s", str);
+      return 1;
+    }
+  return 0;
+}
 
 int
-main (int argc MU_ARG_UNUSED, char **argv)
+get_port (const char *port_str, int *pn)
 {
-  char *line, *s;
-
-  mu_set_program_name (argv[0]);
-  prompt = strdup (DEFAULT_PROMPT);
-  initialize_readline ();      /* Bind our completer. */
-#ifdef WITH_TLS
-  mu_init_tls_libs ();
-#endif  
-  /* Loop reading and executing lines until the user quits. */
-  while (!done)
+  short port_num;
+  long num;
+  char *p;
+  
+  num = port_num = strtol (port_str, &p, 0);
+  if (*p == 0)
     {
-      char *p = expand_prompt ();
-      line = readline (p);
-      free (p);
-      
-      if (!line)
-       break;
-
-      /* Remove leading and trailing whitespace from the line.
-         Then, if there is anything left, add it to the history list
-         and execute it. */
-      s = mu_str_stripws (line);
-
-      if (*s)
+      if (num != port_num)
        {
-         int status;
-         add_history (s);
-         status = execute_line (s);
-         if (status != 0)
-           mu_error ("Error: %s", mu_strerror (status));
+         mu_error ("bad port number: %s", port_str);
+         return 1;
        }
-
-      free (line);
     }
-  exit (0);
+  else
+    {
+      struct servent *sp = getservbyname (port_str, "tcp");
+      if (!sp)
+       {
+         mu_error ("unknown port name");
+         return 1;
+       }
+      port_num = ntohs (sp->s_port);
+    }
+  *pn = port_num;
+  return 0;
 }
-
+
 /* Parse and execute a command line. */
 int
 execute_line (char *line)
 {
-  COMMAND *command;
-  char *word, *arg;
+  int argc;
+  char **argv;
+  int status = 0;
 
-  /* Isolate the command word. */
-  word = mu_str_skip_class (line, MU_CTYPE_SPACE);
-  arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
-  if (*arg)
+  if (mu_argcv_get (line, NULL, "#", &argc, &argv))
     {
-      *arg++ = 0;
-      arg = mu_str_skip_class (arg, MU_CTYPE_SPACE);
+      mu_error("cannot parse input line");
+      return 0;
     }
-      
-  command = find_command (word);
 
-  if (!command)
+  if (argc >= 0)
     {
-      mu_error ("%s: No such command.", word);
-      return 0;
+      COMMAND *command = find_command (argv[0]);
+      
+      if (!command)
+       mu_error ("%s: no such command.", argv[0]);
+      else if (command->argmin > 0 && argc < command->argmin)
+       mu_error ("%s: too few arguments", argv[0]);
+      else if (command->argmax > 0 && argc > command->argmax)
+       mu_error ("%s: too many arguments", argv[0]);
+      else
+       {
+         if (command->argmin <= 0 && argc != 2)
+           {
+             char *word = mu_str_skip_class (line, MU_CTYPE_SPACE);
+             char *arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE);
+             if (*arg)
+               {
+                 *arg++ = 0;
+                 arg = mu_str_skip_class (arg, MU_CTYPE_SPACE);
+               }
+             
+             mu_argcv_free (argc, argv);
+             argc = 2;
+             argv = xcalloc (argc + 1, sizeof (argv[0]));
+             argv[0] = xstrdup (word);
+             argv[1] = xstrdup (arg);
+             argv[2] = NULL;
+           }
+         status = command->func (argc, argv);
+       }
     }
-
-  /* Call the function. */
-  return ((*(command->func)) (arg));
+  mu_argcv_free (argc, argv);
+  return status;
 }
 
 /* Look up NAME as the name of a command, and return a pointer to that
@@ -378,106 +412,139 @@ execute_line (char *line)
 COMMAND *
 find_command (char *name)
 {
-  register int i;
+  COMMAND *cp;
 
-  for (i = 0; commands[i].name; i++)
-    if (strcmp (name, commands[i].name) == 0)
-      return (&commands[i]);
+  for (cp = commands; cp->name; cp++)
+    if (strcmp (cp->name, name) == 0)
+      return cp;
 
-  return ((COMMAND *) NULL);
+  return NULL;
 }
 
 int
-com_verbose (char *arg)
+com_verbose (int argc, char **argv)
 {
-  int status = 0;
-  if (!valid_argument ("verbose", arg))
-    return EINVAL;
-
-  verbose = (strcmp (arg, "on") == 0);
-  if (pop3 != NULL)
+  if (argc == 1)
     {
-      if (verbose == 1)
-       mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
+      if (verbose)
+       printf ("verbose is on\n");
       else
-       mu_pop3_trace (pop3, MU_POP3_TRACE_CLR);
+       printf ("verbose is off\n");
     }
-  return status;
+  else
+    {
+      int bv;
+
+      if (get_bool (argv[1], &bv) == 0)
+       {
+         verbose = bv;
+         if (pop3 != NULL)
+           {
+             if (verbose == 1)
+               mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
+             else
+               mu_pop3_trace (pop3, MU_POP3_TRACE_CLR);
+           }
+       }
+    }
+  return 0;
 }
 
 int
-com_user (char *arg)
+com_user (int argc, char **argv)
 {
   int status;
   
-  if (!valid_argument ("user", arg))
-    return EINVAL;
-  status = mu_pop3_user (pop3, arg);
+  status = mu_pop3_user (pop3, argv[1]);
   if (status == 0)
-    username = strdup (arg);
+    username = strdup (argv[1]);
   return status;
 }
 
 int
-com_apop (char *arg)
+com_apop (int argc, char **argv)
 {
   int status;
-  char *user, *digest;
-
-  if (!valid_argument ("apop", arg))
-    return EINVAL;
-  user = strtok (arg, " ");
-  digest = strtok (NULL, " ");
-  if (!valid_argument ("apop", user) || !valid_argument ("apop", digest))
-    return EINVAL;
-  status = mu_pop3_apop (pop3, user, digest);
+
+  status = mu_pop3_apop (pop3, argv[1], argv[2]);
   if (status == 0)
     {
-      username = strdup (user);
+      username = strdup (argv[1]);
       pop_session_status = pop_session_logged_in;
     }
   return status;
 }
 
 int
-com_capa (char *arg)
+com_capa (int argc, char **argv)
 {
   mu_iterator_t iterator = NULL;
-  int status;
+  int status = 0;
   int reread = 0;
-
-  if (arg && *arg)
+  int i = 1;
+  
+  for (i = 1; i < argc; i++)
     {
-      if (strcmp (arg, "reread") == 0)
+      if (strcmp (argv[i], "-reread") == 0)
        reread = 1;
       else
+       break;
+    }
+
+  if (i < argc)
+    {
+      if (reread)
        {
-         mu_error ("%s: unknown argument", "capa");
-         return 0;
+         status = mu_pop3_capa (pop3, 1, NULL);
+         if (status)
+           return status;
+       }
+      for (; i < argc; i++)
+       {
+         const char *elt;
+         int rc = mu_pop3_capa_test (pop3, argv[i], &elt);
+         switch (rc)
+           {
+           case 0:
+             if (*elt)
+               printf ("%s: %s\n", argv[i], elt);
+             else
+               printf ("%s is set\n", argv[i]);
+             break;
+
+           case MU_ERR_NOENT:
+             printf ("%s is not set\n", argv[i]);
+             break;
+
+           default:
+             return rc;
+           }
        }
     }
-
-  status = mu_pop3_capa (pop3, reread, &iterator);
-
-  if (status == 0)
+  else
     {
-      for (mu_iterator_first (iterator);
-          !mu_iterator_is_done (iterator); mu_iterator_next (iterator))
+      status = mu_pop3_capa (pop3, reread, &iterator);
+
+      if (status == 0)
        {
-         char *capa = NULL;
-         mu_iterator_current (iterator, (void **) &capa);
-         printf ("Capa: %s\n", (capa) ? capa : "");
+         for (mu_iterator_first (iterator);
+              !mu_iterator_is_done (iterator); mu_iterator_next (iterator))
+           {
+             char *capa = NULL;
+             mu_iterator_current (iterator, (void **) &capa);
+             printf ("CAPA: %s\n", capa ? capa : "");
+           }
+         mu_iterator_destroy (&iterator);
        }
-      mu_iterator_destroy (&iterator);
     }
   return status;
 }
 
 int
-com_uidl (char *arg)
+com_uidl (int argc, char **argv)
 {
   int status = 0;
-  if (arg == NULL || *arg == '\0')
+  if (argc == 1)
     {
       mu_iterator_t uidl_iterator = NULL;
       status = mu_pop3_uidl_all (pop3, &uidl_iterator);
@@ -489,7 +556,7 @@ com_uidl (char *arg)
            {
              char *uidl = NULL;
              mu_iterator_current (uidl_iterator, (void **) &uidl);
-             printf ("UIDL: %s\n", (uidl) ? uidl : "");
+             printf ("UIDL: %s\n", uidl ? uidl : "");
            }
          mu_iterator_destroy (&uidl_iterator);
        }
@@ -497,20 +564,20 @@ com_uidl (char *arg)
   else
     {
       char *uidl = NULL;
-      unsigned int msgno = strtoul (arg, NULL, 10);
+      unsigned int msgno = strtoul (argv[1], NULL, 10);
       status = mu_pop3_uidl (pop3, msgno, &uidl);
       if (status == 0)
-       printf ("Msg: %d UIDL: %s\n", msgno, (uidl) ? uidl : "");
+       printf ("Msg: %d UIDL: %s\n", msgno, uidl ? uidl : "");
       free (uidl);
     }
   return status;
 }
 
 int
-com_list (char *arg)
+com_list (int argc, char **argv)
 {
   int status = 0;
-  if (arg == NULL || *arg == '\0')
+  if (argc == 1)
     {
       mu_iterator_t list_iterator;
       status = mu_pop3_list_all (pop3, &list_iterator);
@@ -530,7 +597,7 @@ com_list (char *arg)
   else
     {
       size_t size = 0;
-      unsigned int msgno = strtoul (arg, NULL, 10);
+      unsigned int msgno = strtoul (argv[1], NULL, 10);
       status = mu_pop3_list (pop3, msgno, &size);
       if (status == 0)
        printf ("Msg: %u Size: %lu\n", msgno, (unsigned long) size);
@@ -539,7 +606,7 @@ com_list (char *arg)
 }
 
 int
-com_noop (char *arg MU_ARG_UNUSED)
+com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   return mu_pop3_noop (pop3);
 }
@@ -561,33 +628,31 @@ echo_on (struct termios *stored_settings)
 }
 
 int
-com_prompt (char *arg)
+com_prompt (int argc, char **argv)
 {
   int quote;
   size_t size;
   
-  if (!valid_argument ("prompt", arg))
-    return EINVAL;
-
   free (prompt);
-  size = mu_argcv_quoted_length (arg, &quote);
+  size = mu_argcv_quoted_length (argv[1], &quote);
   prompt = malloc (size + 1);
   if (!prompt)
     {
       mu_error ("Memory exhausted");
       exit (1);
     }
-  mu_argcv_unquote_copy (prompt, arg, size);
+  mu_argcv_unquote_copy (prompt, argv[1], size);
   return 0;
 }
 
 int
-com_pass (char *arg)
+com_pass (int argc, char **argv)
 {
   int status;
   char pass[256];
+  char *pwd;
   
-  if (!arg || *arg == '\0')
+  if (argc == 1)
     {
       struct termios stored_settings;
 
@@ -599,18 +664,20 @@ com_pass (char *arg)
       putchar ('\n');
       fflush (stdout);
       pass[strlen (pass) - 1] = '\0';  /* nuke the trailing line.  */
-      arg = pass;
+      pwd = pass;
     }
-  status = mu_pop3_pass (pop3, arg);
+  else
+    pwd = argv[1];
+  status = mu_pop3_pass (pop3, pwd);
   if (status == 0)
     pop_session_status = pop_session_logged_in;
   return status;
 }
 
 int
-com_stat (char *arg MU_ARG_UNUSED)
+com_stat (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
-  unsigned count = 0;
+  size_t count = 0;
   size_t size = 0;
   int status = 0;
 
@@ -621,32 +688,31 @@ com_stat (char *arg MU_ARG_UNUSED)
 }
 
 int
-com_stls (char *arg MU_ARG_UNUSED)
+com_stls (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   return mu_pop3_stls (pop3);
 }
 
 int
-com_dele (char *arg)
+com_dele (int argc, char **argv)
 {
   unsigned msgno;
-  if (!valid_argument ("dele", arg))
-    return EINVAL;
-  msgno = strtoul (arg, NULL, 10);
+  msgno = strtoul (argv[1], NULL, 10);
   return mu_pop3_dele (pop3, msgno);
 }
 
 /* Print out help for ARG, or for all of the commands if ARG is
    not present. */
 int
-com_help (char *arg)
+com_help (int argc, char **argv)
 {
   int i;
   int printed = 0;
-
+  char *name = argv[1];
+  
   for (i = 0; commands[i].name; i++)
     {
-      if (!*arg || (strcmp (arg, commands[i].name) == 0))
+      if (!name || (strcmp (name, commands[i].name) == 0))
        {
          printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
          printed++;
@@ -655,7 +721,7 @@ com_help (char *arg)
 
   if (!printed)
     {
-      printf ("No commands match `%s'.  Possibilties are:\n", arg);
+      printf ("No commands match `%s'.  Possibilties are:\n", name);
 
       for (i = 0; commands[i].name; i++)
        {
@@ -677,32 +743,24 @@ com_help (char *arg)
 }
 
 int
-com_rset (char *arg MU_ARG_UNUSED)
+com_rset (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   return mu_pop3_rset (pop3);
 }
 
 int
-com_top (char *arg)
+com_top (int argc, char **argv)
 {
   mu_stream_t stream;
   unsigned int msgno;
   unsigned int lines;
-  char *space;
   int status;
 
-  if (!valid_argument ("top", arg))
-    return EINVAL;
-
-  space = strchr (arg, ' ');
-  if (space)
-    {
-      *space++ = '\0';
-      lines = strtoul (space, NULL, 10);
-    }
+  msgno = strtoul (argv[1], NULL, 10);
+  if (argc == 3)
+    lines = strtoul (argv[2], NULL, 10);
   else
-    lines = 0;
-  msgno = strtoul (arg, NULL, 10);
+    lines = 5;
 
   status = mu_pop3_top (pop3, msgno, lines, &stream);
 
@@ -718,16 +776,13 @@ com_top (char *arg)
 }
 
 int
-com_retr (char *arg)
+com_retr (int argc, char **argv)
 {
   mu_stream_t stream;
   unsigned int msgno;
   int status;
 
-  if (!valid_argument ("retr", arg))
-    return EINVAL;
-
-  msgno = strtoul (arg, NULL, 10);
+  msgno = strtoul (argv[1], NULL, 10);
   status = mu_pop3_retr (pop3, msgno, &stream);
 
   if (status == 0)
@@ -742,73 +797,44 @@ com_retr (char *arg)
 }
 
 int
-get_port (const char *port_str, int *pn)
+com_connect (int argc, char **argv)
 {
-  short port_num;
-  long num;
-  char *p;
+  int status;
+  int n = 0;
+  int tls = 0;
+  int i = 1;
   
-  num = port_num = strtol (port_str, &p, 0);
-  if (*p == 0)
-    {
-      if (num != port_num)
-       {
-         mu_error ("bad port number: %s", port_str);
-         return 1;
-       }
-    }
-  else
+  for (i = 1; i < argc; i++)
     {
-      struct servent *sp = getservbyname (port_str, "tcp");
-      if (!sp)
+      if (strcmp (argv[i], "-tls") == 0)
        {
-         mu_error ("unknown port name");
-         return 1;
+         if (WITH_TLS)
+           tls = 1;
+         else
+           {
+             mu_error ("TLS not supported");
+             return 0;
+           }
        }
-      port_num = ntohs (sp->s_port);
+      else
+       break;
     }
-  *pn = port_num;
-  return 0;
-}
 
-int
-com_connect (char *arg)
-{
-  int status;
-  int n = 110;
-  int argc;
-  char **argv;
-  
-  if (!valid_argument ("connect", arg))
-    return 1;
+  argc -= i;
+  argv += i;
   
-  if (mu_argcv_get (arg, NULL, NULL, &argc, &argv))
+  if (argc >= 2)
     {
-      mu_error ("Cannot parse arguments");
-      return 0;
-    }
-  
-  if (!valid_argument ("connect", argv[0]))
-    {
-      mu_argcv_free (argc, argv);
-      return EINVAL;
-    }
-  
-  if (argc > 2)
-    {
-      mu_error ("Too many arguments");
-      mu_argcv_free (argc, argv);
-      return 0;
-    }
-
-  if (argc == 2 && get_port (argv[1], &n))
-    {
-      mu_argcv_free (argc, argv);
-      return 0;
+      if (get_port (argv[1], &n))
+       return 0;
     }
+  else if (tls)
+    n = MU_POP3_DEFAULT_SSL_PORT;
+  else
+    n = MU_POP3_DEFAULT_PORT;
   
   if (pop_session_status != pop_session_disconnected)
-    com_disconnect (NULL);
+    com_disconnect (0, NULL);
   
   status = mu_pop3_create (&pop3);
   if (status == 0)
@@ -816,10 +842,35 @@ com_connect (char *arg)
       mu_stream_t tcp;
 
       if (verbose)
-       com_verbose ("on");
+       mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
       status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
       if (status == 0)
        {
+#ifdef WITH_TLS
+         if (tls)
+           {
+             mu_stream_t tlsstream;
+             
+             status = mu_stream_open (tcp);
+             if (status)
+               {
+                 mu_error ("cannot open connection: %s",
+                           mu_stream_strerror (tcp, status));
+                 mu_stream_destroy (&tcp);
+                 return 0;
+               }
+
+             status = mu_tls_client_stream_create (&tlsstream, tcp, tcp, 0);
+             mu_stream_unref (tcp);
+             if (status)
+               {
+                 mu_error ("cannot create TLS stream: %s",
+                           mu_strerror (status));
+                 return 0;
+               }
+             tcp = tlsstream;
+           }
+#endif
          mu_pop3_set_carrier (pop3, tcp);
          status = mu_pop3_connect (pop3);
        }
@@ -831,14 +882,14 @@ com_connect (char *arg)
     }
 
   if (status)
-    {
-      mu_error ("Failed to create pop3: %s", mu_strerror (status));
-      mu_argcv_free (argc, argv);
-    }
+    mu_error ("Failed to create pop3: %s", mu_strerror (status));
   else
     {
       connect_argc = argc;
-      connect_argv = argv;
+      connect_argv = xcalloc (argc, sizeof (*connect_argv));
+      for (i = 0; i < argc; i++)
+       connect_argv[i] = xstrdup (argv[i]);
+      connect_argv[i] = NULL;
       port = n;
       pop_session_status = pop_session_connected;
     }
@@ -847,7 +898,7 @@ com_connect (char *arg)
 }
 
 int
-com_disconnect (char *arg MU_ARG_UNUSED)
+com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   if (pop3)
     {
@@ -864,14 +915,14 @@ com_disconnect (char *arg MU_ARG_UNUSED)
 }
 
 int
-com_quit (char *arg MU_ARG_UNUSED)
+com_quit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   int status = 0;
   if (pop3)
     {
       if (mu_pop3_quit (pop3) == 0)
        {
-         status = com_disconnect (arg);
+         status = com_disconnect (0, NULL);
        }
       else
        {
@@ -884,7 +935,7 @@ com_quit (char *arg MU_ARG_UNUSED)
 }
 
 int
-com_exit (char *arg MU_ARG_UNUSED)
+com_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
 {
   if (pop3)
     {
@@ -895,16 +946,44 @@ com_exit (char *arg MU_ARG_UNUSED)
   return 0;
 }
 
-/* Return non-zero if ARG is a valid argument for CALLER, else print
-   an error message and return zero. */
+
 int
-valid_argument (const char *caller, char *arg)
+main (int argc MU_ARG_UNUSED, char **argv)
 {
-  if (!arg || !*arg)
+  char *line, *s;
+
+  mu_set_program_name (argv[0]);
+  prompt = strdup (DEFAULT_PROMPT);
+  initialize_readline ();      /* Bind our completer. */
+#ifdef WITH_TLS
+  mu_init_tls_libs ();
+#endif  
+  /* Loop reading and executing lines until the user quits. */
+  while (!done)
     {
-      mu_error ("%s: Argument required", caller);
-      return 0;
-    }
+      char *p = expand_prompt ();
+      line = readline (p);
+      free (p);
+      
+      if (!line)
+       break;
+
+      /* Remove leading and trailing whitespace from the line.
+         Then, if there is anything left, add it to the history list
+         and execute it. */
+      s = mu_str_stripws (line);
 
-  return 1;
+      if (*s)
+       {
+         int status;
+         add_history (s);
+         status = execute_line (s);
+         if (status != 0)
+           mu_error ("Error: %s", mu_strerror (status));
+       }
+
+      free (line);
+    }
+  exit (0);
 }
+
diff --git a/include/mailutils/opool.h b/include/mailutils/opool.h
index 78b66a7..49b1b02 100644
--- a/include/mailutils/opool.h
+++ b/include/mailutils/opool.h
@@ -62,6 +62,10 @@ size_t mu_opool_size (mu_opool_t opool);
    mu_opool_create, above). */
 int mu_opool_coalesce (mu_opool_t opool, size_t *psize);
 
+/* Copy at most SIZE bytes of collected data into BUF.  Return the
+   actual number of bytes copied. */
+size_t mu_opool_copy (mu_opool_t opool, void *buf, size_t size);
+
 /* Return the pointer to the current object head chunk.  If mu_opool_coalesce 
    was called before, the returned value points to the entire object.
    If PSIZE is not NULL, store the size of the head chunk to *PSIZE. */     
diff --git a/include/mailutils/pop3.h b/include/mailutils/pop3.h
index f815be8..a6ced10 100644
--- a/include/mailutils/pop3.h
+++ b/include/mailutils/pop3.h
@@ -32,87 +32,99 @@ struct _mu_pop3;
 typedef struct _mu_pop3 *mu_pop3_t;
 
 #define MU_POP3_DEFAULT_PORT 110
+#define MU_POP3_DEFAULT_SSL_PORT 995
 
-extern int  mu_pop3_create       (mu_pop3_t *pop3);
-extern void mu_pop3_destroy      (mu_pop3_t *pop3);
+int  mu_pop3_create (mu_pop3_t *pop3);
+void mu_pop3_destroy (mu_pop3_t *pop3);
 
-extern int  mu_pop3_set_carrier  (mu_pop3_t pop3, mu_stream_t carrier);
-extern int  mu_pop3_get_carrier  (mu_pop3_t pop3, mu_stream_t *pcarrier);
+int  mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier);
+int  mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier);
 
-extern int  mu_pop3_connect      (mu_pop3_t pop3);
-extern int  mu_pop3_disconnect   (mu_pop3_t pop3);
+int  mu_pop3_connect (mu_pop3_t pop3);
+int  mu_pop3_disconnect (mu_pop3_t pop3);
 
-extern int  mu_pop3_set_timeout  (mu_pop3_t pop3, int timeout);
-extern int  mu_pop3_get_timeout  (mu_pop3_t pop3, int *timeout);
+int  mu_pop3_set_timeout (mu_pop3_t pop3, int timeout);
+int  mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout);
 
 #define MU_POP3_TRACE_CLR 0
 #define MU_POP3_TRACE_SET 1
 #define MU_POP3_TRACE_QRY 2
-extern int mu_pop3_trace (mu_pop3_t pop3, int op);
+int mu_pop3_trace (mu_pop3_t pop3, int op);
 
-extern int  mu_pop3_apop         (mu_pop3_t pop3, const char *name, const char 
*digest);
+int  mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest);
 
-extern int  mu_pop3_stls         (mu_pop3_t pop3);
+int  mu_pop3_stls (mu_pop3_t pop3);
 
 /* It is the responsability of the caller to call mu_iterator_destroy() when
    done with the iterator.  The items returned by the iterator are of type
    "const char *", no processing is done on the item except the removal of
    the trailing newline.  */
-extern int  mu_pop3_capa         (mu_pop3_t pop3, int reread,
-                                 mu_iterator_t *piter);
+int mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter);
+int mu_pop3_capa_test (mu_pop3_t pop3, const char *name, const char **pret);
 
-extern int  mu_pop3_dele         (mu_pop3_t pop3, unsigned int mesgno);
+int  mu_pop3_dele (mu_pop3_t pop3, unsigned int mesgno);
 
-extern int  mu_pop3_list         (mu_pop3_t pop3, unsigned int mesgno, size_t 
*mesg_octet);
+int  mu_pop3_list (mu_pop3_t pop3, unsigned int mesgno, size_t *mesg_octet);
 
-/* An iterator is return with the multi-line answer.  It is the responsability
-   of the caller to call mu_iterator_destroy() to dispose of the iterator.  */
-extern int  mu_pop3_list_all     (mu_pop3_t pop3, mu_iterator_t *piterator);
+/* Send the LIST command and prepare pop3 for receiving a multiline answer.
+   The caller is expected to obtain a stream via mu_pop3_stream_create,
+   or an iterator via mu_pop3_iterator_create and read data from them.
 
-extern int  mu_pop3_noop         (mu_pop3_t pop3);
+   This function is not intended for use by a casual user, better use
+   mu_pop3_list_all or mu_pop3_list_all_stream. */
+int mu_pop3_list_cmd (mu_pop3_t pop3);
+int mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *pitr);
+int mu_pop3_list_all_stream (mu_pop3_t pop3, mu_stream_t *pstream);
 
-extern int  mu_pop3_pass         (mu_pop3_t pop3, const char *pass);
+int  mu_pop3_noop (mu_pop3_t pop3);
 
-extern int  mu_pop3_quit         (mu_pop3_t pop3);
+int  mu_pop3_pass (mu_pop3_t pop3, const char *pass);
+
+int  mu_pop3_quit (mu_pop3_t pop3);
 
 /* A stream is returned with the multi-line answer.  It is the responsability
    of the caller to call mu_stream_destroy() to dipose of the stream.  */
-extern int  mu_pop3_retr         (mu_pop3_t pop3, unsigned int mesgno,
-                                 mu_stream_t *pstream);
+int  mu_pop3_retr (mu_pop3_t pop3, unsigned int mesgno,
+                  mu_stream_t *pstream);
 
-extern int  mu_pop3_rset         (mu_pop3_t pop3);
+int  mu_pop3_rset (mu_pop3_t pop3);
 
-extern int  mu_pop3_stat         (mu_pop3_t pop3, unsigned int *count,
-                                 size_t *octets);
+int  mu_pop3_stat (mu_pop3_t pop3, size_t *count, mu_off_t *octets);
 
 /* A stream is returned with the multi-line answer.  It is the responsability
    of the caller to call mu_stream_destroy() to dipose of the stream.  */
-extern int  mu_pop3_top          (mu_pop3_t pop3, unsigned int mesgno,
-                                 unsigned int lines, mu_stream_t *pstream);
+int  mu_pop3_top (mu_pop3_t pop3, unsigned int mesgno,
+                 unsigned int lines, mu_stream_t *pstream);
 
 /* The uidl is malloc'ed and returned in puidl; it is the responsability of
    the caller to free() the uild when done.  */
-extern int  mu_pop3_uidl         (mu_pop3_t pop3, unsigned int mesgno,
-                                 char **puidl);
-/* An iterator is returned with the multi-line answer.  It is the
-   responsability of the caller to call mu_iterator_destroy() to dispose of
-   the iterator.  */
-extern int  mu_pop3_uidl_all     (mu_pop3_t pop3, mu_iterator_t *piterator);
+int  mu_pop3_uidl (mu_pop3_t pop3, unsigned int mesgno, char **puidl);
 
-extern int  mu_pop3_user         (mu_pop3_t pop3, const char *user);
+/* Send the UIDL command and prepare pop3 for receiving a multiline answer.
+   The caller is expected to obtain a stream via mu_pop3_stream_create,
+   or an iterator via mu_pop3_iterator_create and read data from them.
 
+   This function is not intended for use by a casual user, better use
+   mu_pop3_uidl_all or mu_pop3_uidl_all_stream. */
+int mu_pop3_uidl_all_cmd (mu_pop3_t pop3);
+int mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator);
+int mu_pop3_uidl_all_stream (mu_pop3_t pop3, mu_stream_t *pstream);
 
+int mu_pop3_user (mu_pop3_t pop3, const char *user);
 
 /* Returns the last command acknowledge.  If the server supports RESP-CODE,
    the message could be retrieved, but it is up to the caller to do the
    parsing.  */
-extern int  mu_pop3_response     (mu_pop3_t pop3, size_t *nread);
+int  mu_pop3_response (mu_pop3_t pop3, size_t *nread);
 
-extern int  mu_pop3_writeline    (mu_pop3_t pop3, const char *format, ...)
+int  mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...)
                                   MU_PRINTFLIKE(2,3);
 
-extern int  mu_pop3_sendline     (mu_pop3_t pop3, const char *line);
-extern int mu_pop3_getline       (mu_pop3_t pop3);
+int  mu_pop3_sendline (mu_pop3_t pop3, const char *line);
+int mu_pop3_getline (mu_pop3_t pop3);
+int mu_pop3_read_list (mu_pop3_t pop3, mu_list_t list);
+int mu_pop3_stream_to_list (mu_pop3_t pop3, mu_stream_t stream,
+                           mu_list_t list);
 
 #ifdef __cplusplus
 }
diff --git a/include/mailutils/sys/stream.h b/include/mailutils/sys/stream.h
index 07bee72..3e114b5 100644
--- a/include/mailutils/sys/stream.h
+++ b/include/mailutils/sys/stream.h
@@ -24,6 +24,9 @@
 
 #define _MU_STR_INTERN_MASK   0xf000
 
+#define _MU_STR_EVENT_SET     1
+#define _MU_STR_EVENT_CLR     2
+
 struct _mu_stream
 {
   int ref_count;
@@ -54,6 +57,9 @@ struct _mu_stream
   int (*truncate) (struct _mu_stream *, mu_off_t);
   int (*shutdown) (struct _mu_stream *, int);
 
+  void (*event_cb) (struct _mu_stream *, int, int);
+  int  event_mask;
+  
   const char *(*error_string) (struct _mu_stream *, int);
   
 };
@@ -65,6 +71,9 @@ int mu_stream_write_unbuffered (mu_stream_t stream,
                                const void *buf, size_t size,
                                int full_write, size_t *pnwritten);
 
+void _mu_stream_cleareof (mu_stream_t str);
+void _mu_stream_seteof (mu_stream_t str);
+
 #define _MU_SWAP_FIRST_ONLY         0x01
 #define _MU_SWAP_IOCTL_MUST_SUCCEED 0x02
 
diff --git a/include/mailutils/tls.h b/include/mailutils/tls.h
index 41a5234..dc630a2 100644
--- a/include/mailutils/tls.h
+++ b/include/mailutils/tls.h
@@ -47,19 +47,6 @@ extern int mu_check_tls_environment (void);
 extern int mu_init_tls_libs (void);
 extern void mu_deinit_tls_libs (void);
 
-typedef int (*mu_tls_readline_fn) (void *iodata, int n);
-typedef int (*mu_tls_writeline_fn) (void *iodata, char *buf);
-
-#define MU_TLS_SESS_GET_STREAMS 0
-#define MU_TLS_SESS_SET_STREAMS 1  
-typedef int (*mu_tls_stream_ctl_fn) (void *iodata, int __op,
-                                    mu_stream_t *pstr);
-
-extern int mu_tls_begin (void *iodata, mu_tls_readline_fn reader,
-                        mu_tls_writeline_fn writer,
-                        mu_tls_stream_ctl_fn stream_ctl,
-                        char *keywords[]);
-
 extern int mu_tls_enable;
   
 #ifdef __cplusplus
diff --git a/libmu_auth/tls.c b/libmu_auth/tls.c
index 3b89bac..2d3bd81 100644
--- a/libmu_auth/tls.c
+++ b/libmu_auth/tls.c
@@ -164,94 +164,6 @@ initialize_tls_session (void)
   return session;
 }
 
-int
-mu_tls_begin (void *iodata,
-             mu_tls_readline_fn reader,
-             mu_tls_writeline_fn writer,
-             mu_tls_stream_ctl_fn stream_ctl,
-             char *keywords[])
-{
-  int i = 0;
-  int status;
-  mu_stream_t streams[2], newstr;
-  
-  if (keywords == NULL)
-    return EINVAL;
-
-  for (i = 0; keywords[i]; i++)
-    {
-      switch (i)
-       {
-        case 0:
-          /*
-           *  Send STLS/STARTTLS
-           */
-          status = writer (iodata, keywords[i]);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: writer (0): %s", mu_strerror (status));
-             return status;
-           }
-          
-          status = reader (iodata, i);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: reader (0): %s", mu_strerror (status));
-             return status;
-           }
-
-          status = stream_ctl (iodata, MU_TLS_SESS_GET_STREAMS, streams);
-         if (status)
-           return status;
-          status = mu_tls_client_stream_create (&newstr,
-                                               streams[0], streams[1], 0);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: mu_tls_client_stream_create(0): %s",
-                       mu_strerror (status));
-             stream_ctl (iodata, MU_TLS_SESS_SET_STREAMS, streams);
-             return status;
-           }
-
-          status = mu_stream_open (newstr);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: mu_stream_open (0): %s",
-                       mu_strerror (status));
-             stream_ctl (iodata, MU_TLS_SESS_SET_STREAMS, streams);
-             return status;
-           }
-
-         streams[0] = streams[1] = newstr;
-         stream_ctl (iodata, MU_TLS_SESS_SET_STREAMS, streams);
-         /* FIXME: Unref newstr */
-          break;
-
-        case 1:
-         /*
-          *  Send CAPABILITIES request
-          */
-          status = writer (iodata, keywords[i]);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: writer (1): %s", mu_strerror (status));
-             return status;
-           }
-
-          status = reader (iodata, i);
-          if (status != 0)
-           {
-             mu_error ("mu_tls_begin: reader (1): %s", mu_strerror (status));
-             return status;
-           }
-          break;
-          
-       default:
-         return 1;
-       }
-    }
-  return 0;
-}
 
 /* ************************* TLS Stream Support **************************** */
 
diff --git a/libproto/mailer/smtp.c b/libproto/mailer/smtp.c
index 5fb70f9..31b725f 100644
--- a/libproto/mailer/smtp.c
+++ b/libproto/mailer/smtp.c
@@ -554,68 +554,40 @@ smtp_close (mu_mailer_t mailer)
   return mu_stream_close (mailer->stream);
 }
 
-#ifdef WITH_TLS
 /*
   Client side STARTTLS support.
  */
 
 static int
-smtp_reader (void *iodata)
-{
-  int             status = 0;
-  smtp_t          iop = iodata;
-
-  status = smtp_read_ack (iop);
-  CHECK_EAGAIN (iop, status);
-  return status;
-}
-
-static int
-smtp_writer (void *iodata, char *buf)
-{
-  smtp_t          iop = iodata;
-  int             status;
-
-  if (mu_c_strncasecmp (buf, "EHLO", 4) == 0)
-    status = smtp_writeline (iop, "%s %s\r\n", buf, iop->localhost);
-  else
-    status = smtp_writeline (iop, "%s\r\n", buf);
-  CHECK_ERROR (iop, status);
-  status = smtp_write (iop);
-  CHECK_EAGAIN (iop, status);
-  return status;
-}
-
-static void
-smtp_stream_ctl (void *iodata, mu_stream_t * pold, mu_stream_t new)
-{
-  smtp_t          iop = iodata;
-
-  if (pold)
-    *pold = iop->mailer->stream;
-  if (new)
-    iop->mailer->stream = new;
-}
-#endif
-
-static int
 smtp_starttls (smtp_t smtp)
 {
 #ifdef WITH_TLS
   int             status;
   mu_mailer_t     mailer = smtp->mailer;
-  char           *keywords[] = { "STARTTLS", NULL };
-
+  mu_stream_t     newstr;
+  
   if (!mu_tls_enable || !(smtp->capa & CAPA_STARTTLS))
     return -1;
 
   smtp->capa = 0;
   smtp->auth_mechs = 0;
-  status = mu_tls_begin (smtp, smtp_reader, smtp_writer,
-                        smtp_stream_ctl, keywords);
 
+  status = smtp_writeline (smtp, "STARTTLS\r\n");
+  CHECK_ERROR (smtp, status);
+  status = smtp_write (smtp);
+  CHECK_EAGAIN (smtp, status);
+  status = smtp_read_ack (smtp);
+  CHECK_ERROR (smtp, status);
+  mu_stream_flush (mailer->stream);
+  status = mu_tls_client_stream_create (&newstr, mailer->stream,
+                                       mailer->stream, 0);
+  CHECK_ERROR (smtp, status);
+  status = mu_stream_open (newstr);
   MU_DEBUG1 (mailer->debug, MU_DEBUG_PROT, "TLS negotiation %s\n",
             status == 0 ? "succeeded" : "failed");
+  CHECK_ERROR (smtp, status);
+
+  mailer->stream = newstr;
 
   return status;
 #else
@@ -1399,6 +1371,8 @@ smtp_parse_ehlo_ack (smtp_t smtp)
   int             status;
   int             multi;
 
+  smtp->ptr = smtp->buffer;
+
   do
     {
       multi = 0;
diff --git a/libproto/pop/Makefile.am b/libproto/pop/Makefile.am
index b4bf3a8..5865e4e 100644
--- a/libproto/pop/Makefile.am
+++ b/libproto/pop/Makefile.am
@@ -24,13 +24,14 @@ lib_LTLIBRARIES = libmu_pop.la
 libmu_pop_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
 libmu_pop_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
 
-#  folder.c\
-#  mbox.c\
-#  url.c
 libmu_pop_la_SOURCES = \
+ mbox.c \
+ folder.c\
+ url.c\
  \
  pop3_apop.c \
  pop3_capa.c \
+ pop3_capatst.c \
  pop3_carrier.c \
  pop3_connect.c \
  pop3_create.c \
@@ -39,10 +40,13 @@ libmu_pop_la_SOURCES = \
  pop3_disconnect.c \
  pop3_iterator.c \
  pop3_lista.c \
+ pop3_listas.c \
  pop3_list.c \
+ pop3_list_cmd.c \
  pop3_noop.c \
  pop3_pass.c \
  pop3_quit.c \
+ pop3_rdlist.c \
  pop3_readline.c \
  pop3_response.c \
  pop3_retr.c \
@@ -54,7 +58,9 @@ libmu_pop_la_SOURCES = \
  pop3_timeout.c \
  pop3_top.c \
  pop3_trace.c \
+ pop3_uidl_cmd.c \
  pop3_uidla.c \
+ pop3_uidlas.c \
  pop3_uidl.c \
  pop3_user.c
 
diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c
index 5268a9f..3b538a0 100644
--- a/libproto/pop/mbox.c
+++ b/libproto/pop/mbox.c
@@ -23,21 +23,13 @@
 
 #ifdef ENABLE_POP
 
-#include <termios.h>
-#include <errno.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
-
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
 
+#include <mailutils/pop3.h>
 #include <mailutils/attribute.h>
 #include <mailutils/auth.h>
 #include <mailutils/body.h>
@@ -57,737 +49,61 @@
 #include <mailutils/mutil.h>
 #include <mailutils/cstr.h>
 #include <mailutils/cctype.h>
+#include <mailutils/opool.h>
 
 #include <mailutils/sys/folder.h>
 #include <mailutils/sys/mailbox.h>
 #include <mailutils/sys/registrar.h>
 #include <mailutils/sys/url.h>
 
-#define PROP_RFC822 1
-
-/* Advance declarations.  */
-struct _pop_data;
-struct _pop_message;
+#define _POP3_MSG_INBODY  0x01
+#define _POP3_MSG_SKIPHDR 0x02
+#define _POP3_MSG_SKIPBDY 0x04
 
-typedef struct _pop_data * pop_data_t;
-typedef struct _pop_message * pop_message_t;
-
-/* The different possible states of a Pop client, Note that POP3 is not
-   reentrant i.e. it is only one channel, so it is not possible to start
-   Another operation while one is running.  The only resort is to close the
-   connection and reopen it again.  This is what we do, the downside is that
-   the client as to get the authentication again user/pass.  */
-enum pop_state
+struct _pop3_message
 {
-  POP_NO_STATE, POP_STATE_DONE,
-  POP_OPEN_CONNECTION,
-  POP_GREETINGS,
-  POP_CAPA, POP_CAPA_ACK,
-  POP_APOP, POP_APOP_ACK,
-  POP_DELE, POP_DELE_ACK,
-  POP_LIST, POP_LIST_ACK, POP_LIST_RX,
-  POP_QUIT, POP_QUIT_ACK,
-  POP_NOOP, POP_NOOP_ACK,
-  POP_RETR, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY,
-  POP_RSET, POP_RSET_ACK,
-  POP_STAT, POP_STAT_ACK,
-  POP_STLS, POP_STLS_ACK,
-  POP_TOP,  POP_TOP_ACK,  POP_TOP_RX,
-  POP_UIDL, POP_UIDL_ACK,
-  POP_AUTH, POP_AUTH_DONE,
-  POP_AUTH_USER, POP_AUTH_USER_ACK,
-  POP_AUTH_PASS, POP_AUTH_PASS_ACK
-};
-
-/*  POP3 capabilities  */
-#define CAPA_TOP             0x00000001
-#define CAPA_USER            0x00000002
-#define CAPA_UIDL            0x00000004
-#define CAPA_RESP_CODES      0x00000008
-#define CAPA_LOGIN_DELAY     0x00000010
-#define CAPA_PIPELINING      0x00000020
-#define CAPA_EXPIRE          0x00000040
-#define CAPA_SASL            0x00000080
-#define CAPA_STLS            0x00000100
-#define CAPA_IMPLEMENTATION  0x00000200
-
-static void pop_destroy        (mu_mailbox_t);
-static int pop_capa            (mu_mailbox_t);
-static int pop_stls            (mu_mailbox_t);
-
-/*  Functions/Methods that implements the mu_mailbox_t API.  */
-static int pop_open            (mu_mailbox_t, int);
-static int pop_close           (mu_mailbox_t);
-static int pop_get_message     (mu_mailbox_t, size_t, mu_message_t *);
-static int pop_messages_count  (mu_mailbox_t, size_t *);
-static int pop_messages_recent (mu_mailbox_t, size_t *);
-static int pop_message_unseen  (mu_mailbox_t, size_t *);
-static int pop_expunge         (mu_mailbox_t);
-static int pop_scan            (mu_mailbox_t, size_t, size_t *);
-static int pop_is_updated      (mu_mailbox_t);
-
-/* The implementation of mu_message_t */
-int _pop_user            (mu_authority_t);
-int _pop_apop            (mu_authority_t);
-static int pop_get_size        (mu_mailbox_t, mu_off_t *);
-/* We use pop_top for retreiving headers.  */
-/* static int pop_header_read (mu_header_t, char *, size_t, mu_off_t, size_t 
*); */
-static int pop_body_transport  (mu_stream_t, mu_transport_t *, mu_transport_t 
*);
-static int pop_body_size       (mu_body_t, size_t *);
-static int pop_body_lines      (mu_body_t, size_t *);
-static int pop_body_read       (mu_stream_t, char *, size_t, mu_off_t, size_t 
*);
-static int pop_message_read    (mu_stream_t, char *, size_t, mu_off_t, size_t 
*);
-static int pop_message_size    (mu_message_t, size_t *);
-static int pop_message_transport (mu_stream_t, mu_transport_t *, 
mu_transport_t *);
-static int pop_top             (mu_header_t, char *, size_t, mu_off_t, size_t 
*);
-static int pop_retr            (pop_message_t, char *, size_t, mu_off_t, 
size_t *);
-static int pop_get_transport2   (pop_message_t, mu_transport_t *, 
mu_transport_t *);
-static int pop_get_attribute   (mu_attribute_t, int *);
-static int pop_set_attribute   (mu_attribute_t, int);
-static int pop_unset_attribute (mu_attribute_t, int);
-static int pop_uidl            (mu_message_t, char *, size_t, size_t *);
-static int pop_uid             (mu_message_t, size_t *);
-static int fill_buffer         (pop_data_t, char *, size_t);
-static int pop_sleep           (int);
-static int pop_readline        (pop_data_t);
-static int pop_read_ack        (pop_data_t);
-static int pop_writeline       (pop_data_t, const char *, ...)
-                                 MU_PRINTFLIKE(2,3);
-static int pop_write           (pop_data_t);
-static int pop_get_user        (mu_authority_t);
-static int pop_get_passwd      (mu_authority_t);
-static char *pop_get_timestamp (pop_data_t);
-static int pop_get_md5         (pop_data_t);
-
-/* This structure holds the info for a message. The pop_message_t
-   type, will serve as the owner of the mu_message_t and contains the command 
to
-   send to "RETR"eive the specify message.  The problem comes from the header.
-   If the  POP server supports TOP, we can cleanly fetch the header.
-   But otherwise we use the clumsy approach. .i.e for the header we read 'til
-   ^\n then discard the rest, for the body we read after ^\n and discard the
-   beginning.  This is a waste, Pop was not conceive for this obviously.  */
-struct _pop_message
-{
-  int inbody;
-  int skip_header;
-  int skip_body;
+  int flags;
   size_t body_size;
   size_t header_size;
   size_t body_lines;
   size_t header_lines;
-  size_t mu_message_size;
+  size_t message_size;
   size_t num;
   char *uidl; /* Cache the uidl string.  */
   int attr_flags;
   mu_message_t message;
-  pop_data_t mpd; /* Back pointer.  */
+  struct _pop3_mailbox *mpd; /* Back pointer.  */
 };
-
-/* Structure to hold things general to the POP mailbox, like its state, how
-   many messages we have so far etc ...  */
-struct _pop_data
-{
-  void *func;  /*  Indicate a command is in operation, busy.  */
-  size_t id;   /* A second level of distincion, we maybe in the same function
-                 but working on a different message.  */
-  int pops; /* POPS or POP? */
-  char *greeting_banner; /* A greeting banner */
-  unsigned long capa; /* Server capabilities */
-  enum pop_state state;
-  pop_message_t *pmessages;
-  size_t pmessages_count;
-  size_t messages_count;
-  size_t size;
-
-  /* Working I/O buffers.  */
-  char *buffer;
-  size_t buflen; /* Len of buffer.  */
-  char *ptr; /* Points to the end of the buffer i.e the non consume chars.  */
-  char *nl;  /* Points to the '\n' char in te string.  */
-  mu_off_t offset; /* Dummy, this is use because of the stream buffering.
-                  The mu_stream_t maintains and offset and the offset we use 
must
-                  be in sync.  */
-
-  int is_updated;
-  char *user;     /* Temporary holders for user and passwd.  */
-  mu_secret_t secret;
-  char *digest;
-  mu_mailbox_t mbox; /* Back pointer.  */
-} ;
-
-/* Usefull little Macros, since these are very repetitive.  */
-
-/* Check if we're busy ?  */
-/* POP is a one channel download protocol, so if someone
-   is trying to execute a command while another is running
-   something is seriously incorrect,  So the best course
-   of action is to close down the connection and start a new one.
-   For example mu_mime_t only reads part of the message.  If a client
-   wants to read different part of the message via mime it should
-   download it first.  POP does not have the features of IMAP for
-   multipart messages.
-   Let see a concrete example:
-   {
-     mu_mailbox_t mbox; mu_message_t msg; mu_stream_t stream; char buffer[105];
-     mu_mailbox_create (&mbox, "pop://qnx.com");
-     mu_mailbox_get_message (mbox, 1, &msg);
-     mu_message_get_stream (msg, &stream);
-     while (mu_stream_readline (stream, buffer, sizeof(buffer), NULL) != 0) { 
..}
-   }
-   if in the while of the readline, one try to get another email.  The pop
-   server will get seriously confused, and the second message will still
-   be the first one,  There is no way to tell POP servers yo! stop/abort.
-   The approach is to close the stream and reopen again. So  every time
-   we go in to a function our state is preserve by the triplets
-   mpd->{func,state,id}.  The macro CHECK_BUSY checks if we are not
-   in another operation if not you get access if yes the stream is close
-   and pop_open() is recall again for a new connection.
- */
-#define CHECK_BUSY(mbox, mpd, function, identity) \
-do \
-  { \
-    int err = mu_monitor_wrlock (mbox->monitor); \
-    if (err != 0) \
-      return err; \
-    if ((mpd->func && mpd->func != function) \
-        || (mpd->id && mpd->id != (size_t)identity)) \
-      { \
-        mpd->id = 0; \
-        mpd->func = (void *)pop_open; \
-        mpd->state = POP_NO_STATE; \
-        mu_monitor_unlock (mbox->monitor); \
-        err = pop_open (mbox, mbox->flags); \
-        if (err != 0) \
-          { \
-            return err; \
-          } \
-      } \
-    else \
-      { \
-        mpd->id = (size_t)identity; \
-        mpd->func = func; \
-        mu_monitor_unlock (mbox->monitor); \
-      } \
-  } \
-while (0)
-
-/* Clear the state.  */
-#define CLEAR_STATE(mpd) \
- mpd->id = 0, mpd->func = NULL, mpd->state = POP_NO_STATE
-
-/* Clear the state and close the stream.  */
-#define CHECK_ERROR_CLOSE(mbox, mpd, status) \
-do \
-  { \
-     if (status != 0) \
-       { \
-          mu_stream_close (mbox->stream); \
-          CLEAR_STATE (mpd); \
-          mpd->func = (void *)-1; \
-          MU_DEBUG1 (mbox->debug, MU_DEBUG_PROT, \
-                     "CHECK_ERROR_CLOSE: %s\n", mu_strerror (status));\
-          return status; \
-       } \
-  } \
-while (0)
-
-/* If error, clear the state and return.  */
-#define CHECK_ERROR(mpd, status) \
-do \
-  { \
-     if (status != 0) \
-       { \
-          CLEAR_STATE (mpd); \
-          mpd->func = (void*)-1; \
-          MU_DEBUG1(mpd->mbox->debug, MU_DEBUG_PROT, \
-                    "CHECK_ERROR: %s\n", mu_strerror (status));\
-          return status; \
-       } \
-  } \
-while (0)
-
-/* Clear the state for non recoverable error.  */
-#define CHECK_EAGAIN(mpd, status) \
-do \
-  { \
-    if (status != 0) \
-      { \
-         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
-           { \
-             CLEAR_STATE (mpd); \
-             mpd->func = (void *)-1; \
-             MU_DEBUG1(mpd->mbox->debug, MU_DEBUG_PROT, \
-                       "CHECK_EAGAIN: %s\n", mu_strerror (status));\
-           } \
-         return status; \
-      } \
-   }  \
-while (0)
-
-
-/* Allocate mu_mailbox_t, allocate pop internal structures.  */
-static int
-_mailbox_pop_and_pops_init (mu_mailbox_t mbox, int pops)
-{
-  pop_data_t mpd;
-  int status = 0;
-
-  /* Allocate specifics for pop data.  */
-  mpd = mbox->data = calloc (1, sizeof (*mpd));
-  if (mbox->data == NULL)
-    return ENOMEM;
-
-  mpd->mbox = mbox;            /* Back pointer.  */
-  mpd->state = POP_NO_STATE;   /* Init with no state.  */
-  mpd->pops = pops;
-
-  /* Initialize the structure.  */
-  mbox->_destroy = pop_destroy;
-
-  mbox->_open = pop_open;
-  mbox->_close = pop_close;
-
-  /* Messages.  */
-  mbox->_get_message = pop_get_message;
-  mbox->_messages_count = pop_messages_count;
-  mbox->_messages_recent = pop_messages_recent;
-  mbox->_message_unseen = pop_message_unseen;
-  mbox->_expunge = pop_expunge;
-
-  mbox->_scan = pop_scan;
-  mbox->_is_updated = pop_is_updated;
-
-  mbox->_get_size = pop_get_size;
-
-  /* Set our properties.  */
-  {
-    mu_property_t property = NULL;
-    mu_mailbox_get_property (mbox, &property);
-    mu_property_set_value (property, "TYPE", "POP3", 1);
-  }
-
-  /* Hack! POP does not really have a folder.  */
-  mbox->folder->data = mbox;
-
-  return status;
-}
-
-int
-_mailbox_pop_init (mu_mailbox_t mbox)
-{
-  return _mailbox_pop_and_pops_init (mbox, 0);
-}
-
-int
-_mailbox_pops_init (mu_mailbox_t mbox)
-{
-  return _mailbox_pop_and_pops_init (mbox, 1);
-}
-
-/*  Cleaning up all the ressources associate with a pop mailbox.  */
-static void
-pop_destroy (mu_mailbox_t mbox)
-{
-  if (mbox->data)
-    {
-      pop_data_t mpd = mbox->data;
-      size_t i;
-      mu_monitor_wrlock (mbox->monitor);
-      /* Destroy the pop messages and ressources associated to them.  */
-      for (i = 0; i < mpd->pmessages_count; i++)
-       {
-         if (mpd->pmessages[i])
-           {
-             mu_message_destroy (&(mpd->pmessages[i]->message),
-                              mpd->pmessages[i]);
-             if (mpd->pmessages[i]->uidl)
-               free (mpd->pmessages[i]->uidl);
-             free (mpd->pmessages[i]);
-             mpd->pmessages[i] = NULL;
-           }
-       }
-      if (mpd->greeting_banner)
-       free (mpd->greeting_banner);
-      if (mpd->buffer)
-       free (mpd->buffer);
-      if (mpd->pmessages)
-       free (mpd->pmessages);
-      free (mpd);
-      mbox->data = NULL;
-      mu_monitor_unlock (mbox->monitor);
-    }
-}
-
-static int
-pop_mbox_uidls (mu_mailbox_t mbox, mu_list_t list)
-{
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  status = pop_writeline (mpd, "UIDL\r\n");
-  CHECK_ERROR (mpd, status);
-  MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  status = pop_write (mpd);
-  CHECK_EAGAIN (mpd, status);
-
-  status = pop_read_ack (mpd);
-  CHECK_EAGAIN (mpd, status);
-  MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  if (!mu_c_strncasecmp (mpd->buffer, "+OK", 3))
-    {
-      do
-       {
-         char *p;
-         size_t num;
-         struct mu_uidl *uidl;
-         
-         status = pop_read_ack (mpd);
-         MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-         num = strtoul (mpd->buffer, &p, 10);
-         if (*p == 0 || !mu_isblank (*p))
-           continue; /* FIXME: or error? */
-         p = mu_str_skip_class (p, MU_CTYPE_SPACE);
-         mu_rtrim_cset (p, "\r\n");
-
-         uidl = malloc (sizeof (uidl[0]));
-         if (!uidl)
-           {
-             status = ENOMEM;
-             break;
-           }
-         uidl->msgno = num;
-         strncpy (uidl->uidl, p, MU_UIDL_BUFFER_SIZE);
-         status = mu_list_append (list, uidl);
-       }
-      while (mpd->nl);
-    }
-  else
-    status = ENOSYS;
-  return status;
-}
-
-/*
-  POP3 CAPA support.
- */
-
-static int
-pop_parse_capa (pop_data_t mpd)
-{
-  int status;
-  if (!mu_c_strncasecmp (mpd->buffer, "+OK", 3))
-    {
-      mpd->capa = 0;
-      do
-       {
-         status = pop_read_ack (mpd);
-         MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-         /* Here we check some common capabilities like TOP, USER, UIDL,
-            and STLS. The rest are ignored. Please note that some
-            capabilities might have an extra arguments. For instance,
-            SASL can have CRAM-MD5 and/or KERBEROS_V4, and etc.
-            This is why I suggest adding (in a future) an extra variable,
-            for example `capa_sasl'. It would hold the following flags:
-            SASL_CRAM_MD5, SASL_KERBEROS_V4, and so on. Also the EXPIRE
-            and LOGIN-DELAY capabilities have an extra arguments!
-            Note that there is no APOP capability, even though APOP
-            is an optional command in POP3. -- W.P. */
-
-         if (!mu_c_strncasecmp (mpd->buffer, "TOP", 3))
-           mpd->capa |= CAPA_TOP;
-         else if (!mu_c_strncasecmp (mpd->buffer, "USER", 4))
-           mpd->capa |= CAPA_USER;
-         else if (!mu_c_strncasecmp (mpd->buffer, "UIDL", 4))
-           mpd->capa |= CAPA_UIDL;
-         else if (!mu_c_strncasecmp (mpd->buffer, "STLS", 4))
-           mpd->capa |= CAPA_STLS;
-       }
-      while (mpd->nl);
-
-      if (mpd->capa & CAPA_UIDL)
-       mpd->mbox->_get_uidls = pop_mbox_uidls;
   
-      return status;
-    }
-  else
-    {
-      /* mu_error ("CAPA not implemented"); */ /* FIXME */
-      return ENOSYS;
-    }
-}
-
-static int
-pop_capa (mu_mailbox_t mbox)
-{
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  status = pop_writeline (mpd, "CAPA\r\n");
-  CHECK_ERROR (mpd, status);
-  MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  status = pop_write (mpd);
-  CHECK_EAGAIN (mpd, status);
-  mpd->state = POP_CAPA_ACK;
-
-  /* POP_CAPA_ACK */
-  status = pop_read_ack (mpd);
-  CHECK_EAGAIN (mpd, status);
-  MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-  return pop_parse_capa (mpd);
-}
-
-/* Simple User/pass authentication for pop. We ask for the info
-   from the standard input.  */
-int
-_pop_user (mu_authority_t auth)
-{
-  mu_folder_t folder = mu_authority_get_owner (auth);
-  mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  switch (mpd->state)
-    {
-    case POP_AUTH:
-      /*  Fetch the user from them.  */
-      status = pop_get_user (auth);
-      if (status != 0 || mpd->user == NULL || mpd->user[0] == '\0')
-       {
-         pop_writeline (mpd, "QUIT\r\n");
-         MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-         pop_write (mpd);
-         CHECK_ERROR_CLOSE (mbox, mpd, MU_ERR_NOUSERNAME);
-       }
-      status = pop_writeline (mpd, "USER %s\r\n", mpd->user);
-      CHECK_ERROR_CLOSE(mbox, mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      free (mpd->user);
-      mpd->user = NULL;
-      mpd->state = POP_AUTH_USER;
-
-    case POP_AUTH_USER:
-      /* Send username.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_AUTH_USER_ACK;
-
-    case POP_AUTH_USER_ACK:
-      /* Get the user ack.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       {
-         mu_observable_t observable = NULL;
-         mu_mailbox_get_observable (mbox, &observable);
-         CLEAR_STATE (mpd);
-         mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
-         CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
-       }
-      status = pop_get_passwd (auth);
-      if (status != 0 || mpd->secret == NULL)
-       {
-         pop_writeline (mpd, "QUIT\r\n");
-         MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-         pop_write (mpd);
-         CHECK_ERROR_CLOSE (mbox, mpd, MU_ERR_NOPASSWORD);
-       }
-      status = pop_writeline (mpd, "PASS %s\r\n",
-                             mu_secret_password (mpd->secret));
-      mu_secret_password_unref (mpd->secret);
-      mu_secret_unref (mpd->secret);
-      mpd->secret = NULL;
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, "PASS ***\n");
-      CHECK_ERROR_CLOSE (mbox, mpd, status);
-      mpd->state = POP_AUTH_PASS;
-      /* FIXME: Merge these two cases */
-        
-    case POP_AUTH_PASS:
-      /* Send passwd.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      /* Clear the buffer it contains the passwd.  */
-      memset (mpd->buffer, '\0', mpd->buflen);
-      mpd->state = POP_AUTH_PASS_ACK;
-
-    case POP_AUTH_PASS_ACK:
-      /* Get the ack from passwd.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       {
-         mu_observable_t observable = NULL;
-         mu_mailbox_get_observable (mbox, &observable);
-         CLEAR_STATE (mpd);
-         mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
-         return MU_ERR_AUTH_FAILURE;
-       }
-      mpd->state = POP_AUTH_DONE;
-      break;  /* We're outta here.  */
-
-    default:
-      break;
-    }
-  CLEAR_STATE (mpd);
-  return 0;
-}
-
-int
-_pop_apop (mu_authority_t auth)
-{
-  mu_folder_t folder = mu_authority_get_owner (auth);
-  mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
-  int status;
-
-  switch (mpd->state)
-    {
-    case POP_AUTH:
-      /* Fetch the user from them.  */
-      status = pop_get_user (auth);
-      if (status != 0 || mpd->user == NULL || mpd->user[0] == '\0')
-       {
-         CHECK_ERROR_CLOSE (mbox, mpd, EINVAL);
-       }
-
-      /* Fetch the secret from them.  */
-      status = pop_get_passwd (auth);
-      if (status != 0 || mpd->secret == NULL)
-       {
-         CHECK_ERROR_CLOSE (mbox, mpd, EINVAL);
-       }
-
-      /* Make the MD5 digest string.  */
-      status = pop_get_md5 (mpd);
-      if (status != 0)
-       {
-         CHECK_ERROR_CLOSE (mbox, mpd, status);
-       }
-      status = pop_writeline (mpd, "APOP %s %s\r\n", mpd->user, mpd->digest);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      /* We have to obscure the md5 string.  */
-      memset (mpd->digest, '\0', strlen (mpd->digest));
-      free (mpd->user);
-      free (mpd->digest);
-      mpd->user = NULL;
-      mpd->digest = NULL;
-      CHECK_ERROR_CLOSE (mbox, mpd, status);
-      mpd->state = POP_APOP;
-
-    case POP_APOP:
-      /* Send apop.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      /* Clear the buffer it contains the md5.  */
-      memset (mpd->buffer, '\0', mpd->buflen);
-      mpd->state = POP_APOP_ACK;
-
-    case POP_APOP_ACK:
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-        {
-          mu_observable_t observable = NULL;
-          mu_mailbox_get_observable (mbox, &observable);
-          CLEAR_STATE (mpd);
-          mu_observable_notify (observable, MU_EVT_AUTHORITY_FAILED, NULL);
-          CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
-        }
-      mpd->state = POP_AUTH_DONE;
-      break;  /* We're outta here.  */
-
-    default:
-      break;
-    }
-  CLEAR_STATE (mpd);
-  return 0;
-}
-
-/*
-  Client side STLS support.
- */
-
-static int
-pop_reader (void *iodata)
+struct _pop3_mailbox
 {
-  int status = 0;
-  pop_data_t iop = iodata;
-  status = pop_read_ack (iop);
-  CHECK_EAGAIN (iop, status);
-  MU_DEBUG (iop->mbox->debug, MU_DEBUG_PROT, iop->buffer);
-  return status;/*mu_c_strncasecmp (iop->buffer, "+OK", 3) == 0;*/
-}
-
-static int
-pop_writer (void *iodata, char *buf)
-{
-  pop_data_t iop = iodata;
-  int status;
+  mu_pop3_t pop3;             /* mu_pop3_t is the working horse */
+  int pops;                   /* true if pop3 over SSL is being used */
+  int is_updated;             /* true if the mailbox info is up to date */
   
-  MU_DEBUG1 (iop->mbox->debug, MU_DEBUG_PROT, "%s\n", buf);
-  status = pop_writeline (iop, "%s\r\n", buf);
-  CHECK_ERROR (iop, status);
-  status = pop_write (iop);
-  CHECK_ERROR (iop, status);
-  return status;
-}
+  size_t msg_count;           /* Number of messages in the mailbox */
+  mu_off_t total_size;        /* Total mailbox size. */
+  struct _pop3_message **msg; /* Array of messages */
+  size_t msg_max;             /* Actual size of the array */  
+  mu_mailbox_t mbox;          /* MU mailbox corresponding to this one. */
 
-static void
-pop_stream_ctl (void *iodata, mu_stream_t *pold, mu_stream_t new)
-{
-  pop_data_t iop = iodata;
-  if (pold)
-    *pold = iop->mbox->stream;
-  if (new)
-    iop->mbox->stream = new;
-}
-
-static int
-pop_stls (mu_mailbox_t mbox)
-{
-#ifdef WITH_TLS
-  int status;
-  pop_data_t mpd = mbox->data;
-  char *keywords[] = { "STLS", "CAPA", NULL };
-
-  if (!mu_tls_enable || !(mpd->capa & CAPA_STLS))
-    return -1;
-
-  status = mu_tls_begin (mpd, pop_reader, pop_writer,
-                        pop_stream_ctl, keywords);
-
-  MU_DEBUG1 (mbox->debug, MU_DEBUG_PROT, "TLS negotiation %s\n",
-                 status == 0 ? "succeeded" : "failed");
-
-  if (status == 0)
-    pop_parse_capa (mpd);
-
-  return status;
-#else
-  return -1;
-#endif /* WITH_TLS */
-}
+  char *user;     /* Temporary holders for user and passwd.  */
+  mu_secret_t secret;
+};
 
-/* Open the connection to the sever, and send the authentication. */
 static int
 pop_open (mu_mailbox_t mbox, int flags)
 {
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status;
   const char *host;
   long port = mpd->pops ? MU_POPS_PORT : MU_POP_PORT;
-
-  /* Sanity checks.  */
+  mu_stream_t stream;
+  
+  /* Sanity checks. */
   if (mpd == NULL)
     return EINVAL;
-
+  
   /* Fetch the pop server name and the port in the mu_url_t.  */
   status = mu_url_sget_host (mbox->url, &host);
   if (status != 0)
@@ -796,519 +112,154 @@ pop_open (mu_mailbox_t mbox, int flags)
 
   mbox->flags = flags;
 
-  /* Do not check for reconnect here.  */
-  /* CHECK_BUSY (mbox, mpd, func, 0); */
-
-  /* Enter the pop state machine, and boogy: AUTHORISATION State.  */
-  switch (mpd->state)
+  status = mu_tcp_stream_create (&stream, host, port, mbox->flags);
+  if (status)
+    return status;
+#ifdef WITH_TLS
+  if (mpd->pops)
     {
-    case POP_NO_STATE:
-      /* Allocate a working io buffer.  */
-      if (mpd->buffer == NULL)
+      mu_stream_t newstr;
+      
+      status = mu_stream_open (stream);
+      if (status)
        {
-         /* 255 is the limit lenght of a POP3 command according to RFCs.  */
-         mpd->buflen = 255;
-         mpd->buffer = calloc (mpd->buflen + 1, sizeof (char));
-         if (mpd->buffer == NULL)
-           {
-             CHECK_ERROR (mpd, ENOMEM);
-           }
+         mu_stream_destroy (&stream);
+         return status;
        }
-      else
+      
+      status = mu_tls_client_stream_create (&newstr, stream, stream, 0);
+      mu_stream_unref (stream);
+      if (status)
        {
-         /* Clear any residual from a previous connection.  */
-         memset (mpd->buffer, '\0', mpd->buflen);
+         mu_error ("pop_open: mu_tls_client_stream_create: %s",
+                   mu_strerror (status));
+         return status;
        }
-      mpd->ptr = mpd->buffer;
-
-      /* Create the networking stack.  */
-      if (mbox->stream == NULL)
-       {
-         status = mu_tcp_stream_create (&mbox->stream, host, port,
-                                        mbox->flags);
-         CHECK_ERROR (mpd, status);
-         /* FIXME: How to configure the buffer size? */
-         mu_stream_set_buffer (mbox->stream, mu_buffer_line, 1024);
-
-#ifdef WITH_TLS
-         if (mpd->pops)
-           {
-             mu_stream_t newstr;
-
-             status = mu_stream_open (mbox->stream);
-             CHECK_EAGAIN (mpd, status);
-             CHECK_ERROR_CLOSE (mbox, mpd, status);
-
-             status = mu_tls_client_stream_create (&newstr, 
-                                                   mbox->stream, 
-                                                   mbox->stream, 0);
-             if (status != 0)
-               {
-                 mu_error ("pop_open: mu_tls_client_stream_create: %s",
-                           mu_strerror (status));
-                 return status;
-               }
-             mbox->stream = newstr;
-           }
+      stream = newstr;
+    }
 #endif /* WITH_TLS */
-       }
-      else
-       {
-         /* This is sudden death: for many pop servers, it is important to
-            let them time to remove locks or move the .user.pop files.  This
-            happen when we do BUSY_CHECK().  For example, the user does not
-            want to read the entire file, and wants start to read a new
-            message, closing the connection and immediately contact the
-            server again, and we'll end up having "-ERR Mail Lock busy" or
-            something similar. To prevent this race condition we sleep 2
-            seconds. */
-         mu_stream_close (mbox->stream);
-         pop_sleep (2);
-       }
-      mpd->state = POP_OPEN_CONNECTION;
-
-    case POP_OPEN_CONNECTION:
-      /* Establish the connection.  */
-      MU_DEBUG2 (mbox->debug, MU_DEBUG_PROT, "open (%s:%ld)\n", host, port);
-      status = mu_stream_open (mbox->stream);
-      CHECK_EAGAIN (mpd, status);
-      /* Can't recover bailout.  */
-      CHECK_ERROR_CLOSE (mbox, mpd, status);
-      mpd->state = POP_GREETINGS;
-
-    case POP_GREETINGS:
-      {
-       int gblen = 0;
-       status = pop_read_ack (mpd);
-       CHECK_EAGAIN (mpd, status);
-       MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-       if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-         {
-           CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
-         }
-       gblen = strlen (mpd->buffer);
-       mpd->greeting_banner = calloc (gblen, 1);
-       if (mpd->greeting_banner == NULL)
-         {
-           CHECK_ERROR (mpd, ENOMEM);
-         }
-       memcpy (mpd->greeting_banner, mpd->buffer, gblen);
-       mpd->state = POP_CAPA;
-      }
-
-    case POP_CAPA:
-    case POP_CAPA_ACK:
-      pop_capa (mbox);
-      mpd->state = POP_STLS;
-
-    case POP_STLS:
-    case POP_STLS_ACK:
-      if (!mpd->pops)
-       pop_stls (mbox);
-      mpd->state = POP_AUTH;
-
-    case POP_AUTH:
-    case POP_AUTH_USER:
-    case POP_AUTH_USER_ACK:
-    case POP_AUTH_PASS:
-    case POP_AUTH_PASS_ACK:
-    case POP_APOP:
-    case POP_APOP_ACK:
-      /* Authenticate.  */
-      status = mu_authority_authenticate (mbox->folder->authority);
-      CHECK_EAGAIN (mpd, status);
-
-    case POP_AUTH_DONE:
-      break;
 
-    default:
-      /*
-       mu_error ("pop_open: unknown state");
-      */
-      break;
-    }/* End AUTHORISATION state. */
+  /* FIXME: How to configure buffer size? */
+  mu_stream_set_buffer (stream, mu_buffer_line, 1024);
 
-  /* Clear any state.  */
-  CLEAR_STATE (mpd);
-  return 0;
-}
-
-/* Send the QUIT and close the socket.  */
-static int
-pop_close (mu_mailbox_t mbox)
-{
-  pop_data_t mpd = mbox->data;
-  void *func = (void *)pop_close;
-  int status;
-  size_t i;
-
-  if (mpd == NULL)
-    return EINVAL;
-
-  /* Should not check for Busy, we're shuting down anyway.  */
-  /* CHECK_BUSY (mbox, mpd, func, 0); */
-  mu_monitor_wrlock (mbox->monitor);
-  if (mpd->func && mpd->func != func)
-    mpd->state = POP_NO_STATE;
-  mpd->id = 0;
-  mpd->func = func;
-  mu_monitor_unlock (mbox->monitor);
-
-  /*  Ok boys, it's a wrap: UPDATE State.  */
-  switch (mpd->state)
-    {
-    case POP_NO_STATE:
-      /* Initiate the close.  */
-      status = pop_writeline (mpd, "QUIT\r\n");
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_QUIT;
-
-    case POP_QUIT:
-      /* Send the quit.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_QUIT_ACK;
-
-    case POP_QUIT_ACK:
-      /* Glob the acknowledge.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      /*  Now what ! and how can we tell them about errors ?  So far now
-         lets just be verbose about the error but close the connection
-         anyway.  */
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       mu_error ("pop_close: %s", mpd->buffer);
-      mu_stream_close (mbox->stream);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_close: unknown state");
-      */
-      break;
-    } /* UPDATE state.  */
-
-  /* Free the messages.  */
-  for (i = 0; i < mpd->pmessages_count; i++)
+  status = mu_pop3_create (&mpd->pop3);
+  if (status)
     {
-      if (mpd->pmessages[i])
-       {
-         mu_message_destroy (&(mpd->pmessages[i]->message),
-                          mpd->pmessages[i]);
-         if (mpd->pmessages[i]->uidl)
-           free (mpd->pmessages[i]->uidl);
-         free (mpd->pmessages[i]);
-         mpd->pmessages[i] = NULL;
-       }
+      mu_stream_destroy (&stream);
+      return status;
     }
-  /* And clear any residue.  */
-  if (mpd->greeting_banner)
-    free (mpd->greeting_banner);
-  mpd->greeting_banner = NULL;
-  if (mpd->pmessages)
-    free (mpd->pmessages);
-  mpd->pmessages = NULL;
-  mpd->pmessages_count = 0;
-  mpd->is_updated = 0;
-  if (mpd->buffer)
-    free (mpd->buffer);
-  mpd->buffer = NULL;
-
-  CLEAR_STATE (mpd);
-  return 0;
-}
-
-/*  Only build/setup the mu_message_t structure for a mesgno. pop_message_t,
-    will act as the owner of messages.  */
-static int
-pop_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
-{
-  pop_data_t mpd = mbox->data;
-  mu_message_t msg = NULL;
-  pop_message_t mpm;
-  int status;
-  size_t i;
+  mu_pop3_set_carrier (mpd->pop3, stream);
 
-  /* Sanity.  */
-  if (pmsg == NULL || mpd == NULL)
-    return EINVAL;
+  if (mu_debug_check_level (mbox->debug, MU_DEBUG_PROT))
+    mu_pop3_trace (mpd->pop3, MU_POP3_TRACE_SET);
 
-  /* If we did not start a scanning yet do it now.  */
-  if (!pop_is_updated (mbox))
-    pop_scan (mbox, 1, NULL);
+  do
+    {
+      status = mu_pop3_connect (mpd->pop3);
+      if (status)
+       break;
 
-  if (msgno > mpd->messages_count)
-    return EINVAL;
+      status = mu_pop3_capa (mpd->pop3, 1, NULL);
+      if (status)
+       break;
 
-  mu_monitor_rdlock (mbox->monitor);
-  /* See if we have already this message.  */
-  for (i = 0; i < mpd->pmessages_count; i++)
-    {
-      if (mpd->pmessages[i])
+      if (WITH_TLS && !mpd->pops &&
+         mu_pop3_capa_test (mpd->pop3, "STLS", NULL) == 0)
        {
-         if (mpd->pmessages[i]->num == msgno)
-           {
-             *pmsg = mpd->pmessages[i]->message;
-             mu_monitor_unlock (mbox->monitor);
-             return 0;
-           }
+         status = mu_pop3_stls (mpd->pop3);
+         if (status)
+           break;
        }
-    }
-  mu_monitor_unlock (mbox->monitor);
 
-  mpm = calloc (1, sizeof (*mpm));
-  if (mpm == NULL)
-    return ENOMEM;
-
-  /* Back pointer.  */
-  mpm->mpd = mpd;
-  mpm->num = msgno;
-
-  /* Create the message.  */
-  {
-    mu_stream_t stream = NULL;
-    if ((status = mu_message_create (&msg, mpm)) != 0
-       || (status = mu_stream_create (&stream, mbox->flags, msg)) != 0)
-      {
-       mu_stream_destroy (&stream, msg);
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    /* Help for the readline()s  */
-    mu_stream_setbufsiz (stream, 128);
-    mu_stream_set_read (stream, pop_message_read, msg);
-    mu_stream_set_get_transport2 (stream, pop_message_transport, msg);
-    mu_message_set_stream (msg, stream, mpm);
-    mu_message_set_size (msg, pop_message_size, mpm);
-  }
-
-  /* Create the header.  */
-  {
-    mu_header_t header = NULL;
-    if ((status = mu_header_create (&header, NULL, 0,  msg)) != 0)
-      {
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    mu_header_set_fill (header, pop_top, msg);
-    mu_message_set_header (msg, header, mpm);
-  }
-
-  /* Create the attribute.  */
-  {
-    mu_attribute_t attribute;
-    status = mu_attribute_create (&attribute, msg);
-    if (status != 0)
-      {
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    mu_attribute_set_get_flags (attribute, pop_get_attribute, msg);
-    mu_attribute_set_set_flags (attribute, pop_set_attribute, msg);
-    mu_attribute_set_unset_flags (attribute, pop_unset_attribute, msg);
-    mu_message_set_attribute (msg, attribute, mpm);
-  }
-
-  /* Create the body and its stream.  */
-  {
-    mu_body_t body = NULL;
-    mu_stream_t stream = NULL;
-    if ((status = mu_body_create (&body, msg)) != 0
-       || (status = mu_stream_create (&stream, mbox->flags, body)) != 0)
-      {
-       mu_body_destroy (&body, msg);
-       mu_stream_destroy (&stream, body);
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       return status;
-      }
-    /* Helps for the readline()s  */
-    mu_stream_setbufsiz (stream, 128);
-    mu_stream_set_read (stream, pop_body_read, body);
-    mu_stream_set_get_transport2 (stream, pop_body_transport, body);
-    mu_body_set_size (body, pop_body_size, msg);
-    mu_body_set_lines (body, pop_body_lines, msg);
-    mu_body_set_stream (body, stream, msg);
-    mu_message_set_body (msg, body, mpm);
-  }
-
-  /* Set the UIDL call on the message. */
-  if (mpd->capa & CAPA_UIDL)
-    mu_message_set_uidl (msg, pop_uidl, mpm);
+      status = mu_authority_authenticate (mbox->folder->authority);
+    }
+  while (0);
   
-  /* Set the UID on the message. */
-  mu_message_set_uid (msg, pop_uid, mpm);
-
-  /* Add it to the list.  */
-  mu_monitor_wrlock (mbox->monitor);
-  {
-    pop_message_t *m ;
-    m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m));
-    if (m == NULL)
-      {
-       mu_message_destroy (&msg, mpm);
-       free (mpm);
-       mu_monitor_unlock (mbox->monitor);
-       return ENOMEM;
-      }
-    mpd->pmessages = m;
-    mpd->pmessages[mpd->pmessages_count] = mpm;
-    mpd->pmessages_count++;
-  }
-  mu_monitor_unlock (mbox->monitor);
-
-  /* Save The message pointer.  */
-  mu_message_set_mailbox (msg, mbox, mpm);
-  *pmsg = mpm->message = msg;
-
-  return 0;
+  if (status)
+    mu_pop3_destroy (&mpd->pop3);
+  return status;
 }
-
-/* FIXME: Should use strtoumax ideally */
+  
 static int
-parse_answer0 (const char *buffer, size_t *n1, size_t *n2)
+pop_close (mu_mailbox_t mbox)
 {
-  char *p;
-  unsigned long m;
-  if (strlen (buffer) < 3 || memcmp (buffer, "+OK", 3))
-    return 1;
-  m = *n1 = strtoul (buffer + 3, &p, 10);
-  if (!mu_isspace (*p) || m != *n1)
-    return 1;
-  m = *n2 = strtoul (p, &p, 10);
-  if (!(*p == 0 || mu_isspace (*p)) || m != *n2)
-    return 1;
+  struct _pop3_mailbox *mpd = mbox->data;
+  int status;
+  
+  status = mu_pop3_quit (mpd->pop3);
+  if (status)
+    mu_error ("mu_pop3_quit failed: %s", mu_strerror (status));
+  status = mu_pop3_disconnect (mpd->pop3);
+  if (status)
+    mu_error ("mu_pop3_disconnect failed: %s", mu_strerror (status));
+  mu_pop3_destroy (&mpd->pop3);
   return 0;
 }
 
-/* FIXME: Should use strtoumax ideally */
-static int
-parse_answer1 (const char *buffer, size_t *n1, char *buf, size_t bufsize)
-{
-  char *p;
-  unsigned long m;
-  if (strlen (buffer) < 3 || memcmp (buffer, "+OK", 3))
-    return 1;
-  m = *n1 = strtoul (buffer + 3, &p, 0);
-  if (!mu_isspace (*p) || m != *n1)
-    return 1;
-  while (*p && mu_isspace (*p))
-    p++;
-  if (strlen (p) >= bufsize)
-    return 1;
-  strcpy (buf, p);
-  return 0;
-}
-  
-/* There is no such thing in pop all messages should be consider recent.
-   FIXME: We could cheat and peek at the status if it was not strip
-   by the server ...  */
-static int
-pop_messages_recent (mu_mailbox_t mbox, size_t *precent)
+static void
+pop_destroy (mu_mailbox_t mbox)
 {
-  return pop_messages_count (mbox, precent);
+  struct _pop3_mailbox *mpd = mbox->data;
+  if (mpd)
+    {
+       size_t i;
+      mu_monitor_wrlock (mbox->monitor);
+      /* Destroy the pop messages and ressources associated to them.  */
+      for (i = 0; i < mpd->msg_count; i++)
+       {
+         if (mpd->msg[i])
+           {
+             mu_message_destroy (&mpd->msg[i]->message, mpd->msg[i]);
+             if (mpd->msg[i]->uidl)
+               free (mpd->msg[i]->uidl);
+             free (mpd->msg[i]);
+           }
+       }
+      mu_pop3_destroy (&mpd->pop3);
+      if (mpd->user)
+       free (mpd->user);
+      if (mpd->secret)
+       mu_secret_unref (mpd->secret);
+   }
 }
 
-/* There is no such thing in pop all messages should be consider unseen.
-   FIXME: We could cheat and peek at the status if it was not strip
-   by the server ...  */
+/* Update and scanning.  */
 static int
-pop_message_unseen (mu_mailbox_t mbox, size_t *punseen)
+pop_is_updated (mu_mailbox_t mbox)
 {
-  size_t count = 0;
-  int status = pop_messages_count (mbox, &count);
-  if (status != 0)
-    return status;
-  if (punseen)
-    *punseen = (count > 0) ? 1 : 0;
-  return 0;
+  struct _pop3_mailbox *mpd = mbox->data;
+  if (mpd == NULL)
+    return 0;
+  return mpd->is_updated;
 }
-
-/*  How many messages we have.  Done with STAT.  */
+      
+/* Return the number of messages in the mailbox */
 static int
 pop_messages_count (mu_mailbox_t mbox, size_t *pcount)
 {
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status;
-  void *func = (void *)pop_messages_count;
-
+  
   if (mpd == NULL)
     return EINVAL;
 
-  /* Do not send a STAT if we know the answer.  */
   if (pop_is_updated (mbox))
     {
       if (pcount)
-       *pcount = mpd->messages_count;
+       *pcount = mpd->msg_count;
       return 0;
     }
 
-  /* Flag busy.  */
-  CHECK_BUSY (mbox, mpd, func, 0);
-
-  /* TRANSACTION state.  */
-  switch (mpd->state)
+  status = mu_pop3_stat (mpd->pop3, &mpd->msg_count, &mpd->total_size);
+  if (status == 0)
     {
-    case POP_NO_STATE:
-      status = pop_writeline (mpd, "STAT\r\n");
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_STAT;
-
-    case POP_STAT:
-      /* Send the STAT.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_STAT_ACK;
-
-    case POP_STAT_ACK:
-      /* Get the ACK.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_messages_count: unknown state");
-      */
-      break;
+      if (pcount)
+       *pcount = mpd->msg_count;
+      mpd->is_updated = 1;
     }
-
-
-  /* Parse the answer.  */
-
-  status = parse_answer0 (mpd->buffer, &mpd->messages_count, &mpd->size);
-  /*  Clear the state _after_ the scanf, since another thread could
-      start writing over mpd->buffer.  */
-  CLEAR_STATE (mpd);
-
-  if (status)
-    return EIO;
-
-  if (pcount)
-    *pcount = mpd->messages_count;
-  mpd->is_updated = 1;
-  return 0;
-}
-
-/* Update and scanning.  */
-static int
-pop_is_updated (mu_mailbox_t mbox)
-{
-  pop_data_t mpd = mbox->data;
-  if (mpd == NULL)
-    return 0;
-  return mpd->is_updated;
+  return status;
 }
-
-/* We just simulate by sending a notification for the total msgno.  */
-/* FIXME is message is set deleted should we sent a notif ?  */
+  
 static int
 pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
 {
@@ -1317,10 +268,10 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t 
*pcount)
   size_t count = 0;
 
   status = pop_messages_count (mbox, &count);
-  if (pcount)
-    *pcount = count;
   if (status != 0)
     return status;
+  if (pcount)
+    *pcount = count;
   if (mbox->observable == NULL)
     return 0;
   for (i = msgno; i <= count; i++)
@@ -1338,228 +289,149 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t 
*pcount)
   return 0;
 }
 
-/* This is where we actually send the DELE command. Meaning that when
-   the attribute on the message is set deleted the comand DELE is not
-   sent right away and if we did there is no way to mark a message undeleted
-   beside closing down the connection without going to the update state via
-   QUIT.  So DELE is send only when in expunge.  */
+/* There's no way to retrieve this info via POP3 */
 static int
-pop_expunge (mu_mailbox_t mbox)
+pop_message_unseen (mu_mailbox_t mbox, size_t *punseen)
 {
-  pop_data_t mpd = mbox->data;
-  size_t i;
-  mu_attribute_t attr;
-  int status;
-  void *func = (void *)pop_expunge;
-
-  if (mpd == NULL)
-    return EINVAL;
-
-  /* Busy ?  */
-  CHECK_BUSY (mbox, mpd, func, 0);
-
-  for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = ++i)
-    {
-      if (mu_message_get_attribute (mpd->pmessages[i]->message, &attr) == 0)
-       {
-         if (mu_attribute_is_deleted (attr))
-           {
-             switch (mpd->state)
-               {
-               case POP_NO_STATE:
-                 status = pop_writeline (mpd, "DELE %lu\r\n",
-                                         (unsigned long)
-                                           mpd->pmessages[i]->num);
-                 CHECK_ERROR (mpd, status);
-                 MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-                 mpd->state = POP_DELE;
-
-               case POP_DELE:
-                 /* Send DELETE.  */
-                 status = pop_write (mpd);
-                 CHECK_EAGAIN (mpd, status);
-                 mpd->state = POP_DELE_ACK;
-
-               case POP_DELE_ACK:
-                 /* Ack Delete.  */
-                 status = pop_read_ack (mpd);
-                 CHECK_EAGAIN (mpd, status);
-                 MU_DEBUG (mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-                 if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-                   {
-                     CHECK_ERROR (mpd, ERANGE);
-                   }
-                 mpd->state = POP_NO_STATE;
-                 break;
-
-               default:
-                 /* mu_error ("pop_expunge: unknown state); */
-                 break;
-               } /* switch (state) */
-           } /* if mu_attribute_is_deleted() */
-       } /* mu_message_get_attribute() */
-    } /* for */
-  CLEAR_STATE (mpd);
-  /* Invalidate.  But Really they should shutdown the channel POP protocol
-     is not meant for this like IMAP.  */
-  mpd->is_updated = 0;
+  size_t count = 0;
+  int status = pop_messages_count (mbox, &count);
+  if (status != 0)
+    return status;
+  if (punseen)
+    *punseen = (count > 0) ? 1 : 0;
   return 0;
 }
 
-/* Mailbox size ? It is part of the STAT command */
 static int
 pop_get_size (mu_mailbox_t mbox, mu_off_t *psize)
 {
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status = 0;
 
   if (mpd == NULL)
     return EINVAL;
 
   if (!pop_is_updated (mbox))
-    status = pop_messages_count (mbox, &mpd->size);
+    status = pop_messages_count (mbox, NULL);
   if (psize)
-    *psize = mpd->size;
+    *psize = mpd->total_size;
   return status;
 }
 
-/* Form the RFC:
-   "It is important to note that the octet count for a message on the
-   server host may differ from the octet count assigned to that message
-   due to local conventions for designating end-of-line.  Usually,
-   during the AUTHORIZATION state of the POP3 session, the POP3 server
-   can calculate the size of each message in octets when it opens the
-   maildrop.  For example, if the POP3 server host internally represents
-   end-of-line as a single character, then the POP3 server simply counts
-   each occurrence of this character in a message as two octets."
-
-   This is not perfect if we do not know the number of lines in the message
-   then the octets returned will not be correct so we do our best.
- */
+
 static int
-pop_message_size (mu_message_t msg, size_t *psize)
+pop_create_message (struct _pop3_message *mpm, struct _pop3_mailbox *mpd)
 {
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  int status = 0;
-  void *func = (void *)pop_message_size;
-  size_t num;
-
-  if (mpm == NULL)
-    return EINVAL;
+  int status;
+  mu_message_t msg;
+  
+  status = mu_message_create (&msg, mpm);
+  if (status)
+    return status;
+  // FIXME...
+  mpm->message = msg;
+  return 0;
+}
 
-  /* Did we have it already ?  */
-  if (mpm->mu_message_size != 0)
-    {
-      *psize = mpm->mu_message_size;
-      return 0;
-    }
+
+/* ------------------------------------------------------------------------- */
+/* Header */
 
-  mpd = mpm->mpd;
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
+static int
+pop_header_fill (void *data, char **pbuf, size_t *plen)
+{
+  struct _pop3_message *mpm = data;
+  struct _pop3_mailbox *mpd = mpm->mpd;
+  mu_stream_t stream;
+  mu_opool_t opool;
+  int status;
+  
+  status = mu_opool_create (&opool, 0);
+  if (status)
+    return status;
+  
+  if (mu_pop3_capa_test (mpd->pop3, "TOP", NULL) == 0)
+    status = mu_pop3_top (mpd->pop3, mpm->num, 0, &stream);
+  else
+    status = mu_pop3_retr (mpd->pop3, mpm->num, &stream);
 
-  /* Get the size.  */
-  switch (mpd->state)
+  if (status == 0)
     {
-    case POP_NO_STATE:
-      status = pop_writeline (mpd, "LIST %lu\r\n", (unsigned long) mpm->num);
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_LIST;
-
-    case POP_LIST:
-      /* Send the LIST.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_LIST_ACK;
-
-    case POP_LIST_ACK:
-      /* Resp from LIST. */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_message_size: unknown state");
-      */
-      break;
-    }
-
-  /* FIXME */
-  status = parse_answer0 (mpd->buffer, &num, &mpm->mu_message_size);
-  CLEAR_STATE (mpd);
-
-  if (status != 0)
-    return MU_ERR_PARSE;
+      size_t size = 0;
+      char *buf = NULL;
+      size_t n;
 
-  /* The size of the message is with the extra '\r' octet for everyline.
-     Substract to get, hopefully, a good count.  */
-  if (psize)
-    *psize = mpm->mu_message_size - (mpm->header_lines + mpm->body_lines);
-  return 0;
-}
+      while (mu_stream_getline (stream, &buf, &size, &n) == 0
+            && n > 0)
+       {
+         size_t len = mu_rtrim_cset (buf, "\r\n");
+         if (len == 0)
+           break;
+         mu_opool_append (opool, buf, len);
+         mu_opool_append_char (opool, '\n');
+       }
 
-/* Another source of trouble, POP only gives the size of the message
-   not the size of subparts like headers, body etc .. Again we're doing
-   our best with what we know but the only way to get a precise number
-   is by dowloading the whole message.  */
-static int
-pop_body_size (mu_body_t body, size_t *psize)
-{
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
+      if (!mu_stream_eof (stream))
+       /* Drain the stream. */
+       while (mu_stream_getline (stream, &buf, &size, &n) == 0
+              && n > 0);
+      mu_stream_destroy (&stream);
 
-  if (mpm == NULL)
-    return EINVAL;
+      n = mu_opool_size (opool);
+      if (n > size)
+       {
+         char *p = realloc (buf, n);
+         if (!p)
+           {
+             free (buf);
+             mu_opool_destroy (&opool);
+             return ENOMEM;
+           }
+         buf = p;
+       }
 
-  /* Did we have it already ?  */
-  if (mpm->body_size != 0)
-    {
-      *psize = mpm->body_size;
-    }
-  else if (mpm->mu_message_size != 0)
-    {
-      /* Take a guest.  */
-      *psize = mpm->mu_message_size - mpm->header_size - mpm->body_lines;
+      mu_opool_copy (opool, buf, n);
+      *pbuf = buf;
+      *plen = n;
+      status = 0;
     }
-  else
-    *psize = 0;
-
-  return 0;
+  mu_opool_destroy (&opool);
+  
+  return status;
 }
 
-/* Not know until the whole message get downloaded.  */
 static int
-pop_body_lines (mu_body_t body, size_t *plines)
+pop_create_header (struct _pop3_message *mpm)
 {
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  if (mpm == NULL)
-    return EINVAL;
-  if (plines)
-    *plines = mpm->body_lines;
+  int status;
+  mu_header_t header = NULL;
+
+  status = mu_header_create (&header, NULL, 0);
+  if (status)
+    return status;
+  mu_header_set_fill (header, pop_header_fill, mpm);
+  mu_message_set_header (mpm->message, header, mpm);
   return 0;
 }
 
-/* Pop does not have any command for this, We fake by reading the "Status: "
-   header.  But this is hackish some POP server(Qpopper) skip it.  Also
-   because we call mu_header_get_value the function may return EAGAIN... 
uncool.
-   To put it another way, many servers simply remove the "Status:" header
-   field, when you dowload a message, so a message will always look like
-   new even if you already read it.  There is also no way to set an attribute
-   on remote mailbox via the POP server and many server once you do a RETR
-   and in some cases a TOP will mark the message as read; "Status: RO"
-   or maybe worst some ISP configure there servers to delete after
-   the RETR some go as much as deleting after the TOP, since technicaly
-   you can download a message via TOP without RET'reiving it.  */
+
+/* ------------------------------------------------------------------------- */
+/* Attributes */
+
+/* There is no POP3 command to return message attributes, therefore we
+   have to recurse to reading the "Status:" header.  Unfortunately, some
+   servers remove it when you dowload a message, and in this case a message
+   will always look like new even if you already read it.  There is also
+   no way to set an attribute on remote mailbox via the POP server and
+   many server once you do a RETR (and in some cases a TOP) will mark the
+   message as read (Status: RO).  Even worse, some servers may be configured
+   to delete after the RETR, and some go as much as deleting after the TOP,
+   since technicaly you can download a message via TOP without RETR'eiving
+   it.  */
 static int
 pop_get_attribute (mu_attribute_t attr, int *pflags)
 {
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  pop_message_t mpm = mu_message_get_owner (msg);
+  struct _pop3_message *mpm = mu_attribute_get_owner (attr);
   char hdr_status[64];
   mu_header_t header = NULL;
 
@@ -1568,9 +440,11 @@ pop_get_attribute (mu_attribute_t attr, int *pflags)
   if (mpm->attr_flags == 0)
     {
       hdr_status[0] = '\0';
+
       mu_message_get_header (mpm->message, &header);
-      mu_header_get_value (header, "Status", hdr_status, sizeof hdr_status, 
NULL);
-      mu_string_to_flags (hdr_status, &(mpm->attr_flags));
+      mu_header_get_value (header, MU_HEADER_STATUS,
+                          hdr_status, sizeof hdr_status, NULL);
+      mu_string_to_flags (hdr_status, &mpm->attr_flags);
     }
   *pflags = mpm->attr_flags;
   return 0;
@@ -1579,8 +453,7 @@ pop_get_attribute (mu_attribute_t attr, int *pflags)
 static int
 pop_set_attribute (mu_attribute_t attr, int flags)
 {
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  pop_message_t mpm = mu_message_get_owner (msg);
+  struct _pop3_message *mpm = mu_attribute_get_owner (attr);
 
   if (mpm == NULL)
     return EINVAL;
@@ -1591,8 +464,7 @@ pop_set_attribute (mu_attribute_t attr, int flags)
 static int
 pop_unset_attribute (mu_attribute_t attr, int flags)
 {
-  mu_message_t msg = mu_attribute_get_owner (attr);
-  pop_message_t mpm = mu_message_get_owner (msg);
+  struct _pop3_message *mpm = mu_attribute_get_owner (attr);
 
   if (mpm == NULL)
     return EINVAL;
@@ -1600,575 +472,225 @@ pop_unset_attribute (mu_attribute_t attr, int flags)
   return 0;
 }
 
-/* Stub to call the fd from body object.  */
 static int
-pop_body_transport (mu_stream_t stream, mu_transport_t *ptr, mu_transport_t 
*ptr2)
+pop_create_attribute (struct _pop3_message *mpm)
 {
-  mu_body_t body = mu_stream_get_owner (stream);
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  return pop_get_transport2 (mpm, ptr, ptr2);
-}
-
-/* Stub to call the fd from message object.  */
-static int
-pop_message_transport (mu_stream_t stream, mu_transport_t *ptr, mu_transport_t 
*ptr2)
-{
-  mu_message_t msg = mu_stream_get_owner (stream);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  return pop_get_transport2 (mpm, ptr, ptr2);
-}
+  int status;
+  mu_attribute_t attribute;
+  
+  status = mu_attribute_create (&attribute, mpm);
+  if (status)
+    return status;
 
-static int
-pop_get_transport2 (pop_message_t mpm, mu_transport_t *ptr, mu_transport_t 
*ptr2)
-{
-  if (mpm && mpm->mpd && mpm->mpd->mbox)
-       return mu_stream_get_transport2 (mpm->mpd->mbox->stream, ptr, ptr2);
-  return EINVAL;
+  mu_attribute_set_get_flags (attribute, pop_get_attribute, mpm);
+  mu_attribute_set_set_flags (attribute, pop_set_attribute, mpm);
+  mu_attribute_set_unset_flags (attribute, pop_unset_attribute, mpm);
+  mu_message_set_attribute (mpm->message, attribute, mpm);
+  return 0;
 }
+
+/* ------------------------------------------------------------------------- */
+/* Body */
 
 static int
-pop_uid (mu_message_t msg,  size_t *puid)
+pop_create_body (struct _pop3_message *mpm)
 {
-  pop_message_t mpm = mu_message_get_owner (msg);
-  if (puid)
-    *puid = mpm->num;
-  return 0;
+  /* FIXME */
+  return ENOSYS;
 }
 
-/* Get the UIDL.  The client should be prepared, since it may fail.  UIDL is
-   optional on many POP servers.
-   FIXME:  We should check the "mpd->capa & CAPA_UIDL" and fall back to
-   a md5 scheme ? Or maybe check for "X-UIDL" a la Qpopper ?  */
+
+/* FIXME: change prototype to avoid fixed size buffer */
 static int
 pop_uidl (mu_message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
 {
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  int status = 0;
-  void *func = (void *)pop_uidl;
-  size_t num;
-  char uniq[MU_UIDL_BUFFER_SIZE];
-
-  if (mpm == NULL)
-    return EINVAL;
-
-  /* Is it cached ?  */
-  if (mpm->uidl)
+  struct _pop3_message *mpm = mu_message_get_owner (msg);
+  struct _pop3_mailbox *mpd = mpm->mpd;
+  size_t len;
+  
+  if (!mpm->uidl)
     {
-      size_t len = strlen (mpm->uidl);
-      if (buffer)
+      if (mu_pop3_capa_test (mpd->pop3, "UIDL", NULL) == 0)
        {
-         buflen--; /* Leave space for the null.  */
-         buflen = (len > buflen) ? buflen : len;
-         memcpy (buffer, mpm->uidl, buflen);
-         buffer[buflen] = '\0';
+         int status = mu_pop3_uidl (mpd->pop3, mpm->num, &mpm->uidl);
+         if (status)
+           return status;
        }
       else
-       buflen = len;
-      if (pnwriten)
-       *pnwriten = buflen;
-      return 0;
-    }
-
-  mpd = mpm->mpd;
-
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, 0);
-
-  /* Get the UIDL.  */
-  switch (mpd->state)
-    {
-    case POP_NO_STATE:
-      status = pop_writeline (mpd, "UIDL %lu\r\n", (unsigned long) mpm->num);
-      CHECK_ERROR (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      mpd->state = POP_UIDL;
-
-    case POP_UIDL:
-      /* Send the UIDL.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_UIDL_ACK;
-
-    case POP_UIDL_ACK:
-      /* Resp from UIDL. */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      break;
-
-    default:
-      /*
-       mu_error ("pop_uidl: unknown state");
-      */
-      break;
+       return ENOSYS;
     }
 
-  /* FIXME:  I should cache the result.  */
-  *uniq = '\0';
-  status = parse_answer1 (mpd->buffer, &num, uniq, sizeof uniq);
-  if (status)
+  len = strlen (mpm->uidl);
+  if (buffer)
     {
-      status = MU_ERR_PARSE;
-      buflen = 0;
+      buflen--; /* Leave space for the null.  */
+      buflen = (len > buflen) ? buflen : len;
+      memcpy (buffer, mpm->uidl, buflen);
+      buffer[buflen] = 0;
     }
   else
-    {
-      num = strlen (uniq);
-      uniq[num - 1] = '\0'; /* Nuke newline.  */
-      if (buffer)
-       {
-         buflen--; /* Leave space for the null.  */
-         buflen = (buflen < num) ? buflen : num;
-         memcpy (buffer, uniq, buflen);
-         buffer [buflen] = '\0';
-       }
-      else
-       buflen = num - 1; /* Do not count newline.  */
-      mpm->uidl = strdup (uniq);
-      status = 0;
-    }
-
-  CLEAR_STATE (mpd);
-
+    buflen = len;
   if (pnwriten)
     *pnwriten = buflen;
-  return status;
+  return 0;
 }
 
-/* How we retrieve the headers.  If it fails we jump to the pop_retr()
-   code i.e. send a RETR and skip the body, ugly.
-   NOTE: if the offset is different, flag an error, offset is meaningless
-   on a socket but we better warn them, some stuff like mu_mime_t may try to
-   read ahead, for example for the headers.  */
 static int
-pop_top (mu_header_t header, char *buffer, size_t buflen,
-        mu_off_t offset, size_t *pnread)
+pop_uid (mu_message_t msg,  size_t *puid)
 {
-  mu_message_t msg = mu_header_get_owner (header);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  size_t nread = 0;
-  int status = 0;
-  void *func = (void *)pop_top;
-
-  if (mpm == NULL)
-    return EINVAL;
-
-  mpd = mpm->mpd;
-
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
-
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->header_size = 0;
-
-  /* Throw an error if trying to seek back.  */
-  if ((size_t)offset < mpm->header_size)
-    return ESPIPE;
-
-  /* Get the header.  */
-  switch (mpd->state)
-    {
-    case POP_NO_STATE:
-      if (mpd->capa & CAPA_TOP)
-        {
-         status = pop_writeline (mpd, "TOP %lu 0\r\n",
-                                 (unsigned long) mpm->num);
-         CHECK_ERROR (mpd, status);
-         MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-         mpd->state = POP_TOP;
-       }
-      else /* Fall back to RETR call.  */
-        {
-         mpd->state = POP_NO_STATE;
-         mpm->skip_header = 0;
-         mpm->skip_body = 1;
-         return pop_retr (mpm, buffer, buflen, offset, pnread);
-        }
-
-    case POP_TOP:
-      /* Send the TOP.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_TOP_ACK;
-
-    case POP_TOP_ACK:
-      /* Ack from TOP. */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       CHECK_ERROR (mpd, EINVAL);
-      mpd->state = POP_TOP_RX;
-
-    case POP_TOP_RX:
-      /* Get the header.  */
-      do
-       {
-         /* Seek in position.  */
-         ssize_t pos = offset - mpm->header_size;
-         /* Do we need to fill up.  */
-         if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
-           {
-             status = pop_readline (mpd);
-             CHECK_EAGAIN (mpd, status);
-             mpm->header_lines++;
-           }
-         /* If we have to skip some data to get to the offset.  */
-         if (pos > 0)
-           nread = fill_buffer (mpd, NULL, pos);
-         else
-           nread = fill_buffer (mpd, buffer, buflen);
-         mpm->header_size += nread;
-       }
-      while (nread > 0 && (size_t)offset > mpm->header_size);
-      break;
-
-    default:
-      /* Probaly TOP was not supported so we have fall back to RETR.  */
-      mpm->skip_header = 0;
-      mpm->skip_body = 1;
-      return pop_retr (mpm, buffer, buflen, offset, pnread);
-    } /* switch (state) */
-
-  if (nread == 0)
-    {
-      CLEAR_STATE (mpd);
-    }
-  if (pnread)
-    *pnread = nread;
+  struct _pop3_message *mpm = mu_message_get_owner (msg);
+  if (puid)
+    *puid = mpm->num;
   return 0;
 }
 
-/* This is no longer use, see pop_top to retreive headers, we still
-   keep it around for debugging purposes.  */
-#if 0
-/* Stub to call pop_retr ().   Call form the stream object of the header.  */
 static int
-pop_header_read (mu_header_t header, char *buffer, size_t buflen, mu_off_t 
offset,
-                size_t *pnread)
+pop_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg)
 {
-  mu_message_t msg = mu_header_get_owner (header);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  void *func = (void *)pop_header_read;
+  struct _pop3_mailbox *mpd = mbox->data;
+  struct _pop3_message *mpm;
+  int status;
 
-  if (mpm == NULL)
+  /* Sanity checks. */
+  if (pmsg == NULL || mpd == NULL)
     return EINVAL;
 
-  mpd = mpm->mpd;
-
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
-
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->header_size = mpm->inbody = 0;
-
-  /* Throw an error if trying to seek back.  */
-  if ((size_t)offset < mpm->header_size)
-    return ESPIPE;
+  /* If we did not start a scanning yet do it now.  */
+  if (!pop_is_updated (mbox))
+    pop_scan (mbox, 1, NULL);
 
-  mpm->skip_header = 0;
-  mpm->skip_body = 1;
-  return pop_retr (mpm, buffer, buflen, offset, pnread);
-}
-#endif
+  if (msgno > mpd->msg_count)
+    return EINVAL;
 
-/* Stub to call pop_retr (). Call from the stream object of the body.  */
-static int
-pop_body_read (mu_stream_t is, char *buffer, size_t buflen, mu_off_t offset,
-              size_t *pnread)
-{
-  mu_body_t body = mu_stream_get_owner (is);
-  mu_message_t msg = mu_body_get_owner (body);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  void *func = (void *)pop_body_read;
+  if (!mpd->msg)
+    {
+      mpd->msg = calloc (mpd->msg_count, sizeof (mpd->msg[0]));
+      if (!mpd->msg)
+       return ENOMEM;
+    }
+  if (mpd->msg[msgno])
+    {
+      *pmsg = mpd->msg[msgno]->message;
+      return 0;
+    }
 
+  mpm = calloc (1, sizeof (*mpm));
   if (mpm == NULL)
-    return EINVAL;
+    return ENOMEM;
 
-  mpd = mpm->mpd;
+  /* Back pointer.  */
+  mpm->mpd = mpd;
+  mpm->num = msgno;
+  
+  status = pop_create_message (mpm, mpd);
+  if (status)
+    {
+      free (mpm);
+      return status;
+    }
 
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
+  do
+    {
+      status = pop_create_header (mpm);
+      if (status)
+       break;
+      status = pop_create_attribute (mpm);
+      if (status)
+       break;
+      status = pop_create_body (mpm);
+    }
+  while (0);
+  
+  if (status)
+    {
+      mu_message_destroy (&mpm->message, mpm);
+      free (mpm);
+      return status;
+    }
 
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->body_size = mpm->inbody = 0;
+  if (mu_pop3_capa_test (mpd->pop3, "UIDL", NULL) == 0)
+    mu_message_set_uidl (mpm->message, pop_uidl, mpm);
 
-  /* Can not seek back this a stream socket.  */
-  if ((size_t)offset < mpm->body_size)
-    return ESPIPE;
+  mu_message_set_uid (mpm->message, pop_uid, mpm);
 
-  mpm->skip_header = 1;
-  mpm->skip_body = 0;
-  return pop_retr (mpm, buffer, buflen, offset, pnread);
+  mpd->msg[msgno] = mpm;
+  mu_message_set_mailbox (mpm->message, mbox, mpm);
+  *pmsg = mpm->message;
+  return 0;
 }
-
-/* Stub to call pop_retr (), calling from the stream object of a message.  */
+
 static int
-pop_message_read (mu_stream_t is, char *buffer, size_t buflen, mu_off_t offset,
-                 size_t *pnread)
+_pop3_mailbox_init (mu_mailbox_t mbox, int pops)
 {
-  mu_message_t msg = mu_stream_get_owner (is);
-  pop_message_t mpm = mu_message_get_owner (msg);
-  pop_data_t mpd;
-  void *func = (void *)pop_message_read;
-
-  if (mpm == NULL)
-    return EINVAL;
-
-  mpd = mpm->mpd;
+  struct _pop3_mailbox *mpd;
+  int status = 0;
 
-  /* Busy ? */
-  CHECK_BUSY (mpd->mbox, mpd, func, msg);
+  /* Allocate specifics for pop data.  */
+  mpd = mbox->data = calloc (1, sizeof (*mpd));
+  if (mbox->data == NULL)
+    return ENOMEM;
 
-  /* We start fresh then reset the sizes.  */
-  if (mpd->state == POP_NO_STATE)
-    mpm->header_size = mpm->body_size = mpm->inbody = 0;
+  mpd->pop3 = NULL;
+  
+  mpd->mbox = mbox;            /* Back pointer.  */
+  mpd->pops = pops;
 
-  /* Can not seek back this is a stream socket.  */
-  if ((size_t)offset < (mpm->body_size + mpm->header_size))
-    return ESPIPE;
+  /* Initialize the structure.  */
+  mbox->_destroy = pop_destroy;
 
-  mpm->skip_header = mpm->skip_body = 0;
-  return pop_retr (mpm, buffer, buflen, offset, pnread);
-}
+  mbox->_open = pop_open;
+  mbox->_close = pop_close;
+  mbox->_messages_count = pop_messages_count;
+  /* FIXME: There is no way to retrieve the number of recent messages via
+     POP3 protocol, so we consider all messages recent. */
+  mbox->_messages_recent = pop_messages_count;
+  mbox->_is_updated = pop_is_updated;
+  mbox->_scan = pop_scan;
+  mbox->_message_unseen = pop_message_unseen;
+  mbox->_get_size = pop_get_size;
+  
+#if 0 //FIXME
+  /* Messages.  */
+  mbox->_get_message = pop_get_message;
+  mbox->_expunge = pop_expunge;
 
-/* Little helper to fill the buffer without overflow.  */
-static int
-fill_buffer (pop_data_t mpd, char *buffer, size_t buflen)
-{
-  int nleft, n, nread = 0;
 
-  /* How much we can copy ?  */
-  n = mpd->ptr - mpd->buffer;
-  nleft = buflen - n;
 
- /* We got more then requested.  */
-  if (nleft < 0)
-    {
-      size_t sentinel;
-      nread = buflen;
-      sentinel = mpd->ptr - (mpd->buffer + nread);
-      if (buffer)
-       memcpy (buffer, mpd->buffer, nread);
-      memmove (mpd->buffer, mpd->buffer + nread, sentinel);
-      mpd->ptr = mpd->buffer + sentinel;
-    }
-  else
-    {
-      /* Drain our buffer.  */;
-      nread = n;
-      if (buffer)
-       memcpy (buffer, mpd->buffer, nread);
-      mpd->ptr = mpd->buffer;
-    }
+  /* Set our properties.  */
+  {
+    mu_property_t property = NULL;
+    mu_mailbox_get_property (mbox, &property);
+    mu_property_set_value (property, "TYPE", "POP3", 1);
+  }
 
-  return nread;
+#endif
+  /* Hack! POP does not really have a folder.  */
+  mbox->folder->data = mbox;
+  return status;
 }
 
-/* The heart of most funtions.  Send the RETR and skip different parts.  */
-static int
-pop_retr (pop_message_t mpm, char *buffer, size_t buflen,  
-          mu_off_t offset MU_ARG_UNUSED, size_t *pnread)
+int
+_mailbox_pop_init (mu_mailbox_t mbox)
 {
-  pop_data_t mpd;
-  size_t nread = 0;
-  int status = 0;
-  size_t oldbuflen = buflen;
-
-  mpd = mpm->mpd;
-
-  if (pnread)
-    *pnread = nread;
-
-  /*  Take care of the obvious.  */
-  if (buffer == NULL || buflen == 0)
-    {
-      CLEAR_STATE (mpd);
-      return 0;
-    }
-
-  /* pop_retr() is not call directly so we assume that the locks were set.  */
-
-  switch (mpd->state)
-    {
-    case POP_NO_STATE:
-      mpm->body_lines = mpm->body_size = 0;
-      status = pop_writeline (mpd, "RETR %lu\r\n",
-                             (unsigned long) mpm->num);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-      CHECK_ERROR (mpd, status);
-      mpd->state = POP_RETR;
-
-    case POP_RETR:
-      /* Send the RETR command.  */
-      status = pop_write (mpd);
-      CHECK_EAGAIN (mpd, status);
-      mpd->state = POP_RETR_ACK;
-
-    case POP_RETR_ACK:
-      /* RETR ACK.  */
-      status = pop_read_ack (mpd);
-      CHECK_EAGAIN (mpd, status);
-      MU_DEBUG (mpd->mbox->debug, MU_DEBUG_PROT, mpd->buffer);
-
-      if (mu_c_strncasecmp (mpd->buffer, "+OK", 3) != 0)
-       {
-         CHECK_ERROR (mpd, EACCES);
-       }
-      mpd->state = POP_RETR_RX_HDR;
-
-    case POP_RETR_RX_HDR:
-      /* Skip/Take the header.  */
-      while (!mpm->inbody)
-        {
-         /* Do we need to fill up.  */
-         if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
-           {
-             status = pop_readline (mpd);
-             if (status != 0)
-               {
-                 /* Do we have something in the buffer flush it first.  */
-                 if (buflen != oldbuflen)
-                   return 0;
-                 CHECK_EAGAIN (mpd, status);
-               }
-             mpm->header_lines++;
-           }
-         /* Oops !! Hello houston we have a major problem here.  */
-         if (mpd->buffer[0] == '\0')
-           {
-             /* Still Do the right thing.  */
-             if (buflen != oldbuflen)
-               {
-                 CLEAR_STATE (mpd);
-               }
-             else
-               mpd->state = POP_STATE_DONE;
-             return 0;
-           }
-         /* The problem is that we are using RETR instead of TOP to retreive
-            headers, i.e the server contacted does not support it.  So we
-            have to make sure that the next line really means end of the
-            headers.  Still some cases we may loose.  But 99.9% of POPD
-            encounter support TOP.  In the 0.1% case get GNU pop3d, or the
-            hack below will suffice.  */
-         if (mpd->buffer[0] == '\n' && mpd->buffer[1] == '\0')
-           mpm->inbody = 1; /* break out of the while.  */
-         if (!mpm->skip_header)
-           {
-             ssize_t pos = offset  - mpm->header_size;
-             if (pos > 0)
-               {
-                 nread = fill_buffer (mpd, NULL, pos);
-                 mpm->header_size += nread;
-               }
-             else
-               {
-                 nread = fill_buffer (mpd, buffer, buflen);
-                 mpm->header_size += nread;
-                 if (pnread)
-                   *pnread += nread;
-                 buflen -= nread ;
-                 if (buflen > 0)
-                   buffer += nread;
-                 else
-                   return 0;
-               }
-           }
-         else
-           mpd->ptr = mpd->buffer;
-       }
-      mpd->state = POP_RETR_RX_BODY;
-
-    case POP_RETR_RX_BODY:
-      /* Start/Take the body.  */
-      while (mpm->inbody)
-       {
-         /* Do we need to fill up.  */
-         if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
-           {
-             status = pop_readline (mpd);
-             if (status != 0)
-               {
-                 /* Flush The Buffer ?  */
-                 if (buflen != oldbuflen)
-                   return 0;
-                 CHECK_EAGAIN (mpd, status);
-               }
-             mpm->body_lines++;
-           }
+  return _pop3_mailbox_init (mbox, 0);
+}
 
-           if (mpd->buffer[0] == '\0')
-             mpm->inbody = 0; /* Breakout of the while.  */
-
-           if (!mpm->skip_body)
-             {
-               /* If we did not skip the header, it means that we are
-                  downloading the entire message and the mu_header_size should 
be
-                  part of the offset count.  */
-               ssize_t pos = offset - (mpm->body_size + ((mpm->skip_header) ?
-                                       0 : mpm->header_size));
-               if (pos > 0)
-                 {
-                   nread = fill_buffer (mpd, NULL, pos);
-                   mpm->body_size += nread;
-                 }
-               else
-                 {
-                   nread = fill_buffer (mpd, buffer, buflen);
-                   mpm->body_size += nread;
-                   if (pnread)
-                     *pnread += nread;
-                   buflen -= nread ;
-                   if (buflen > 0)
-                     buffer += nread;
-                   else
-                     return 0;
-                 }
-             }
-           else
-             {
-               mpm->body_size += (mpd->ptr - mpd->buffer);
-               mpd->ptr = mpd->buffer;
-             }
-         }
-      mpm->mu_message_size = mpm->body_size + mpm->header_size;
-      mpd->state = POP_STATE_DONE;
-      /* Return here earlier, because we want to return nread = 0 to notify
-        the callee that we've finish, since there is already data
-        we have to return them first and _then_ tell them its finish.  If we
-        don't we will start over again by sending another RETR.  */
-      if (buflen != oldbuflen)
-       return 0;
-
-    case POP_STATE_DONE:
-      /* A convenient break, this is here we can return 0, we're done.  */
-
-    default:
-      /* mu_error ("pop_retr: unknown state"); */
-      break;
-    } /* Switch state.  */
-
-  CLEAR_STATE (mpd);
-  mpm->skip_header = mpm->skip_body = 0;
-  return 0;
+int
+_mailbox_pops_init (mu_mailbox_t mbox)
+{
+  return _pop3_mailbox_init (mbox, 1);
 }
 
+
+/* Authentication */
+
 /* Extract the User from the URL or the ticket.  */
 static int
 pop_get_user (mu_authority_t auth)
 {
   mu_folder_t folder = mu_authority_get_owner (auth);
   mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   mu_ticket_t ticket = NULL;
   int status;
   /*  Fetch the user from them.  */
@@ -2195,7 +717,7 @@ pop_get_passwd (mu_authority_t auth)
 {
   mu_folder_t folder = mu_authority_get_owner (auth);
   mu_mailbox_t mbox = folder->data;
-  pop_data_t mpd = mbox->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   mu_ticket_t ticket = NULL;
   int status;
 
@@ -2212,217 +734,60 @@ pop_get_passwd (mu_authority_t auth)
   return 0;
 }
 
-
-static char *
-pop_get_timestamp (pop_data_t mpd)
-{
-  char *right, *left;
-  char *timestamp = NULL;
-  size_t len;
-
-  len = strlen (mpd->greeting_banner);
-  right = memchr (mpd->greeting_banner, '<', len);
-  if (right)
-    {
-      len = len - (right - mpd->greeting_banner);
-      left = memchr (right, '>', len);
-      if (left)
-       {
-         len = left - right + 1;
-         timestamp = calloc (len + 1, 1);
-         if (timestamp != NULL)
-           {
-             memcpy (timestamp, right, len);
-           }
-       }
-    }
-  return timestamp;
-}
-
-/*  Make the MD5 string.  */
-static int
-pop_get_md5 (pop_data_t mpd)
+int
+_pop_apop (mu_authority_t auth)
 {
-  struct mu_md5_ctx md5context;
-  unsigned char md5digest[16];
-  char digest[64]; /* Really it just has to be 32 + 1(null).  */
-  char *tmp;
-  size_t n;
-  char *timestamp;
-
-  timestamp = pop_get_timestamp (mpd);
-  if (timestamp == NULL)
-    return EINVAL;
+  mu_folder_t folder = mu_authority_get_owner (auth);
+  mu_mailbox_t mbox = folder->data;
+  struct _pop3_mailbox *mpd = mbox->data;
+  int status;
+  
+  status = pop_get_user (auth);
+  if (status)
+    return status;
 
-  mu_md5_init_ctx (&md5context);
-  mu_md5_process_bytes (timestamp, strlen (timestamp), &md5context);
-  mu_md5_process_bytes (mu_secret_password (mpd->secret),
-                       mu_secret_length (mpd->secret),
-                       &md5context);
+  /* Fetch the secret from them.  */
+  status = pop_get_passwd (auth);
+  if (status)
+    return status;
+  status = mu_pop3_apop (mpd->pop3, mpd->user,
+                        mu_secret_password (mpd->secret));
   mu_secret_password_unref (mpd->secret);
   mu_secret_unref (mpd->secret);
   mpd->secret = NULL;
-  mu_md5_finish_ctx (&md5context, md5digest);
-  
-  for (tmp = digest, n = 0; n < 16; n++, tmp += 2)
-    sprintf (tmp, "%02x", md5digest[n]);
-  *tmp = '\0';
-  free (timestamp);
-  mpd->digest = strdup (digest);
-  return 0;
-}
-
-/* GRRRRR!!  We can not use sleep in the library since this we'll
-   muck up any alarm() done by the user.  */
-static int
-pop_sleep (int seconds)
-{
-  struct timeval tval;
-  tval.tv_sec = seconds;
-  tval.tv_usec = 0;
-  return select (1, NULL, NULL, NULL, &tval);
-}
-
-/* C99 says that a conforming implementation of snprintf () should return the
-   number of char that would have been call but many old GNU/Linux && BSD
-   implementations return -1 on error.  Worse QnX/Neutrino actually does not
-   put the terminal null char.  So let's try to cope.  */
-static int
-pop_writeline (pop_data_t mpd, const char *format, ...)
-{
-  int len;
-  va_list ap;
-  int done = 1;
-
-  if (mpd->buffer == NULL)
-    return EINVAL;
-  va_start(ap, format);
-  do
-    {
-      len = vsnprintf (mpd->buffer, mpd->buflen - 1, format, ap);
-      if (len < 0 || len >= (int)mpd->buflen
-         || !memchr (mpd->buffer, '\0', len + 1))
-       {
-         mpd->buflen *= 2;
-         mpd->buffer = realloc (mpd->buffer, mpd->buflen);
-         if (mpd->buffer == NULL)
-           return ENOMEM;
-         done = 0;
-       }
-      else
-       done = 1;
-    }
-  while (!done);
-  va_end(ap);
-  mpd->ptr = mpd->buffer + len;
-  return 0;
-}
-
-/* A socket may write less then expected and we have to cope with nonblocking.
-   if the write failed we keep track and restart where left.  */
-static int
-pop_write (pop_data_t mpd)
-{
-  int status = 0;
-  if (mpd->ptr > mpd->buffer)
-    {
-      size_t len;
-      size_t n = 0;
-      len = mpd->ptr - mpd->buffer;
-      status = mu_stream_write (mpd->mbox->stream, mpd->buffer, len, 0, &n);
-      if (status == 0)
-       {
-         memmove (mpd->buffer, mpd->buffer + n, len - n);
-         mpd->ptr -= n;
-       }
-    }
-  else
-    mpd->ptr = mpd->buffer;
-  return status;
-}
-
-/* Call readline and reset the mpd->ptr to the buffer, signalling that we have
-   done the read to completion. */
-static int
-pop_read_ack (pop_data_t mpd)
-{
-  int status = pop_readline (mpd);
-  if (status == 0)
-    mpd->ptr = mpd->buffer;
+  free (mpd->user);
+  mpd->user = NULL;
   return status;
 }
 
-/* Read a complete line form the pop server. Transform CRLF to LF, remove
-   the stuff byte termination octet ".", put a null in the buffer
-   when done.  */
-static int
-pop_readline (pop_data_t mpd)
+int
+_pop_user (mu_authority_t auth)
 {
-  size_t n = 0;
-  size_t total = mpd->ptr - mpd->buffer;
+  mu_folder_t folder = mu_authority_get_owner (auth);
+  mu_mailbox_t mbox = folder->data;
+  struct _pop3_mailbox *mpd = mbox->data;
   int status;
-
-  /* Must get a full line before bailing out.  */
-  do
-    {
-      status = mu_stream_readline (mpd->mbox->stream, mpd->buffer + total,
-                               mpd->buflen - total,  mpd->offset, &n);
-      if (status != 0)
-       return status;
-
-      /* The server went away:  It maybe a timeout and some pop server
-        does not send the -ERR.  Consider this like an error.  */
-      if (n == 0)
-       return EIO;
-
-      total += n;
-      mpd->offset += n;
-      mpd->nl = memchr (mpd->buffer, '\n', total);
-      if (mpd->nl == NULL)  /* Do we have a full line.  */
-       {
-         /* Allocate a bigger buffer ?  */
-         if (total >= mpd->buflen -1)
-           {
-             mpd->buflen *= 2;
-             mpd->buffer = realloc (mpd->buffer, mpd->buflen + 1);
-             if (mpd->buffer == NULL)
-               return ENOMEM;
-           }
-       }
-      mpd->ptr = mpd->buffer + total;
-    }
-  while (mpd->nl == NULL);
-
-  /* When examining a multi-line response, the client checks to see if the
-     line begins with the termination octet "."(DOT). If yes and if octets
-     other than CRLF follow, the first octet of the line (the termination
-     octet) is stripped away.  */
-  if (total >= 3  && mpd->buffer[0] == '.')
+  
+  status = pop_get_user (auth);
+  if (status)
+    return status;
+  status = mu_pop3_user (mpd->pop3, mpd->user);
+  if (status == 0)
     {
-      if (mpd->buffer[1] != '\r' && mpd->buffer[2] != '\n')
-       {
-         memmove (mpd->buffer, mpd->buffer + 1, total - 1);
-         mpd->ptr--;
-         mpd->nl--;
-       }
-      /* And if CRLF immediately follows the termination character, then the
-        response from the POP server is ended and the line containing
-        ".CRLF" is not considered part of the multi-line response.  */
-      else if (mpd->buffer[1] == '\r' && mpd->buffer[2] == '\n')
+      /* Fetch the secret from them.  */
+      status = pop_get_passwd (auth);
+      if (status == 0) 
        {
-         mpd->buffer[0] = '\0';
-         mpd->ptr = mpd->buffer;
-         mpd->nl = NULL;
+         status = mu_pop3_pass (mpd->pop3, mu_secret_password (mpd->secret));
+         mu_secret_password_unref (mpd->secret);
+         mu_secret_unref (mpd->secret);
+         mpd->secret = NULL;
        }
     }
-  /* \r\n --> \n\0, conversion.  */
-  if (mpd->nl > mpd->buffer)
-    {
-      *(mpd->nl - 1) = '\n';
-      *(mpd->nl) = '\0';
-      mpd->ptr = mpd->nl;
-    }
-  return 0;
+  free (mpd->user);
+  mpd->user = NULL;
+  return status;
 }
 
-#endif
+
+#endif /* ENABLE_POP */
diff --git a/libproto/pop/pop3_capa.c b/libproto/pop/pop3_capa.c
index 181c602..e6402af 100644
--- a/libproto/pop/pop3_capa.c
+++ b/libproto/pop/pop3_capa.c
@@ -33,36 +33,18 @@
 #include <mailutils/sys/pop3.h>
 
 static int
-string_comp (const void *item, const void *value)
+capa_comp (const void *item, const void *value)
 {
-  return strcmp (item, value);
-}
-
-int
-_mu_pop3_fill_list (mu_pop3_t pop3, mu_list_t list)
-{
-  mu_stream_t stream;
-  size_t n;
-  int status = mu_pop3_stream_create (pop3, &stream);
-  if (status)
-    return status;
-  
-  while (mu_stream_getline (stream, &pop3->rdbuf, &pop3->rdsize, &n) == 0
-        && n > 0)
+  const char *capa = item;
+  const char *needle = value;
+  for (; *needle; capa++, needle++)
     {
-      char *np = strdup (pop3->rdbuf);
-      if (!np)
-       {
-         status = ENOMEM;
-         break;
-       }
-      mu_rtrim_class (np, MU_CTYPE_SPACE);
-      status = mu_list_append (list, np);
-      if (status)
-       break;
+      if (!*capa)
+       return 1;
+      if (mu_tolower (*capa) != mu_tolower (*needle))
+       return 1;
     }
-  mu_stream_destroy (&stream);
-  return status;
+  return !(*capa == 0 || mu_isspace (*capa));
 }
 
 /*
@@ -91,7 +73,7 @@ mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t 
*piter)
   status = mu_list_create (&pop3->capa);
   if (status)
     return status;
-  mu_list_set_comparator (pop3->capa, string_comp);
+  mu_list_set_comparator (pop3->capa, capa_comp);
   mu_list_set_destroy_item (pop3->capa, mu_list_free_item);
   
   switch (pop3->state)
@@ -109,7 +91,7 @@ mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t 
*piter)
       pop3->state = MU_POP3_CAPA_RX;
 
     case MU_POP3_CAPA_RX:
-      status = _mu_pop3_fill_list (pop3, pop3->capa);
+      status = mu_pop3_read_list (pop3, pop3->capa);
       MU_POP3_CHECK_ERROR (pop3, status);
       if (piter)
        status = mu_list_get_iterator (pop3->capa, piter);
diff --git a/mailbox/freeitem.c b/libproto/pop/pop3_capatst.c
similarity index 71%
copy from mailbox/freeitem.c
copy to libproto/pop/pop3_capatst.c
index c268ea4..37d740b 100644
--- a/mailbox/freeitem.c
+++ b/libproto/pop/pop3_capatst.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 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
@@ -19,11 +20,18 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
+
 #include <stdlib.h>
+#include <mailutils/list.h>
+#include <mailutils/sys/pop3.h>
 
-/* Default destroy_item function. */
-void
-mu_list_free_item (void *item)
+int
+mu_pop3_capa_test (mu_pop3_t pop3, const char *name, const char **pret)
 {
-  free (item);
+  int rc;
+
+  rc = mu_pop3_capa (pop3, 0, NULL);
+  if (rc)
+    return rc;
+  return mu_list_locate (pop3->capa, (void*) name, (void**)pret);
 }
diff --git a/libproto/pop/pop3_create.c b/libproto/pop/pop3_create.c
index eb6a6e8..dc92360 100644
--- a/libproto/pop/pop3_create.c
+++ b/libproto/pop/pop3_create.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <mailutils/errno.h>
 #include <mailutils/sys/pop3.h>
+#include <mailutils/list.h>
 
 /* Initialise a mu_pop3_t handle.  */
 
@@ -58,6 +59,7 @@ _mu_pop3_init (mu_pop3_t pop3)
       mu_list_destroy (&pop3->capa);
       pop3->flags = 0;
     }
+  return 0;
 }
 
   
diff --git a/libproto/pop/pop3_destroy.c b/libproto/pop/pop3_destroy.c
index 75ee7d7..010a063 100644
--- a/libproto/pop/pop3_destroy.c
+++ b/libproto/pop/pop3_destroy.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <mailutils/errno.h>
 #include <mailutils/sys/pop3.h>
+#include <mailutils/list.h>
 
 void
 mu_pop3_destroy (mu_pop3_t *ppop3)
diff --git a/libproto/pop/pop3_list.c b/libproto/pop/pop3_list.c
index d63272e..e6bccb5 100644
--- a/libproto/pop/pop3_list.c
+++ b/libproto/pop/pop3_list.c
@@ -40,7 +40,7 @@ mu_pop3_list (mu_pop3_t pop3, unsigned int msgno, size_t 
*psize)
   switch (pop3->state)
     {
     case MU_POP3_NO_STATE:
-      status = mu_pop3_writeline (pop3, "LIST %d\r\n", msgno);
+      status = mu_pop3_writeline (pop3, "LIST %u\r\n", msgno);
       MU_POP3_CHECK_ERROR (pop3, status);
       MU_POP3_FCLR (pop3, MU_POP3_ACK);
       pop3->state = MU_POP3_LIST;
diff --git a/libproto/pop/pop3_lista.c b/libproto/pop/pop3_list_cmd.c
similarity index 86%
copy from libproto/pop/pop3_lista.c
copy to libproto/pop/pop3_list_cmd.c
index 66ee948..2917e21 100644
--- a/libproto/pop/pop3_lista.c
+++ b/libproto/pop/pop3_list_cmd.c
@@ -21,21 +21,16 @@
 # include <config.h>
 #endif
 
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <mailutils/sys/pop3.h>
 
 int
-mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator)
+mu_pop3_list_cmd (mu_pop3_t pop3)
 {
   int status = 0;
 
   if (pop3 == NULL)
     return EINVAL;
-  if (piterator == NULL)
-    return MU_ERR_OUT_PTR_NULL;
 
   switch (pop3->state)
     {
@@ -49,8 +44,6 @@ mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator)
       status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
       MU_POP3_CHECK_OK (pop3);
-      status = mu_pop3_iterator_create (pop3, piterator);
-      MU_POP3_CHECK_ERROR (pop3, status);
       pop3->state = MU_POP3_LIST_RX;
 
     case MU_POP3_LIST_RX:
diff --git a/libproto/pop/pop3_lista.c b/libproto/pop/pop3_lista.c
index 66ee948..4ce2ff1 100644
--- a/libproto/pop/pop3_lista.c
+++ b/libproto/pop/pop3_lista.c
@@ -21,51 +21,19 @@
 # include <config.h>
 #endif
 
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <mailutils/sys/pop3.h>
 
 int
 mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator)
 {
-  int status = 0;
+  int status = mu_pop3_list_cmd (pop3);
 
-  if (pop3 == NULL)
-    return EINVAL;
-  if (piterator == NULL)
-    return MU_ERR_OUT_PTR_NULL;
+  if (status)
+    return status;
 
-  switch (pop3->state)
-    {
-    case MU_POP3_NO_STATE:
-      status = mu_pop3_writeline (pop3, "LIST\r\n");
-      MU_POP3_CHECK_ERROR (pop3, status);
-      MU_POP3_FCLR (pop3, MU_POP3_ACK);
-      pop3->state = MU_POP3_LIST;
-
-    case MU_POP3_LIST:
-      status = mu_pop3_response (pop3, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      MU_POP3_CHECK_OK (pop3);
-      status = mu_pop3_iterator_create (pop3, piterator);
-      MU_POP3_CHECK_ERROR (pop3, status);
-      pop3->state = MU_POP3_LIST_RX;
-
-    case MU_POP3_LIST_RX:
-      /* The mu_iterator_t will read the stream and set the state to
-        MU_POP3_NO_STATE when done.  */
-      break;
-
-      /* They must deal with the error first by reopening.  */
-    case MU_POP3_ERROR:
-      status = ECANCELED;
-      break;
-
-    default:
-      status = EINPROGRESS;
-    }
+  status = mu_pop3_iterator_create (pop3, piterator);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_LIST_RX;
 
   return status;
 }
diff --git a/mailbox/dbgsyslog.c b/libproto/pop/pop3_listas.c
similarity index 70%
copy from mailbox/dbgsyslog.c
copy to libproto/pop/pop3_listas.c
index f906cd3..0227650 100644
--- a/mailbox/dbgsyslog.c
+++ b/libproto/pop/pop3_listas.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2010 Free Software
+   Copyright (C) 1999, 2000, 2001, 2004, 2007, 2010 Free Software
    Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
@@ -21,14 +21,19 @@
 # include <config.h>
 #endif
 
-#include <mailutils/debug.h>
-#include <syslog.h>
+#include <mailutils/sys/pop3.h>
 
 int
-mu_debug_syslog_printer (void *unused, mu_log_level_t level, const char *str)
+mu_pop3_list_all_stream (mu_pop3_t pop3, mu_stream_t *pstream)
 {
-  syslog ((level == MU_DEBUG_ERROR) ? LOG_ERR : LOG_DEBUG, "%s", str);
-  return 0;
-}
+  int status = mu_pop3_list_cmd (pop3);
+
+  if (status)
+    return status;
 
+  status = mu_pop3_stream_create (pop3, pstream);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_LIST_RX;
 
+  return status;
+}
diff --git a/libproto/pop/pop3_quit.c b/libproto/pop/pop3_rdlist.c
similarity index 53%
copy from libproto/pop/pop3_quit.c
copy to libproto/pop/pop3_rdlist.c
index 8ec8178..3544a31 100644
--- a/libproto/pop/pop3_quit.c
+++ b/libproto/pop/pop3_rdlist.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2007, 2010 Free Software Foundation,
+   Copyright (C) 2003, 2004, 2005, 2007, 2010 Free Software Foundation,
    Inc.
 
    This library is free software; you can redistribute it and/or
@@ -22,36 +22,44 @@
 #endif
 
 #include <string.h>
-#include <errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/list.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
 #include <mailutils/sys/pop3.h>
 
 int
-mu_pop3_quit (mu_pop3_t pop3)
+mu_pop3_stream_to_list (mu_pop3_t pop3, mu_stream_t stream, mu_list_t list)
 {
   int status;
-
-  if (pop3 == NULL)
-    return EINVAL;
-
-  switch (pop3->state)
+  size_t n;
+  
+  while (mu_stream_getline (stream, &pop3->rdbuf, &pop3->rdsize, &n) == 0
+        && n > 0)
     {
-    case MU_POP3_NO_STATE:
-      status = mu_pop3_writeline (pop3, "QUIT\r\n");
-      MU_POP3_CHECK_ERROR (pop3, status);
-      MU_POP3_FCLR (pop3, MU_POP3_ACK);
-      pop3->state = MU_POP3_QUIT;
-
-    case MU_POP3_QUIT:
-      status = mu_pop3_response (pop3, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      MU_POP3_CHECK_OK (pop3);
-      pop3->state = MU_POP3_NO_STATE;
-      _mu_pop3_init (pop3);
-      break;
-
-    default:
-      status = EINPROGRESS;
+      char *np = strdup (pop3->rdbuf);
+      if (!np)
+       {
+         status = ENOMEM;
+         break;
+       }
+      mu_rtrim_class (np, MU_CTYPE_SPACE);
+      status = mu_list_append (list, np);
+      if (status)
+       break;
     }
+  return status;
+}
 
+int
+mu_pop3_read_list (mu_pop3_t pop3, mu_list_t list)
+{
+  mu_stream_t stream;
+  int status = mu_pop3_stream_create (pop3, &stream);
+  if (status)
+    return status;
+  status = mu_pop3_stream_to_list (pop3, stream, list);
+  mu_stream_destroy (&stream);
   return status;
 }
+
diff --git a/libproto/pop/pop3_retr.c b/libproto/pop/pop3_retr.c
index 12a5c0a..2189075 100644
--- a/libproto/pop/pop3_retr.c
+++ b/libproto/pop/pop3_retr.c
@@ -48,12 +48,11 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, 
mu_stream_t *pstream)
       status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
       MU_POP3_CHECK_OK (pop3);
+      status = mu_pop3_stream_create (pop3, pstream);
+      MU_POP3_CHECK_ERROR (pop3, status);
       pop3->state = MU_POP3_RETR_RX;
 
     case MU_POP3_RETR_RX:
-      status = mu_pop3_stream_create (pop3, pstream);
-      MU_POP3_CHECK_ERROR (pop3, status);
-      pop3->state = MU_POP3_NO_STATE;
       break;
 
       /* They must deal with the error first by reopening.  */
diff --git a/libproto/pop/pop3_stat.c b/libproto/pop/pop3_stat.c
index 3dd5de0..707fe7d 100644
--- a/libproto/pop/pop3_stat.c
+++ b/libproto/pop/pop3_stat.c
@@ -27,10 +27,10 @@
 #include <mailutils/sys/pop3.h>
 
 int
-mu_pop3_stat (mu_pop3_t pop3, unsigned *msg_count, size_t *size)
+mu_pop3_stat (mu_pop3_t pop3, size_t *msg_count, mu_off_t *size)
 {
   int status;
-  unsigned long lv;
+  unsigned long lv, count;
   
   if (pop3 == NULL || msg_count == NULL)
     return EINVAL;
@@ -55,7 +55,8 @@ mu_pop3_stat (mu_pop3_t pop3, unsigned *msg_count, size_t 
*size)
       *msg_count = 0;
       lv = 0;
       /* FIXME: Error checking */
-      sscanf (pop3->ackbuf, "+OK %d %lu", msg_count, &lv);
+      sscanf (pop3->ackbuf, "+OK %lu %lu", &count, &lv);
+      *msg_count = count;
       *size = lv;
       break;
 
diff --git a/libproto/pop/pop3_stream.c b/libproto/pop/pop3_stream.c
index ae4024a..689bec4 100644
--- a/libproto/pop/pop3_stream.c
+++ b/libproto/pop/pop3_stream.c
@@ -39,6 +39,7 @@ struct mu_pop3_stream
 enum pop3_decode_state
   {
     pds_init,  /* initial state */
+    pds_char,  /* Any character excepting [\r\n.] */
     pds_cr,    /* prev. char was \r */
     pds_crlf,  /* 2 prev. char were \r\n */
     pds_dot,   /* 3 prev. chars were \r\n. */
@@ -56,6 +57,16 @@ newstate (int state, int c)
        {
        case '\r':
          return pds_cr;
+       case '.':
+         return pds_dot;
+       }
+      break;
+      
+    case pds_char:
+      switch (c)
+       {
+       case '\r':
+         return pds_cr;
        }
       break;
       
@@ -93,7 +104,7 @@ newstate (int state, int c)
          return pds_end;
        }
     }
-  return pds_init;
+  return pds_char;
 }
 
 /* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n
@@ -140,9 +151,10 @@ _pop3_decoder (void *xd,
          if (*iptr == '\n')
            continue;
        }
-      else if (c == '.' && *pstate == pds_crlf)
+      else if (c == '.' && (*pstate == pds_init || *pstate == pds_crlf))
        {
-         if (i + 1 == isize)
+         /* Make sure we have two more characters in the buffer */
+         if (i + 2 == isize)
            break;
          *pstate = newstate (*pstate, c);
          if (*iptr != '\r')
@@ -154,22 +166,48 @@ _pop3_decoder (void *xd,
     }
   
   if (*pstate == pds_end)
-    iobuf->eof = 1;
+    {
+      j -= 2; /* remove the trailing .\n */
+      iobuf->eof = 1;
+    }
   iobuf->isize = i;
   iobuf->osize = j;
   return mu_filter_ok;
 }
 
+static void
+_pop3_event_cb (mu_stream_t str, int ev, int flags)
+{
+  if (ev == _MU_STR_EVENT_SET)
+    {
+      mu_transport_t trans[2];
+
+      if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0)
+       {
+         struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
+         sp->pop3->state = MU_POP3_NO_STATE;
+       }
+    }
+}
+
 static int
 mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream)
 {
+  int rc;
   int *state = malloc (sizeof (*state));
   if (!state)
     return ENOMEM;
-  return mu_filter_stream_create (pstream, stream,
-                                 MU_FILTER_DECODE,
-                                 _pop3_decoder, state,
-                                 MU_STREAM_READ);
+  rc = mu_filter_stream_create (pstream, stream,
+                               MU_FILTER_DECODE,
+                               _pop3_decoder, state,
+                               MU_STREAM_READ);
+  if (rc == 0)
+    {
+      mu_stream_t str = *pstream;
+      str->event_cb = _pop3_event_cb;
+      str->event_mask = _MU_STR_EOF;
+    }
+  return rc;
 }
 
 
@@ -253,6 +291,7 @@ mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream)
   sp->stream.readdelim = _mu_pop3_readdelim; 
   sp->stream.flush = _mu_pop3_flush;
   sp->stream.wait = _mu_pop3_wait;
+  
   sp->pop3 = pop3;
   sp->done = 0;
   str = (mu_stream_t) sp;
diff --git a/libproto/pop/pop3_top.c b/libproto/pop/pop3_top.c
index 0ca0379..93957e5 100644
--- a/libproto/pop/pop3_top.c
+++ b/libproto/pop/pop3_top.c
@@ -48,12 +48,11 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int 
lines,
       status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
       MU_POP3_CHECK_OK (pop3);
+      status = mu_pop3_stream_create (pop3, pstream);
+      MU_POP3_CHECK_ERROR (pop3, status);
       pop3->state = MU_POP3_TOP_RX;
 
     case MU_POP3_TOP_RX:
-      status = mu_pop3_stream_create (pop3, pstream);
-      MU_POP3_CHECK_ERROR (pop3, status);
-      pop3->state = MU_POP3_NO_STATE;
       break;
 
       /* They must deal with the error first by reopening.  */
diff --git a/libproto/pop/pop3_uidla.c b/libproto/pop/pop3_uidl_cmd.c
similarity index 82%
copy from libproto/pop/pop3_uidla.c
copy to libproto/pop/pop3_uidl_cmd.c
index 3054b6b..23d7866 100644
--- a/libproto/pop/pop3_uidla.c
+++ b/libproto/pop/pop3_uidl_cmd.c
@@ -20,20 +20,16 @@
 # include <config.h>
 #endif
 
-#include <string.h>
-# include <errno.h>
 #include <stdlib.h>
 #include <mailutils/sys/pop3.h>
 
 int
-mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator)
+mu_pop3_uidl_all_cmd (mu_pop3_t pop3)
 {
   int status = 0;
 
   if (pop3 == NULL)
     return EINVAL;
-  if (piterator == NULL)
-    return MU_ERR_OUT_PTR_NULL;
 
   switch (pop3->state)
     {
@@ -47,13 +43,9 @@ mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator)
       status = mu_pop3_response (pop3, NULL);
       MU_POP3_CHECK_EAGAIN (pop3, status);
       MU_POP3_CHECK_OK (pop3);
-      status = mu_pop3_iterator_create (pop3, piterator);
-      MU_POP3_CHECK_ERROR (pop3, status);
       pop3->state = MU_POP3_UIDL_RX;
 
     case MU_POP3_UIDL_RX:
-      /* The mu_iterator_t will read the stream and set the state to
-        MU_POP3_NO_STATE when done.  */
       break;
 
       /* They must deal with the error first by reopening.  */
diff --git a/libproto/pop/pop3_uidla.c b/libproto/pop/pop3_uidla.c
index 3054b6b..78ff0ff 100644
--- a/libproto/pop/pop3_uidla.c
+++ b/libproto/pop/pop3_uidla.c
@@ -20,50 +20,17 @@
 # include <config.h>
 #endif
 
-#include <string.h>
-# include <errno.h>
-#include <stdlib.h>
 #include <mailutils/sys/pop3.h>
 
 int
 mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator)
 {
-  int status = 0;
-
-  if (pop3 == NULL)
-    return EINVAL;
-  if (piterator == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  switch (pop3->state)
-    {
-    case MU_POP3_NO_STATE:
-      status = mu_pop3_writeline (pop3, "UIDL\r\n");
-      MU_POP3_CHECK_ERROR (pop3, status);
-      MU_POP3_FCLR (pop3, MU_POP3_ACK);
-      pop3->state = MU_POP3_UIDL;
-
-    case MU_POP3_UIDL:
-      status = mu_pop3_response (pop3, NULL);
-      MU_POP3_CHECK_EAGAIN (pop3, status);
-      MU_POP3_CHECK_OK (pop3);
-      status = mu_pop3_iterator_create (pop3, piterator);
-      MU_POP3_CHECK_ERROR (pop3, status);
-      pop3->state = MU_POP3_UIDL_RX;
-
-    case MU_POP3_UIDL_RX:
-      /* The mu_iterator_t will read the stream and set the state to
-        MU_POP3_NO_STATE when done.  */
-      break;
-
-      /* They must deal with the error first by reopening.  */
-    case MU_POP3_ERROR:
-      status = ECANCELED;
-      break;
-
-    default:
-      status = EINPROGRESS;
-    }
+  int status = mu_pop3_uidl_all_cmd (pop3);
+  if (status)
+    return status;
+  status = mu_pop3_iterator_create (pop3, piterator);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_UIDL_RX;
 
   return status;
 }
diff --git a/mailbox/dbgsyslog.c b/libproto/pop/pop3_uidlas.c
similarity index 69%
copy from mailbox/dbgsyslog.c
copy to libproto/pop/pop3_uidlas.c
index f906cd3..82771fd 100644
--- a/mailbox/dbgsyslog.c
+++ b/libproto/pop/pop3_uidlas.c
@@ -1,6 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2010 Free Software
-   Foundation, Inc.
+   Copyright (C) 2003, 2004, 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
@@ -21,14 +20,17 @@
 # include <config.h>
 #endif
 
-#include <mailutils/debug.h>
-#include <syslog.h>
+#include <mailutils/sys/pop3.h>
 
 int
-mu_debug_syslog_printer (void *unused, mu_log_level_t level, const char *str)
+mu_pop3_uidl_all_stream (mu_pop3_t pop3, mu_stream_t *pstream)
 {
-  syslog ((level == MU_DEBUG_ERROR) ? LOG_ERR : LOG_DEBUG, "%s", str);
-  return 0;
+  int status = mu_pop3_uidl_all_cmd (pop3);
+  if (status)
+    return status;
+  status = mu_pop3_stream_create (pop3, pstream);
+  MU_POP3_CHECK_ERROR (pop3, status);
+  pop3->state = MU_POP3_UIDL_RX;
+
+  return status;
 }
-
-
diff --git a/mailbox/fltstream.c b/mailbox/fltstream.c
index 3190c2c..5e9b78d 100644
--- a/mailbox/fltstream.c
+++ b/mailbox/fltstream.c
@@ -159,21 +159,12 @@ filter_read (mu_stream_t stream, char *buf, size_t size, 
size_t *pret)
          switch (res)
            {
            case mu_filter_ok:
-             if (iobuf.isize == 0 || iobuf.osize == 0)
-               {
-                 /* FIXME: Hack to handle eventual buggy filters */
-                 if (iobuf.isize == 0)
-                   min_input_level++;
-                 if (iobuf.osize == 0)
-                   min_output_size++;
-                 continue;
-               }
              if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
                  || iobuf.osize > MFB_FREESIZE (fs->outbuf))
                return MU_ERR_FAILURE; /* FIXME: special error code? */
              if (iobuf.eof)
                {
-                 stream->flags |= _MU_STR_EOF;
+                 _mu_stream_seteof (stream);
                  stop = 1;
                }
              break;
diff --git a/mailbox/opool.c b/mailbox/opool.c
index acb29ac..991b527 100644
--- a/mailbox/opool.c
+++ b/mailbox/opool.c
@@ -205,6 +205,25 @@ mu_opool_size (mu_opool_t opool)
   return size;
 }
 
+size_t
+mu_opool_copy (mu_opool_t opool, void *buf, size_t size)
+{
+  char *cp = buf;
+  size_t total = 0;
+  struct mu_opool_bucket *p;
+  
+  for (p = opool->head; p && total < size; p = p->next)
+    {
+      size_t cpsize = size - total;
+      if (cpsize > p->level)
+       cpsize = p->level;
+      memcpy (cp, p->buf, cpsize);
+      cp += cpsize;
+      total += cpsize;
+    }
+  return total;
+}
+
 int
 mu_opool_coalesce (mu_opool_t opool, size_t *psize)
 {
diff --git a/mailbox/stream.c b/mailbox/stream.c
index 70186f1..55af4ab 100644
--- a/mailbox/stream.c
+++ b/mailbox/stream.c
@@ -32,6 +32,22 @@
 #include <mailutils/stream.h>
 #include <mailutils/sys/stream.h>
 
+static void
+_stream_setflag (struct _mu_stream *stream, int flag)
+{
+  if (stream->event_cb && (stream->event_mask & flag))
+    stream->event_cb (stream, _MU_STR_EVENT_SET, flag);
+  stream->flags |= flag;
+}
+
+static void
+_stream_clrflag (struct _mu_stream *stream, int flag)
+{
+  if (stream->event_cb && (stream->event_mask & flag))
+    stream->event_cb (stream, _MU_STR_EVENT_CLR, flag);
+  stream->flags &= ~flag;
+}
+
 int
 mu_stream_seterr (struct _mu_stream *stream, int code, int perm)
 {
@@ -45,12 +61,23 @@ mu_stream_seterr (struct _mu_stream *stream, int code, int 
perm)
 
     default:
       if (perm)
-       stream->flags |= _MU_STR_ERR;
+       _stream_setflag (stream, _MU_STR_ERR);
     }
   return code;
 }
 
-#define _stream_cleareof(s) ((s)->flags &= ~_MU_STR_EOF)
+void
+_mu_stream_cleareof (mu_stream_t str)
+{
+  _stream_clrflag (str, _MU_STR_EOF);
+}
+
+void
+_mu_stream_seteof (mu_stream_t str)
+{
+  _stream_setflag (str, _MU_STR_EOF);
+}
+
 #define _stream_advance_buffer(s,n) ((s)->cur += n, (s)->level -= n)
 #define _stream_buffer_offset(s) ((s)->cur - (s)->buffer)
 #define _stream_orig_level(s) ((s)->level + _stream_buffer_offset (s))
@@ -82,9 +109,13 @@ _stream_fill_buffer (struct _mu_stream *stream)
       for (n = 0;
           n < stream->bufsize
             && (rc = mu_stream_read_unbuffered (stream,
-                                                &c, 1, 0, &rdn)) == 0
-            && rdn; )
+                                                &c, 1, 0, &rdn)) == 0;)
        {
+         if (rdn == 0)
+           {
+             _stream_setflag (stream, _MU_STR_EOF);
+             break;
+           }
          stream->buffer[n++] = c;
          if (c == '\n')
            break;
@@ -175,7 +206,7 @@ _stream_flush_buffer (struct _mu_stream *stream, int all)
     }
   else
     {
-      stream->flags &= ~_MU_STR_DIRTY;
+      _stream_clrflag (stream, _MU_STR_DIRTY);
       stream->level = 0;
     }
   stream->cur = stream->buffer;
@@ -269,7 +300,7 @@ void
 mu_stream_clearerr (mu_stream_t stream)
 {
   stream->last_err = 0;
-  stream->flags &= ~_MU_STR_ERR;
+  _stream_clrflag (stream, _MU_STR_ERR);
 }
 
 int
@@ -327,7 +358,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int 
whence,
        return rc;
       if (rc)
        return mu_stream_seterr (stream, rc, 1);
-      _stream_cleareof (stream);
+      _mu_stream_cleareof (stream);
     }
   
   if (pres)
@@ -469,7 +500,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, 
size_t size,
          {
            if (rdbytes == 0)
              {
-               stream->flags |= _MU_STR_EOF;
+               _stream_setflag (stream, _MU_STR_EOF);
                break;
              }
            buf += rdbytes;
@@ -487,7 +518,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, 
size_t size,
        if (rc == 0)
          {
            if (nread == 0)
-             stream->flags |= _MU_STR_EOF;
+             _stream_setflag (stream, _MU_STR_EOF);
            stream->bytes_in += nread;
          }
        mu_stream_seterr (stream, rc, rc != 0);
@@ -551,7 +582,7 @@ mu_stream_write_unbuffered (mu_stream_t stream,
       if (rc == 0)
        stream->bytes_out += nwritten;
     }
-  stream->flags |= _MU_STR_WRT;
+  _stream_setflag (stream, _MU_STR_WRT);
   stream->offset += nwritten;
   if (pnwritten)
     *pnwritten = nwritten;
@@ -806,7 +837,7 @@ mu_stream_write (mu_stream_t stream, const void *buf, 
size_t size,
          nbytes += n;
          bufp += n;
          size -= n;
-         stream->flags |= _MU_STR_DIRTY;
+         _stream_setflag (stream, _MU_STR_DIRTY);
        }
       if (pnwritten)
        *pnwritten = nbytes;
@@ -835,7 +866,7 @@ mu_stream_flush (mu_stream_t stream)
     return rc;
   if ((stream->flags & _MU_STR_WRT) && stream->flush)
     return stream->flush (stream);
-  stream->flags &= ~_MU_STR_WRT;
+  _stream_clrflag (stream, _MU_STR_WRT);
   return 0;
 }
 
diff --git a/mailbox/xscript-stream.c b/mailbox/xscript-stream.c
index 51e2016..9930475 100644
--- a/mailbox/xscript-stream.c
+++ b/mailbox/xscript-stream.c
@@ -201,7 +201,10 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
     case MU_IOCTL_SWAP_STREAM:
       if (!arg)
        return EINVAL;
-      status = mu_stream_ioctl (sp->transport, op, arg);
+      if (!sp->transport)
+       status = ENOSYS;
+      else
+       status = mu_stream_ioctl (sp->transport, op, arg);
       if (status == EINVAL || status == ENOSYS)
        {
          mu_stream_t *pstr = arg;


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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