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-547-ge4dc718


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-547-ge4dc718
Date: Fri, 23 Dec 2011 10:42:20 +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=e4dc7185c62a3042b9a05828be83c1f1ca308dcb

The branch, master has been updated
       via  e4dc7185c62a3042b9a05828be83c1f1ca308dcb (commit)
      from  22ec4913c13137b497c6d6ee7f433d0b94e059cd (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 e4dc7185c62a3042b9a05828be83c1f1ca308dcb
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Dec 23 12:40:44 2011 +0200

    Implement imap mailbox (read-only, so far).
    
    * include/mailutils/sys/imap.h (_mu_imap_mailbox_init): New proto.
    (_mu_imap_message,_mu_imap_mailbox): New structures.
    * libproto/imap/mbox.c: New file.
    * libproto/imap/Makefile.am (libmu_imap_la_SOURCES): Put back mbox.c
    * libproto/imap/fetch.c: Fix body/bodystructure parsing.
    * libproto/imap/folder.c (_mu_imap_folder_destroy): Close folder.
    (_mu_imap_folder_open): Implement STARTTLS.
    (_imap_record): Accept parameters in URL, use _mu_imap_mailbox_init
    to initialize mailbox.

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

Summary of changes:
 include/mailutils/sys/imap.h |   39 ++-
 libproto/imap/Makefile.am    |    3 +-
 libproto/imap/fetch.c        |   34 +-
 libproto/imap/folder.c       |   54 ++-
 libproto/imap/mbox.c         |  946 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1037 insertions(+), 39 deletions(-)
 create mode 100644 libproto/imap/mbox.c

diff --git a/include/mailutils/sys/imap.h b/include/mailutils/sys/imap.h
index 68bdf06..a06e1b0 100644
--- a/include/mailutils/sys/imap.h
+++ b/include/mailutils/sys/imap.h
@@ -235,9 +235,46 @@ int _mu_imap_url_init (mu_url_t url);
 int _mu_imaps_url_init (mu_url_t url);
 
 /* ----------------------------- */
-/* Folder interface              */
+/* Mailbox interface             */
 /* ----------------------------- */
 
+int _mu_imap_mailbox_init (mu_mailbox_t mailbox);
+
+#define _MU_IMAP_MSG_SCANNED   0x01
+#define _MU_IMAP_MSG_CACHED    0x02
+#define _MU_IMAP_MSG_LINES     0x04
+
+struct _mu_imap_message
+{
+  int flags;
+  size_t uid;               /* Message UID */   
+  int attr_flags;           /* Attributes */
+  mu_off_t offset;          /* Offset in the message cache stream */
+  mu_off_t body_start;      /* Start of message, relative to offset */
+  mu_off_t body_end;        /* End of message, relative to offset */  
+  size_t header_lines;      /* Number of lines in the header */
+  size_t body_lines;        /* Number of lines in the body */
+  size_t message_size;      /* Message size */
+  size_t message_lines;     /* Number of lines in the message */
+  struct mu_imapenvelope *env; /* IMAP envelope */
+  mu_message_t message;     /* Pointer to the message structure */ 
+  struct _mu_imap_mailbox *imbx; /* Back pointer.  */
+};
+
+#define _MU_IMAP_MBX_UPTODATE  0x01
+
+struct _mu_imap_mailbox
+{
+  int flags;
+  mu_off_t total_size;        /* Total mailbox size. */
+  struct mu_imap_stat stats;     /* Mailbox statistics */ 
+  struct _mu_imap_message *msgs; /* Array of messages */
+  size_t msgs_cnt;               /* Number of used slots in msgs */
+  size_t msgs_max;               /* Number of slots in msgs */
+  mu_stream_t cache;          /* Message cache stream */
+  int last_error;             /* Last error code */
+  mu_mailbox_t mbox;
+};
 
 # ifdef __cplusplus
 }
diff --git a/libproto/imap/Makefile.am b/libproto/imap/Makefile.am
index 181ac35..e950890 100644
--- a/libproto/imap/Makefile.am
+++ b/libproto/imap/Makefile.am
@@ -23,8 +23,6 @@ libmu_imap_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} 
@INTLLIBS@
 
 SUBDIRS = . tests
 
-# FIXME: Put this back when ready
-#  mbox.c
 libmu_imap_la_SOURCES = \
  appmsg.c\
  appstr.c\
@@ -68,4 +66,5 @@ libmu_imap_la_SOURCES = \
  unselect.c\
  unsubscribe.c\
  folder.c\
+ mbox.c\
  url.c
diff --git a/libproto/imap/fetch.c b/libproto/imap/fetch.c
index aa5c090..22937df 100644
--- a/libproto/imap/fetch.c
+++ b/libproto/imap/fetch.c
@@ -618,7 +618,7 @@ _parse_bodystructure_simple (struct imap_list_element *elt,
   struct body_field_map *map;
   
   mu_list_count (elt->v.list, &n);
-  if (n < 8)
+  if (n < 7)
     return MU_ERR_PARSE;
 
   tok = _mu_imap_list_at (elt->v.list, BSTOK_BODY_TYPE);
@@ -976,6 +976,7 @@ _extract_string (void **itmv, size_t itmc, void *call_data)
 static int
 _fetch_fold (void *item, void *data)
 {
+  int rc;
   struct imap_list_element *elt = item;
   struct parse_response_env *env = data;
 
@@ -983,7 +984,6 @@ _fetch_fold (void *item, void *data)
     {
     case resp_kw:
       {
-       int rc;
        char *kw;
        size_t kwlen;
        struct mapper_tab *mt;
@@ -1020,6 +1020,26 @@ _fetch_fold (void *item, void *data)
        break;
       }
       
+    case resp_body:
+      if (_mu_imap_list_element_is_string (elt, "["))
+       {
+         env->state = resp_body_section;
+         break;
+       }
+      else
+       {
+         env->mapper = _bodystructure_mapper;
+         _free_fetch_response (env->resp);
+         rc = alloc_response (&env->resp, MU_IMAP_FETCH_BODYSTRUCTURE);
+         if (rc)
+           {
+             env->status = rc;
+             return MU_ERR_FAILURE;
+           }
+         env->state = resp_val;
+       }
+      /* fall through */
+      
     case resp_val:
       if (env->mapper)
        {
@@ -1034,16 +1054,6 @@ _fetch_fold (void *item, void *data)
       env->state = resp_kw;
       break;
       
-    case resp_body:
-      if (_mu_imap_list_element_is_string (elt, "["))
-       env->state = resp_body_section;
-      else
-       {
-         env->mapper = _bodystructure_mapper;
-         env->state = resp_val;
-       }
-      break;
-      
     case resp_body_section:
       if (elt->type != imap_eltype_string)
        {
diff --git a/libproto/imap/folder.c b/libproto/imap/folder.c
index 1bf637f..02712d2 100644
--- a/libproto/imap/folder.c
+++ b/libproto/imap/folder.c
@@ -39,21 +39,13 @@
 #include <mailutils/sys/imap.h>
 #include <mailutils/sys/folder.h>
 
-/* Placeholders. */
-#define _mu_imap_mailbox_init NULL
-#define _mu_imaps_mailbox_init NULL
-
-
 static void
 _mu_imap_folder_destroy (mu_folder_t folder)
 {
   mu_imap_t imap = folder->data;
   if (imap)
     {
-      /*
-       mu_imap_logout (imap);
-       mu_imap_disconnect (imap);
-      */
+      mu_folder_close (folder);
       mu_imap_destroy (&imap);
       folder->data = imap;
     }
@@ -90,13 +82,6 @@ _mu_folder_bad_callback (void *data, int code, size_t sdat, 
void *pdat)
   mu_error (_("This probably indicates a bug in Mailutils client code."));
   mu_error (_("Please, report that to <%s>."), PACKAGE_BUGREPORT);
 }
-#if 0
-static void
-_mu_folder_fetch_callback (void *data, int code, size_t sdat, void *pdat)
-{
-  mu_folder_t folder = data;
-}
-#endif
 
 /* Set up an IMAP(S) connection for this folder */
 static int
@@ -187,11 +172,6 @@ _mu_imap_folder_open (mu_folder_t folder, int flags)
   mu_imap_register_callback_function (imap, MU_IMAP_CB_BAD,
                                      _mu_folder_bad_callback,
                                      folder);
-#if 0
-  mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH,
-                                     _mu_folder_fetch_callback,
-                                     folder);
-#endif
   rc = mu_imap_connect (imap);
   if (rc)
     {
@@ -206,6 +186,32 @@ _mu_imap_folder_open (mu_folder_t folder, int flags)
       return rc;
     }
 
+#ifdef WITH_TLS
+  if (!tls && mu_imap_capability_test (imap, "STARTTLS", NULL) == 0)
+    {
+      size_t parmc = 0;
+      char **parmv = NULL;
+
+      tls = 1;
+      if (mu_url_sget_fvpairs (folder->url, &parmc, &parmv) == 0)
+       {
+         size_t i;
+      
+         for (i = 0; i < parmc; i++)
+           {
+             if (strcmp (parmv[i], "notls") == 0)
+               tls = 0;
+             /*FIXME:
+               else if (strncmp (parmv[i], "auth=", 5) == 0)
+             */
+             /* unrecognized arguments silently ignored */
+           }
+       }
+
+      if (tls)
+       mu_imap_starttls (imap);
+    }
+#endif
   if (mu_imap_session_state (imap) == MU_IMAP_SESSION_NONAUTH)
     {
       rc = mu_authority_authenticate (folder->authority);
@@ -217,7 +223,7 @@ _mu_imap_folder_open (mu_folder_t folder, int flags)
          mu_folder_close (folder);
        }
     }
-  
+    
   return rc;
 }
 
@@ -551,7 +557,7 @@ static struct _mu_record _imap_record =
   MU_IMAP_PRIO,
   MU_IMAP_SCHEME,
   MU_RECORD_DEFAULT,
-  MU_URL_SCHEME | MU_URL_CRED | MU_URL_INET | MU_URL_PATH,
+  MU_URL_SCHEME | MU_URL_CRED | MU_URL_INET | MU_URL_PATH | MU_URL_PARAM,
   MU_URL_HOST,
   _mu_imap_url_init,     /* url entry.  */
   _mu_imap_mailbox_init, /* Mailbox entry.  */
@@ -576,7 +582,7 @@ static struct _mu_record _imaps_record =
   MU_URL_SCHEME | MU_URL_CRED | MU_URL_INET | MU_URL_PATH | MU_URL_PARAM,
   MU_URL_HOST,
   _mu_imaps_url_init,     /* url entry.  */
-  _mu_imaps_mailbox_init, /* Mailbox entry.  */
+  _mu_imap_mailbox_init,  /* Mailbox entry.  */
   NULL,                /* Mailer entry.  */
   _mu_imap_folder_init,   /* Folder entry.  */
   NULL, /* No need for a back pointer.  */
diff --git a/libproto/imap/mbox.c b/libproto/imap/mbox.c
new file mode 100644
index 0000000..841942e
--- /dev/null
+++ b/libproto/imap/mbox.c
@@ -0,0 +1,946 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <mailutils/errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/message.h>
+#include <mailutils/folder.h>
+#include <mailutils/assoc.h>
+#include <mailutils/url.h>
+#include <mailutils/io.h>
+#include <mailutils/nls.h>
+#include <mailutils/diag.h>
+#include <mailutils/filter.h>
+#include <mailutils/observer.h>
+#include <mailutils/envelope.h>
+#include <mailutils/address.h>
+#include <mailutils/attribute.h>
+#include <mailutils/header.h>
+#include <mailutils/body.h>
+#include <mailutils/sys/imap.h>
+
+#define _imap_mbx_clrerr(imbx) ((imbx)->last_error = 0)
+#define _imap_mbx_errno(imbx) ((imbx)->last_error)
+#define _imap_mbx_uptodate(imbx) ((imbx)->flags & _MU_IMAP_MBX_UPTODATE)
+
+static int _imap_mbx_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount);
+static int _imap_mbx_is_updated (mu_mailbox_t mbox);
+
+/* ------------------------------- */
+/* Auxiliary message functions     */
+/* ------------------------------- */
+
+static size_t
+_imap_msg_no (struct _mu_imap_message *imsg)
+{
+  return imsg - imsg->imbx->msgs + 1;
+}
+
+static int
+_imap_fetch_with_callback (mu_imap_t imap, char *msgset, char *items,
+                          mu_imap_callback_t cb, void *data)
+{
+  int rc;
+  
+  mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH, cb, data);
+  rc = mu_imap_fetch (imap, 0, msgset, items);
+  mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH, NULL, NULL);
+  return rc;
+}
+
+static void
+_imap_msg_free (struct _mu_imap_message *msg)
+{
+  mu_message_imapenvelope_free (msg->env);
+  mu_message_destroy (&msg->message, msg);
+}
+
+struct save_closure
+{
+  mu_stream_t save_stream;
+  size_t size;
+  struct _mu_imap_message *imsg;
+};
+
+static void
+_save_message (void *data, int code, size_t sdat, void *pdat)
+{
+  struct save_closure *clos = data;
+  struct _mu_imap_message *imsg = clos->imsg;
+  struct _mu_imap_mailbox *imbx = imsg->imbx;
+  mu_list_t list = pdat;
+  union mu_imap_fetch_response *resp;
+  int rc;
+  mu_stream_t istr, flt;
+  mu_off_t size;
+  
+  rc = mu_list_get (list, 0, (void**)&resp);
+  if (rc)
+    {
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+               (_("cannot get response item: %s"),
+                mu_strerror (rc)));
+      imbx->last_error = rc;
+      return;
+    }
+
+  if (resp->type != MU_IMAP_FETCH_BODY)
+    {
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+               (_("fetch returned a not requested item %d"), resp->type));
+      imbx->last_error = MU_ERR_FAILURE;
+      return;
+    }
+  rc = mu_static_memory_stream_create (&istr, resp->body.text,
+                                      strlen (resp->body.text));
+
+  if (rc)
+    {
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+               (_("mu_static_memory_stream_create: %s"),
+                mu_strerror (rc)));
+      imbx->last_error = rc;
+      return;
+    }
+
+  rc = mu_filter_create (&flt, istr, "CRLF", MU_FILTER_DECODE, MU_STREAM_READ);
+  mu_stream_unref (istr);
+  if (rc)
+    {
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+               (_("mu_filter_create: %s"), mu_strerror (rc)));
+      imbx->last_error = rc;
+      return;
+    }
+      
+  rc = mu_stream_copy (clos->save_stream, flt, 0, &size);
+  mu_stream_destroy (&flt);
+  if (rc)
+    {
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+               (_("copying to cache failed: %s"), mu_strerror (rc)));
+      imbx->last_error = rc;
+      return;
+    }
+  clos->size = size;
+}
+
+static int
+__imap_msg_get_stream (struct _mu_imap_message *imsg, size_t msgno,
+                      mu_stream_t *pstr)
+{
+  int rc;
+  struct _mu_imap_mailbox *imbx = imsg->imbx;
+  mu_folder_t folder = imbx->mbox->folder;
+  mu_imap_t imap = folder->data;
+  
+  if (!(imsg->flags & _MU_IMAP_MSG_CACHED))
+    {
+      char *msgset;
+         
+      if (!imbx->cache)
+       {
+         rc = mu_temp_file_stream_create (&imbx->cache, NULL, 0);
+         if (rc)
+           /* FIXME: Try to recover first */
+           return rc;
+
+         mu_stream_set_buffer (imbx->cache, mu_buffer_full, 8192);
+       }
+
+      rc = mu_stream_size (imbx->cache, &imsg->offset);
+      if (rc)
+       return rc;
+
+      rc = mu_asprintf (&msgset, "%lu", msgno);
+      if (rc == 0)
+       {
+         struct save_closure clos;
+         clos.imsg = imsg;
+         clos.save_stream = imbx->cache;
+         _imap_mbx_clrerr (imbx);
+         rc = _imap_fetch_with_callback (imap, msgset, "BODY[]",
+                                         _save_message, &clos);
+         free (msgset);
+         if (rc == 0 && !_imap_mbx_errno (imbx))
+           imsg->message_size = clos.size;
+       }
+
+      if (rc)
+       return rc;
+
+      imsg->flags |= _MU_IMAP_MSG_CACHED;
+    }
+  return mu_streamref_create_abridged (pstr, imbx->cache,
+                                      imsg->offset,
+                                      imsg->offset + imsg->message_size - 1);
+}
+
+static int
+_imap_msg_scan (struct _mu_imap_message *imsg)
+{
+  int rc;
+  mu_stream_t stream;
+  struct mu_message_scan scan;
+  size_t msgno = _imap_msg_no (imsg);
+  
+  if (imsg->flags & _MU_IMAP_MSG_SCANNED)
+    return 0;
+  
+  rc = __imap_msg_get_stream (imsg, msgno, &stream);
+  if (rc)
+    return rc;
+  
+  scan.flags = MU_SCAN_SEEK | MU_SCAN_SIZE;
+  scan.message_start = 0;
+  scan.message_size = imsg->message_size;
+  rc = mu_stream_scan_message (stream, &scan);
+  mu_stream_unref (stream);
+
+  if (rc == 0)
+    {
+      imsg->body_start = scan.body_start;
+      imsg->body_end = scan.body_end;
+      imsg->header_lines = scan.header_lines;
+      imsg->body_lines = scan.body_lines;
+      imsg->message_lines = imsg->header_lines + 1 + imsg->body_lines;
+      imsg->flags |= _MU_IMAP_MSG_SCANNED;
+    }
+  
+  return rc;
+}
+
+/* ------------------------------- */
+/* Message envelope                */
+/* ------------------------------- */
+
+static int
+_imap_env_date (mu_envelope_t env, char *buf, size_t len,
+               size_t *pnwrite)
+{
+  struct _mu_imap_message *imsg = mu_envelope_get_owner (env);
+  mu_stream_t str;
+  int rc;
+  
+  if (!buf)
+    rc = mu_nullstream_create (&str, MU_STREAM_WRITE);
+  else
+    rc = mu_fixed_memory_stream_create (&str, buf, len, MU_STREAM_WRITE);
+  if (rc == 0)
+    {
+      mu_stream_stat_buffer statbuf;
+      mu_stream_set_stat (str, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT),
+                         statbuf);
+      rc = mu_c_streamftime (str, MU_DATETIME_FROM,
+                            &imsg->env->date, &imsg->env->tz);
+      mu_stream_destroy (&str);
+      if (pnwrite)
+       *pnwrite = statbuf[MU_STREAM_STAT_OUT];
+    }
+  return rc;
+}
+
+static int
+_imap_env_sender (mu_envelope_t env, char *buf, size_t len,
+                 size_t *pnwrite)
+{
+  struct _mu_imap_message *imsg = mu_envelope_get_owner (env);
+  mu_address_t addr = imsg->env->sender ? imsg->env->sender : imsg->env->from;
+
+  if (!addr)
+    return MU_ERR_NOENT;
+  return mu_address_get_email (addr, 1, buf, len, pnwrite);
+}
+  
+static int
+_imap_msg_env_setup (struct _mu_imap_message *imsg, mu_message_t message)
+{
+  mu_envelope_t env;
+  int rc = mu_envelope_create (&env, imsg);
+  if (rc == 0)
+    {
+      mu_envelope_set_sender (env, _imap_env_sender, imsg);
+      mu_envelope_set_date (env, _imap_env_date, imsg);
+      rc = mu_message_set_envelope (message, env, imsg);
+    }
+  return rc;
+}
+
+/* ------------------------------- */
+/* Message attributes              */
+/* ------------------------------- */
+static int
+_imap_attr_get_flags (mu_attribute_t attr, int *pflags)
+{
+  struct _mu_imap_message *imsg = mu_attribute_get_owner (attr);
+
+  if (!imsg)
+    return EINVAL;
+  if (pflags)
+    *pflags = imsg->attr_flags;
+  return 0;
+}
+
+static int
+_imap_attr_set_flags (mu_attribute_t attr, int flags)
+{
+  struct _mu_imap_message *imsg = mu_attribute_get_owner (attr);
+
+  if (!imsg)
+    return EINVAL;
+  imsg->attr_flags |= flags;
+  return 0;
+}
+
+static int
+_imap_attr_clr_flags (mu_attribute_t attr, int flags)
+{
+  struct _mu_imap_message *imsg = mu_attribute_get_owner (attr);
+
+  if (!imsg)
+    return EINVAL;
+  imsg->attr_flags |= flags;
+  return 0;
+}
+
+int
+_imap_msg_attr_setup (struct _mu_imap_message *imsg, mu_message_t message)
+{
+  mu_attribute_t attribute;
+  int rc = mu_attribute_create (&attribute, imsg);
+  if (rc == 0)
+    {
+      mu_attribute_set_get_flags (attribute, _imap_attr_get_flags, imsg);
+      mu_attribute_set_set_flags (attribute, _imap_attr_set_flags, imsg);
+      mu_attribute_set_unset_flags (attribute, _imap_attr_clr_flags, imsg);
+      rc = mu_message_set_attribute (message, attribute, imsg);
+    }
+  return rc;
+}
+
+/* ------------------------------- */
+/* Header functions                */
+/* ------------------------------- */
+static int
+_imap_hdr_fill (void *data, char **pbuf, size_t *plen)
+{
+  struct _mu_imap_message *imsg = data;
+  struct _mu_imap_mailbox *imbx = imsg->imbx;
+  mu_imap_t imap = imbx->mbox->folder->data;
+  struct save_closure clos;
+  char *msgset;
+  unsigned long msgno = _imap_msg_no (imsg);
+  int rc;
+  
+  clos.imsg = imsg;
+  rc = mu_memory_stream_create (&clos.save_stream, MU_STREAM_RDWR);
+  _imap_mbx_clrerr (imbx);
+  rc = mu_asprintf (&msgset, "%lu", msgno);
+  if (rc == 0)
+    {
+      rc = _imap_fetch_with_callback (imap, msgset, "BODY.PEEK[HEADER]",
+                                     _save_message, &clos);
+      free (msgset);
+      if (rc == 0)
+       {
+         char *buf;
+         mu_off_t size;
+         
+         mu_stream_size (clos.save_stream, &size);
+         buf = malloc (size + 1);
+         if (!buf)
+           rc = ENOMEM;
+         else
+           {
+             mu_stream_seek (clos.save_stream, 0, MU_SEEK_SET, NULL);
+             rc = mu_stream_read (clos.save_stream, buf, size, NULL);
+             if (rc == 0)
+               {
+                 *pbuf = buf;
+                 *plen = size;
+               }
+             else
+               free (buf);
+           }
+       }
+    }
+  mu_stream_destroy (&clos.save_stream);
+  return rc;
+}
+
+static int
+_imap_msg_header_setup (struct _mu_imap_message *imsg, mu_message_t message)
+{
+  int rc;
+  mu_header_t header = NULL;
+
+  rc = mu_header_create (&header, NULL, 0);
+  if (rc)
+    return rc;
+  mu_header_set_fill (header, _imap_hdr_fill, imsg);
+  return mu_message_set_header (message, header, imsg);
+}
+
+/* ------------------------------- */
+/* Body functions                  */
+/* ------------------------------- */
+static int
+_imap_body_get_stream (mu_body_t body, mu_stream_t *pstr)
+{
+  mu_message_t msg = mu_body_get_owner (body);
+  struct _mu_imap_message *imsg = mu_message_get_owner (msg);
+  struct _mu_imap_mailbox *imbx = imsg->imbx;
+  int rc;
+
+  rc = _imap_msg_scan (imsg);
+  if (rc)
+    return rc;
+  return mu_streamref_create_abridged (pstr, imbx->cache,
+                                      imsg->offset + imsg->body_start,
+                                      imsg->offset + imsg->body_end - 1);
+}
+
+static int
+_imap_body_size (mu_body_t body, size_t *psize)
+{
+  mu_message_t msg = mu_body_get_owner (body);
+  struct _mu_imap_message *imsg = mu_message_get_owner (msg);
+  int rc;
+
+  rc = _imap_msg_scan (imsg);
+  if (rc)
+    return rc;
+  *psize = imsg->body_end - imsg->body_start;
+  return 0;
+}
+
+static int
+_imap_body_lines (mu_body_t body, size_t *psize)
+{
+  mu_message_t msg = mu_body_get_owner (body);
+  struct _mu_imap_message *imsg = mu_message_get_owner (msg);
+  int rc;
+
+  rc = _imap_msg_scan (imsg);
+  if (rc)
+    return rc;
+  *psize = imsg->body_lines;
+  return 0;
+}
+
+static int
+_imap_mbx_body_setup (struct _mu_imap_message *imsg, mu_message_t message)
+{
+  int rc;
+  mu_body_t body;
+
+  /* FIXME: The owner of the body *must* be the message it belongs to. */
+  rc = mu_body_create (&body, message);
+  if (rc)
+    return rc;
+
+  mu_body_set_get_stream (body, _imap_body_get_stream, message);
+  mu_body_set_size (body, _imap_body_size, message);
+  mu_body_set_lines (body, _imap_body_lines, message);
+
+  return mu_message_set_body (message, body, imsg);
+}
+
+
+/* ------------------------------- */
+/* Message functions               */
+/* ------------------------------- */
+
+static int
+_imap_msg_get_stream (mu_message_t msg, mu_stream_t *pstr)
+{
+  struct _mu_imap_message *imsg = mu_message_get_owner (msg);
+  return __imap_msg_get_stream (imsg, _imap_msg_no (imsg), pstr);
+}
+
+static int
+_imap_msg_size (mu_message_t msg, size_t *psize)
+{
+  struct _mu_imap_message *imsg = mu_message_get_owner (msg);
+  *psize = imsg->message_size;
+  return 0;
+}
+
+static int
+_imap_msg_lines (mu_message_t msg, size_t *plines, int quick)
+{
+  struct _mu_imap_message *imsg = mu_message_get_owner (msg);
+  struct _mu_imap_mailbox *imbx = imsg->imbx;
+  mu_mailbox_t mbox = imbx->mbox;
+  
+  if (!(imsg->flags & _MU_IMAP_MSG_LINES))
+    {
+      int rc;
+      
+      if (quick && !(imsg->flags & _MU_IMAP_MSG_CACHED))
+       return MU_ERR_INFO_UNAVAILABLE;
+      if (!_imap_mbx_uptodate (imbx))
+       _imap_mbx_scan (mbox, 1, NULL);
+      rc = _imap_msg_scan (imsg);
+      if (rc)
+       return rc;
+    }
+  *plines = imsg->message_lines;
+  return 0;
+}
+
+static int
+_imap_mbx_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
+{
+  struct _mu_imap_mailbox *imbx = mailbox->data;
+  struct _mu_imap_message *imsg;
+  int rc;
+  
+  /* If we did not start a scanning yet do it now.  */
+  if (!_imap_mbx_uptodate (imbx))
+    _imap_mbx_scan (mailbox, 1, NULL);
+
+  if (msgno > imbx->msgs_cnt)
+    return MU_ERR_NOENT;
+
+  imsg = imbx->msgs + msgno - 1;
+  if (!imsg->message)
+    {
+      mu_message_t msg;
+  
+      rc = mu_message_create (&msg, imsg);
+      if (rc)
+       return rc;
+      mu_message_set_get_stream (msg, _imap_msg_get_stream, imsg);
+      mu_message_set_size (msg, _imap_msg_size, imsg);
+      mu_message_set_lines (msg, _imap_msg_lines, imsg);
+
+      do
+       {
+         rc = _imap_msg_env_setup (imsg, msg);
+         if (rc)
+           break;
+         rc = _imap_msg_attr_setup (imsg, msg);
+         if (rc)
+           break;
+         rc = _imap_msg_header_setup (imsg, msg);
+         if (rc)
+           break;
+         rc = _imap_mbx_body_setup (imsg, msg);
+       }
+      while (0);
+      
+      if (rc)
+       {
+         mu_message_destroy (&msg, imsg);
+         return rc;
+       }
+      imsg->message = msg;
+
+    }
+  *pmsg = imsg->message;
+  return 0;
+}
+
+/* ------------------------------- */
+/* Mailbox functions               */
+/* ------------------------------- */
+static int
+_imap_realloc_messages (struct _mu_imap_mailbox *imbx, size_t count)
+{
+  if (count > imbx->msgs_max)
+    {
+      struct _mu_imap_message *newmsgs = realloc (imbx->msgs,
+                                                 count * sizeof (*newmsgs));
+      if (!newmsgs)
+       return ENOMEM;
+      memset (newmsgs + imbx->msgs_max, 0,
+             sizeof (*newmsgs) * (count - imbx->msgs_max));
+      imbx->msgs = newmsgs;
+      imbx->msgs_max = count;
+    }
+  return 0;
+}
+
+static void
+_imap_mbx_destroy (mu_mailbox_t mailbox)
+{
+  size_t i;
+  struct _mu_imap_mailbox *imbx = mailbox->data;
+  
+  if (!imbx)
+    return;
+
+  if (imbx->msgs)
+    {
+      for (i = 0; i < imbx->msgs_cnt; i++)
+       _imap_msg_free (imbx->msgs + i);
+      free (imbx->msgs);
+    }
+  mu_stream_unref (imbx->cache);
+  free (imbx);
+  mailbox->data = NULL;
+}
+
+static void
+_imap_update_callback (void *data, int code, size_t sdat, void *pdat)
+{
+  struct _mu_imap_mailbox *imbx = data;
+  memcpy (&imbx->stats, pdat, sizeof (imbx->stats));
+  imbx->flags &= ~_MU_IMAP_MBX_UPTODATE;
+}
+
+static int
+_imap_mbx_open (mu_mailbox_t mbox, int flags)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  mu_folder_t folder = mbox->folder;
+  int rc;
+  const char *mbox_name;
+  mu_url_t url;
+  mu_imap_t imap;
+  
+  rc = mu_mailbox_get_url (mbox, &url);
+  if (rc)
+    return rc;
+  rc = mu_url_sget_path (url, &mbox_name);
+  if (rc == MU_ERR_NOENT)
+    mbox_name = "INBOX";
+  else if (rc)
+    return rc;
+      
+  rc = mu_folder_open (folder, flags);
+  if (rc)
+    return rc;
+
+  imap = folder->data;
+
+  mu_imap_register_callback_function (imap, MU_IMAP_CB_RECENT_COUNT,
+                                     _imap_update_callback,
+                                     imbx);
+  mu_imap_register_callback_function (imap, MU_IMAP_STAT_MESSAGE_COUNT,
+                                     _imap_update_callback,
+                                     imbx);
+  
+  rc = mu_imap_select (imap, mbox_name,
+                      flags & (MU_STREAM_WRITE|MU_STREAM_APPEND),
+                      &imbx->stats);
+  if (rc)
+    return rc;
+
+  if (imbx->stats.flags & MU_IMAP_STAT_MESSAGE_COUNT)
+    rc = _imap_realloc_messages (imbx, imbx->stats.message_count);
+  
+  return rc;
+}
+
+static int
+_imap_mbx_close (mu_mailbox_t mbox)
+{
+  int rc;
+  mu_folder_t folder = mbox->folder;
+  mu_imap_t imap = folder->data;
+
+  if (mu_imap_capability_test (imap, "UNSELECT", NULL) == 0)
+    rc = mu_imap_unselect (imap);
+  else
+    rc = mu_imap_close (imap);
+  return rc;
+}
+
+static int
+_imap_messages_count (mu_mailbox_t mbox, size_t *pcount)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  if (imbx->stats.flags & MU_IMAP_STAT_MESSAGE_COUNT)
+    *pcount = imbx->stats.message_count;
+  else
+    return MU_ERR_INFO_UNAVAILABLE;
+  return 0;
+}
+  
+static int
+_imap_messages_recent (mu_mailbox_t mbox, size_t *pcount)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  if (imbx->stats.flags & MU_IMAP_STAT_RECENT_COUNT)
+    *pcount = imbx->stats.recent_count;
+  else
+    return MU_ERR_INFO_UNAVAILABLE;
+  return 0;
+}
+
+static int
+_imap_uidnext (mu_mailbox_t mbox, size_t *pn)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  if (imbx->stats.flags & MU_IMAP_STAT_UIDNEXT)
+    *pn = imbx->stats.uidnext;
+  else
+    return MU_ERR_INFO_UNAVAILABLE;
+  return 0;
+}
+
+static int
+_imap_message_unseen (mu_mailbox_t mbox, size_t *pn)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  if (imbx->stats.flags & MU_IMAP_STAT_FIRST_UNSEEN)
+    *pn = imbx->stats.uidnext;
+  else
+    return MU_ERR_INFO_UNAVAILABLE;
+  return 0;
+}
+
+static int
+_imap_uidvalidity (mu_mailbox_t mbox, unsigned long *pn)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  if (imbx->stats.flags & MU_IMAP_STAT_UIDVALIDITY)
+    *pn = imbx->stats.uidvalidity;
+  else
+    return MU_ERR_INFO_UNAVAILABLE;
+  return 0;
+}
+
+static int
+_imap_mbx_expunge (mu_mailbox_t mbox)
+{
+  mu_folder_t folder = mbox->folder;
+  mu_imap_t imap = folder->data;
+  return mu_imap_expunge (imap);
+}
+
+static int _compute_lines (struct mu_bodystructure *bs, size_t *pcount);
+
+static int
+sum_lines (void *item, void *data)
+{
+  struct mu_bodystructure *bs = item;
+  size_t *pn = data;
+  size_t n;
+
+  if (_compute_lines (bs, &n))
+    return 1;
+  *pn += n;
+  return 0;
+}
+
+static int
+_compute_lines (struct mu_bodystructure *bs, size_t *pcount)
+{
+  switch (bs->body_message_type)
+    {
+    case mu_message_other:
+      break;
+
+    case mu_message_text:
+      *pcount = bs->v.text.body_lines;
+      return 0;
+
+    case mu_message_rfc822:
+      *pcount = bs->v.rfc822.body_lines;
+      return 0;
+      
+    case mu_message_multipart:
+      *pcount = 0;
+      return mu_list_foreach (bs->v.multipart.body_parts, sum_lines, pcount);
+    }
+  return 1;
+}
+
+static int
+fetch_response_parser (void *item, void *data)
+{
+  union mu_imap_fetch_response *resp = item;
+  struct _mu_imap_message *imsg = data;
+
+  switch (resp->type)
+    {
+    case MU_IMAP_FETCH_UID:
+      imsg->uid = resp->uid.uid;
+      break;
+      
+    case MU_IMAP_FETCH_FLAGS:
+      imsg->attr_flags = resp->flags.flags;
+      break;
+      
+    case MU_IMAP_FETCH_ENVELOPE:
+      imsg->env = resp->envelope.imapenvelope;
+      resp->envelope.imapenvelope = NULL; /* Steal the envelope */
+      break;
+      
+    case MU_IMAP_FETCH_RFC822_SIZE:
+      imsg->message_size = resp->rfc822_size.size;
+      break;
+      
+    case MU_IMAP_FETCH_BODYSTRUCTURE:
+      {
+       size_t n;
+       if (_compute_lines (resp->bodystructure.bs, &n) == 0)
+         {
+           imsg->message_lines = n;
+           imsg->flags |= _MU_IMAP_MSG_LINES;
+         }
+      }
+      break;
+      
+    default:
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE0,
+               (_("fetch returned a not requested item %d"),
+                resp->type));
+      break;
+    }
+  return 0;
+}
+  
+static void
+_imap_fetch_callback (void *data, int code, size_t sdat, void *pdat)
+{
+  struct _mu_imap_mailbox *imbx = data;
+  mu_mailbox_t mbox = imbx->mbox;
+  mu_list_t list = pdat;
+  int rc;
+  struct _mu_imap_message *imsg;
+  
+  rc = _imap_realloc_messages (imbx, sdat - 1);
+  if (rc)
+    {
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+               (_("cannot reallocate array of messages: %s"),
+                mu_strerror (rc)));
+      imbx->last_error = rc;
+      return;
+    }
+  if (imbx->msgs_cnt < sdat)
+    imbx->msgs_cnt = sdat;
+  imsg = imbx->msgs + sdat - 1;
+  imsg->imbx = imbx;
+  mu_list_foreach (list, fetch_response_parser, imsg);
+
+  if (mbox->observable)
+    {
+      if (((sdat + 1) % 10) == 0)
+       mu_observable_notify (imbx->mbox->observable,
+                             MU_EVT_MAILBOX_PROGRESS, NULL);
+    }
+}
+
+static int
+_imap_mbx_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  mu_folder_t folder = mbox->folder;
+  mu_imap_t imap = folder->data;
+  char *msgset;
+  int rc;
+  static char _imap_scan_items[] = "(UID FLAGS ENVELOPE RFC822.SIZE BODY)";
+  
+  rc = mu_asprintf (&msgset, "%lu:*", (unsigned long) msgno);
+  if (rc)
+    return rc;
+
+  _imap_mbx_clrerr (imbx);
+  rc = _imap_fetch_with_callback (imap, msgset, _imap_scan_items,
+                                 _imap_fetch_callback, imbx);
+  free (msgset);
+  if (rc == 0)
+    rc = _imap_mbx_errno (imbx);
+  if (rc == 0)
+    {
+      size_t i;
+      mu_off_t total = 0;
+
+      imbx->flags |= _MU_IMAP_MBX_UPTODATE;
+
+      for (i = 1; i <= imbx->msgs_cnt; i++)
+       {
+         total += imbx->msgs[i-1].message_size;
+         /* MU_EVT_MESSAGE_ADD must be delivered only when it is already
+            possible to retrieve the message in question.  It could not be
+            done in the fetch handler for obvious reasons.  Hence the extra
+            loop. */
+         if (mbox->observable)
+           mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, &i);
+       }
+      imbx->total_size = total;
+      
+      if (pcount)
+       *pcount = imbx->msgs_cnt;
+    }
+  return rc;
+}
+
+static int
+_imap_mbx_is_updated (mu_mailbox_t mbox)
+{
+  struct _mu_imap_mailbox *imbx = mbox->data;
+  mu_folder_t folder = mbox->folder;
+  mu_imap_t imap = folder->data;
+  int rc;
+  
+  rc = mu_imap_noop (imap);
+  if (rc)
+    {
+      mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+               (_("mu_imap_noop: %s"), mu_strerror (rc)));
+      imbx->last_error = rc;
+    }
+  return imbx->flags & _MU_IMAP_MBX_UPTODATE;
+}
+
+int
+_mu_imap_mailbox_init (mu_mailbox_t mailbox)
+{
+  struct _mu_imap_mailbox *mbx = calloc (1, sizeof (*mbx));
+
+  if (!mbx)
+    return ENOMEM;
+  mbx->mbox = mailbox;
+  mailbox->data = mbx;
+
+  mailbox->_destroy = _imap_mbx_destroy;
+  mailbox->_open = _imap_mbx_open;
+  mailbox->_close = _imap_mbx_close;
+  mailbox->_expunge = _imap_mbx_expunge;
+
+  mailbox->_messages_count = _imap_messages_count;
+  mailbox->_messages_recent = _imap_messages_recent;
+  mailbox->_message_unseen = _imap_message_unseen;
+  mailbox->_uidvalidity = _imap_uidvalidity;
+  mailbox->_uidnext = _imap_uidnext;
+  
+  mailbox->_scan = _imap_mbx_scan;
+  mailbox->_is_updated = _imap_mbx_is_updated;
+  mailbox->_get_message = _imap_mbx_get_message;
+  
+  //FIXME
+#if 0
+
+  /* Messages.  */
+  mailbox->_append_message = _mu_imap_append_message;
+
+#endif
+  return 0;
+}


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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