commit-mailutils
[Top][All Lists]
Advanced

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

[SCM] GNU Mailutils branch, master, updated. release-2.2-179-g439f8c1


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-179-g439f8c1
Date: Tue, 09 Nov 2010 14:13:40 +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=439f8c1a9f99409087694f95c82f40c12e286371

The branch, master has been updated
       via  439f8c1a9f99409087694f95c82f40c12e286371 (commit)
       via  96cfdb5e8ef877b1f8773e426061ef4d3442997e (commit)
       via  78e57f7ec9df1547dd5e176a97fa1f8954b51c09 (commit)
       via  78d43b05bf6dfd37b5f251715211f48f3f22fb58 (commit)
      from  966a860c0eef32bfe8cab5c5c05c54a8e115270b (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 439f8c1a9f99409087694f95c82f40c12e286371
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Nov 9 16:00:31 2010 +0200

    imap client: implement login and id commands.
    
    * libproto/imap/id.c: New file.
    * libproto/imap/login.c: New file.
    * libproto/imap/Makefile.am: Add new files.
    * libproto/imap/capability.c (mu_imap_capability): Clear
    MU_IMAP_RESP before reading response.
    Add MU_WRDSF_QUOTE to mu_wordsplit flags.
    * libproto/imap/err.c (_mu_imap_seterrstr): Bugfix: initialize
    imap->errstr.
    * libproto/imap/logout.c (mu_imap_logout): Clear
    MU_IMAP_RESP before reading response.
    * libproto/imap/response.c (_mu_imap_response): Set error string.
    * mu/imap.c (com_login, com_id): New functions.
    (imap_comtab) <login, id>: New keywords.

commit 96cfdb5e8ef877b1f8773e426061ef4d3442997e
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Nov 9 12:41:22 2010 +0200

    Make sure stream->offset points to the position in stream corresponding to 
the start of the buffer.
    
    * libmailutils/stream/stream.c (_stream_fill_buffer): Keep
    track of the current offset.
    (mu_stream_seek): avoid unnecessary seeks.
    (_stream_skip_input_bytes): Call _stream_flush_buffer before
    _stream_fill_buffer.
    (_stream_write_unbuffered): Do not modify current offset.
    (mu_stream_read,mu_stream_write): For unbuffered streams,
    modify current offset after invoking the corresponding I/O
    call.
    (_stream_scandelim): Call _stream_flush_buffer before
    _stream_fill_buffer.

commit 78e57f7ec9df1547dd5e176a97fa1f8954b51c09
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Nov 9 11:14:53 2010 +0200

    Fix the "UNIX mailbox first message symptom".
    
    UFMS, or "UNIX mailbox first message symptom", is a long-standing
    bug that existed in all previous versions of Mailutils:  under
    certain circumstances, a fragment of the message headers would get
    prepended to the body of the very first message in a UNIX mailbox.
    See the detailed description in testsuite/ufms.c.
    
    Along with fixing this bug, this change also ensures a proper restoring
    of UIDs from UNIX mailboxes.
    
    * libproto/mbox/mbox.c (_msg_body_setup): Call mu_body_clear_modified
    after constructing the body.
    (new_message): Ditto for mu_message_clear_modified.
    (mbox_reset): Rewrite.  Drop all cached messages and rescan entire
    mailbox to avoid the "1st message symptom".
    (mbox_expunge0): Change the call to mbox_reset.
    * libproto/mbox/mboxscan.c (IS_X_UID, IS_X_IMAPBASE): New macros.
    (mbox_scan_internal): Change handling of min_uid.
    Attempt to get UID and imapbase from the corresponding message headers.
    (mbox_scan0): Reflect the above changes.
    
    * testsuite/.gitignore: Add ufms.
    * testsuite/Makefile.am (noinst_PROGRAMS): Add ufms.
    (TESTSUITE_AT): Add ufms.at.
    * testsuite/testsuite.at: Include ufms.at.
    * testsuite/ufms.at: New test case.
    * testsuite/ufms.c: New test program.
    
    * imap4d/testsuite/imap4d/expunge.exp: Fix UIDNEXT expectation.

commit 78d43b05bf6dfd37b5f251715211f48f3f22fb58
Author: Sergey Poznyakoff <address@hidden>
Date:   Mon Nov 8 21:23:09 2010 +0200

    Begin imap client implementation.
    
    * include/mailutils/imap.h: New file.
    * include/mailutils/Makefile.am (pkginclude_HEADERS): Add imap.h
    
    * libproto/imap/capability.c: New file.
    * libproto/imap/capatst.c: New file.
    * libproto/imap/carrier.c: New file.
    * libproto/imap/connect.c: New file.
    * libproto/imap/create.c: New file.
    * libproto/imap/destroy.c: New file.
    * libproto/imap/disconnect.c: New file.
    * libproto/imap/err.c: New file.
    * libproto/imap/fake-folder.c: New file.
    * libproto/imap/logout.c: New file.
    * libproto/imap/response.c: New file.
    * libproto/imap/state.c: New file.
    * libproto/imap/tag.c: New file.
    * libproto/imap/trace.c: New file.
    * libproto/imap/Makefile.am (libmu_imap_la_SOURCES): Temporarly
    remove folder.c, mbox.c and url.c. Add new files.
    
    * mu/getarg.c: New file.
    * mu/imap.c: New file.
    * mu/verbose.c: New file.
    * mu/Makefile.am (IDLE_MODULES): New variable.
    (IMAP_C): New variable.
    (MODULES): Add $(IMAP_C).
    (mu_SOURCES): Add getarg.c and verbose.c
    (mu-setup.h, mu-setup.c): Add IDLE_MODULES both to the dependencies
    and to the mu-setup.awk command line.
    * mu/mu-setup.awk: New keyword mu-cond.
    * mu/pop.c: Add mu-cond keyword.
    
    * include/mailutils/sys/imap.h: Rewrite.
    * include/mailutils/sys/pop3.h (MU_POP3_CHECK_EAGAIN): Take into
    account MU_ERR_REPLY and MU_ERR_BADREPLY, which are recoverable errors.
    
    * libmailutils/base/list.c (mu_list_clear): Return immediately if
    list is NULL.
    * libmu_auth/sql.c (sql_escape_string): Remove unused variable.
    
    * libproto/pop/pop3_carrier.c (mu_pop3_get_carrier): Increase refcount
    on the returned stream.
    * libproto/pop/pop3_response.c (mu_pop3_response): Check POP3 reply code.

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

Summary of changes:
 imap4d/testsuite/imap4d/expunge.exp                |    2 +-
 include/mailutils/Makefile.am                      |    1 +
 include/mailutils/imap.h                           |   80 +++
 include/mailutils/sys/imap.h                       |  284 ++++-------
 include/mailutils/sys/pop3.h                       |   35 +-
 libmailutils/base/list.c                           |    4 +-
 libmailutils/stream/stream.c                       |  161 ++++---
 libmailutils/tests/wsp.c                           |    3 +-
 libmu_auth/sql.c                                   |    1 -
 libproto/imap/Makefile.am                          |   26 +-
 libproto/imap/capability.c                         |  147 ++++++
 libproto/{pop/pop3_capatst.c => imap/capatst.c}    |   13 +-
 libproto/{pop/pop3_carrier.c => imap/carrier.c}    |   32 +-
 libproto/imap/connect.c                            |  119 +++++
 libproto/{pop/pop3_create.c => imap/create.c}      |   45 +-
 libproto/{pop/pop3_destroy.c => imap/destroy.c}    |   41 +-
 .../{nntp/nntp_timeout.c => imap/disconnect.c}     |   31 +-
 .../mailbox/hdrfirst.c => libproto/imap/err.c      |   49 ++-
 libproto/imap/fake-folder.c                        |    7 +
 libproto/imap/id.c                                 |  180 +++++++
 libproto/imap/login.c                              |   80 +++
 libproto/{nntp/nntp_quit.c => imap/logout.c}       |   54 +-
 libproto/imap/response.c                           |  125 +++++
 libproto/{nntp/nntp_timeout.c => imap/state.c}     |   34 +-
 libproto/imap/tag.c                                |  103 ++++
 libproto/{pop/pop3_trace.c => imap/trace.c}        |   66 ++--
 libproto/mbox/mbox.c                               |   34 +-
 libproto/mbox/mboxscan.c                           |   55 ++-
 libproto/pop/Makefile.am                           |    2 +-
 libproto/pop/pop3_carrier.c                        |    1 +
 libproto/pop/pop3_response.c                       |    7 +
 mu/Makefile.am                                     |   22 +-
 mu/{cflags.c => getarg.c}                          |   68 ++-
 mu/imap.c                                          |  519 ++++++++++++++++++++
 mu/mu-setup.awk                                    |    4 +
 mu/mu.h                                            |   18 +
 mu/pop.c                                           |  182 +------
 mu/verbose.c                                       |  114 +++++
 testsuite/.gitignore                               |    1 +
 testsuite/Makefile.am                              |    4 +-
 testsuite/testsuite.at                             |    1 +
 readmsg/tests/twomsg.at => testsuite/ufms.at       |   37 +-
 testsuite/ufms.c                                   |  100 ++++
 43 files changed, 2203 insertions(+), 689 deletions(-)
 create mode 100644 include/mailutils/imap.h
 create mode 100644 libproto/imap/capability.c
 copy libproto/{pop/pop3_capatst.c => imap/capatst.c} (73%)
 copy libproto/{pop/pop3_carrier.c => imap/carrier.c} (65%)
 create mode 100644 libproto/imap/connect.c
 copy libproto/{pop/pop3_create.c => imap/create.c} (60%)
 copy libproto/{pop/pop3_destroy.c => imap/destroy.c} (62%)
 copy libproto/{nntp/nntp_timeout.c => imap/disconnect.c} (65%)
 copy libmailutils/mailbox/hdrfirst.c => libproto/imap/err.c (60%)
 create mode 100644 libproto/imap/fake-folder.c
 create mode 100644 libproto/imap/id.c
 create mode 100644 libproto/imap/login.c
 copy libproto/{nntp/nntp_quit.c => imap/logout.c} (51%)
 create mode 100644 libproto/imap/response.c
 copy libproto/{nntp/nntp_timeout.c => imap/state.c} (60%)
 create mode 100644 libproto/imap/tag.c
 copy libproto/{pop/pop3_trace.c => imap/trace.c} (61%)
 copy mu/{cflags.c => getarg.c} (50%)
 create mode 100644 mu/imap.c
 create mode 100644 mu/verbose.c
 copy readmsg/tests/twomsg.at => testsuite/ufms.at (69%)
 create mode 100644 testsuite/ufms.c

diff --git a/imap4d/testsuite/imap4d/expunge.exp 
b/imap4d/testsuite/imap4d/expunge.exp
index cc114c2..e410168 100644
--- a/imap4d/testsuite/imap4d/expunge.exp
+++ b/imap4d/testsuite/imap4d/expunge.exp
@@ -63,7 +63,7 @@ imap4d_test "SELECT mbox1" \
 "1 EXISTS"\
 "0 RECENT"\
 -re {OK \[UIDVALIDITY [0-9]+\] UID valididy status}\
-"OK \[UIDNEXT 2\] Predicted next uid"\
+"OK \[UIDNEXT 6\] Predicted next uid"\
 "OK \[UNSEEN 1\] first unseen messsage"\
 "FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)"\
 "OK \[PERMANENTFLAGS (\\Answered \\Deleted \\Seen)\] Permanent flags" \
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index 787d04e..cd17f85 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -52,6 +52,7 @@ pkginclude_HEADERS = \
  gsasl.h\
  guile.h\
  header.h\
+ imap.h\
  io.h\
  iterator.h\
  kwd.h\
diff --git a/include/mailutils/imap.h b/include/mailutils/imap.h
new file mode 100644
index 0000000..6d8e14a
--- /dev/null
+++ b/include/mailutils/imap.h
@@ -0,0 +1,80 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifndef _MAILUTILS_IMAP_H
+#define _MAILUTILS_IMAP_H
+
+#include <mailutils/iterator.h>
+#include <mailutils/debug.h>
+#include <mailutils/stream.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MU_IMAP_DEFAULT_PORT 143
+#define MU_IMAP_DEFAULT_SSL_PORT 993
+  
+typedef struct _mu_imap *mu_imap_t;
+
+enum mu_imap_state
+  {
+    MU_IMAP_STATE_INIT,     /* Initial state */
+    MU_IMAP_STATE_NONAUTH,  /* Non-Authenticated State */
+    MU_IMAP_STATE_AUTH,     /* Authenticated State */
+    MU_IMAP_STATE_SELECTED, /* Selected State */
+    MU_IMAP_STATE_LOGOUT    /* Logout State */
+  };
+  
+int mu_imap_create (mu_imap_t *pimap);
+void mu_imap_destroy (mu_imap_t *pimap);
+
+int mu_imap_connect (mu_imap_t imap);
+int mu_imap_disconnect (mu_imap_t imap);
+
+int mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter);
+int mu_imap_capability_test (mu_imap_t imap, const char *name,
+                            const char **pret);
+
+int mu_imap_login (mu_imap_t imap, const char *user, const char *pass);
+int mu_imap_logout (mu_imap_t imap);
+
+int mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist);
+  
+int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier);
+int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier);
+
+#define MU_IMAP_TRACE_CLR 0
+#define MU_IMAP_TRACE_SET 1
+#define MU_IMAP_TRACE_QRY 2
+int mu_imap_trace (mu_imap_t imap, int op);
+int mu_imap_trace_mask (mu_imap_t imap, int op, int lev);
+
+int mu_imap_strerror (mu_imap_t imap, const char **pstr);
+
+int mu_imap_state (mu_imap_t imap, int *pstate);
+int mu_imap_state_str (int state, const char **pstr);
+
+int mu_imap_tag (mu_imap_t imap, const char **pseq);
+  
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_IMAP_H */
+  
+  
diff --git a/include/mailutils/sys/imap.h b/include/mailutils/sys/imap.h
index 6bb154d..d23f597 100644
--- a/include/mailutils/sys/imap.h
+++ b/include/mailutils/sys/imap.h
@@ -1,6 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2005, 2007, 2009, 2010 Free Software
-   Foundation, Inc.
+   Copyright (C) 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
@@ -13,7 +12,7 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifndef _MAILUTILS_SYS_IMAP_H
@@ -23,211 +22,122 @@
 # include <mailutils/sys/mailbox.h>
 # include <mailutils/sys/registrar.h>
 # include <mailutils/sys/auth.h>
+# include <mailutils/imap.h>
 
 # ifdef __cplusplus
 extern "C" {
 # endif
 
-# define CLEAR_STATE(f_imap)                           \
- f_imap->selected = NULL, f_imap->state = IMAP_NO_STATE
-
-/* Clear the state and close the stream.  */
-# define CHECK_ERROR_CLOSE(folder, f_imap, status)     \
-  do                                                   \
-    {                                                  \
-      if (status != 0)                                 \
-       {                                               \
-          mu_stream_close (folder->stream);            \
-          CLEAR_STATE (f_imap);                                \
-          return status;                               \
-       }                                               \
-    }                                                  \
-  while (0)
+#define MU_IMAP_RESP  0x01
+#define MU_IMAP_TRACE 0x02  
+#define MU_IMAP_XSCRIPT_MASK(n) (1<<((n)+1))
+
+enum mu_imap_client_state
+  {
+    MU_IMAP_NO_STATE,
+    MU_IMAP_ERROR,
+    MU_IMAP_CONNECT,
+    MU_IMAP_GREETINGS,
+    MU_IMAP_CONNECTED,
+    MU_IMAP_CAPABILITY_RX,
+    MU_IMAP_LOGIN_RX,
+    MU_IMAP_LOGOUT_RX,
+    MU_IMAP_ID_RX,
+  };
+
+enum mu_imap_response
+  {
+    MU_IMAP_OK,
+    MU_IMAP_NO,
+    MU_IMAP_BAD
+  };
+  
+struct _mu_imap
+  {
+    int flags;
+
+    /* Holds the tagged response to the last command */
+    char *tagbuf;
+    size_t tagsize;
+    enum mu_imap_response resp_code;
+    
+    /* Untagged responses */
+    mu_list_t untagged_resp;
+
+    /* Error string (if any) */
+    char *errstr;
+    size_t errsize;
+    
+    /* Input line buffer */
+    char *rdbuf;
+    size_t rdsize;
+
+    enum mu_imap_state state;
+    enum mu_imap_state imap_state;
+
+    /* Tag */
+    size_t tag_len;  /* Length of the command tag */
+    int *tag_buf;    /* Tag number (BCD) */
+    char *tag_str;   /* String representation (tag_len + 1 bytes, asciiz) */
+    
+    mu_list_t capa;
+    mu_stream_t carrier;
+};
+
+#define MU_IMAP_FSET(p,f) ((p)->flags |= (f))
+#define MU_IMAP_FISSET(p,f) ((p)->flags & (f))  
+#define MU_IMAP_FCLR(p,f) ((p)->flags &= ~(f))
 
-/* Clear the state.  */
-# define CHECK_ERROR(f_imap, status)           \
+int _mu_imap_init (mu_imap_t imap);
+int _mu_imap_trace_enable (mu_imap_t imap);
+int _mu_imap_trace_disable (mu_imap_t imap);
+int _mu_imap_xscript_level (mu_imap_t imap, int xlev);
+
+/* If status indicates an error, return.
+  */
+#define MU_IMAP_CHECK_ERROR(imap, status)      \
   do                                           \
     {                                          \
       if (status != 0)                         \
        {                                       \
-          CLEAR_STATE (f_imap);                        \
+          imap->state = MU_IMAP_ERROR;         \
           return status;                       \
        }                                       \
     }                                          \
-while (0)
+  while (0)
 
-/* Clear the state for non recoverable error.  */
-# define CHECK_EAGAIN(f_imap, status)          \
+/* Check if status indicates an error.
+   If the error is recoverable just return the status.
+   Otherwise, set the error state and return the status
+ */
+#define MU_IMAP_CHECK_EAGAIN(imap, status)     \
   do                                           \
     {                                          \
-      if (status != 0)                         \
-       {                                                               \
-         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
-           {                                                           \
-             CLEAR_STATE (f_imap);                                     \
-           }                                                           \
-         return status;                                                \
-       }                                                               \
-    }                                                                  \
+      switch (status)                          \
+       {                                       \
+        case 0:                                 \
+         break;                                \
+        case EAGAIN:                            \
+        case EINPROGRESS:                       \
+        case EINTR:                             \
+        case MU_ERR_REPLY:                      \
+        case MU_ERR_BADREPLY:                   \
+         return status;                        \
+        default:                                \
+          imap->state = MU_IMAP_ERROR;         \
+         return status;                        \
+       }                                       \
+    }                                          \
   while (0)
 
-struct _f_imap;
-struct _m_imap;
-struct _msg_imap;
-typedef struct _f_imap *f_imap_t;
-typedef struct _m_imap *m_imap_t;
-typedef struct _msg_imap *msg_imap_t;
-
-enum imap_state
-{
-  IMAP_NO_STATE=0,
-  IMAP_AUTH, IMAP_AUTH_DONE,
-  IMAP_APPEND, IMAP_APPEND_CONT, IMAP_APPEND_SEND, IMAP_APPEND_ACK,
-  IMAP_BODY,
-  IMAP_CLOSE, IMAP_CLOSE_ACK,
-  IMAP_COPY, IMAP_COPY_ACK,
-  IMAP_CREATE, IMAP_CREATE_ACK,
-  IMAP_DELETE, IMAP_DELETE_ACK,
-  IMAP_EXPUNGE, IMAP_EXPUNGE_ACK,
-  IMAP_FETCH, IMAP_FETCH_ACK,
-  IMAP_GREETINGS,
-  IMAP_HEADER,
-  IMAP_HEADER_FIELD,
-  IMAP_LIST, IMAP_LIST_PARSE, IMAP_LIST_ACK,
-  IMAP_LOGIN, IMAP_LOGIN_ACK,
-  IMAP_LOGOUT, IMAP_LOGOUT_ACK,
-  IMAP_LSUB, IMAP_LSUB_ACK,
-  IMAP_MESSAGE,
-  IMAP_NOOP, IMAP_NOOP_ACK,
-  IMAP_OPEN_CONNECTION,
-  IMAP_RENAME, IMAP_RENAME_ACK,
-  IMAP_SCAN, IMAP_SCAN_ACK,
-  IMAP_SELECT, IMAP_SELECT_ACK,
-  IMAP_STORE, IMAP_STORE_ACK,
-  IMAP_SUBSCRIBE, IMAP_SUBSCRIBE_ACK,
-  IMAP_UNSUBSCRIBE, IMAP_UNSUBSCRIBE_ACK
-};
+int _mu_imap_seterrstr (mu_imap_t imap, const char *str, size_t len);
+void _mu_imap_clrerrstr (mu_imap_t imap);
 
-enum imap_auth_state
-{
-  /* ANONYMOUS */
-  IMAP_AUTH_ANON_REQ_WRITE,
-  IMAP_AUTH_ANON_REQ_SEND,
-  IMAP_AUTH_ANON_WAIT_CONT,
-  IMAP_AUTH_ANON_MSG,
-  IMAP_AUTH_ANON_MSG_SEND,
-  IMAP_AUTH_ANON_WAIT_RESP
-};
-
-struct literal_string
-{
-  char *buffer;
-  size_t buflen;
-  size_t total;
-  msg_imap_t msg_imap;
-  enum imap_state type;
-  size_t nleft;  /* nleft to read in the literal. */
-};
-
-struct _f_imap
-{
-  /* Back pointer.  */
-  mu_folder_t folder;
-  m_imap_t selected;
+int _mu_imap_tag_next (mu_imap_t imap);
+int _mu_imap_tag_clr (mu_imap_t imap);
 
-  enum imap_state state;
-  int imaps; /* IMAPS or IMAP? */
-
-  size_t seq; /* Sequence number to build a tag.  */
-  char **capav; /* Cabilities of the server.  */
-  int capac;    /* Number of capabilities in the above array */
-  int flags;
-
-  /* IO use to hold the literal and quoted strings send by
-     the IMAP server.  */
-  struct
-  {
-    mu_stream_t stream;
-    mu_off_t offset;
-    size_t nleft;  /* nleft to read in the literal. */
-    msg_imap_t msg_imap;
-    enum imap_state type;
-  } string;
-
-  /* Use for LIST and LSUB.  */
-  mu_list_t flist;
-  mu_folder_enumerate_fp enum_fun;
-  void *enum_data;
-  int enum_stop;
+int _mu_imap_response (mu_imap_t imap);
   
-  int isopen;
-
-  /* Server channel buffer I/O  */
-  size_t buflen;
-  char *buffer;
-  char *ptr;
-  char *nl;
-  mu_off_t offset; /* Dummy, this is used because of the stream buffering.
-                   The mu_stream_t maintains and offset and the offset we
-                  use must be in sync.  */
-
-  /* Login  */
-  char *user;
-  mu_secret_t secret;
-
-  /* AUTHENTICATE states */
-  enum imap_auth_state auth_state;
-};
-
-struct _m_imap
-{
-  /* Back pointers.  */
-  mu_mailbox_t mailbox;
-  f_imap_t f_imap;
-  size_t messages_count;
-  size_t imessages_count;
-  msg_imap_t *imessages;
-  size_t recent;
-  size_t unseen;
-  unsigned long uidvalidity;
-  size_t uidnext;
-  char *name;
-  enum imap_state state;
-    /* mailbox operations can be sequences of folder operations, and
-       thus need to keep meta-state, mailbox_imap_open(), for example. */
-};
-
-struct _msg_imap
-{
-  /* Back pointers.  */
-  mu_message_t message;
-  m_imap_t m_imap;
-  size_t num;
-  size_t part;
-  size_t num_parts;
-  msg_imap_t *parts;
-  msg_imap_t parent;
-  int flags;
-  size_t uid;
-
-  mu_header_t fheader;
-  char *internal_date;
-
-  size_t mu_message_size;
-  size_t mu_message_lines;
-  size_t body_size;
-  size_t body_lines;
-  size_t header_size;
-  size_t header_lines;
-};
-
-int imap_writeline    (f_imap_t,  const char *format, ...) MU_PRINTFLIKE(2,3);
-int imap_write        (f_imap_t);
-int imap_send         (f_imap_t);
-int imap_parse        (f_imap_t);
-int imap_readline     (f_imap_t);
-char *section_name    (msg_imap_t);
-
 # ifdef __cplusplus
 }
 # endif
diff --git a/include/mailutils/sys/pop3.h b/include/mailutils/sys/pop3.h
index 96d8d61..eba6f57 100644
--- a/include/mailutils/sys/pop3.h
+++ b/include/mailutils/sys/pop3.h
@@ -93,28 +93,31 @@ int _mu_pop3_trace_disable (mu_pop3_t pop3);
 
 int _mu_pop3_init (mu_pop3_t pop3);
   
-/* Check for non recoverable error.
-   The error is consider not recoverable if not part of the signal set:
-   EAGAIN, EINPROGRESS, EINTR.
-   For unrecoverable error we reset, by moving the working ptr
-   to the begining of the buffer and setting the state to error.
+/* Check if status indicates an error.
+   If the error is recoverable just return the status.
+   Otherwise, set the error state and return the status
  */
 #define MU_POP3_CHECK_EAGAIN(pop3, status)     \
   do                                           \
     {                                          \
-      if (status != 0)                         \
-       {                                                               \
-         if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
-           {                                                           \
-             pop3->state = MU_POP3_ERROR;                              \
-           }                                                           \
-         return status;                                                \
-       }                                                               \
-    }                                                                  \
+      switch (status)                          \
+       {                                       \
+        case 0:                                 \
+         break;                                \
+        case EAGAIN:                            \
+        case EINPROGRESS:                       \
+        case EINTR:                             \
+        case MU_ERR_REPLY:                      \
+        case MU_ERR_BADREPLY:                   \
+         return status;                        \
+        default:                                \
+          pop3->state = MU_POP3_ERROR;         \
+         return status;                        \
+       }                                       \
+    }                                          \
   while (0)
 
-/* If error return.
-   Check status an reset(see MU_POP2_CHECK_EAGAIN) the buffer.
+/* If status indicates an error, return.
   */
 #define MU_POP3_CHECK_ERROR(pop3, status)      \
   do                                           \
diff --git a/libmailutils/base/list.c b/libmailutils/base/list.c
index 9147ef8..89240ce 100644
--- a/libmailutils/base/list.c
+++ b/libmailutils/base/list.c
@@ -64,7 +64,9 @@ mu_list_clear (mu_list_t list)
 {
   struct list_data *current;
   struct list_data *previous;
-  
+
+  if (!list)
+    return;
   mu_monitor_wrlock (list->monitor);
   for (current = list->head.next; current != &list->head;)
     {
diff --git a/libmailutils/stream/stream.c b/libmailutils/stream/stream.c
index 6084479..367db90 100644
--- a/libmailutils/stream/stream.c
+++ b/libmailutils/stream/stream.c
@@ -110,7 +110,6 @@ _stream_fill_buffer (struct _mu_stream *stream)
   int rc = 0;
   char c;
 
-  stream->offset += stream->level;
   switch (stream->buftype)
     {
     case mu_buffer_none:
@@ -127,7 +126,8 @@ _stream_fill_buffer (struct _mu_stream *stream)
       for (n = 0;
           n < stream->bufsize
             && (rc = _stream_read_unbuffered (stream,
-                                              &c, 1, 0, &rdn)) == 0;)
+                                              &c, 1,
+                                              0, &rdn)) == 0;)
        {
          if (rdn == 0)
            {
@@ -143,7 +143,6 @@ _stream_fill_buffer (struct _mu_stream *stream)
     }
   if (rc == 0)
     {
-      stream->offset -= stream->level;
       stream->pos = 0;
       _stream_event (stream, _MU_STR_EVENT_FILLBUF,
                     stream->level, _stream_curp (stream));
@@ -193,7 +192,8 @@ _stream_flush_buffer (struct _mu_stream *stream, int flags)
            
        case mu_buffer_full:
          if ((rc = _stream_write_unbuffered (stream, stream->buffer,
-                                             stream->level, 1, NULL)))
+                                             stream->level,
+                                             1, NULL)))
            return rc;
          _stream_event (stream, _MU_STR_EVENT_FLUSHBUF,
                         stream->level, stream->buffer);
@@ -208,7 +208,8 @@ _stream_flush_buffer (struct _mu_stream *stream, int flags)
               end = memchr (start, '\n', wrsize))
            {
              size_t size = end - start + 1;
-             rc = _stream_write_unbuffered (stream, start, size, 1, NULL);
+             rc = _stream_write_unbuffered (stream, start, size,
+                                            1, NULL);
              if (rc)
                return rc;
              _stream_event (stream, _MU_STR_EVENT_FLUSHBUF,
@@ -231,18 +232,26 @@ _stream_flush_buffer (struct _mu_stream *stream, int 
flags)
                             wrsize, stream->buffer);
              wrsize = 0;
            }
-         if (wrsize)
-           memmove (stream->buffer, start, wrsize);
-         else
-           _stream_clrflag (stream, _MU_STR_DIRTY);
-         stream->level = stream->pos = wrsize;
-         return 0;
+         if (!(flags & _MU_STR_FLUSH_KEEP))
+           {
+             if (wrsize)
+               memmove (stream->buffer, start, wrsize);
+             else
+               _stream_clrflag (stream, _MU_STR_DIRTY);
+             stream->offset += stream->level - wrsize;
+             stream->level = stream->pos = wrsize;
+             return 0;
+           }
        }
       _stream_clrflag (stream, _MU_STR_DIRTY);
     }
 
   if (!(flags & _MU_STR_FLUSH_KEEP))
-    stream->pos = stream->level = 0;
+    {
+      stream->offset += stream->level;
+      stream->pos = stream->level = 0;
+    }
+  
   return 0;
 }
 
@@ -413,19 +422,21 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int 
whence,
       return mu_stream_seterr (stream, EINVAL, 1);
     }
 
-  if (stream->buftype == mu_buffer_none ?
-      (offset != stream->offset)
-       : (stream->level == 0
-         || offset < stream->offset
-         || offset > stream->offset + stream->level))
+  if (!(stream->buftype == mu_buffer_none ?
+       (offset == stream->offset)
+       : (stream->offset <= offset &&
+          offset < stream->offset + stream->level)))
     {
       if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
        return rc;
-      rc = stream->seek (stream, offset, &stream->offset);
-      if (rc == ESPIPE)
-       return rc;
-      if (rc)
-       return mu_stream_seterr (stream, rc, 1);
+      if (stream->offset != offset)
+       {
+         rc = stream->seek (stream, offset, &stream->offset);
+         if (rc == ESPIPE)
+           return rc;
+         if (rc)
+           return mu_stream_seterr (stream, rc, 1);
+       }
       _mu_stream_cleareof (stream);
     }
   else if (stream->buftype != mu_buffer_none)
@@ -476,10 +487,10 @@ _stream_skip_input_bytes (mu_stream_t stream, mu_off_t 
count, mu_off_t *pres)
        {
          for (pos = 0;;)
            {
-             if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
-               return rc;
              if (stream->pos == stream->level)
                {
+                 if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
+                   return rc;
                  rc = _stream_fill_buffer (stream);
                  if (rc)
                    break;
@@ -585,44 +596,42 @@ _stream_read_unbuffered (mu_stream_t stream, void *buf, 
size_t size,
       return 0;
     }
     
-    if (full_read)
-      {
-       size_t rdbytes;
-
-       nread = 0;
-       while (size > 0
-              && (rc = stream->read (stream, buf, size, &rdbytes)) == 0)
-         {
-           if (rdbytes == 0)
-             {
-               _stream_setflag (stream, _MU_STR_EOF);
-               break;
-             }
-           buf += rdbytes;
-           nread += rdbytes;
-           size -= rdbytes;
-           stream->bytes_in += rdbytes;
-           
-         }
-       if (size && rc)
-         rc = mu_stream_seterr (stream, rc, 0);
-      }
-    else
-      {
-       rc = stream->read (stream, buf, size, &nread);
-       if (rc == 0)
-         {
-           if (nread == 0)
+  if (full_read)
+    {
+      size_t rdbytes;
+
+      nread = 0;
+      while (size > 0
+            && (rc = stream->read (stream, buf, size, &rdbytes)) == 0)
+       {
+         if (rdbytes == 0)
+           {
              _stream_setflag (stream, _MU_STR_EOF);
-           stream->bytes_in += nread;
-         }
-       mu_stream_seterr (stream, rc, rc != 0);
-      }
-    stream->offset += nread;
-    if (pnread)
-      *pnread = nread;
-    
-    return rc;
+             break;
+           }
+         buf += rdbytes;
+         nread += rdbytes;
+         size -= rdbytes;
+         stream->bytes_in += rdbytes;
+       }
+      if (size && rc)
+       rc = mu_stream_seterr (stream, rc, 0);
+    }
+  else
+    {
+      rc = stream->read (stream, buf, size, &nread);
+      if (rc == 0)
+       {
+         if (nread == 0)
+           _stream_setflag (stream, _MU_STR_EOF);
+         stream->bytes_in += nread;
+       }
+      mu_stream_seterr (stream, rc, rc != 0);
+    }
+  if (pnread)
+    *pnread = nread;
+  
+  return rc;
 }
 
 static int
@@ -657,7 +666,7 @@ _stream_write_unbuffered (mu_stream_t stream,
       nwritten = 0;
       while (size > 0
             && (rc = stream->write (stream, bufp, size, &wrbytes))
-                    == 0)
+            == 0)
        {
          if (wrbytes == 0)
            {
@@ -677,7 +686,6 @@ _stream_write_unbuffered (mu_stream_t stream,
        stream->bytes_out += nwritten;
     }
   _stream_setflag (stream, _MU_STR_WRT);
-  stream->offset += nwritten;
   if (pnwritten)
     *pnwritten = nwritten;
   mu_stream_seterr (stream, rc, rc != 0);
@@ -695,7 +703,14 @@ mu_stream_read (mu_stream_t stream, void *buf, size_t 
size, size_t *pread)
     }
   
   if (stream->buftype == mu_buffer_none)
-    return _stream_read_unbuffered (stream, buf, size, !pread, pread);
+    {
+      size_t nread = 0;
+      int rc = _stream_read_unbuffered (stream, buf, size, !pread, &nread);
+      stream->offset += nread;
+      if (pread)
+       *pread = nread;
+      return rc;
+    }
   else
     {
       char *bufp = buf;
@@ -712,6 +727,12 @@ mu_stream_read (mu_stream_t stream, void *buf, size_t 
size, size_t *pread)
          
          if (stream->pos == stream->level)
            {
+             if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
+               {
+                 if (nbytes)
+                   break;
+                 return rc;
+               }
              if ((rc = _stream_fill_buffer (stream)))
                {
                  if (nbytes)
@@ -757,6 +778,8 @@ _stream_scandelim (mu_stream_t stream, char *buf, size_t 
size, int delim,
       
       if (stream->pos == stream->level)
        {
+         if ((rc = _stream_flush_buffer (stream, _MU_STR_FLUSH_ALL)))
+           break;
          if ((rc = _stream_fill_buffer (stream)) || stream->level == 0)
            break;
        }
@@ -959,8 +982,14 @@ mu_stream_write (mu_stream_t stream, const void *buf, 
size_t size,
     }
 
   if (stream->buftype == mu_buffer_none)
-    rc = _stream_write_unbuffered (stream, buf, size,
-                                  !pnwritten, pnwritten);
+    {
+      size_t nwritten;
+      rc = _stream_write_unbuffered (stream, buf, size,
+                                    !pnwritten, &nwritten);
+      stream->offset += nwritten;
+      if (pnwritten)
+       *pnwritten = nwritten;
+    }
   else
     {
       size_t nbytes = 0;
diff --git a/libmailutils/tests/wsp.c b/libmailutils/tests/wsp.c
index bbb3416..b6c2a66 100644
--- a/libmailutils/tests/wsp.c
+++ b/libmailutils/tests/wsp.c
@@ -33,6 +33,7 @@ struct mu_kwd bool_keytab[] = {
   /*{ "reuse",  MU_WRDSF_REUSE },*/
   { "undef",  MU_WRDSF_UNDEF },
   { "novar",  MU_WRDSF_NOVAR },
+  { "nocmd",  MU_WRDSF_NOCMD },
   { "ws",     MU_WRDSF_WS },
   { "quote",  MU_WRDSF_QUOTE },
   { "squeeze_delims", MU_WRDSF_SQUEEZE_DELIMS },
@@ -205,7 +206,7 @@ main (int argc, char **argv)
          plaintext_option = !negate;
          continue;
        }
-         
+    
       if (mu_kwd_xlat_name (bool_keytab, opt, &flag) == 0)
        {
          if (negate)
diff --git a/libmu_auth/sql.c b/libmu_auth/sql.c
index c4e3dfb..20b79db 100644
--- a/libmu_auth/sql.c
+++ b/libmu_auth/sql.c
@@ -88,7 +88,6 @@ sql_escape_string (const char *ustr)
 char *
 mu_sql_expand_query (const char *query, const char *ustr)
 {
-  int rc;
   char *res;
   char *esc_ustr;
   struct mu_wordsplit ws;
diff --git a/libproto/imap/Makefile.am b/libproto/imap/Makefile.am
index 7c01741..efbf0db 100644
--- a/libproto/imap/Makefile.am
+++ b/libproto/imap/Makefile.am
@@ -13,7 +13,7 @@
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
-## along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. 
+## along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>.
 
 INCLUDES = @MU_LIB_COMMON_INCLUDES@ 
 
@@ -21,8 +21,26 @@ lib_LTLIBRARIES = libmu_imap.la
 libmu_imap_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
 libmu_imap_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ 
 
+# FIXME: Put these back when ready
+
+#  folder.c\
+#  mbox.c\
+#  url.c
 libmu_imap_la_SOURCES = \
- folder.c\
- mbox.c\
- url.c
+ fake-folder.c\
+ capability.c\
+ capatst.c\
+ carrier.c\
+ connect.c\
+ create.c\
+ destroy.c\
+ disconnect.c\
+ err.c\
+ id.c\
+ login.c\
+ logout.c\
+ response.c\
+ state.c\
+ tag.c\
+ trace.c
 
diff --git a/libproto/imap/capability.c b/libproto/imap/capability.c
new file mode 100644
index 0000000..a2f1aac
--- /dev/null
+++ b/libproto/imap/capability.c
@@ -0,0 +1,147 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <mailutils/types.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/list.h>
+#include <mailutils/wordsplit.h>
+#include <mailutils/sys/imap.h>
+
+static int
+capa_comp (const void *item, const void *value)
+{
+  const char *capa = item;
+  const char *needle = value;
+  for (; *needle; capa++, needle++)
+    {
+      if (!*capa)
+       return 1;
+      if (mu_tolower (*capa) != mu_tolower (*needle))
+       return 1;
+    }
+  return !(*capa == 0 || *capa == '=');
+}
+
+int
+mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
+{
+  int status;
+  
+  if (imap == NULL)
+    return EINVAL;
+  if (!imap->carrier)
+    return MU_ERR_NO_TRANSPORT;
+  if (imap->state != MU_IMAP_CONNECTED)
+    return MU_ERR_SEQ;
+
+  if (imap->capa)
+    {
+      if (!reread)
+       {
+         if (!piter)
+           return 0;
+         return mu_list_get_iterator (imap->capa, piter);
+       }
+      mu_list_clear (imap->capa);
+    }
+  else
+    {
+      status = mu_list_create (&imap->capa);
+      MU_IMAP_CHECK_ERROR (imap, status);
+      mu_list_set_comparator (imap->capa, capa_comp);
+      mu_list_set_destroy_item (imap->capa, mu_list_free_item);
+    }
+
+  switch (imap->state)
+    {
+    case MU_IMAP_CONNECTED:
+      status = _mu_imap_tag_next (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      status = mu_stream_printf (imap->carrier, "%s CAPABILITY\r\n",
+                                imap->tag_str); 
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      MU_IMAP_FCLR (imap, MU_IMAP_RESP);
+      imap->state = MU_IMAP_CAPABILITY_RX;
+
+    case MU_IMAP_CAPABILITY_RX:
+      status = _mu_imap_response (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      if (imap->resp_code != MU_IMAP_OK)
+       return MU_ERR_REPLY;
+      else
+       {
+         size_t count;
+         char *str;
+         
+         imap->state = MU_IMAP_CONNECTED;
+         mu_list_count (imap->untagged_resp, &count);
+         if (mu_list_get (imap->untagged_resp, 0, (void*)&str) == 0)
+           {
+             size_t i;
+             
+             struct mu_wordsplit ws;
+
+             if (mu_wordsplit (str, &ws,
+                               MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
+                               MU_WRDSF_QUOTE | MU_WRDSF_SQUEEZE_DELIMS))
+               {
+                 int ec = errno;
+                 mu_error ("mu_imap_capability: cannot split line: %s",
+                           mu_wordsplit_strerror (&ws));
+                 return ec;
+               }
+             if (ws.ws_wordc > 1 &&
+                 mu_c_strcasecmp (ws.ws_wordv[0], "CAPABILITY") == 0)
+               {
+                 for (i = 1; i < ws.ws_wordc; i++)
+                   {
+                     mu_list_append (imap->capa, ws.ws_wordv[i]);
+                     ws.ws_wordv[i] = NULL;
+                   }
+               }
+             mu_wordsplit_free (&ws);
+           }
+         if (piter)
+           status = mu_list_get_iterator (imap->capa, piter);
+         else
+           status = 0;
+       }  
+      break;
+      
+    case MU_IMAP_ERROR:
+      status = ECANCELED;
+      break;
+
+    default:
+      status = EINPROGRESS;
+    }
+  return status;
+}
+    
+
+  
+
+  
+  
+
diff --git a/libproto/pop/pop3_capatst.c b/libproto/imap/capatst.c
similarity index 73%
copy from libproto/pop/pop3_capatst.c
copy to libproto/imap/capatst.c
index 4fd4466..e14dff6 100644
--- a/libproto/pop/pop3_capatst.c
+++ b/libproto/imap/capatst.c
@@ -1,6 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2003, 2004, 2005, 2007, 2010 Free Software Foundation,
-   Inc.
+   Copyright (C) 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
@@ -20,17 +19,17 @@
 # include <config.h>
 #endif
 
-#include <stdlib.h>
+#include <mailutils/types.h>
 #include <mailutils/list.h>
-#include <mailutils/sys/pop3.h>
+#include <mailutils/sys/imap.h>
 
 int
-mu_pop3_capa_test (mu_pop3_t pop3, const char *name, const char **pret)
+mu_imap_capability_test (mu_imap_t imap, const char *name, const char **pret)
 {
   int rc;
 
-  rc = mu_pop3_capa (pop3, 0, NULL);
+  rc = mu_imap_capability (imap, 0, NULL);
   if (rc)
     return rc;
-  return mu_list_locate (pop3->capa, (void*) name, (void**)pret);
+  return mu_list_locate (imap->capa, (void*) name, (void**)pret);
 }
diff --git a/libproto/pop/pop3_carrier.c b/libproto/imap/carrier.c
similarity index 65%
copy from libproto/pop/pop3_carrier.c
copy to libproto/imap/carrier.c
index 265669d..78398c0 100644
--- a/libproto/pop/pop3_carrier.c
+++ b/libproto/imap/carrier.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -22,39 +22,41 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <mailutils/sys/pop3.h>
+#include <mailutils/errno.h>
+#include <mailutils/sys/imap.h>
 
 int
-mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier)
+mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier)
 {
   /* Sanity checks.  */
-  if (pop3 == NULL)
+  if (imap == NULL)
     return EINVAL;
 
-  if (pop3->carrier)
+  if (imap->carrier)
     {
       /* Close any old carrier.  */
-      mu_pop3_disconnect (pop3);
-      mu_stream_destroy (&pop3->carrier);
+      mu_imap_disconnect (imap);
+      mu_stream_destroy (&imap->carrier);
     }
   mu_stream_ref (carrier);
-  pop3->carrier = carrier;
-  if (MU_POP3_FISSET (pop3, MU_POP3_TRACE))
-    _mu_pop3_trace_enable (pop3);
-  pop3->state = MU_POP3_CONNECT;
+  imap->carrier = carrier;
+  if (MU_IMAP_FISSET (imap, MU_IMAP_TRACE))
+    _mu_imap_trace_enable (imap);
+  imap->state = MU_IMAP_CONNECT;
   return 0;
 }
 
-/* FIXME: Is it needed? */
 int
-mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier)
+mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier)
 {
   /* Sanity checks.  */
-  if (pop3 == NULL)
+  if (imap == NULL)
     return EINVAL;
   if (pcarrier == NULL)
     return MU_ERR_OUT_PTR_NULL;
 
-  *pcarrier = pop3->carrier;
+  mu_stream_ref (imap->carrier);
+  *pcarrier = imap->carrier;
   return 0;
 }
+
diff --git a/libproto/imap/connect.c b/libproto/imap/connect.c
new file mode 100644
index 0000000..621035b
--- /dev/null
+++ b/libproto/imap/connect.c
@@ -0,0 +1,119 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <mailutils/errno.h>
+#include <mailutils/wordsplit.h>
+#include <mailutils/sys/imap.h>
+
+
+int
+mu_imap_connect (mu_imap_t imap)
+{
+  int status;
+
+  if (imap == NULL)
+    return EINVAL;
+  if (imap->carrier == NULL)
+    return EINVAL;
+  switch (imap->state)
+    {
+    default:
+    case MU_IMAP_NO_STATE:
+      status = mu_imap_disconnect (imap);
+      if (status != 0)
+       {
+         /* Sleep for 2 seconds (FIXME: Must be configurable) */
+         struct timeval tval;
+         tval.tv_sec = 2;
+         tval.tv_usec = 0;
+         select (0, NULL, NULL, NULL, &tval);
+       }
+      imap->state = MU_IMAP_CONNECT;
+
+    case MU_IMAP_CONNECT:
+      /* Establish the connection.  */
+      if (!mu_stream_is_open (imap->carrier))
+        {
+          status = mu_stream_open (imap->carrier);
+          MU_IMAP_CHECK_EAGAIN (imap, status);
+          MU_IMAP_FCLR (imap, MU_IMAP_RESP);
+        }
+      imap->state = MU_IMAP_GREETINGS;
+
+    case MU_IMAP_GREETINGS:
+      status = mu_stream_getline (imap->carrier, &imap->rdbuf,
+                                 &imap->rdsize, NULL);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      if (imap->rdsize < 2 ||
+         !(imap->rdbuf[0] == '*' && imap->rdbuf[1] == ' '))
+       {
+         mu_error ("mu_imap_connect: invalid server response: %s",
+                   imap->rdbuf);
+         imap->state = MU_IMAP_ERROR;
+         return MU_ERR_BADREPLY;
+       }
+      else
+       {
+         struct mu_wordsplit ws;
+         
+         if (mu_wordsplit (imap->rdbuf, &ws,
+                           MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
+                           MU_WRDSF_SQUEEZE_DELIMS))
+           {
+             int ec = errno;
+             mu_error ("mu_imap_connect: cannot split line: %s",
+                       mu_wordsplit_strerror (&ws));
+             imap->state = MU_IMAP_ERROR;
+             return ec;
+           }
+         if (ws.ws_wordc < 2)
+           status = MU_ERR_BADREPLY;
+         else if (strcmp (ws.ws_wordv[1], "BYE") == 0)
+           {
+             status = EACCES;
+             _mu_imap_seterrstr (imap, imap->rdbuf + 2,
+                                 strlen (imap->rdbuf + 2));
+           }
+         else if (strcmp (ws.ws_wordv[1], "PREAUTH") == 0)
+           {
+             status = 0;
+             imap->state = MU_IMAP_CONNECTED;
+             imap->imap_state = MU_IMAP_STATE_AUTH;
+           }
+         else if (strcmp (ws.ws_wordv[1], "OK") == 0)
+           {
+             status = 0;
+             imap->state = MU_IMAP_CONNECTED;
+             imap->imap_state = MU_IMAP_STATE_NONAUTH;
+           }
+         else
+           {
+             status = MU_ERR_BADREPLY;
+             imap->state = MU_IMAP_ERROR;
+           }
+         mu_wordsplit_free (&ws);
+       }
+    }
+  
+  return status;
+}
diff --git a/libproto/pop/pop3_create.c b/libproto/imap/create.c
similarity index 60%
copy from libproto/pop/pop3_create.c
copy to libproto/imap/create.c
index dbb7a4b..1832910 100644
--- a/libproto/pop/pop3_create.c
+++ b/libproto/imap/create.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2003, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -22,43 +22,46 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <mailutils/errno.h>
-#include <mailutils/sys/pop3.h>
+#include <mailutils/sys/imap.h>
 #include <mailutils/list.h>
 
-/* Initialise a mu_pop3_t handle.  */
-
 int
-mu_pop3_create (mu_pop3_t *ppop3)
+mu_imap_create (mu_imap_t *pimap)
 {
-  mu_pop3_t pop3;
+  mu_imap_t imap;
 
   /* Sanity check.  */
-  if (ppop3 == NULL)
+  if (pimap == NULL)
     return EINVAL;
 
-  pop3 = calloc (1, sizeof *pop3);
-  if (pop3 == NULL)
+  imap = calloc (1, sizeof *imap);
+  if (imap == NULL)
     return ENOMEM;
 
-  pop3->state = MU_POP3_NO_STATE; /* Init with no state.  */
-  pop3->timeout = (10 * 60) * 100; /* The default Timeout is 10 minutes.  */
-  MU_POP3_FCLR (pop3, MU_POP3_ACK); /* No Ack received.  */
+  _mu_imap_init (imap);
 
-  *ppop3 = pop3;
-  return 0; /* Okdoke.  */
+  *pimap = imap;
+  return 0;
 }
 
 int
-_mu_pop3_init (mu_pop3_t pop3)
+_mu_imap_init (mu_imap_t imap)
 {
-  if (pop3 == NULL)
+  if (imap == NULL)
     return EINVAL;
-  if (pop3->carrier == 0)
+  if (imap->carrier == 0)
     {
-      mu_list_destroy (&pop3->capa);
-      pop3->flags = 0;
+      int rc;
+      
+      if (imap->untagged_resp)
+       mu_list_clear (imap->untagged_resp);
+      mu_list_destroy (&imap->capa);
+      _mu_imap_clrerrstr (imap);
+      rc = _mu_imap_tag_clr (imap);
+      imap->flags = 0;
+      if (rc)
+       return rc;
     }
+  imap->state = MU_IMAP_NO_STATE; /* Init with no state.  */
   return 0;
 }
-
-  
diff --git a/libproto/pop/pop3_destroy.c b/libproto/imap/destroy.c
similarity index 62%
copy from libproto/pop/pop3_destroy.c
copy to libproto/imap/destroy.c
index de70748..707f09b 100644
--- a/libproto/pop/pop3_destroy.c
+++ b/libproto/imap/destroy.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2003, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 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,35 +21,38 @@
 
 #include <stdlib.h>
 #include <mailutils/errno.h>
-#include <mailutils/sys/pop3.h>
+#include <mailutils/sys/imap.h>
 #include <mailutils/list.h>
 
 void
-mu_pop3_destroy (mu_pop3_t *ppop3)
+mu_imap_destroy (mu_imap_t *pimap)
 {
-  if (ppop3 && *ppop3)
+  if (pimap && *pimap)
     {
-      mu_pop3_t pop3 = *ppop3;
-
+      mu_imap_t imap = *pimap;
+      
       /* Free the response buffer.  */
-      if (pop3->ackbuf)
-       free (pop3->ackbuf);
+      if (imap->tagbuf)
+       free (imap->tagbuf);
       /* Free the read buffer.  */
-      if (pop3->rdbuf)
-       free (pop3->rdbuf);
+      if (imap->rdbuf)
+       free (imap->rdbuf);
 
-      /* Free the timestamp use for APOP.  */
-      if (pop3->timestamp)
-       free (pop3->timestamp);
+      if (imap->errstr)
+       free (imap->errstr);
 
-      mu_list_destroy (&pop3->capa);
+      if (imap->tag_str)
+       free (imap->tag_str);
+      if (imap->tag_buf)
+       free (imap->tag_buf);
+      
+      mu_list_destroy (&imap->untagged_resp);
+      mu_list_destroy (&imap->capa);
       
-      /* Release the carrier.  */
-      if (pop3->carrier)
-       mu_stream_destroy (&pop3->carrier);
+      mu_stream_destroy (&imap->carrier);
 
-      free (pop3);
+      free (imap);
 
-      *ppop3 = NULL;
+      *pimap = NULL;
     }
 }
diff --git a/libproto/nntp/nntp_timeout.c b/libproto/imap/disconnect.c
similarity index 65%
copy from libproto/nntp/nntp_timeout.c
copy to libproto/imap/disconnect.c
index 8b35ed0..a376ace 100644
--- a/libproto/nntp/nntp_timeout.c
+++ b/libproto/imap/disconnect.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2004, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -20,29 +20,28 @@
 #endif
 
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
-#include <mailutils/sys/nntp.h>
+#include <mailutils/sys/imap.h>
 
 int
-mu_nntp_set_timeout (mu_nntp_t nntp, int timeout)
+mu_imap_disconnect (mu_imap_t imap)
 {
   /* Sanity checks.  */
-  if (nntp == NULL)
+  if (imap == NULL)
     return EINVAL;
 
-  nntp->timeout = timeout;
-  return 0;
-}
+  imap->state = MU_IMAP_NO_STATE;
+  MU_IMAP_FCLR (imap, MU_IMAP_RESP);
 
-int
-mu_nntp_get_timeout (mu_nntp_t nntp, int *ptimeout)
-{
-  /* Sanity checks.  */
-  if (nntp == NULL)
-    return EINVAL;
-  if (ptimeout == NULL)
-    return MU_ERR_OUT_PTR_NULL;
+  if (imap->rdbuf)
+    imap->rdbuf[0] = 0;
 
-  *ptimeout = nntp->timeout;
+  mu_list_clear (imap->untagged_resp);
+  mu_list_clear (imap->capa);
+  
+  /* Close the stream.  */
+  if (mu_stream_is_open (imap->carrier))
+    return mu_stream_close (imap->carrier);
   return 0;
 }
diff --git a/libmailutils/mailbox/hdrfirst.c b/libproto/imap/err.c
similarity index 60%
copy from libmailutils/mailbox/hdrfirst.c
copy to libproto/imap/err.c
index 363021f..8b49072 100644
--- a/libmailutils/mailbox/hdrfirst.c
+++ b/libproto/imap/err.c
@@ -18,31 +18,42 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-
 #include <stdlib.h>
-#include <mailutils/types.h>
-#include <mailutils/header.h>
+#include <string.h>
 #include <mailutils/errno.h>
+#include <mailutils/sys/imap.h>
 
 int
-mu_header_sget_firstof (mu_header_t hdr, char **names,
-                       const char **pval, int *pidx)
+_mu_imap_seterrstr (mu_imap_t imap, const char *str, size_t len)
+{
+  if (len + 1 > imap->errsize)
+    {
+      char *p = realloc (imap->errstr, len + 1);
+      if (!p)
+       return ENOMEM;
+      imap->errsize = len + 1;
+      imap->errstr = p;
+    }
+  memcpy (imap->errstr, str, len);
+  imap->errstr[len] = 0;
+  return 0;
+}
+
+void
+_mu_imap_clrerrstr (mu_imap_t imap)
+{
+  if (imap->errstr)
+    imap->errstr[0] = 0;
+}
+    
+int
+mu_imap_strerror (mu_imap_t imap, const char **pstr)
 {
-  int status;
-  const char *s = NULL;
-  int i;
-  
-  for (i = 0; names[i]; i++)
+  if (imap->errstr)
     {
-      status = mu_header_sget_value (hdr, names[i], &s);
-      if (status == 0 && *s != 0)
-       {
-         if (pval)
-           *pval = s;
-         if (pidx)
-           *pidx = i;
-         return 0;
-       }
+      *pstr = imap->errstr;
+      return 0;
     }
+  *pstr = "(no error)";
   return MU_ERR_NOENT;
 }
diff --git a/libproto/imap/fake-folder.c b/libproto/imap/fake-folder.c
new file mode 100644
index 0000000..fb59c49
--- /dev/null
+++ b/libproto/imap/fake-folder.c
@@ -0,0 +1,7 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <mailutils/mailutils.h>
+
+mu_record_t mu_imap_record = NULL;
+mu_record_t mu_imaps_record = NULL;
diff --git a/libproto/imap/id.c b/libproto/imap/id.c
new file mode 100644
index 0000000..5513d54
--- /dev/null
+++ b/libproto/imap/id.c
@@ -0,0 +1,180 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/errno.h>
+#include <mailutils/cstr.h>
+#include <mailutils/wordsplit.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/imap.h>
+
+static int
+id_comp (const void *item, const void *value)
+{
+  const char *id = item;
+  const char *needle = value;
+  return mu_c_strcasecmp (id, needle);
+}
+
+static int
+parse_id_reply (mu_imap_t imap, mu_list_t *plist)
+{
+  mu_list_t list;
+  int rc;
+  const char *response;
+  struct mu_wordsplit ws;
+  size_t i;
+    
+  rc = mu_list_create (&list);
+  if (rc)
+    return rc;
+  mu_list_set_comparator (list, id_comp);
+  mu_list_set_destroy_item (list, mu_list_free_item);
+  
+  rc = mu_list_get (imap->untagged_resp, 0, (void*) &response);
+  if (rc == MU_ERR_NOENT)
+    {
+      *plist = list;
+      return 0;
+    }
+  else if (rc)
+    {
+      mu_list_destroy (&list);
+      return rc;
+    }
+
+  ws.ws_delim = "() \t";
+  if (mu_wordsplit (response, &ws,
+                   MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
+                   MU_WRDSF_QUOTE | MU_WRDSF_DELIM |
+                   MU_WRDSF_SQUEEZE_DELIMS |
+                   MU_WRDSF_WS))
+    {
+      int ec = errno;
+      mu_error ("mu_imap_id: cannot split line: %s",
+               mu_wordsplit_strerror (&ws));
+      mu_list_destroy (&list);
+      return ec;
+    }
+
+  for (i = 1; i < ws.ws_wordc; i += 2)
+    {
+      size_t len, l1, l2;
+      char *elt;
+      
+      if (i + 1 == ws.ws_wordc)
+       break;
+      l1 = strlen (ws.ws_wordv[i]);
+      l2 = strlen (ws.ws_wordv[i+1]);
+      len = l1 + l2 + 1;
+      elt = malloc (len + 1);
+      if (!elt)
+       break;
+
+      memcpy (elt, ws.ws_wordv[i], l1);
+      elt[l1] = 0;
+      memcpy (elt + l1 + 1, ws.ws_wordv[i+1], l2);
+      elt[len] = 0;
+      mu_list_append (list, elt);
+    }
+  mu_wordsplit_free (&ws);
+  *plist = list;
+  return 0;
+}
+
+int
+mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
+{
+  int status;
+  
+  if (imap == NULL)
+    return EINVAL;
+  if (!imap->carrier)
+    return MU_ERR_NO_TRANSPORT;
+  if (imap->state != MU_IMAP_CONNECTED)
+    return MU_ERR_SEQ;
+
+  switch (imap->state)
+    {
+    case MU_IMAP_CONNECTED:
+      status = _mu_imap_tag_next (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      status = mu_stream_printf (imap->carrier, "%s ID ",
+                                imap->tag_str);
+      MU_IMAP_CHECK_ERROR (imap, status);
+      if (!idenv)
+       status = mu_stream_printf (imap->carrier, "NIL");
+      else
+       {
+         if (idenv[0])
+           {
+             int i;
+             char *delim = "(";
+             for (i = 0; idenv[i]; i++)
+               {
+                 status = mu_stream_printf (imap->carrier, "%s\"%s\"",
+                                            delim, idenv[i]);
+                 MU_IMAP_CHECK_ERROR (imap, status);
+                 
+                 delim = " ";
+                 if (status)
+                   break;
+               }
+             status = mu_stream_printf (imap->carrier, ")");
+           }
+         else
+           status = mu_stream_printf (imap->carrier, "()");
+       }
+      MU_IMAP_CHECK_ERROR (imap, status);
+      status = mu_stream_printf (imap->carrier, "\r\n");
+      MU_IMAP_CHECK_ERROR (imap, status);
+      MU_IMAP_FCLR (imap, MU_IMAP_RESP);
+      imap->state = MU_IMAP_ID_RX;
+
+    case MU_IMAP_ID_RX:
+      status = _mu_imap_response (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      switch (imap->resp_code)
+       {
+       case MU_IMAP_OK:
+         imap->imap_state = MU_IMAP_STATE_AUTH;
+         if (plist)
+           status = parse_id_reply (imap, plist);
+         break;
+
+       case MU_IMAP_NO:
+         status = EACCES;
+         break;
+
+       case MU_IMAP_BAD:
+         status = MU_ERR_BADREPLY;
+         break;
+       }
+      imap->state = MU_IMAP_CONNECTED;
+      break;
+
+    default:
+      status = EINPROGRESS;
+    }
+  return status;
+}
+      
diff --git a/libproto/imap/login.c b/libproto/imap/login.c
new file mode 100644
index 0000000..94313e8
--- /dev/null
+++ b/libproto/imap/login.c
@@ -0,0 +1,80 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/imap.h>
+
+int
+mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
+{
+  int status;
+  
+  if (imap == NULL)
+    return EINVAL;
+  if (!imap->carrier)
+    return MU_ERR_NO_TRANSPORT;
+  if (imap->state != MU_IMAP_CONNECTED)
+    return MU_ERR_SEQ;
+  if (imap->imap_state != MU_IMAP_STATE_NONAUTH)
+    return MU_ERR_SEQ;
+  
+  switch (imap->state)
+    {
+    case MU_IMAP_CONNECTED:
+      if (mu_imap_trace_mask (imap, MU_IMAP_TRACE_QRY, MU_XSCRIPT_SECURE))
+       _mu_imap_xscript_level (imap, MU_XSCRIPT_SECURE);
+      status = _mu_imap_tag_next (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      status = mu_stream_printf (imap->carrier, "%s LOGIN \"%s\" \"%s\"\r\n",
+                                imap->tag_str, user, pass);
+      _mu_imap_xscript_level (imap, MU_XSCRIPT_NORMAL);
+      /* FIXME: how to obscure the passwd in the stream buffer? */
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      MU_IMAP_FCLR (imap, MU_IMAP_RESP);
+      imap->state = MU_IMAP_LOGIN_RX;
+
+    case MU_IMAP_LOGIN_RX:
+      status = _mu_imap_response (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      switch (imap->resp_code)
+       {
+       case MU_IMAP_OK:
+         imap->imap_state = MU_IMAP_STATE_AUTH;
+         break;
+
+       case MU_IMAP_NO:
+         status = EACCES;
+         break;
+
+       case MU_IMAP_BAD:
+         status = MU_ERR_BADREPLY;
+         break;
+       }
+      imap->state = MU_IMAP_CONNECTED;
+      break;
+
+    default:
+      status = EINPROGRESS;
+    }
+  return status;
+}
+
diff --git a/libproto/nntp/nntp_quit.c b/libproto/imap/logout.c
similarity index 51%
copy from libproto/nntp/nntp_quit.c
copy to libproto/imap/logout.c
index 5fcd091..925fd7f 100644
--- a/libproto/nntp/nntp_quit.c
+++ b/libproto/imap/logout.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2004, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 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,43 +19,43 @@
 # include <config.h>
 #endif
 
-#include <string.h>
-#include <errno.h>
-#include <mailutils/sys/nntp.h>
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/sys/imap.h>
 
 int
-mu_nntp_quit (mu_nntp_t nntp)
+mu_imap_logout (mu_imap_t imap)
 {
   int status;
-
-  if (nntp == NULL)
+  
+  if (imap == NULL)
     return EINVAL;
+  if (!imap->carrier)
+    return MU_ERR_NO_TRANSPORT;
+  if (imap->state != MU_IMAP_CONNECTED)
+    return MU_ERR_SEQ;
 
-  switch (nntp->state)
+  switch (imap->state)
     {
-    case MU_NNTP_NO_STATE:
-      status = mu_nntp_writeline (nntp, "QUIT\r\n");
-      MU_NNTP_CHECK_ERROR (nntp, status);
-      mu_nntp_debug_cmd (nntp);
-      nntp->state = MU_NNTP_QUIT;
-
-    case MU_NNTP_QUIT:
-      status = mu_nntp_send (nntp);
-      MU_NNTP_CHECK_EAGAIN (nntp, status);
-      nntp->acknowledge = 0;
-      nntp->state = MU_NNTP_QUIT_ACK;
-
-    case MU_NNTP_QUIT_ACK:
-      status = mu_nntp_response (nntp, NULL, 0, NULL);
-      MU_NNTP_CHECK_EAGAIN (nntp, status);
-      mu_nntp_debug_ack (nntp);
-      MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_CLOSING);
-      nntp->state = MU_NNTP_NO_STATE;
+    case MU_IMAP_CONNECTED:
+      status = _mu_imap_tag_next (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      status = mu_stream_printf (imap->carrier, "%s LOGOUT\r\n",
+                                imap->tag_str); 
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      MU_IMAP_FCLR (imap, MU_IMAP_RESP);
+      imap->state = MU_IMAP_LOGOUT_RX;
+
+    case MU_IMAP_LOGOUT_RX:
+      status = _mu_imap_response (imap);
+      MU_IMAP_CHECK_EAGAIN (imap, status);
+      imap->state = MU_IMAP_NO_STATE;
+      imap->imap_state = MU_IMAP_STATE_LOGOUT;
       break;
 
     default:
       status = EINPROGRESS;
     }
-
   return status;
 }
+      
diff --git a/libproto/imap/response.c b/libproto/imap/response.c
new file mode 100644
index 0000000..dc5a7a9
--- /dev/null
+++ b/libproto/imap/response.c
@@ -0,0 +1,125 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
+#include <mailutils/stream.h>
+#include <mailutils/errno.h>
+#include <mailutils/sys/imap.h>
+
+#define IS_PREFIX(s, len, pfx)                         \
+  ((len) >= sizeof (pfx) - 1 &&                                \
+   memcmp ((s), (pfx), sizeof (pfx) - 1) == 0 &&       \
+   s[sizeof (pfx) - 1] == ' ')
+
+int
+_mu_imap_response (mu_imap_t imap)
+{
+  size_t n = 0;
+  int status = 0;
+
+  if (imap == NULL)
+    return EINVAL;
+
+  if (MU_IMAP_FISSET (imap, MU_IMAP_RESP))
+    return 0;
+
+  _mu_imap_clrerrstr (imap);
+  if (imap->untagged_resp)
+    mu_list_clear (imap->untagged_resp);
+  else
+    {
+      status = mu_list_create (&imap->untagged_resp);
+      MU_IMAP_CHECK_ERROR (imap, status);
+      mu_list_set_destroy_item (imap->untagged_resp, mu_list_free_item);
+    }
+
+  while (1)
+    {
+      status = mu_stream_getline (imap->carrier, &imap->rdbuf,
+                                 &imap->rdsize, NULL);
+      if (status == 0)
+       {
+         n = mu_rtrim_class (imap->rdbuf, MU_CTYPE_SPACE);
+         if (imap->rdbuf[0] == '*' && imap->rdbuf[1] == ' ')
+           {
+             char *p = mu_str_skip_cset (imap->rdbuf + 2, " ");
+             mu_list_append (imap->untagged_resp, strdup (p));
+           }
+         else if (n > imap->tag_len + 3 &&
+                  memcmp (imap->rdbuf, imap->tag_str, imap->tag_len) == 0
+                  && imap->rdbuf[imap->tag_len] == ' ')
+           {
+             char *p = mu_str_skip_cset (imap->rdbuf + imap->tag_len, " ");
+             size_t len = strlen (p);
+
+             if (len >= imap->tagsize)
+               {
+                 char *np = realloc (imap->tagbuf, len + 1);
+                 if (!np)
+                   {
+                     imap->state = MU_IMAP_ERROR;
+                     return ENOMEM;
+                   }
+                 imap->tagsize = len + 1;
+                 imap->tagbuf = np;
+               }
+             strcpy (imap->tagbuf, p);
+             if (IS_PREFIX (p, len, "OK"))
+               {
+                 imap->resp_code = MU_IMAP_OK;
+                 p = mu_str_skip_cset (p + 2, " ");
+                 _mu_imap_seterrstr (imap, p, strlen (p));
+               }
+             else if (IS_PREFIX (p, len, "NO"))
+               {
+                 imap->resp_code = MU_IMAP_NO;
+                 p = mu_str_skip_cset (p + 2, " ");
+                 _mu_imap_seterrstr (imap, p, strlen (p));
+               }
+             else if (IS_PREFIX (p, len, "BAD"))
+               {
+                 imap->resp_code = MU_IMAP_BAD;
+                 p = mu_str_skip_cset (p + 2, " ");
+                 _mu_imap_seterrstr (imap, p, strlen (p));
+               }
+             else
+               status = MU_ERR_BADREPLY;
+             MU_IMAP_FSET (imap, MU_IMAP_RESP);
+             break;
+           }
+         else
+           {
+             imap->state = MU_IMAP_ERROR;
+             return MU_ERR_BADREPLY;
+           }
+       }
+      else
+       {
+         imap->state = MU_IMAP_ERROR;
+         return status;
+       }
+    }
+  return status;
+}
+         
diff --git a/libproto/nntp/nntp_timeout.c b/libproto/imap/state.c
similarity index 60%
copy from libproto/nntp/nntp_timeout.c
copy to libproto/imap/state.c
index 8b35ed0..4ce3230 100644
--- a/libproto/nntp/nntp_timeout.c
+++ b/libproto/imap/state.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2004, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -18,31 +18,33 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-
-#include <stdlib.h>
 #include <errno.h>
-#include <mailutils/sys/nntp.h>
+#include <mailutils/nls.h>
+#include <mailutils/sys/imap.h>
+
+const char *_mu_imap_state_name[] = {
+  N_("initial"),
+  N_("non-authenticated"),
+  N_("authenticated"),
+  N_("selected"),
+  N_("logout")
+};
+int _mu_imap_state_count = MU_ARRAY_SIZE (_mu_imap_state_name);
 
 int
-mu_nntp_set_timeout (mu_nntp_t nntp, int timeout)
+mu_imap_state (mu_imap_t imap, int *pstate)
 {
-  /* Sanity checks.  */
-  if (nntp == NULL)
+  if (imap == NULL || pstate == NULL)
     return EINVAL;
-
-  nntp->timeout = timeout;
+  *pstate = imap->imap_state;
   return 0;
 }
 
 int
-mu_nntp_get_timeout (mu_nntp_t nntp, int *ptimeout)
+mu_imap_state_str (int state, const char **pstr)
 {
-  /* Sanity checks.  */
-  if (nntp == NULL)
+  if (state < 0 || state >= _mu_imap_state_count)
     return EINVAL;
-  if (ptimeout == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-
-  *ptimeout = nntp->timeout;
+  *pstr = gettext (_mu_imap_state_name[state]);
   return 0;
 }
diff --git a/libproto/imap/tag.c b/libproto/imap/tag.c
new file mode 100644
index 0000000..3317219
--- /dev/null
+++ b/libproto/imap/tag.c
@@ -0,0 +1,103 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <mailutils/sys/imap.h>
+
+static int
+_mu_imap_tag_incr (mu_imap_t imap)
+{
+  int i = 0;
+  
+  while (1)
+    {
+      if (++imap->tag_buf[i] <= 9)
+       break;
+      imap->tag_buf[i] = 0;
+      if (++i == imap->tag_len)
+       {
+         char *sp;
+         int *np = realloc (imap->tag_buf, imap->tag_len + 1);
+         if (!np)
+           return ENOMEM;
+         imap->tag_buf = np;
+         sp = realloc (imap->tag_str, imap->tag_len + 2);
+         if (!sp)
+           return ENOMEM;
+         imap->tag_str = sp;
+         imap->tag_len++;
+       }
+    }
+  return 0;
+}
+
+static void
+_mu_imap_tag_print (mu_imap_t imap)
+{
+  int i;
+
+  for (i = 0; i < imap->tag_len; i++)
+    imap->tag_str[imap->tag_len-i-1] = imap->tag_buf[i] + '0';
+  imap->tag_str[i] = 0;
+}
+
+int
+_mu_imap_tag_clr (mu_imap_t imap)
+{
+  int i;
+  
+  if (imap->tag_len == 0)
+    {
+      imap->tag_len = 2;
+      imap->tag_buf = calloc (imap->tag_len, sizeof (imap->tag_buf[0]));
+      if (!imap->tag_buf)
+       return ENOMEM;
+      imap->tag_str = calloc (imap->tag_len + 1, sizeof (imap->tag_str[0]));
+      if (!imap->tag_str)
+       {
+         free (imap->tag_buf);
+         return ENOMEM;
+       }
+    }
+  for (i = 0; i < imap->tag_len; i++)
+    imap->tag_buf[i] = 0;
+  _mu_imap_tag_print (imap);
+  return 0;
+}
+
+int
+_mu_imap_tag_next (mu_imap_t imap)
+{
+  int status;
+  status = _mu_imap_tag_incr (imap);
+  if (status == 0)
+    _mu_imap_tag_print (imap);
+  return status;
+}
+
+int
+mu_imap_tag (mu_imap_t imap, const char **ptag)
+{
+  if (!imap)
+    return EINVAL;
+  *ptag = imap->tag_str;
+  return 0;
+}
diff --git a/libproto/pop/pop3_trace.c b/libproto/imap/trace.c
similarity index 61%
copy from libproto/pop/pop3_trace.c
copy to libproto/imap/trace.c
index 8ed7eab..3fff598 100644
--- a/libproto/pop/pop3_trace.c
+++ b/libproto/imap/trace.c
@@ -1,6 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2007, 2009, 2010 Free Software
-   Foundation, Inc.
+   Copyright (C) 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
@@ -24,24 +23,25 @@
 #include <errno.h>
 #include <stdio.h>
 #include <mailutils/error.h>
+#include <mailutils/errno.h>
 #include <mailutils/nls.h>
 #include <mailutils/stream.h>
-#include <mailutils/sys/pop3.h>
+#include <mailutils/sys/imap.h>
 
-static const char *pop3_prefix[] = {
+static const char *imap_prefix[] = {
   "S: ", "C: "
 };
 
 int
-_mu_pop3_trace_enable (mu_pop3_t pop3)
+_mu_imap_trace_enable (mu_imap_t imap)
 {
   int rc = 0;
   mu_debug_t debug;
   mu_stream_t dstr, xstr;
 
-  if (!pop3->carrier)
+  if (!imap->carrier)
     {
-      MU_POP3_FSET (pop3, MU_POP3_TRACE);
+      MU_IMAP_FSET (imap, MU_IMAP_TRACE);
       return 0;
     }
   
@@ -53,16 +53,16 @@ _mu_pop3_trace_enable (mu_pop3_t pop3)
              mu_strerror (rc));
   else
     {
-      rc = mu_xscript_stream_create (&xstr, pop3->carrier, dstr,
-                                    pop3_prefix);
+      rc = mu_xscript_stream_create (&xstr, imap->carrier, dstr,
+                                    imap_prefix);
       if (rc)
        mu_error (_("cannot create transcript stream: %s"),
                  mu_strerror (rc));
       else
        {
-         mu_stream_unref (pop3->carrier);
-         pop3->carrier = xstr;
-         MU_POP3_FSET (pop3, MU_POP3_TRACE);
+         mu_stream_unref (imap->carrier);
+         imap->carrier = xstr;
+         MU_IMAP_FSET (imap, MU_IMAP_TRACE);
        }
     }
 
@@ -70,9 +70,9 @@ _mu_pop3_trace_enable (mu_pop3_t pop3)
 }
 
 int
-_mu_pop3_trace_disable (mu_pop3_t pop3)
+_mu_imap_trace_disable (mu_imap_t imap)
 {
-  mu_stream_t xstr = pop3->carrier;
+  mu_stream_t xstr = imap->carrier;
   mu_stream_t stream[2];
   int rc;
 
@@ -83,30 +83,30 @@ _mu_pop3_trace_disable (mu_pop3_t pop3)
   if (rc)
     return rc;
 
-  pop3->carrier = stream[0];
+  imap->carrier = stream[0];
   mu_stream_destroy (&xstr);
-  MU_POP3_FCLR (pop3, MU_POP3_TRACE);
+  MU_IMAP_FCLR (imap, MU_IMAP_TRACE);
   return 0;
 }
 
 int
-mu_pop3_trace (mu_pop3_t pop3, int op)
+mu_imap_trace (mu_imap_t imap, int op)
 {
-  int trace_on = MU_POP3_FISSET (pop3, MU_POP3_TRACE);
+  int trace_on = MU_IMAP_FISSET (imap, MU_IMAP_TRACE);
   
   switch (op)
     {
-    case MU_POP3_TRACE_SET:
+    case MU_IMAP_TRACE_SET:
       if (trace_on)
        return MU_ERR_EXISTS;
-      return _mu_pop3_trace_enable (pop3);
+      return _mu_imap_trace_enable (imap);
       
-    case MU_POP3_TRACE_CLR:
+    case MU_IMAP_TRACE_CLR:
       if (!trace_on)
        return MU_ERR_NOENT;
-      return _mu_pop3_trace_disable (pop3);
+      return _mu_imap_trace_disable (imap);
 
-    case MU_POP3_TRACE_QRY:
+    case MU_IMAP_TRACE_QRY:
       if (!trace_on)
        return MU_ERR_NOENT;
       return 0;
@@ -115,20 +115,20 @@ mu_pop3_trace (mu_pop3_t pop3, int op)
 }
 
 int
-mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev)
+mu_imap_trace_mask (mu_imap_t imap, int op, int lev)
 {
   switch (op)
     {
-    case MU_POP3_TRACE_SET:
-      pop3->flags |= MU_POP3_XSCRIPT_MASK(lev);
+    case MU_IMAP_TRACE_SET:
+      imap->flags |= MU_IMAP_XSCRIPT_MASK(lev);
       break;
       
-    case MU_POP3_TRACE_CLR:
-      pop3->flags &= ~MU_POP3_XSCRIPT_MASK(lev);
+    case MU_IMAP_TRACE_CLR:
+      imap->flags &= ~MU_IMAP_XSCRIPT_MASK(lev);
       break;
       
-    case MU_POP3_TRACE_QRY:
-      if (pop3->flags & MU_POP3_XSCRIPT_MASK(lev))
+    case MU_IMAP_TRACE_QRY:
+      if (imap->flags & MU_IMAP_XSCRIPT_MASK(lev))
        break;
       return MU_ERR_NOENT;
       
@@ -139,11 +139,9 @@ mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev)
 }
 
 int
-_mu_pop3_xscript_level (mu_pop3_t pop3, int xlev)
+_mu_imap_xscript_level (mu_imap_t imap, int xlev)
 {
-  if (mu_stream_ioctl (pop3->carrier, MU_IOCTL_LEVEL, &xlev) == 0)
+  if (mu_stream_ioctl (imap->carrier, MU_IOCTL_LEVEL, &xlev) == 0)
     return xlev;
   return MU_XSCRIPT_NORMAL;
 }
-
-  
diff --git a/libproto/mbox/mbox.c b/libproto/mbox/mbox.c
index 0411c23..5c0dd1b 100644
--- a/libproto/mbox/mbox.c
+++ b/libproto/mbox/mbox.c
@@ -349,6 +349,7 @@ _msg_body_setup (mu_message_t msg, mbox_message_t mum)
       mu_body_set_stream (body, stream, msg);
       mu_body_set_size (body, mbox_body_size, msg);
       mu_body_set_lines (body, mbox_body_lines, msg);
+      mu_body_clear_modified (body);
       mu_message_set_body (msg, body, mum);
     }
   return status;
@@ -571,6 +572,8 @@ new_message (mu_mailbox_t mailbox, mbox_message_t mum, 
mu_message_t *pmsg)
   mum->message = msg;
   mu_message_set_mailbox (msg, mailbox, mum);
 
+  mu_message_clear_modified (msg);
+
   *pmsg = msg;
   
   return 0;
@@ -1149,37 +1152,18 @@ mbox_append_message (mu_mailbox_t mailbox, mu_message_t 
msg)
 
 
 static void
-mbox_reset (mu_mailbox_t mailbox, size_t dirty, int remove_deleted)
+mbox_reset (mu_mailbox_t mailbox)
 {
   mbox_data_t mud = mailbox->data;
   size_t i;
-  size_t dlast;
 
   mu_monitor_wrlock (mailbox->monitor);
-  for (i = dirty, dlast = mud->messages_count - 1; i <= dlast; i++)
+  for (i = 0; i < mud->messages_count; i++)
     {
       /* Clear all the references */
       mbox_message_t mum = mud->umessages[i];
-      if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags))
-       {
-         if ((i + 1) <= dlast)
-           {
-             /* Move all the pointers up.  So the message pointer
-                part of mum will be at the right position.  */
-             memmove (mud->umessages + i, mud->umessages + i + 1,
-                      (dlast - i) * sizeof (mum));
-             memset (mum, 0, sizeof (*mum));
-             /* We are not free()ing the useless mum, but instead
-                we put it back in the pool, to be reused.  */
-             mud->umessages[dlast] = mum;
-             dlast--;
-             /* Set mum to the new value after the memmove so it
-                gets cleared to.  */
-             mum = mud->umessages[i];
-           }
-         else
-           memset (mum, 0, sizeof (*mum));
-       }
+      mu_message_destroy (&mum->message, mum);
+      memset (mum, 0, sizeof (*mum));
       mum->envel_from = mum->envel_from_end = 0;
       mum->body = mum->body_end = 0;
       mum->header_lines = mum->body_lines = 0;
@@ -1187,7 +1171,7 @@ mbox_reset (mu_mailbox_t mailbox, size_t dirty, int 
remove_deleted)
   mu_monitor_unlock (mailbox->monitor);
   /* This resets the messages_count, the last argument 0 means
      not to send event notification.  */
-  mbox_scan0 (mailbox, dirty, NULL, 0);
+  mbox_scan0 (mailbox, 1, NULL, 0);
 }
 
 static int
@@ -1434,7 +1418,7 @@ mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted)
       mu_stream_destroy (&tempstr);
       
       if (status == 0)
-       mbox_reset (mailbox, dirty, remove_deleted);
+       mbox_reset (mailbox);
     }
   if (mailbox->locker)
     mu_locker_unlock (mailbox->locker);
diff --git a/libproto/mbox/mboxscan.c b/libproto/mbox/mboxscan.c
index 3a35e6f..90f4a6b 100644
--- a/libproto/mbox/mboxscan.c
+++ b/libproto/mbox/mboxscan.c
@@ -34,6 +34,8 @@
 
 #include <stdlib.h>
 #include <mbox0.h>
+#include <mailutils/cctype.h>
+#include <mailutils/cstr.h>
 
 /* Parsing.
    The approach is to detect the "From " as start of a new message, give the
@@ -279,6 +281,26 @@ do                                                         
                  \
  && (buf[5] == 'S' || buf[5] == 's')                                          \
  && (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t'))
 
+#define IS_X_UID(buf) (                                                \
+ (buf[0] == 'X' || buf[0] == 'x')                              \
+  && buf[1] == '-'                                             \
+  && (buf[2] == 'U' || buf[2] == 'u')                          \
+  && (buf[3] == 'I' || buf[3] == 'i')                          \
+  && (buf[4] == 'D' || buf[4] == 'd')                          \
+  && (buf[5] == ':' || buf[5] == ' ' || buf[5] == '\t'))
+#define IS_X_IMAPBASE(buf) (                                   \
+ (buf[0] == 'X' || buf[0] == 'x')                              \
+  && buf[1] == '-'                                             \
+  && (buf[2] == 'I' || buf[2] == 'i')                          \
+  && (buf[3] == 'M' || buf[3] == 'm')                          \
+  && (buf[4] == 'A' || buf[4] == 'a')                          \
+  && (buf[5] == 'P' || buf[5] == 'p')                          \
+  && (buf[6] == 'B' || buf[6] == 'b')                          \
+  && (buf[7] == 'A' || buf[7] == 'a')                          \
+  && (buf[8] == 'S' || buf[8] == 's')                          \
+  && (buf[9] == 'E' || buf[9] == 'e')                          \
+  && (buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t'))
+
 #define MBOX_SCAN_NOTIFY 0x1
 #define MBOX_SCAN_ONEMSG 0x2
 
@@ -298,7 +320,7 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
   int newline;
   size_t n = 0;
   mu_stream_t stream;
-  size_t min_uid = 0;
+  size_t min_uid = 1;
   int zn, isfrom = 0;
   char *temp;
   
@@ -345,9 +367,9 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
                  mum->body_end = total - n - newline;
                  mum->body_lines = --lines - newline;
 
-                 if (mum->uid <= min_uid)
+                 if (mum->uid < min_uid)
                    {
-                     mum->uid = ++min_uid;
+                     mum->uid = min_uid++;
                      /* Note that modification for when expunging.  */
                      mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
                    }
@@ -370,13 +392,32 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
              mum->attr_flags = 0;
              lines = 0;
            }
-         else if (ISSTATUS(buf))
+         else if (ISSTATUS (buf))
            {
              ATTRIBUTE_SET(buf, mum, 'r', 'R', MU_ATTRIBUTE_READ);
              ATTRIBUTE_SET(buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN);
              ATTRIBUTE_SET(buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED);
              ATTRIBUTE_SET(buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED);
            }
+         else if (IS_X_UID (buf))
+           {
+             char *p;
+             unsigned long n = strtoul (buf + 6, &p, 10);
+             if (*p == 0 || mu_isspace (*p))
+               mum->uid = min_uid = n;
+           }
+         else if (mud->messages_count == 1 && IS_X_IMAPBASE (buf))
+           {
+             char *p;
+             unsigned long n = strtoul (buf + 11, &p, 10);
+             if (mu_isspace (*p))
+               mud->uidvalidity = n;
+             n = strtoul (mu_str_skip_cset (p, " \t"), &p, 10);
+             if (*p == 0 || mu_isspace (*p))
+               mud->uidnext = n;
+             else
+               mud->uidvalidity = 0;
+           }
        }
 
       /* Body.  */
@@ -410,9 +451,9 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t 
mum,
       mum->body_end = total - newline;
       mum->body_lines = lines - newline;
 
-      if (mum->uid <= min_uid)
+      if (mum->uid < min_uid)
        {
-         mum->uid = ++min_uid;
+         mum->uid = min_uid++;
          /* Note that modification for when expunging.  */
          mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
        }
@@ -498,7 +539,7 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t 
*pcount, int do_notif)
        }
     }
       
-  if (mud->messages_count > 0 && min_uid >= mud->uidnext)
+  if (mud->messages_count > 0 && min_uid > mud->uidnext)
     {
       mum = mud->umessages[0];
       mud->uidnext = min_uid + 1;
diff --git a/libproto/pop/Makefile.am b/libproto/pop/Makefile.am
index 749e515..258f8b7 100644
--- a/libproto/pop/Makefile.am
+++ b/libproto/pop/Makefile.am
@@ -13,7 +13,7 @@
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
-## along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. 
+## along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>.
 
 INCLUDES = @MU_LIB_COMMON_INCLUDES@
 
diff --git a/libproto/pop/pop3_carrier.c b/libproto/pop/pop3_carrier.c
index 265669d..b793be4 100644
--- a/libproto/pop/pop3_carrier.c
+++ b/libproto/pop/pop3_carrier.c
@@ -55,6 +55,7 @@ mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier)
   if (pcarrier == NULL)
     return MU_ERR_OUT_PTR_NULL;
 
+  mu_stream_ref (pop3->carrier);
   *pcarrier = pop3->carrier;
   return 0;
 }
diff --git a/libproto/pop/pop3_response.c b/libproto/pop/pop3_response.c
index 63ecc7a..d56cad1 100644
--- a/libproto/pop/pop3_response.c
+++ b/libproto/pop/pop3_response.c
@@ -67,6 +67,13 @@ mu_pop3_response (mu_pop3_t pop3, size_t *pnread)
   else if (pop3->ackbuf)
     n = strlen (pop3->ackbuf);
 
+  if (n < 3)
+    status = MU_ERR_BADREPLY;
+  else if (strncmp (pop3->ackbuf, "-ERR", 4) == 0)
+    status = MU_ERR_REPLY;
+  else if (strncmp (pop3->ackbuf, "+OK", 3))
+    status = MU_ERR_BADREPLY;
+  
   if (pnread)
     *pnread = n;
   return status;
diff --git a/mu/Makefile.am b/mu/Makefile.am
index 52ab78c..dfd2c44 100644
--- a/mu/Makefile.am
+++ b/mu/Makefile.am
@@ -18,16 +18,24 @@
 bin_PROGRAMS = mu
 dist_bin_SCRIPTS = mailutils-config
 
+IDLE_MODULES=
+
 if MU_COND_SUPPORT_POP
  POP_C=pop.c
+else
+ IDLE_MODULES+=pop.c
 endif
 
-EXTRA_DIST=pop.c mu-setup.h mu-setup.c mu-setup.awk
-BUILT_SOURCES=mu-setup.h mu-setup.c
+if MU_COND_SUPPORT_IMAP
+ IMAP_C=imap.c
+else
+ IDLE_MODULES+=imap.c
+endif
 
 MODULES = \
  acl.c\
  cflags.c\
+ $(IMAP_C)\
  filter.c\
  flt2047.c\
  help.c\
@@ -39,9 +47,11 @@ MODULES = \
 
 mu_SOURCES = \
  dispatch.c\
+ getarg.c\
  mu.h\
  mu.c\
  shell.c\
+ verbose.c\
  $(MODULES)
 
 mu_LDADD = \
@@ -68,8 +78,10 @@ AM_CPPFLAGS = \
   -DPYTHON_LIBS="\"$(PYTHON_LIBS)\"" \
   -DI18NLIBS="\"$(LIBINTL)\""
 
-mu-setup.h: Makefile.am $(MODULES)
-       $(AM_V_GEN)$(AWK) -f $(top_srcdir)/mu/mu-setup.awk -v mode=h $(MODULES) 
> mu-setup.h
+mu-setup.h: Makefile.am $(MODULES) $(IDLE_MODULES) 
+       $(AM_V_GEN)$(AWK) -f $(top_srcdir)/mu/mu-setup.awk -v mode=h \
+           $(MODULES) $(IDLE_MODULES) > mu-setup.h
 
 mu-setup.c: Makefile.am $(MODULES)
-       $(AM_V_GEN)$(AWK) -f $(top_srcdir)/mu/mu-setup.awk -v mode=c $(MODULES) 
> mu-setup.c
+       $(AM_V_GEN)$(AWK) -f $(top_srcdir)/mu/mu-setup.awk -v mode=c \
+           $(MODULES) $(IDLE_MODULES) > mu-setup.c
diff --git a/mu/cflags.c b/mu/getarg.c
similarity index 50%
copy from mu/cflags.c
copy to mu/getarg.c
index ea510da..f86cc96 100644
--- a/mu/cflags.c
+++ b/mu/getarg.c
@@ -18,36 +18,56 @@
 # include <config.h>
 #endif
 #include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
 #include <mailutils/mailutils.h>
-#include <mailutils/libcfg.h>
-#include <argp.h>
-
-static char cflags_doc[] = N_("mu cflags - show compiler options");
-char cflags_docstring[] = N_("show compiler options");
-
-static struct argp cflags_argp = {
-  NULL,
-  NULL,
-  NULL,
-  cflags_doc,
-  NULL,
-  NULL,
-  NULL
-};
+#include "mu.h"
 
 int
-mutool_cflags (int argc, char **argv)
+get_bool (const char *str, int *pb)
 {
-  if (argp_parse (&cflags_argp, argc, argv, ARGP_IN_ORDER, NULL, NULL))
+  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
     return 1;
-  printf ("%s\n", COMPILE_FLAGS);
+
   return 0;
 }
 
-/*
-  MU Setup: cflags
-  mu-handler: mutool_cflags
-  mu-docstring: cflags_docstring
-  End MU Setup:
-*/
+int
+get_port (const char *port_str, int *pn)
+{
+  short port_num;
+  long num;
+  char *p;
+  
+  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
+    {
+      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;
+}
 
diff --git a/mu/imap.c b/mu/imap.c
new file mode 100644
index 0000000..764547e
--- /dev/null
+++ b/mu/imap.c
@@ -0,0 +1,519 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <mailutils/mailutils.h>
+#include <mailutils/imap.h>
+#include "mu.h"
+#include "argp.h"
+#include "xalloc.h"
+
+static char imap_doc[] = N_("mu imap - IMAP4 client shell.");
+char imap_docstring[] = N_("IMAP4 client shell");
+static char imap_args_doc[] = "";
+
+static struct argp_option imap_options[] = {
+  { NULL }
+};
+
+static error_t
+imap_parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+static struct argp imap_argp = {
+  imap_options,
+  imap_parse_opt,
+  imap_args_doc,
+  imap_doc,
+  NULL,
+  NULL,
+  NULL
+};
+
+
+static mu_imap_t imap;
+
+static enum mu_imap_state
+current_imap_state ()
+{
+  int state;
+  if (imap == NULL)
+    state = MU_IMAP_STATE_INIT;
+  else
+    {
+      mu_imap_state (imap, &state);
+      if (state == MU_IMAP_STATE_LOGOUT)
+       state = MU_IMAP_STATE_INIT;
+    }
+  return state;
+}
+
+
+static void
+imap_set_verbose ()
+{
+  if (imap)
+    {
+      if (QRY_VERBOSE ())
+       mu_imap_trace (imap, MU_IMAP_TRACE_SET);
+      else
+       mu_imap_trace (imap, MU_IMAP_TRACE_CLR);
+    }
+}
+
+void
+imap_set_verbose_mask ()
+{
+  if (imap)
+    {
+      mu_imap_trace_mask (imap, QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE)
+                                 ? MU_IMAP_TRACE_SET : MU_IMAP_TRACE_CLR,
+                             MU_XSCRIPT_SECURE);
+      mu_imap_trace_mask (imap, QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD)
+                                 ? MU_IMAP_TRACE_SET : MU_IMAP_TRACE_CLR,
+                             MU_XSCRIPT_PAYLOAD);
+    }
+}
+
+static int
+com_verbose (int argc, char **argv)
+{
+  return shell_verbose (argc, argv,
+                       imap_set_verbose, imap_set_verbose_mask);
+  
+}
+
+static int connect_argc;
+static char **connect_argv;
+#define host connect_argv[0]
+static int port = MU_IMAP_DEFAULT_PORT;
+
+static char *username;
+
+static void
+imap_prompt_env ()
+{
+  enum mu_imap_state state = current_imap_state ();
+  if (!mutool_prompt_env)
+    mutool_prompt_env = xcalloc (2*7 + 1, sizeof(mutool_prompt_env[0]));
+
+  mutool_prompt_env[0] = "user";
+  mutool_prompt_env[1] = (state >= MU_IMAP_STATE_AUTH && username) ?
+                           username : "[nouser]";
+
+  mutool_prompt_env[2] = "host"; 
+  mutool_prompt_env[3] = connect_argv ? host : "[nohost]";
+
+  mutool_prompt_env[4] = "program-name";
+  mutool_prompt_env[5] = (char*) mu_program_name;
+
+  mutool_prompt_env[6] = "canonical-program-name";
+  mutool_prompt_env[7] = "mu";
+
+  mutool_prompt_env[8] = "package";
+  mutool_prompt_env[9] = PACKAGE;
+
+  mutool_prompt_env[10] = "version";
+  mutool_prompt_env[11] = PACKAGE_VERSION;
+
+  mutool_prompt_env[12] = "status";
+  if (mu_imap_state_str (state, (const char **) &mutool_prompt_env[13]))
+    mutool_prompt_env[12] = NULL;
+
+  mutool_prompt_env[14] = NULL;
+}
+
+
+static int
+com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
+{
+  if (imap)
+    {
+      mu_imap_disconnect (imap);
+      mu_imap_destroy (&imap);
+      
+      mu_argcv_free (connect_argc, connect_argv);
+      connect_argc = 0;
+      connect_argv = NULL;
+      imap_prompt_env ();
+    }
+  return 0;
+}
+
+static int
+com_connect (int argc, char **argv)
+{
+  int status;
+  int n = 0;
+  int tls = 0;
+  int i = 1;
+  enum mu_imap_state state;
+  
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "-tls") == 0)
+       {
+         if (WITH_TLS)
+           tls = 1;
+         else
+           {
+             mu_error ("TLS not supported");
+             return 0;
+           }
+       }
+      else
+       break;
+    }
+
+  argc -= i;
+  argv += i;
+  
+  if (argc >= 2)
+    {
+      if (get_port (argv[1], &n))
+       return 0;
+    }
+  else if (tls)
+    n = MU_IMAP_DEFAULT_SSL_PORT;
+  else
+    n = MU_IMAP_DEFAULT_PORT;
+
+  state = current_imap_state ();
+  
+  if (state != MU_IMAP_STATE_INIT)
+    com_disconnect (0, NULL);
+  
+  status = mu_imap_create (&imap);
+  if (status == 0)
+    {
+      mu_stream_t tcp;
+
+      if (QRY_VERBOSE ())
+       {
+         imap_set_verbose ();
+         imap_set_verbose_mask ();
+       }
+      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_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_imap_set_carrier (imap, tcp);
+         status = mu_imap_connect (imap);
+         if (status)
+           {
+             const char *err;
+
+             mu_error ("Failed to connect: %s", mu_strerror (status));
+             if (mu_imap_strerror (imap, &err))
+               mu_error ("server response: %s", err);
+             mu_imap_destroy (&imap);
+           }
+       }
+      else
+       mu_imap_destroy (&imap);
+    }
+  else
+    mu_error ("Failed to create imap: %s", mu_strerror (status));
+  
+  if (!status)
+    {
+      connect_argc = argc;
+      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;
+    
+      imap_prompt_env ();
+    }
+  
+  return status;
+}
+
+static int
+com_logout (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
+{
+  int status = 0;
+  if (imap)
+    {
+      if (mu_imap_logout (imap) == 0)
+       {
+         status = com_disconnect (0, NULL);
+       }
+      else
+       {
+         mu_stream_printf (mustrout, "Try 'exit' to leave %s\n",
+                           mu_program_name);
+       }
+    }
+  else
+    mu_stream_printf (mustrout, "Try 'exit' to leave %s\n", mu_program_name);
+  return status;
+}
+
+static int
+com_capability (int argc, char **argv)
+{
+  mu_iterator_t iterator = NULL;
+  int status = 0;
+  int reread = 0;
+  int i = 1;
+  
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "-reread") == 0)
+       reread = 1;
+      else
+       break;
+    }
+
+  if (i < argc)
+    {
+      if (reread)
+       {
+         status = mu_imap_capability (imap, 1, NULL);
+         if (status)
+           return status;
+       }
+      for (; i < argc; i++)
+       {
+         const char *elt;
+         int rc = mu_imap_capability_test (imap, argv[i], &elt);
+         switch (rc)
+           {
+           case 0:
+             if (*elt)
+               mu_stream_printf (mustrout, "%s: %s\n", argv[i], elt);
+             else
+               mu_stream_printf (mustrout, "%s is set\n", argv[i]);
+             break;
+
+           case MU_ERR_NOENT:
+             mu_stream_printf (mustrout, "%s is not set\n", argv[i]);
+             break;
+
+           default:
+             return rc;
+           }
+       }
+    }
+  else
+    {
+      status = mu_imap_capability (imap, reread, &iterator);
+
+      if (status == 0)
+       {
+         for (mu_iterator_first (iterator);
+              !mu_iterator_is_done (iterator); mu_iterator_next (iterator))
+           {
+             char *capa = NULL;
+             mu_iterator_current (iterator, (void **) &capa);
+             mu_stream_printf (mustrout, "CAPA: %s\n", capa ? capa : "");
+           }
+         mu_iterator_destroy (&iterator);
+       }
+    }
+  return status;
+}
+
+static int
+com_login (int argc, char **argv)
+{
+  int status;
+  char *pwd, *passbuf = NULL;
+
+  if (argc == 2)
+    {
+      if (!mutool_shell_interactive)
+       {
+         mu_error (_("login: password required"));
+         return 1;
+       }
+      status = mu_getpass (mustrin, mustrout, "Password:", &passbuf);
+      if (status)
+       return status;
+      pwd = passbuf;
+    }
+  else
+    pwd = argv[2];
+
+  status = mu_imap_login (imap, argv[1], pwd);
+  memset (pwd, 0, strlen (pwd));
+  free (passbuf);
+  if (status == 0)
+    imap_prompt_env ();
+  else
+    {
+      const char *str;
+      
+      mu_error ("authentication failed: %s", mu_strerror (status));
+      if (mu_imap_strerror (imap, &str) == 0)
+       mu_error ("server reply: %s", str);
+    }
+  return 0;
+}
+
+
+static int
+_print_id (void *item, void *data)
+{
+  const char *id = item;
+  mu_stream_printf (mustrout, "ID: %s %s\n", id, id + strlen (id) + 1);
+  return 0;
+}
+
+static int
+com_id (int argc, char **argv)
+{
+  mu_list_t list;
+  char *test = NULL;
+  int status;
+  
+  argv++;
+  if (argv[0] && strcmp (argv[0], "-test") == 0)
+    {
+      argv++;
+      if (argv[0] == NULL)
+       {
+         mu_error ("id -test requires an argument");
+         return 0;
+       }
+      test = argv[0];
+      argv++;
+    }
+  
+  status = mu_imap_id (imap, argv + 1, &list);
+  if (status == 0)
+    {
+      if (test)
+       {
+         const char *res;
+         int rc = mu_list_locate (list, test, (void*)&res);
+
+         switch (rc)
+           {
+           case 0:
+             mu_stream_printf (mustrout, "%s: %s\n", test,
+                               res + strlen (res) + 1);
+             break;
+             
+           case MU_ERR_NOENT:
+             mu_stream_printf (mustrout, "%s is not set\n", test);
+             break;
+
+           default:
+             return rc;
+           }
+       }
+      else
+       mu_list_do (list, _print_id, NULL);
+      mu_list_destroy (&list);
+    }
+  return status;
+}
+
+
+struct mutool_command imap_comtab[] = {
+  { "capability", 1, -1, com_capability,
+    /* TRANSLATORS: -reread is a keyword; do not translate. */
+    N_("[-reread] [NAME...]"),
+    N_("list server capabilities") },
+  { "verbose",    1, 4, com_verbose,
+    "[on|off|mask|unmask] [secure [payload]]",
+    N_("control the protocol tracing") },
+  { "connect",    1, 4, com_connect,
+    /* TRANSLATORS: --tls is a keyword. */
+    N_("[-tls] HOSTNAME [PORT]"),
+    N_("open connection") },
+  { "disconnect", 1, 1,
+    com_disconnect,
+    NULL,
+    N_("close connection") },
+  { "login",        2, 3, com_login,
+    N_("USER [PASS]"),
+    N_("login to the server") },
+  { "logout",       1, 1, com_logout,
+    NULL,
+    N_("quit imap session") },
+  { "id",           1, -1, com_id,
+    N_("[-test KW] [ARG [ARG...]]"),
+    N_("send ID command") },
+  { "quit",         1, 1, com_logout,
+    NULL,
+    N_("same as `logout'") },
+  { NULL }
+};
+
+int
+mutool_imap (int argc, char **argv)
+{
+  int index;
+
+  if (argp_parse (&imap_argp, argc, argv, ARGP_IN_ORDER, &index, NULL))
+    return 1;
+
+  argc -= index;
+  argv += index;
+
+  if (argc)
+    {
+      mu_error (_("too many arguments"));
+      return 1;
+    }
+
+  /* Command line prompt */
+  mutool_shell_prompt = xstrdup ("imap> ");
+  imap_prompt_env ();
+  mutool_shell ("imap", imap_comtab);
+  return 0;
+}
+
+/*
+  MU Setup: imap
+  mu-handler: mutool_imap
+  mu-docstring: imap_docstring
+  mu-cond: ENABLE_IMAP
+  End MU Setup:
+*/
diff --git a/mu/mu-setup.awk b/mu/mu-setup.awk
index 5d261f1..637fb2e 100644
--- a/mu/mu-setup.awk
+++ b/mu/mu-setup.awk
@@ -55,7 +55,11 @@ END {
       print "extern int", setup[name,"handler"], "(int argc, char **argv);"
       print "extern char " setup[name,"docstring"] "[];"
     } else {
+      if (setup[name,"cond"])
+       print "#ifdef", setup[name,"cond"]
       print "{", "\"" name "\",", setup[name,"handler"] ",", 
setup[name,"docstring"], "},"
+      if (setup[name,"cond"])
+       print "#endif"
     }
   }
 }
diff --git a/mu/mu.h b/mu/mu.h
index d46bc41..01150ae 100644
--- a/mu/mu.h
+++ b/mu/mu.h
@@ -40,3 +40,21 @@ mu_stream_t mutool_open_pager (void);
 int mu_help (void);
 mutool_action_t dispatch_find_action (const char *name);
 char *dispatch_docstring (const char *text);
+
+
+#define VERBOSE_MASK(n) (1<<((n)+1))
+#define SET_VERBOSE_MASK(n) (shell_verbose_flags |= VERBOSE_MASK (n))
+#define CLR_VERBOSE_MASK(n) (shell_verbose_flags &= ~VERBOSE_MASK (n))
+#define QRY_VERBOSE_MASK(n) (shell_verbose_flags & VERBOSE_MASK (n))
+#define HAS_VERBOSE_MASK(n) (shell_verbose_flags & ~1)
+#define SET_VERBOSE() (shell_verbose_flags |= 1)
+#define CLR_VERBOSE() (shell_verbose_flags &= ~1)
+#define QRY_VERBOSE() (shell_verbose_flags & 1)
+
+extern int shell_verbose_flags;
+int shell_verbose (int argc, char **argv,
+                  void (*set_verbose) (void), void (*set_mask) (void));
+
+
+int get_bool (const char *str, int *pb);
+int get_port (const char *port_str, int *pn);
diff --git a/mu/pop.c b/mu/pop.c
index bf2c938..5a77e56 100644
--- a/mu/pop.c
+++ b/mu/pop.c
@@ -19,9 +19,7 @@
 #endif
 #include <stdlib.h>
 #include <string.h>
-#include <termios.h>
 #include <unistd.h>
-#include <netdb.h>
 #include <mailutils/mailutils.h>
 #include "mu.h"
 #include "argp.h"
@@ -56,67 +54,8 @@ static struct argp pop_argp = {
   NULL
 };
 
-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
-    return 1;
-
-  return 0;
-}
-
-int
-get_port (const char *port_str, int *pn)
-{
-  short port_num;
-  long num;
-  char *p;
-  
-  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
-    {
-      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;
-}
-
-
 /* Global handle for pop3.  */
-mu_pop3_t pop3;
-
-/* Flag if verbosity is needed.  */
-int verbose;
-#define VERBOSE_MASK(n) (1<<((n)+1))
-#define SET_VERBOSE_MASK(n) (verbose |= VERBOSE_MASK (n))
-#define CLR_VERBOSE_MASK(n) (verbose &= VERBOSE_MASK (n))
-#define QRY_VERBOSE_MASK(n) (verbose & VERBOSE_MASK (n))
-#define HAS_VERBOSE_MASK(n) (verbose & ~1)
-#define SET_VERBOSE() (verbose |= 1)
-#define CLR_VERBOSE() (verbose &= ~1)
-#define QRY_VERBOSE() (verbose & 1)
+static mu_pop3_t pop3;
 
 enum pop_session_status
   {
@@ -125,15 +64,15 @@ enum pop_session_status
     pop_session_logged_in
   };
 
-enum pop_session_status pop_session_status;
+static enum pop_session_status pop_session_status;
 
-int connect_argc;
-char **connect_argv;
+static int connect_argc;
+static char **connect_argv;
 
 /* Host we are connected to. */
 #define host connect_argv[0]
-int port = 110;
-char *username;
+static int port = 110;
+static char *username;
 
 const char *
 pop_session_str (enum pop_session_status stat)
@@ -185,63 +124,27 @@ pop_prompt_env ()
 }
 
 
-static int
-string_to_xlev (const char *name, int *pv)
-{
-  if (strcmp (name, "secure") == 0)
-    *pv = MU_XSCRIPT_SECURE;
-  else if (strcmp (name, "payload") == 0)
-    *pv = MU_XSCRIPT_PAYLOAD;
-  else
-    return 1;
-  return 0;
-}
-
-static int
-change_verbose_mask (int set, int argc, char **argv)
-{
-  int i;
-  
-  for (i = 0; i < argc; i++)
-    {
-      int lev;
-      
-      if (string_to_xlev (argv[i], &lev))
-       {
-         mu_error ("unknown level: %s", argv[i]);
-         return 1;
-       }
-      if (set)
-       SET_VERBOSE_MASK (lev);
-      else
-       CLR_VERBOSE_MASK (lev);
-    }
-  return 0;
-}
-
-void
-set_verbose (mu_pop3_t p)
+static void
+pop_set_verbose (void)
 {
-  if (p)
+  if (pop3)
     {
       if (QRY_VERBOSE ())
-       {
-         mu_pop3_trace (p, MU_POP3_TRACE_SET);
-       }
+       mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
       else
-       mu_pop3_trace (p, MU_POP3_TRACE_CLR);
+       mu_pop3_trace (pop3, MU_POP3_TRACE_CLR);
     }
 }
 
-void
-set_verbose_mask (mu_pop3_t p)
+static void
+pop_set_verbose_mask (void)
 {
-  if (p)
+  if (pop3)
     {
-      mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE)
+      mu_pop3_trace_mask (pop3, QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE)
                                  ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
                              MU_XSCRIPT_SECURE);
-      mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD)
+      mu_pop3_trace_mask (pop3, QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD)
                                  ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
                              MU_XSCRIPT_PAYLOAD);
     }
@@ -250,50 +153,8 @@ set_verbose_mask (mu_pop3_t p)
 static int
 com_verbose (int argc, char **argv)
 {
-  if (argc == 1)
-    {
-      if (QRY_VERBOSE ())
-       {
-         mu_stream_printf (mustrout, "verbose is on");
-         if (HAS_VERBOSE_MASK ())
-           {
-             char *delim = " (";
-           
-             if (QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE))
-               {
-                 mu_stream_printf (mustrout, "%ssecure", delim);
-                 delim = ", ";
-               }
-             if (QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD))
-               mu_stream_printf (mustrout, "%spayload", delim);
-             mu_stream_printf (mustrout, ")");
-           }
-         mu_stream_printf (mustrout, "\n");
-       }
-      else
-       mu_stream_printf (mustrout, "verbose is off\n");
-    }
-  else
-    {
-      int bv;
-
-      if (get_bool (argv[1], &bv) == 0)
-       {
-         verbose |= bv;
-         if (argc > 2)
-           change_verbose_mask (verbose, argc - 2, argv + 2);
-         set_verbose (pop3);
-       }
-      else if (strcmp (argv[1], "mask") == 0)
-       change_verbose_mask (1, argc - 2, argv + 2);
-      else if (strcmp (argv[1], "unmask") == 0)
-       change_verbose_mask (0, argc - 2, argv + 2);
-      else
-       mu_error ("unknown subcommand");
-      set_verbose_mask (pop3);
-    }
-
-  return 0;
+  return shell_verbose (argc, argv,
+                       pop_set_verbose, pop_set_verbose_mask);
 }
 
 static int
@@ -655,8 +516,8 @@ com_connect (int argc, char **argv)
 
       if (QRY_VERBOSE ())
        {
-         set_verbose (pop3);
-         set_verbose_mask (pop3);
+         pop_set_verbose ();
+         pop_set_verbose_mask ();
        }
       status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
       if (status == 0)
@@ -779,7 +640,7 @@ struct mutool_command pop_comtab[] = {
     N_("NAME"),
     N_("send login") },
   { "verbose",    1, 4, com_verbose,
-    "[on|off|mask|unmask] [secret [payload]]",
+    "[on|off|mask|unmask] [secure [payload]]",
     N_("control the protocol tracing") },
   { NULL }
 };
@@ -813,5 +674,6 @@ mutool_pop (int argc, char **argv)
   MU Setup: pop
   mu-handler: mutool_pop
   mu-docstring: pop_docstring
+  mu-cond: ENABLE_POP
   End MU Setup:
 */
diff --git a/mu/verbose.c b/mu/verbose.c
new file mode 100644
index 0000000..e043abe
--- /dev/null
+++ b/mu/verbose.c
@@ -0,0 +1,114 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/mailutils.h>
+#include "mu.h"
+
+/* Manipulations with verbosity flags, which are common for pop and imap. */
+int shell_verbose_flags;
+
+static int
+string_to_xlev (const char *name, int *pv)
+{
+  if (strcmp (name, "secure") == 0)
+    *pv = MU_XSCRIPT_SECURE;
+  else if (strcmp (name, "payload") == 0)
+    *pv = MU_XSCRIPT_PAYLOAD;
+  else
+    return 1;
+  return 0;
+}
+
+static int
+change_verbose_mask (int set, int argc, char **argv)
+{
+  int i;
+  
+  for (i = 0; i < argc; i++)
+    {
+      int lev;
+      
+      if (string_to_xlev (argv[i], &lev))
+       {
+         mu_error ("unknown level: %s", argv[i]);
+         return 1;
+       }
+      if (set)
+       SET_VERBOSE_MASK (lev);
+      else
+       CLR_VERBOSE_MASK (lev);
+    }
+  return 0;
+}
+
+int
+shell_verbose (int argc, char **argv,
+              void (*set_verbose) (void), void (*set_mask) (void))
+{
+  if (argc == 1)
+    {
+      if (QRY_VERBOSE ())
+       {
+         mu_stream_printf (mustrout, "verbose is on");
+         if (HAS_VERBOSE_MASK ())
+           {
+             char *delim = " (";
+           
+             if (QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE))
+               {
+                 mu_stream_printf (mustrout, "%ssecure", delim);
+                 delim = ", ";
+               }
+             if (QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD))
+               mu_stream_printf (mustrout, "%spayload", delim);
+             mu_stream_printf (mustrout, ")");
+           }
+         mu_stream_printf (mustrout, "\n");
+       }
+      else
+       mu_stream_printf (mustrout, "verbose is off\n");
+    }
+  else
+    {
+      int bv;
+
+      if (get_bool (argv[1], &bv) == 0)
+       {
+         if (bv)
+           SET_VERBOSE ();
+         else
+           CLR_VERBOSE ();
+         if (argc > 2)
+           change_verbose_mask (shell_verbose_flags, argc - 2, argv + 2);
+         set_verbose ();
+       }
+      else if (strcmp (argv[1], "mask") == 0)
+       change_verbose_mask (1, argc - 2, argv + 2);
+      else if (strcmp (argv[1], "unmask") == 0)
+       change_verbose_mask (0, argc - 2, argv + 2);
+      else
+       mu_error ("unknown subcommand");
+      set_mask ();
+    }
+
+  return 0;
+}
+
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index b312f4d..9db984b 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -7,3 +7,4 @@ testsuite.log
 mbdel
 mimetest
 smtpsend
+ufms
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 5c243b1..6e36255 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -42,7 +42,8 @@ INCLUDES = @MU_LIB_COMMON_INCLUDES@
 noinst_PROGRAMS = \
  mbdel\
  mimetest\
- smtpsend
+ smtpsend\
+ ufms
 
 LDADD = \
  ${MU_LIB_MBOX}\
@@ -68,6 +69,7 @@ smtpsend_LDADD = \
 TESTSUITE_AT = \
  mbdel.at\
  mime.at\
+ ufms.at\
  testsuite.at
 
 TESTSUITE = $(srcdir)/testsuite
diff --git a/testsuite/testsuite.at b/testsuite/testsuite.at
index 7bb3e05..63553e7 100644
--- a/testsuite/testsuite.at
+++ b/testsuite/testsuite.at
@@ -20,3 +20,4 @@ AT_INIT
 
 m4_include([mime.at])
 m4_include([mbdel.at])
+m4_include([ufms.at])
diff --git a/readmsg/tests/twomsg.at b/testsuite/ufms.at
similarity index 69%
copy from readmsg/tests/twomsg.at
copy to testsuite/ufms.at
index 5de48b1..2811c5f 100644
--- a/readmsg/tests/twomsg.at
+++ b/testsuite/ufms.at
@@ -1,5 +1,5 @@
 # This file is part of GNU Mailutils. -*- Autotest -*-
-# Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+# Copyright (C) 2010 Free Software Foundation, Inc.
 #
 # GNU Mailutils is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
@@ -14,13 +14,29 @@
 # You should have received a copy of the GNU General Public License
 # along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>.
 
-READMSGTEST([readmsg 1 2],[twomsg],
-[1 2],
+# Check for "UNIX mbox 1st message symptom" bug.  See the description in
+# ufms.c, for a detailed description.
+
+AT_SETUP([UNIX mbox 1st message symptom])
+AT_KEYWORDS([mailbox mbox mbox-ufms ufms])
+AT_CHECK([
+MUT_MBCOPY($abs_top_srcdir/testsuite/spool/mbox1)
+ufms mbox:mbox1 || exit $?
+sed 's/^\(X-IMAPbase\): \([[0-9][0-9]*]\) \(.*\)/\1: UIDVALIDITY \3/' mbox1
+],
 [0],
-[Date: Fri, 28 Dec 2001 22:18:08 +0200
+[From address@hidden  Fri Dec 28 22:18:09 2001
+Received: (from address@hidden)
+       by nonexistent.net id fBSKI8N04906
+       for address@hidden; Fri, 28 Dec 2001 22:18:08 +0200
+Date: Fri, 28 Dec 2001 22:18:08 +0200
 From: Foo Bar <address@hidden>
+Message-Id: <address@hidden>
 To: Bar <address@hidden>
 Subject: Jabberwocky
+X-IMAPbase: UIDVALIDITY 6
+Status: R
+X-UID: 1
 
 `Twas brillig, and the slithy toves
 Did gyre and gimble in the wabe;
@@ -58,16 +74,7 @@ All mimsy were the borogoves,
 And the mome raths outgrabe.
 
 
-Date: Fri, 28 Dec 2001 23:28:08 +0200
-From: Bar <address@hidden>
-To: Foo Bar <address@hidden>
-Subject: Re: Jabberwocky
-
-It seems very pretty, but it's *rather* hard to understand!'
-Somehow it seems to fill my head with ideas -- only I don't
-exactly know what they are!  However, SOMEBODY killed SOMETHING:
-that's clear, at any rate...
-
-
 ])
 
+AT_CLEANUP
+
diff --git a/testsuite/ufms.c b/testsuite/ufms.c
new file mode 100644
index 0000000..e1c1c89
--- /dev/null
+++ b/testsuite/ufms.c
@@ -0,0 +1,100 @@
+/* ufms.c - a test of "UNIX mailbox first message symptom"
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   GNU Mailutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GNU Mailutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mailutils/mailutils.h>
+
+/* UFMS, or "UNIX mailbox first message symptom", is a bug that 
+   existed in all versions of Mailutils up to 2.2.1 and 2.9.90
+   as of 2010-11-07.
+
+   Due to improperly designed expunge routine, the body of the very
+   first message in a UNIX mailbox would get corrupted under certain
+   circumstances.  The following three lines would appear at the top
+   of the body:
+
+   -IMAPbase: X Y
+   Status: S
+   X-UID: Z
+
+   where (X, Y, Z are decimal numbers and S is a status string).
+
+   Prerequisites for triggering the bug:
+
+   1. Mailbox contains more than one message.
+   2. The first message does not carry X-IMAPbase and X-UID headers.
+
+   Recipe for triggering the bug:
+
+   1. Delete some messages.
+   2. Expunge the mailbox.
+   3. Modify attributes of the first message.
+   4. Flush your changes.
+*/   
+   
+
+int
+main (int argc, char **argv)
+{
+  mu_mailbox_t mbox;
+  size_t i, count;
+  mu_message_t msg;
+  mu_attribute_t attr;
+  
+  if (argc != 2)
+    {
+      fprintf (stderr, "usage: %s MBOX\n", argv[0]);
+      return 1;
+    }
+
+  mu_registrar_record (mu_mbox_record);
+
+  /* Open the mailbox */
+  MU_ASSERT (mu_mailbox_create (&mbox, argv[1]));
+  MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_RDWR));
+  mu_mailbox_messages_count (mbox, &count);
+  if (count < 2)
+    {
+      fprintf (stderr,
+              "%s: input mailbox should contain at least two messages\n",
+              argv[0]);
+      exit (1);
+    }
+  /* Delete all records except the first and expunge the mailbox. */
+  for (i = 2; i <= count; i++)
+    {
+      MU_ASSERT (mu_mailbox_get_message (mbox, i, &msg));
+      MU_ASSERT (mu_message_get_attribute (msg, &attr));
+      MU_ASSERT (mu_attribute_set_deleted (attr));
+    }
+  mu_mailbox_expunge (mbox);
+
+  /* Modify attributes on the remaining message and synch */
+  MU_ASSERT (mu_mailbox_get_message (mbox, 1, &msg));
+  MU_ASSERT (mu_message_get_attribute (msg, &attr));
+  MU_ASSERT (mu_attribute_set_read (attr));
+  mu_mailbox_sync (mbox);
+
+  /* Cleanup & exit */
+  mu_mailbox_close (mbox);
+  mu_mailbox_destroy (&mbox);
+  return 0;
+}


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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