[balsa] Add COMPRESS=DEFLATE IMAP extension support.



commit 49ce71edbc0cd63d092d5262d75e5057c50c9519
Author: Pawel Salek <pawsa damage localdomain>
Date:   Sun Jan 3 21:08:28 2010 +0100

    Add COMPRESS=DEFLATE IMAP extension support.
    
    * libbalsa/imap-server.c: enable compression by default.
    * libbalsa/imap/Makefile.am: add imap_compress.[hc]
    * libbalsa/imap/imap-commands.c: imap_cmd_exec returns ImapResponse.
    * libbalsa/imap/imap-handle.c: add COMPRESS=DEFLATE capability
    * libbalsa/imap/imap_compress.[ch]: support the extension.
    * libbalsa/imap/imap_tst.c: allow compression testing.
    * configure.in: zlib.h is unconditionally required.

 ChangeLog                     |    9 ++
 configure.in                  |    1 +
 libbalsa/imap-server.c        |   20 +++++
 libbalsa/imap/Makefile.am     |    2 +
 libbalsa/imap/imap-commands.c |    4 +-
 libbalsa/imap/imap-handle.c   |   37 +++++++--
 libbalsa/imap/imap-handle.h   |   11 ++-
 libbalsa/imap/imap_compress.c |  184 +++++++++++++++++++++++++++++++++++++++++
 libbalsa/imap/imap_compress.h |   40 +++++++++
 libbalsa/imap/imap_private.h  |   11 ++-
 libbalsa/imap/imap_tst.c      |   47 +++++++++--
 11 files changed, 342 insertions(+), 24 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index cac92a0..b69322b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-01-03  Pawel Salek
+
+	* libbalsa/imap-server.c: enable compression by default.
+	* libbalsa/imap/Makefile.am: add imap_compress.[hc]
+	* libbalsa/imap/imap-commands.c: imap_cmd_exec returns ImapResponse.
+	* libbalsa/imap/imap-handle.c: add COMPRESS=DEFLATE capability
+	* libbalsa/imap/imap_compress.[ch]: support the extension.
+	* libbalsa/imap/imap_tst.c: allow compression testing.
+
 2010-01-02  Peter Bloomfield
 
 	* src/balsa-mime-widget-text.c (balsa_mime_widget_new_text),
diff --git a/configure.in b/configure.in
index 8789b61..032d875 100644
--- a/configure.in
+++ b/configure.in
@@ -862,6 +862,7 @@ AC_STDC_HEADERS
 AC_DEFINE([_XOPEN_SOURCE],[500],[We strive for XOPEN compliance])
 AC_CHECK_DECLS([localtime_r, gmtime_r, ctime_r], [], [], [[#include <time.h>]])
 AC_CHECK_FUNCS([localtime_r gmtime_r ctime_r])
+AC_CHECK_HEADER([zlib.h],,AC_MSG_ERROR([zlib library required]))
 
 # more warnings.
 #
diff --git a/libbalsa/imap-server.c b/libbalsa/imap-server.c
index d43b954..77b303e 100644
--- a/libbalsa/imap-server.c
+++ b/libbalsa/imap-server.c
@@ -1,4 +1,23 @@
 /* -*-mode:c; c-basic-offset:4; -*- */
+/* Balsa E-Mail Client
+ * Copyright (C) 1997-2010 Stuart Parmenter and others,
+ *                         See the file AUTHORS for a list.
+ *
+ * This program 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 2, or (at your option) 
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+ * GNU General Public License for more details.
+ *  
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
+ * 02111-1307, USA.
+ */
 /*
   LibBalsaImapServer is a class for managing connections to one IMAP
   server. Idle connections are disconnected after a timeout, or when
@@ -353,6 +372,7 @@ lb_imap_server_info_new(LibBalsaServer *server)
 #else
     imap_handle_set_option(handle, IMAP_OPT_BINARY, TRUE);
 #endif
+    imap_handle_set_option(handle, IMAP_OPT_COMPRESS, TRUE);
     imap_handle_set_option(handle, IMAP_OPT_IDLE,
                            LIBBALSA_IMAP_SERVER(server)->use_idle);
     return info;
diff --git a/libbalsa/imap/Makefile.am b/libbalsa/imap/Makefile.am
index 6d8a3e2..cb7f780 100644
--- a/libbalsa/imap/Makefile.am
+++ b/libbalsa/imap/Makefile.am
@@ -21,6 +21,8 @@ libimap_a_SOURCES = \
 	imap-auth.h	\
 	imap-commands.c	\
 	imap-commands.h	\
+	imap_compress.c	\
+	imap_compress.h	\
 	imap-handle.c	\
 	imap-handle.h	\
 	imap_search.c	\
diff --git a/libbalsa/imap/imap-commands.c b/libbalsa/imap/imap-commands.c
index 16591f6..f8a4f52 100644
--- a/libbalsa/imap/imap-commands.c
+++ b/libbalsa/imap/imap-commands.c
@@ -1,5 +1,5 @@
 /* libimap library.
- * Copyright (C) 2003-2004 Pawel Salek.
+ * Copyright (C) 2003-2010 Pawel Salek.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -119,7 +119,7 @@ imap_check_capability(ImapMboxHandle* handle)
 {
   IMAP_REQUIRED_STATE3(handle, IMHS_CONNECTED, IMHS_AUTHENTICATED,
                        IMHS_SELECTED, FALSE);
-  if (imap_cmd_exec(handle, "CAPABILITY") != 0)
+  if (imap_cmd_exec(handle, "CAPABILITY") != IMR_OK)
     return FALSE;
 
   if (!(imap_mbox_handle_can_do(handle, IMCAP_IMAP4) ||
diff --git a/libbalsa/imap/imap-handle.c b/libbalsa/imap/imap-handle.c
index 7ae8b63..3e10d7b 100644
--- a/libbalsa/imap/imap-handle.c
+++ b/libbalsa/imap/imap-handle.c
@@ -1,5 +1,5 @@
 /* libimap library.
- * Copyright (C) 2003-2004 Pawel Salek.
+ * Copyright (C) 2003-2010 Pawel Salek.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -166,6 +166,8 @@ imap_mbox_handle_init(ImapMboxHandle *handle)
   handle->enable_binary    = 0;
   handle->enable_idle      = 1;
   mbox_view_init(&handle->mbox_view);
+
+  imap_compress_init(&handle->compress);
 #if defined(BALSA_USE_THREADS)
   pthread_mutex_init(&handle->mutex, NULL);
 #endif
@@ -234,10 +236,11 @@ void
 imap_handle_set_option(ImapMboxHandle *h, ImapOption opt, gboolean state)
 {
   switch(opt) {
-  case IMAP_OPT_ANONYMOUS: h->enable_anonymous = !!state; break;
+  case IMAP_OPT_ANONYMOUS:   h->enable_anonymous   = !!state; break;
+  case IMAP_OPT_BINARY:      h->enable_binary      = !!state; break;
   case IMAP_OPT_CLIENT_SORT: h->enable_client_sort = !!state; break;
-  case IMAP_OPT_BINARY:    h->enable_binary    = !!state; break;
-  case IMAP_OPT_IDLE:      h->enable_idle      = !!state; break;
+  case IMAP_OPT_COMPRESS:    h->enable_compress    = !!state; break;
+  case IMAP_OPT_IDLE:        h->enable_idle        = !!state; break;
   default: g_warning("imap_set_option: invalid option\n");
   }
 }
@@ -599,6 +602,11 @@ imap_mbox_handle_connect(ImapMboxHandle* ret, const char *host, int over_ssl)
 
   if( (rc=imap_mbox_connect(ret)) == IMAP_SUCCESS) {
     rc = imap_authenticate(ret);
+    if (rc == IMAP_SUCCESS) {
+      ImapResponse response = imap_compress(ret);
+      if ( !(response == IMR_NO || response == IMR_OK))
+        rc = IMAP_PROTOCOL_ERROR;
+    }
   }
 
   HANDLE_UNLOCK(ret);
@@ -635,13 +643,23 @@ imap_mbox_handle_reconnect(ImapMboxHandle* h, gboolean *readonly)
 
   if( (rc=imap_mbox_connect(h)) == IMAP_SUCCESS) {
     if( (rc = imap_authenticate(h)) == IMAP_SUCCESS) {
+      ImapResponse response;
       imap_mbox_resize_cache(h, 0); /* invalidate cache */
       mbox_view_dispose(&h->mbox_view); /* FIXME: recreate it here? */
 
-      if(h->mbox && 
-         imap_mbox_select_unlocked(h, h->mbox, readonly) != IMR_OK) {
-        rc = IMAP_SELECT_FAILED;
+      response = imap_compress(h);
+      if (response == IMR_OK || response == IMR_NO) {
+        rc = IMAP_SUCCESS;
+        if(h->mbox && 
+           imap_mbox_select_unlocked(h, h->mbox, readonly) != IMR_OK) {
+          rc = IMAP_SELECT_FAILED;
+        }
+
+      } else {
+        /* compression was apparently attempted but failed. */
+        rc = IMAP_PROTOCOL_ERROR;
       }
+
     }
   }
   HANDLE_UNLOCK(h);
@@ -1000,6 +1018,7 @@ imap_mbox_handle_finalize(GObject* gobject)
   g_free(handle->msg_cache); handle->msg_cache = NULL;
   g_array_free(handle->flag_cache, TRUE);
 
+  imap_compress_release(&handle->compress);
   HANDLE_UNLOCK(handle);
 #if defined(BALSA_USE_THREADS)
   pthread_mutex_destroy(&handle->mutex);
@@ -2285,7 +2304,9 @@ ir_capability_data(ImapMboxHandle *handle)
   static const char* capabilities[] = {
     "IMAP4", "IMAP4rev1", "STATUS",
     "AUTH=ANONYMOUS", "AUTH=CRAM-MD5", "AUTH=GSSAPI", "AUTH=PLAIN",
-    "ACL", "BINARY", "CHILDREN", "ESEARCH", "IDLE", "LITERAL+",
+    "ACL", "BINARY", "CHILDREN",
+    "COMPRESS=DEFLATE",
+    "ESEARCH", "IDLE", "LITERAL+",
     "LOGINDISABLED", "MULTIAPPEND", "NAMESPACE", "SASL-IR",
     "SCAN", "STARTTLS",
     "SORT", "THREAD=ORDEREDSUBJECT", "THREAD=REFERENCES",
diff --git a/libbalsa/imap/imap-handle.h b/libbalsa/imap/imap-handle.h
index 0e84bb0..02d94c0 100644
--- a/libbalsa/imap/imap-handle.h
+++ b/libbalsa/imap/imap-handle.h
@@ -65,19 +65,19 @@ typedef enum
   IMCAP_ACL,			/* RFC 2086: IMAP4 ACL extension */
   IMCAP_BINARY,                 /* RFC 3516 */
   IMCAP_CHILDREN,               /* RFC 3348 */
+  IMCAP_COMPRESS_DEFLATE,       /* RFC 4978 */
   IMCAP_ESEARCH,                /* RFC 4731 */
   IMCAP_IDLE,                   /* RFC 2177 */
   IMCAP_LITERAL,                /* RFC 2088 */
   IMCAP_LOGINDISABLED,		/* RFC 2595 */
   IMCAP_MULTIAPPEND,            /* RFC 3502 */
   IMCAP_NAMESPACE,              /* RFC 2342: IMAP4 Namespace */
-  IMCAP_SASLIR,                 /* imap-sasl-initial-response: SASL-IR */
+  IMCAP_SASLIR,                 /* RFC 4959 */
   IMCAP_SCAN,                   /* FIXME: RFC? */
   IMCAP_STARTTLS,		/* RFC 2595: STARTTLS */
   IMCAP_SORT,                   /* SORT and THREAD described at: */
-  IMCAP_THREAD_ORDEREDSUBJECT,
-  IMCAP_THREAD_REFERENCES,
-  /* http://www.ietf.org/internet-drafts/draft-ietf-imapext-sort-13.txt */
+  IMCAP_THREAD_ORDEREDSUBJECT,  /* RFC 5256 */
+  IMCAP_THREAD_REFERENCES,      
   IMCAP_UIDPLUS,                /* RFC 4315 */
   IMCAP_UNSELECT,               /* RFC 3691 */
   IMCAP_FETCHBODY,              /* basic imap implemented correctly by
@@ -90,7 +90,8 @@ typedef enum {
   IMAP_OPT_ANONYMOUS,   /**< try anonymous authentication */
   IMAP_OPT_CLIENT_SORT, /**< allow client-side sorting */
   IMAP_OPT_BINARY,      /**< enable binary=no-transfer-encoding msg transfer */
-  IMAP_OPT_IDLE         /**< enable IDLE */
+  IMAP_OPT_IDLE,        /**< enable IDLE */
+  IMAP_OPT_COMPRESS,    /**< enable COMPRESS */
 }  ImapOption;
 
 typedef struct _ImapMboxHandleClass ImapMboxHandleClass;
diff --git a/libbalsa/imap/imap_compress.c b/libbalsa/imap/imap_compress.c
new file mode 100644
index 0000000..06f1723
--- /dev/null
+++ b/libbalsa/imap/imap_compress.c
@@ -0,0 +1,184 @@
+/* libimap library.
+ * Copyright (C) 2003-2010 Pawel Salek.
+ *
+ * This program 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 2, or (at your option) 
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+ * GNU General Public License for more details.
+ *  
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
+ * 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <zlib.h>
+#include "siobuf.h"
+#include "imap-handle.h"
+#include "imap_private.h"
+
+/** Arbitrary - not really a useful one. */
+static const unsigned IMAP_COMPRESS_BUFFER_SIZE = 65536;
+
+static void
+imap_compress_cb(char **dstbuf, int *dstlen,
+                 const char *srcbuf, int srclen, void *arg)
+{
+  struct ImapCompressContext *icb = &((ImapMboxHandle*)arg)->compress;
+  int err;
+
+  *dstbuf = icb->out_buffer;
+
+  icb->out_stream.next_in  = (Bytef*)srcbuf;
+  icb->out_stream.avail_in = srclen;
+
+  icb->out_stream.next_out = (Byte*)*dstbuf;
+  icb->out_stream.avail_out = IMAP_COMPRESS_BUFFER_SIZE;
+
+  do {
+    if (icb->out_stream.avail_out ==0){
+      printf("Buffer reallocation not implemented, aborting.\n");
+      /* FIXME1 */
+      break;
+    }
+    /* check sizes here */
+    err = deflate(&icb->out_stream, Z_SYNC_FLUSH);
+    if ( !(err == Z_OK || err == Z_STREAM_END || err == Z_BUF_ERROR) ) {
+      fprintf(stderr, "deflate error1 %d\n", err);
+      /* FIXME - break the connection here, no point in continuing. */
+    }
+  } while (icb->out_stream.avail_out == 0);
+
+  *dstlen = IMAP_COMPRESS_BUFFER_SIZE - icb->out_stream.avail_out;
+  /* printf("imap_compress_cb %d bytes to %d\n", srclen, *dstlen); */
+  icb->out_uncompressed += srclen;
+  icb->out_compressed += *dstlen;
+}
+
+static void
+imap_decompress_cb(char **dstbuf, int *dstlen,
+                   const char *srcbuf, int srclen, void *arg)
+{
+  struct ImapCompressContext *icb = &((ImapMboxHandle*)arg)->compress;
+  int err;
+
+  *dstbuf = icb->in_buffer;
+
+  icb->in_stream.next_in  = (Bytef*)srcbuf;
+  icb->in_stream.avail_in = srclen;
+
+  icb->in_stream.next_out = (Byte*)*dstbuf;
+  icb->in_stream.avail_out =  IMAP_COMPRESS_BUFFER_SIZE;
+  err = inflate(&icb->in_stream, Z_SYNC_FLUSH);
+  
+  if (!(err == Z_OK || err == Z_BUF_ERROR || err == Z_STREAM_END)) {
+    fprintf(stderr, "inflate error %d\n", err);
+    /* FIXME break the connection. */
+  }
+
+  *dstlen = IMAP_COMPRESS_BUFFER_SIZE - icb->in_stream.avail_out;
+  /* printf("imap_decompress_cb %d bytes to %d\n", srclen, *dstlen); */
+  icb->in_compressed += srclen;
+  icb->in_uncompressed += *dstlen;
+}
+
+/** Enables COMPRESS extension if available. Assumes that the handle
+    is already locked. */
+ImapResponse
+imap_compress(ImapMboxHandle *handle)
+{
+  struct ImapCompressContext *icb;
+  int err;
+
+  if (!handle->enable_compress ||
+      !imap_mbox_handle_can_do(handle, IMCAP_COMPRESS_DEFLATE))
+    return IMR_NO;
+
+  if (imap_cmd_exec(handle, "COMPRESS DEFLATE") != IMR_OK)
+    return IMR_NO;
+
+  icb = &handle->compress;
+  icb->in_buffer = malloc(IMAP_COMPRESS_BUFFER_SIZE);
+  icb->out_buffer = malloc(IMAP_COMPRESS_BUFFER_SIZE);
+
+  if (!icb->in_buffer || !icb->out_buffer)
+    return IMR_NO;
+
+  /* Compression enabled. Everything that we send and receive now must
+     go through compression/decompression routines enabled in sio. */
+
+  icb->out_stream.zalloc = Z_NULL;
+  icb->out_stream.zfree = Z_NULL;
+  icb->out_stream.opaque = (voidpf)0;
+
+  /* amazingly enough, deflateInit() won't do */
+  err = deflateInit2(&icb->out_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+                     -15, 8, Z_DEFAULT_STRATEGY);
+  if (err != Z_OK) {
+    fprintf(stderr, "deflateInit error: %d\n", err);
+    return IMR_NO;
+  }
+
+  icb->in_stream.next_in = Z_NULL;
+  icb->in_stream.avail_in = 0;
+  icb->in_stream.zalloc = Z_NULL;
+  icb->in_stream.zfree = Z_NULL;
+  icb->in_stream.opaque = (voidpf)0;
+
+  /* amazingly enough, inflateInit() won't do */
+  err = inflateInit2(&icb->in_stream, -15);
+  if (err != Z_OK) {
+    fprintf(stderr, "inflateInit error: %d\n", err);
+    return IMR_NO;
+  }
+
+  if (handle->sio) {
+    sio_set_securitycb(handle->sio, imap_compress_cb, imap_decompress_cb,
+                       handle);
+    return IMR_OK;
+  } else {
+    fprintf(stderr, "SIO not set!\n");
+    return IMR_NO;
+  }
+}
+
+void
+imap_compress_init(struct ImapCompressContext *buf)
+{
+  memset(buf, 0, sizeof(buf));
+}
+
+/** releases any data that might have been allocated by compression routines. */
+
+void
+imap_compress_release(struct ImapCompressContext *buf)
+{
+
+  if (buf->in_buffer) {
+    inflateEnd(&buf->in_stream);
+    free(buf->in_buffer);
+  }
+
+  if (buf->out_buffer) {
+    deflateEnd(&buf->out_stream);
+    free(buf->out_buffer);
+  }
+  if (buf->in_uncompressed) {
+    printf("IMAP server compression %lu -> %lu sent %5.1f %% over wire\n",
+           buf->in_compressed, buf->in_uncompressed,  
+           100.0*(buf->in_compressed/(float)buf->in_uncompressed));
+  }
+  if (buf->in_uncompressed) {
+    printf("IMAP client compression %lu -> %lu sent %5.1f %% over wire\n",
+           buf->out_uncompressed, buf->out_compressed,  
+           100.0*(buf->out_compressed/(float)buf->out_uncompressed));
+  }
+}
+
+
diff --git a/libbalsa/imap/imap_compress.h b/libbalsa/imap/imap_compress.h
new file mode 100644
index 0000000..47c4256
--- /dev/null
+++ b/libbalsa/imap/imap_compress.h
@@ -0,0 +1,40 @@
+#ifndef __IMAP_COMPRESS_H__
+#define __IMAP_COMPRESS_H__ 1
+/* libimap library.
+ * Copyright (C) 2003-2010 Pawel Salek.
+ *
+ * This program 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 2, or (at your option) 
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+ * GNU General Public License for more details.
+ *  
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
+ * 02111-1307, USA.
+ */
+
+#include <zlib.h>
+
+#include "imap-handle.h"
+
+struct ImapCompressContext {
+  z_stream out_stream;
+  z_stream in_stream;
+  char *in_buffer;
+  char *out_buffer;
+  unsigned long in_uncompressed, in_compressed;
+  unsigned long out_uncompressed, out_compressed;
+};
+
+ImapResponse imap_compress(ImapMboxHandle* h);
+
+void imap_compress_init(struct ImapCompressContext *buf);
+void imap_compress_release(struct ImapCompressContext *buf);
+
+#endif /* __IMAP_COMPRESS_H__ */
diff --git a/libbalsa/imap/imap_private.h b/libbalsa/imap/imap_private.h
index 2e5f66b..cb748a6 100644
--- a/libbalsa/imap/imap_private.h
+++ b/libbalsa/imap/imap_private.h
@@ -35,6 +35,7 @@
 #endif
 
 #include "imap-commands.h"
+#include "imap_compress.h"
 
 typedef enum {
   IMAP_BODY_TYPE_RFC822, /**< as fetched with RFC822 */
@@ -92,6 +93,9 @@ struct _ImapMboxHandle {
                           * processing of current line is finished. */
   GNode *thread_root; /* deprecated! */
 
+  /** Compression data */
+  struct ImapCompressContext compress;
+
   struct {
     GList* src; /**< returned by COPY */
     GList* dst; /**< returned by APPEND and COPY */
@@ -134,10 +138,11 @@ struct _ImapMboxHandle {
   unsigned can_fetch_body:1; /* set for servers that always respond
                               * correctly to FETCH x BODY[y]
                               * requests. */
-  unsigned enable_anonymous:1; /* try anonymous if possible */
+  unsigned enable_anonymous:1;   /**< try anonymous if possible */
+  unsigned enable_binary:1;      /**< enable binary extension */
   unsigned enable_client_sort:1; /**< client side sorting allowed */
-  unsigned enable_idle:1;    /**< use IDLE - no problem with firewalls */
-  unsigned enable_binary:1; /* enable binary extension */
+  unsigned enable_compress:1; /**< enable compress extension */
+  unsigned enable_idle:1;     /**< use IDLE - no problem with firewalls */
 
   /* conditional stuff at the end for the safety. */
 #ifdef USE_TLS
diff --git a/libbalsa/imap/imap_tst.c b/libbalsa/imap/imap_tst.c
index e59193b..8f6767b 100644
--- a/libbalsa/imap/imap_tst.c
+++ b/libbalsa/imap/imap_tst.c
@@ -1,3 +1,21 @@
+/* libimap library.
+ * Copyright (C) 2003-2010 Pawel Salek.
+ *
+ * This program 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 2, or (at your option) 
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+ * GNU General Public License for more details.
+ *  
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
+ * 02111-1307, USA.
+ */
 /** @file imap_tst.c tests some IMAP capabilities. It is very useful
     for stress-testing the imap part of balsa. */
 
@@ -26,7 +44,8 @@ struct {
   gboolean over_ssl;
   gboolean monitor;
   gboolean anonymous;
-} TestContext = { NULL, NULL, IMAP_TLS_ENABLED, FALSE, FALSE, FALSE };
+  gboolean compress;
+} TestContext = { NULL, NULL, IMAP_TLS_ENABLED, FALSE, FALSE, FALSE, FALSE };
 
 static void
 monitor_cb(const char *buffer, int length, int direction, void *arg)
@@ -49,8 +68,8 @@ get_user(const char* method) {
     printf("Login with method %s as user: %s\n", method, TestContext.user);
     return g_strdup(TestContext.user);
   } else {
-    printf("Login with method %s as user: ", method);
-    fflush(stdout);
+    fprintf(stderr, "Login with method %s as user: ", method);
+    fflush(stderr);
     if(!fgets(buf, sizeof(buf), stdin))
       return NULL;
 
@@ -151,6 +170,8 @@ get_handle(const char *host)
   if(TestContext.anonymous)
     imap_handle_set_option(h, IMAP_OPT_ANONYMOUS, TRUE);
 
+  if(TestContext.compress)
+    imap_handle_set_option(h, IMAP_OPT_COMPRESS, TRUE);
   if(TestContext.monitor)
     imap_handle_set_monitorcb(h, monitor_cb, NULL);
 
@@ -274,7 +295,7 @@ dump_mbox(const char *host, const char *mailbox,
   }
 
   if(imap_mbox_select(h, mailbox, &read_only) == IMR_OK) {
-    unsigned cnt = imap_mbox_handle_get_exists(h);
+    unsigned cnt =  imap_mbox_handle_get_exists(h);
     unsigned i;
 #define FETCH_AT_ONCE 300
     for(i=0; i<cnt; i+= FETCH_AT_ONCE) {
@@ -339,6 +360,7 @@ test_mbox_dumpfile(int argc, char *argv[])
 struct DumpdirState {
   const char *dst_directory;
   int error;
+  unsigned last_seqno;
 };
 
 static void
@@ -351,7 +373,8 @@ dumpdir_cb(unsigned seqno, const char *buf, size_t buflen, void *arg)
 
   g_snprintf(num, sizeof(num), "%u", seqno);
   fname = g_build_filename(dds->dst_directory, num, NULL);
-  f = fopen(fname, "wt");
+  f = fopen(fname, seqno == dds->last_seqno ? "at" : "wt");
+  dds->last_seqno = seqno;
   if(!f) {
     fprintf(stderr, "Cannot open %s for writing.\n", fname);
     dds->error = 1;
@@ -387,7 +410,7 @@ test_mbox_dumpdir(int argc, char *argv[])
     fprintf(stderr, "%s is not a directory\n", state.dst_directory);
     return 1;
   }
-
+  state.last_seqno = 0;
   return dump_mbox(argv[0], argv[1], dumpdir_cb, &state);
 }
 
@@ -613,6 +636,8 @@ process_options(int argc, char *argv[])
       TestContext.over_ssl = TRUE;
     }  else if( strcmp(argv[first_arg], "-a") == 0) {
       TestContext.anonymous = TRUE;
+    }  else if( strcmp(argv[first_arg], "-c") == 0) {
+      TestContext.compress = TRUE;
     } else {
       break; /* break the loop - non-option encountered. */
     }
@@ -651,6 +676,16 @@ main(int argc, char *argv[]) {
 	    argv[first_arg]);
     for(i=0; i<sizeof(cmds)/sizeof(cmds[0]); i++)
       fprintf(stderr, "%s %s\n", cmds[i].cmd, cmds[i].help);
+    fprintf(stderr, "Known options:\n"
+            "-u USER specify user\n"
+            "-p PASSWORD specify password\n"
+            "-m enable monitor\n"
+            "-T tls required\n"
+            "-t tls disabled\n"
+            "-s over ssl\n"
+            "-a anonymous\n"
+            "-c compress\n");
+
     return 1;
   }
 



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