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-3.1.1-15-gc07fc42


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-3.1.1-15-gc07fc42
Date: Sun, 25 Dec 2016 18:27:34 +0000 (UTC)

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=c07fc42cdc414e0281b4453d31a0855af07db5a4

The branch, master has been updated
       via  c07fc42cdc414e0281b4453d31a0855af07db5a4 (commit)
       via  7a77cc6f80ae220c6adee5c862b53c43ed515270 (commit)
       via  8571d58b012a8c920073d9b9d139547dd44bd42a (commit)
      from  48bfe14edfa7612b2aea89f408ffa7952e88940a (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 c07fc42cdc414e0281b4453d31a0855af07db5a4
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Dec 25 20:22:37 2016 +0200

    Improve attachment creation API.
    
    * include/mailutils/message.h (mu_attachment_create)
    (mu_attachment_copy_from_stream)
    (mu_attachment_copy_from_file): New functions.
    * libmailutils/mime/attachment.c: Likewise.
    (mu_message_create_attachment): Rewrite using the three functions above.

commit 7a77cc6f80ae220c6adee5c862b53c43ed515270
Author: Sergey Poznyakoff <address@hidden>
Date:   Sun Dec 25 19:37:39 2016 +0200

    New string functions
    
    * libmailutils/string/strcount.c (mu_str_count): Take an array of
    (ASCII) characters to count occurrences of.  Optionally store individual
    counts in an array passed as the 3rd argument.
    * include/mailutils/cstr.h (mu_str_count): Change proto.
    (mu_c_str_escape, mu_c_str_escape_trans)
    (mu_c_str_unescape_inplace, mu_c_str_unescape)
    (mu_c_str_unescape_trans): New protos.
    * libmailutils/string/cstrescape.c: New file.
    * libmailutils/string/cstrunescape.c: New file.
    * libmailutils/string/Makefile.am: Add new files.

commit 8571d58b012a8c920073d9b9d139547dd44bd42a
Author: Sergey Poznyakoff <address@hidden>
Date:   Thu Dec 22 13:31:33 2016 +0200

    New command: mailutils stat
    
    * include/mailutils/util.h (mu_c_storage_t): New data type.
    * mu/stat.c: New file.
    * mu/Makefile.am: Add stat
    * doc/texinfo/programs.texi: Document mailutils stat

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

Summary of changes:
 doc/texinfo/programs.texi          |   70 +++++++
 examples/fremove.c                 |    2 +-
 examples/frename.c                 |    4 +-
 include/mailutils/cstr.h           |   13 +-
 include/mailutils/message.h        |   11 ++
 include/mailutils/util.h           |   20 ++
 libmailutils/mime/attachment.c     |  222 +++++++++++++++------
 libmailutils/string/Makefile.am    |    2 +
 libmailutils/string/cstrescape.c   |  162 +++++++++++++++
 libmailutils/string/cstrunescape.c |  204 +++++++++++++++++++
 libmailutils/string/strcount.c     |   32 ++-
 mu/Makefile.am                     |    1 +
 mu/stat.c                          |  382 ++++++++++++++++++++++++++++++++++++
 13 files changed, 1052 insertions(+), 73 deletions(-)
 create mode 100644 libmailutils/string/cstrescape.c
 create mode 100644 libmailutils/string/cstrunescape.c
 create mode 100644 mu/stat.c

diff --git a/doc/texinfo/programs.texi b/doc/texinfo/programs.texi
index 1afb2ba..6ac084c 100644
--- a/doc/texinfo/programs.texi
+++ b/doc/texinfo/programs.texi
@@ -7816,6 +7816,7 @@ with Mailutils.
 * mailutils info::                Show Mailutils configuration.
 * mailutils cflags::              Show compiler options.
 * mailutils ldflags::             List libraries required to link.
+* mailutils stat::                Show mailbox status.
 * mailutils query::               Query configuration values.
 * mailutils 2047::                Decode/encode email message headers.
 * mailutils filter::              Apply a chain of filters to the input.
@@ -8004,6 +8005,75 @@ Provide Guile language bindings.
 Provide Python language bindings.
 @end table
 
address@hidden mailutils stat
address@hidden mailutils stat
+The command @command{mailutils stat} shows status of a mailbox.  The
+name or URL of the mailbox to operate upon is supplied in the first
+argument.  If not given, the command will display status of the
+invoking user system mailbox.
+
address@hidden
+$ mailutils stat
+type: maildir
+path: /var/mail/smith
+URL: /var/mail/smith
+size: 3498
+messages: 24
+recent messages: 3
+first unseen: 20
+uidvalidity: 1338543026
+next uid: 87
+access: 2016-12-15 09:15:08 +0200
address@hidden example
+
+The output format is controlled by the @option{--format} (@option{-c})
+option.  Its argument is the desired format string, composed of
+ordinary characters, which are reporduced on standard output verbatim,
+backslash sequences, and format specifiers, beginning with @samp{%}.
+
address@hidden sequences} are interpreted as in C.
+
+A @dfn{format specifier} consists of a leading @samp{%} followed by a
+letter.  Optional @samp{:} may occur between @samp{%} and the letter.
+Its presense instructs the program to print the description of the
+corresponding value before the value itself.
+
+The following format sequences are understood:
+
address@hidden @asis
address@hidden %f
+Name of the mailbox as supplied in the command line.  If
address@hidden stat} was used without explicit mailbox argument,
address@hidden is equivalent to @samp{%U}.
address@hidden %t
+Type of the mailbox (@samp{mbox}, @samp{maildir}, etc.).  The
+description string is @samp{type}.
address@hidden %p
+Path to the mailbox.  In case of remote mailboxes, it is the path
+part of the mailbox URL.  Description string: @samp{path}.
address@hidden %U
+URL of the mailbox.  Description string: @samp{URL}.
address@hidden %s
+Size of the mailbox in octets.  Description string: @samp{size}.
address@hidden %c
+Number of messages in the mailbox.  Description string:
address@hidden
address@hidden %r
+Number of recent (unread) messages in the mailbox.  Description string:
address@hidden messages}.
address@hidden %u
+Index of the first unseen message.  Description string: @samp{first unseen}.
address@hidden %v
+The UIDVALIDITY value.  Description string: @samp{uidvalidity}.
address@hidden %n
+The UID value which will be assigned to the new message to be
+incorporated into the mailbox.  Description string: @samp{next uid}.
address@hidden %a
+Access time of the mailbox, as a number of seconds since the epoch.
address@hidden %A
+Access time of the mailbox in human-readable format.
address@hidden table
+
 @node mailutils query
 @subsection mailutils query
 The @command{mailutils query} command queries values from Mailutils
diff --git a/examples/fremove.c b/examples/fremove.c
index e7c2d91..991f5ba 100644
--- a/examples/fremove.c
+++ b/examples/fremove.c
@@ -32,7 +32,7 @@ main (int argc, char **argv)
     }
 
   if (!mu_file_name_is_safe (argv[0])
-      || (argv[0][0] == '/' && mu_str_count (argv[0], '/') < 2))
+      || (argv[0][0] == '/' && mu_str_count (argv[0], "/", NULL) < 2))
     {
       mu_error ("unsafe file name");
       return 1;
diff --git a/examples/frename.c b/examples/frename.c
index 1bf6556..9fcf673 100644
--- a/examples/frename.c
+++ b/examples/frename.c
@@ -36,13 +36,13 @@ main (int argc, char **argv)
     }
 
   if (!mu_file_name_is_safe (argv[0])
-      || (argv[0][0] == '/' && mu_str_count (argv[0], '/') < 2))
+      || (argv[0][0] == '/' && mu_str_count (argv[0], "/", NULL) < 2))
     {
       mu_error ("%s: unsafe file name", argv[0]);
       return 1;
     }
   if (!mu_file_name_is_safe (argv[1])
-      || (argv[1][0] == '/' && mu_str_count (argv[1], '/') < 2))
+      || (argv[1][0] == '/' && mu_str_count (argv[1], "/", NULL) < 2))
     {
       mu_error ("%sunsafe file name", argv[0]);
       return 1;
diff --git a/include/mailutils/cstr.h b/include/mailutils/cstr.h
index 579a496..d98259b 100644
--- a/include/mailutils/cstr.h
+++ b/include/mailutils/cstr.h
@@ -46,7 +46,18 @@ char *mu_str_stripws (char *string);
 
 int mu_string_split (const char *string, char *delim, mu_list_t list);
 
-size_t mu_str_count (char const *str, int chr);
+size_t mu_str_count (char const *str, char const *chr, size_t *cnt);
+
+int mu_c_str_escape (char const *str, char const *chr, char const *xtab,
+                    char **ret_str);
+int mu_c_str_escape_trans (char const *str, char const *trans, char **ret_str);
+
+int mu_c_str_unescape_inplace (char *str, char const *chr, char const *xtab);
+int mu_c_str_unescape (char const *str, char const *chr, char const *xtab,
+                      char **ret_str);
+int mu_c_str_unescape_trans (char const *str, char const *trans,
+                            char **ret_str);
+
   
 #ifdef __cplusplus
 }
diff --git a/include/mailutils/message.h b/include/mailutils/message.h
index d149923..a1c04a8 100644
--- a/include/mailutils/message.h
+++ b/include/mailutils/message.h
@@ -211,10 +211,21 @@ extern int mu_message_set_bodystructure (mu_message_t msg,
       void *owner);
   
 /* misc functions */
+extern int mu_attachment_create (mu_message_t *newmsg,
+                                const char *content_type,
+                                const char *encoding,
+                                const char *name, const char *filename);
+extern int mu_attachment_copy_from_stream (mu_message_t att,
+                                          mu_stream_t stream,
+                                          char const *encoding);
+extern int mu_attachment_copy_from_file (mu_message_t att,
+                                        char const *filename,
+                                        char const *encoding);
 extern int mu_message_create_attachment (const char *content_type,
                                         const char *encoding,
                                         const char *filename,
                                         mu_message_t *newmsg);
+  
 extern int mu_message_save_attachment (mu_message_t msg,
                                       const char *filename,
                                       mu_mime_io_buffer_t buf);
diff --git a/include/mailutils/util.h b/include/mailutils/util.h
index d539099..afec5ae 100644
--- a/include/mailutils/util.h
+++ b/include/mailutils/util.h
@@ -23,6 +23,7 @@
 
 #include <mailutils/list.h>
 #include <mailutils/types.h>
+#include <mailutils/cidr.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -198,6 +199,25 @@ enum mu_c_type
   };
 
 typedef enum mu_c_type mu_c_type_t;
+
+union mu_c_storage
+{
+  char *c_string;
+  signed short c_short;
+  unsigned short c_ushort;
+  int c_int;
+  unsigned int c_uint;
+  long c_long;
+  unsigned long c_ulong;
+  size_t c_size;
+  mu_off_t c_off;
+  time_t c_time;
+  int c_bool;
+  struct mu_cidr c_cidr;
+};
+
+typedef union mu_c_storage mu_c_storage_t;
+
 extern char const *mu_c_type_str[];
 int mu_str_to_c (char const *string, mu_c_type_t type, void *tgt,
                 char **errmsg);
diff --git a/libmailutils/mime/attachment.c b/libmailutils/mime/attachment.c
index 55e3791..c4796e6 100644
--- a/libmailutils/mime/attachment.c
+++ b/libmailutils/mime/attachment.c
@@ -55,79 +55,179 @@ struct _mu_mime_io_buffer
   mu_stream_t fstream; /* output file stream for saving attachment */
 };
 
-int
-mu_message_create_attachment (const char *content_type, const char *encoding,
-                             const char *filename, mu_message_t *newmsg)
+static int
+at_hdr (mu_header_t hdr, const char *content_type, const char *encoding,
+       const char *name, const char *filename)
 {
-  mu_header_t hdr;
-  mu_body_t body;
-  mu_stream_t fstream = NULL, tstream = NULL;
-  char *header = NULL, *name = NULL, *fname = NULL;
-  int ret;
-
-  if (newmsg == NULL)
-    return MU_ERR_OUT_PTR_NULL;
-  if (filename == NULL)
-    return EINVAL;
+  int rc;
+  char *val, *str;
 
-  if ((ret = mu_message_create (newmsg, NULL)) == 0)
+  if (!name)
     {
-      if (content_type == NULL)
-       content_type = "text/plain";
-      if (encoding == NULL)
-       encoding = "7bit";
-      if ((fname = strdup (filename)) != NULL)
+      if (filename)
        {
-         name = strrchr (fname, '/');
+         name = strrchr (filename, '/');
          if (name)
            name++;
          else
-           name = fname;
-         ret = mu_asprintf (&header,
-                            "Content-Type: %s; name=%s\n"
-                            "Content-Transfer-Encoding: %s\n"
-                            "Content-Disposition: attachment; filename=%s\n\n",
-                            content_type, name, encoding, name);
-         if (ret == 0)
-           {
-             if ((ret = mu_header_create (&hdr, header,
-                                          strlen (header))) == 0)
-               {
-                 mu_stream_t bstr;
-                 mu_message_get_body (*newmsg, &body);
-                 mu_body_get_streamref (body, &bstr);
-                 
-                 if ((ret = mu_file_stream_create (&fstream, filename,
-                                                   MU_STREAM_READ)) == 0)
-                   {
-                     if ((ret = mu_filter_create (&tstream, fstream, encoding,
-                                                  MU_FILTER_ENCODE,
-                                                  MU_STREAM_READ)) == 0)
-                       {
-                         mu_stream_copy (bstr, tstream, 0, NULL);
-                         mu_stream_unref (tstream);
-                         mu_message_set_header (*newmsg, hdr, NULL);
-                       }
-                   }
-                 mu_stream_unref (bstr);
-                 free (header);
-               }
-           }
+           name = filename;
        }
     }
+
+  if (name)
+    {
+      rc = mu_c_str_escape (name, "\\\"", NULL, &str);
+      if (rc)
+       return rc;
+      rc = mu_asprintf (&val, "%s; name=\"%s\"", content_type, str);
+      free (str);
+      if (rc)
+       return rc;
+      rc = mu_header_append (hdr, MU_HEADER_CONTENT_TYPE, val);
+      free (val);
+    }
+  else
+    rc = mu_header_append (hdr, MU_HEADER_CONTENT_TYPE, content_type);
+  
+  if (rc)
+    return rc;
+  
+  if (filename)
+    {
+      rc = mu_c_str_escape (filename, "\\\"", NULL, &str);
+      if (rc)
+       return rc;
+      rc = mu_asprintf (&val, "%s; filename=\"%s\"", "attachment", str);
+      free (str);
+      if (rc)
+       return rc;
+      rc = mu_header_append (hdr, MU_HEADER_CONTENT_DISPOSITION, val);
+      free (val);
+    }
+  else
+    rc = mu_header_append (hdr, MU_HEADER_CONTENT_DISPOSITION, "attachment");
+  if (rc)
+    return rc;
+  return mu_header_append (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, encoding);
+}
+
+/* Create in *NEWMSG an empty attachment of given CONTENT_TYPE and ENCODING.
+   NAME, if not NULL, supplies the name of the attachment.
+   FILENAME, if not NULL, gives the file name.
+ */
+int
+mu_attachment_create (mu_message_t *newmsg,
+                     const char *content_type, const char *encoding,
+                     const char *name,
+                     const char *filename)
+{
+  int rc;
+  mu_header_t hdr;
   
-  if (ret)
+  if (newmsg == NULL)
+    return MU_ERR_OUT_PTR_NULL;
+
+  rc = mu_message_create (newmsg, NULL);
+  if (rc)
+    return rc;
+
+  rc = mu_header_create (&hdr, NULL, 0);
+  if (rc)
     {
-      if (*newmsg)
-       mu_message_destroy (newmsg, NULL);
-      if (hdr)
-       mu_header_destroy (&hdr);
-      if (fstream)
-       mu_stream_destroy (&fstream);
-      if (fname)
-       free (fname);
+      mu_message_destroy (newmsg, NULL);
+      return rc;
     }
-  return ret;
+  mu_message_set_header (*newmsg, hdr, NULL);
+
+  rc = at_hdr (hdr, content_type, encoding, name, filename);
+
+  if (rc)
+    mu_message_destroy (newmsg, NULL);
+  
+  return rc;
+}
+
+/* ATT is an attachment created by a previous call to mu_attachment_create().
+
+   Fills in the attachment body with the data from STREAM using the specified
+   ENCODING.
+ */
+int
+mu_attachment_copy_from_stream (mu_message_t att, mu_stream_t stream,
+                               char const *encoding)
+{
+  mu_body_t body;
+  mu_stream_t bstr;
+  mu_stream_t tstream;
+  int rc;
+  
+  mu_message_get_body (att, &body);
+  rc = mu_body_get_streamref (body, &bstr);
+  if (rc)
+    return rc;
+  
+  rc = mu_filter_create (&tstream, stream, encoding, MU_FILTER_ENCODE,
+                        MU_STREAM_READ);
+  if (rc == 0)
+    {
+      rc = mu_stream_copy (bstr, tstream, 0, NULL);
+      mu_stream_unref (tstream);
+    }
+  mu_stream_unref (bstr);
+  return rc;
+}
+
+/* ATT is an attachment created by a previous call to mu_attachment_create().
+
+   Fills in the attachment body with the data from FILENAME using the specified
+   ENCODING.
+ */
+int
+mu_attachment_copy_from_file (mu_message_t att, char const *filename,
+                             char const *encoding)
+{
+  mu_stream_t stream;
+  int rc;
+
+  rc = mu_file_stream_create (&stream, filename, MU_STREAM_READ);
+  if (rc == 0)
+    {
+      rc = mu_attachment_copy_from_stream (att, stream, encoding);
+      mu_stream_unref (stream);
+    }
+  return rc;
+} 
+
+int
+mu_message_create_attachment (const char *content_type, const char *encoding,
+                             const char *filename, mu_message_t *newmsg)
+{
+  int rc;
+  char const *name;
+  mu_message_t att;
+  
+  if (content_type == NULL)
+    content_type = "text/plain";
+  if (encoding == NULL)
+    encoding = "7bit";
+
+  name = strrchr (filename, '/');
+  if (name)
+    name++;
+  else
+    name = filename;
+
+  rc = mu_attachment_create (&att, content_type, encoding, name, filename);
+  if (rc == 0)
+    {
+      rc = mu_attachment_copy_from_file (att, filename, encoding);
+      if (rc)
+       mu_message_destroy (&att, NULL);
+    }
+  if (rc == 0)
+    *newmsg = att;
+
+  return rc;
 }
 
 int
diff --git a/libmailutils/string/Makefile.am b/libmailutils/string/Makefile.am
index 4bcea5b..4555744 100644
--- a/libmailutils/string/Makefile.am
+++ b/libmailutils/string/Makefile.am
@@ -21,6 +21,8 @@ libstring_la_SOURCES = \
  cpystr.c\
  cstrcasecmp.c\
  cstrcasestr.c\
+ cstrescape.c\
+ cstrunescape.c\
  cstrlower.c\
  cstrupper.c\
  hexstr.c\
diff --git a/libmailutils/string/cstrescape.c b/libmailutils/string/cstrescape.c
new file mode 100644
index 0000000..dca7927
--- /dev/null
+++ b/libmailutils/string/cstrescape.c
@@ -0,0 +1,162 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2016 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/cstr.h>
+#include <mailutils/errno.h>
+
+/* Examines STR for occurrences of characters from CHR.  Returns in RET_STR
+   a malloc'ed string where each occurrence of CHR[i] is replaced by a
+   backslash, followed by XTAB[i].
+
+   If CHR is NULL, RET_STR contains a malloc'ed copy of STR (XTAB is
+   ignored).
+
+   If XTAB is NULL, XTAB = CHR is assumed.
+
+   Callers are advised to include backslash into both CHR and XTAB.
+
+   Returns 0 on success, error code if an error occurred.
+   
+   Example:
+
+   Escape each occurrence of backslash and double quote:
+   
+     mu_c_str_escape (str, "\\\"", NULL, &ret_str)
+*/
+int
+mu_c_str_escape (char const *str, char const *chr, char const *xtab,
+                char **ret_str)
+{
+  char *newstr;
+  size_t n;
+  int c;
+  
+  if (!ret_str)
+    return MU_ERR_OUT_PTR_NULL;
+  
+  if (!str)
+    {
+      *ret_str = NULL;
+      return 0;
+    }
+
+  if (!chr)
+    {
+      newstr = strdup (str);
+      if (!newstr)
+       return errno;
+      *ret_str = newstr;
+      return 0;
+    }
+
+  n = strlen (chr);
+
+  if (xtab)
+    {
+      if (strlen (xtab) != n)
+       return EINVAL;
+    }
+  else
+    xtab = chr;
+  
+  n = mu_str_count (str, chr, NULL);
+  
+  newstr = malloc (strlen (str) + n + 1);
+  if (!newstr)
+    return errno;
+  *ret_str = newstr;
+  
+  if (n == 0)
+    {
+      strcpy (newstr, str);
+      return 0;
+    }
+
+  while ((c = *str++) != 0)
+    {
+      char *p = strchr (chr, c);
+
+      if (p)
+       {
+         *newstr++ = '\\';
+          *newstr++ = xtab[p - chr];
+       }
+      else
+       *newstr++ = c;
+    }
+  *newstr = 0;
+
+  return 0;
+}
+
+/* Escape certain characters in STR.  Return allocated string in RET_STR.
+
+   Escapable characters are defined by the array TRANS, which consists of an
+   even number of elements.  Each pair of characters in this array contains:
+
+     TRANS[i+1]  - character to be escaped
+     TRANS[i]    - character to use in escape sequence for TRANS[i+1].
+
+   Each TRANS[i+1] is replaced by backslash + TRANS[i].
+
+   Returns 0 on success, or error code if an error occurred.
+
+   E.g., to escape control characters, backslash and double-quote using
+   C convention:
+
+      mu_c_str_escape_trans (str, "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v", &ret)
+
+   See also mu_wordsplit_c_escape_tab in wordsplit.c
+*/
+int
+mu_c_str_escape_trans (char const *str, char const *trans, char **ret_str)
+{
+  char *chr, *xtab;
+  size_t n, i;
+  int rc;
+  
+  if (trans)
+    {
+      n = strlen (trans);
+      if (n % 2)
+       return EINVAL;
+      chr = malloc (n + 2);
+      if (!chr)
+       return errno;
+      xtab = chr + n / 2 + 1;
+      for (i = 0; i < n; i += 2)
+       {
+         chr[i / 2] = trans[i + 1];
+         xtab[i / 2] = trans[i];
+       }
+      chr[i / 2] = xtab[i / 2] = 0;
+    }
+  else
+    {
+      chr = xtab = NULL;
+    }
+
+  rc = mu_c_str_escape (str, chr, xtab, ret_str);
+
+  free (chr);
+
+  return rc;
+}
+       
+    
diff --git a/libmailutils/string/cstrunescape.c 
b/libmailutils/string/cstrunescape.c
new file mode 100644
index 0000000..b5034ea
--- /dev/null
+++ b/libmailutils/string/cstrunescape.c
@@ -0,0 +1,204 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2016 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/>. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/cstr.h>
+#include <mailutils/errno.h>
+
+/* Copy characters from IN to OUT.  Replace each occurrences of backslash
+   followed by a character XTAB[i] with CHR[i].
+
+   OUT should be large enough to accomodate the translated string (same length
+   as IN, in the worst case).  It is OK if IN==OUT.
+
+   Both XTAB and CHR must not be NULL and must contain the same number of
+   elements. 
+ */
+static void
+c_str_unescape (char const *in, char *out, char const *chr, char const *xtab)
+{
+  size_t i, j;
+  
+  for (i = j = 0; in[i]; i++, j++)
+    {
+      if (in[i] == '\\')
+       break;
+      out[j] = in[i];
+    }
+
+  if (in[i])
+    {
+      for (; in[i]; i++, j++)
+       {
+         if (in[i] == '\\')
+           {
+             char *p;
+             if (in[i+1] && (p = strchr (xtab, in[i+1])) != NULL)
+               {
+                 out[j] = chr[p - xtab];
+                 i++;
+                 continue;
+               }
+           }
+         out[j] = in[i];
+       }
+    }
+  out[j] = 0;
+}
+
+/* Modifies STR, by replacing each occurrence of \ followed by a charater
+   XTAB[i] with CHR[i].
+
+   Either XTAB or CHR can be NULL, in which case XTAB=CHR is assumed.
+
+   If both XTAB and CHR are NULL, STR is unchanged.
+   
+   STR == NULL is OK.
+
+   Returns 0 success, and EINVAL if lengths of CHR and XTAB differ.
+*/
+int
+mu_c_str_unescape_inplace (char *str, char const *chr, char const *xtab)
+{
+  if (!str)
+    return 0;
+  if (!xtab)
+    {
+      if (chr)
+       xtab = chr;
+      else
+       return 0;
+    }
+  else if (!chr)
+    chr = xtab;
+  else if (strlen (chr) != strlen (xtab))
+    return EINVAL;
+  c_str_unescape (str, str, chr, xtab);
+  return 0;
+}
+
+/* A counterpart of mu_c_str_escape.  Creates an allocated (using malloc(3))
+   copy of STR, where each occurrence of \ followed by a charater XTAB[i]
+   is replaced with single character CHR[i].
+
+   Either XTAB or CHR can be NULL, in which case XTAB=CHR is assumed.
+
+   If both XTAB and CHR are NULL, the result is *RET_STR will contain exact
+   malloc'ed copy of STR.
+   
+   STR == NULL is OK: in that case *RET_STR will also be NULL.
+
+   Returns 0 success, EINVAL if lengths of CHR and XTAB differ,
+   MU_ERR_OUT_PTR_NULL if RET_STR is NULL, and ENOMEM if memory allocation
+   failed.
+ */
+int
+mu_c_str_unescape (char const *str, char const *chr, char const *xtab,
+                  char **ret_str)
+{
+  char *newstr;
+  size_t i, size;
+  
+  if (!ret_str)
+    return MU_ERR_OUT_PTR_NULL;
+  
+  if (!str)
+    {
+      *ret_str = NULL;
+      return 0;
+    }
+
+  if (!xtab)
+    {
+      if (chr)
+       xtab = chr;
+      else
+       {
+         char *p = strdup (str);
+         if (!p)
+           return errno;
+         *ret_str = p;
+       }
+    }
+  else if (!chr)
+    chr = xtab;
+  else if (strlen (chr) != strlen (xtab))
+    return EINVAL;
+
+  size = 0;
+  for (i = 0; str[i]; i++)
+    {
+      if (str[i] == '\\' && str[i + 1] && strchr (xtab, str[i + 1]))
+       i++;
+      size++;
+    }
+
+  newstr = malloc (size + 1);
+  if (!newstr)
+    return errno;
+  *ret_str = newstr;
+  
+  c_str_unescape (str, newstr, chr, xtab);
+
+  return 0;
+}
+
+/* A counterpart of mu_c_str_escape_trans.
+
+   Creates an allocated (using malloc(3)) copy of STR, where each occurrence 
+   of \ followed by TRANS[i] is replaced by TRANS[i+1].
+
+   Returns 0 on success, or error code if an error occurred.
+   
+   See also mu_wordsplit_c_escape_tab in wordsplit.c
+ */
+int
+mu_c_str_unescape_trans (char const *str, char const *trans, char **ret_str)
+{
+  char *chr, *xtab;
+  size_t n, i;
+  int rc;
+  
+  if (trans)
+    {
+      n = strlen (trans);
+      if (n % 2)
+       return EINVAL;
+      chr = malloc (n + 2);
+      if (!chr)
+       return errno;
+      xtab = chr + n / 2 + 1;
+      for (i = 0; i < n; i += 2)
+       {
+         chr[i / 2] = trans[i + 1];
+         xtab[i / 2] = trans[i];
+       }
+      chr[i / 2] = xtab[i / 2] = 0;
+    }
+  else
+    {
+      chr = xtab = NULL;
+    }
+
+  rc = mu_c_str_unescape (str, chr, xtab, ret_str);
+
+  free (chr);
+
+  return rc;
+}
+  
diff --git a/libmailutils/string/strcount.c b/libmailutils/string/strcount.c
index 4316c0a..9937214 100644
--- a/libmailutils/string/strcount.c
+++ b/libmailutils/string/strcount.c
@@ -16,28 +16,44 @@
 
 #include <config.h>
 #include <limits.h>
+#include <string.h>
 #include <mailutils/util.h>
 
-/* Return the number of occurrences of the ASCII character CHR in the
-   UTF-8 string STR. */
+/* Count number of occurrences of each ASCII character from CHR in the
+   UTF-8 string STR.  Unless CNT is NULL, fill it with the counts for
+   each character (so that CNT[i] contains number of occurrences of
+   CHR[i]).  Return total number of occurrences. */
 size_t
-mu_str_count (char const *str, int chr)
+mu_str_count (char const *str, char const *chr, size_t *cnt)
 {
   unsigned char c;
-  size_t count = 0;
   int consume = 0;
-  
-  if (!str || chr < 0 || chr > UCHAR_MAX)
+  size_t count = 0;
+
+  if (!str || !chr)
     return 0;
   
+  if (cnt)
+    {
+      int i;
+      
+      for (i = 0; chr[i]; i++)
+       cnt[i] = 0;
+    }
+  
   while ((c = *str++) != 0)
     {
       if (consume)
        consume--;
       else if (c < 0xc0)
        {
-         if (c == chr)
-           count++;
+         char *p = strchr (chr, c);
+         if (p)
+           {
+             if (cnt)
+               cnt[p - chr]++;
+             count++;
+           }
        }
       else if (c & 0xc0)
        consume = 1;
diff --git a/mu/Makefile.am b/mu/Makefile.am
index d9355df..146c4c4 100644
--- a/mu/Makefile.am
+++ b/mu/Makefile.am
@@ -59,6 +59,7 @@ MODULES = \
  $(POP_C)\
  query.c\
  send.c\
+ stat.c\
  $(SMTP_C)\
  wicket.c
 
diff --git a/mu/stat.c b/mu/stat.c
new file mode 100644
index 0000000..170f6d7
--- /dev/null
+++ b/mu/stat.c
@@ -0,0 +1,382 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010-2012, 2014-2016 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/>. */
+
+#include "mu.h"
+
+char stat_docstring[] = N_("display mailbox status");
+char stat_args_doc[] = N_("[MAILBOX]");
+
+char *format_string = "%:t\n\
+%:p\n\
+%:U\n\
+%:s\n\
+%:c\n\
+%:r\n\
+%:u\n\
+%:v\n\
+%:n\n\
+%:A\n";
+
+static struct mu_option stat_options[] = {
+  { "format", 'c', N_("STRING"), MU_OPTION_DEFAULT,
+    N_("defines output format"),
+    mu_c_string, &format_string },
+  MU_OPTION_END
+};
+
+#define prcat2(a, b) a ## b
+#define PR_C(field, fmt)                       \
+  static void                                  \
+  prcat2(pr_,field) (mu_c_storage_t *stor)     \
+  {                                            \
+    mu_printf (fmt, stor->field);              \
+  }                                            \
+
+PR_C(c_string, "%s")
+PR_C(c_short, "%hd")
+PR_C(c_ushort, "%hu")
+PR_C(c_int, "%d")
+PR_C(c_uint, "%u")
+PR_C(c_long, "%ld")
+PR_C(c_ulong, "%lu")
+PR_C(c_size, "%zu")
+PR_C(c_off, "%" MU_PRI_OFF_T)
+
+static void
+pr_c_time (mu_c_storage_t *stor)
+{
+  mu_printf ("%lu", (unsigned long)stor->c_time);
+}
+
+static void
+pr_c_time_h (mu_c_storage_t *stor)
+{
+  struct tm *tm = localtime (&stor->c_time);
+  mu_c_streamftime (mu_strout, "%Y-%m-%d %H:%M:%S %Z", tm, NULL);
+}
+
+static void (*c_fmt[]) (mu_c_storage_t *stor) = {
+#define D(t) [prcat2(mu_,t)] = prcat2(pr_,t)
+  D(c_string),
+  D(c_short),
+  D(c_ushort),
+  D(c_int),
+  D(c_uint),
+  D(c_long),
+  D(c_ulong),
+  D(c_size),
+  D(c_off),
+  D(c_time)
+#undef D
+};
+
+static void
+mu_c_output (mu_c_type_t type, mu_c_storage_t *cstor)
+{
+  if (c_fmt[type])
+    c_fmt[type] (cstor);
+  else
+    abort ();
+}
+
+struct mbox_property
+{
+  char fmt;
+  char *title;
+  mu_c_type_t type;
+  int (*fun) (mu_mailbox_t, char const *, mu_c_storage_t *);
+  void (*prt) (mu_c_storage_t *stor);
+};
+
+static int get_type (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_path (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_url (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_size (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_count (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_recent (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_unseen (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_uidvalidity (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_uidnext (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_atime (mu_mailbox_t, char const *, mu_c_storage_t *);
+static int get_name (mu_mailbox_t, char const *, mu_c_storage_t *);
+
+static struct mbox_property proptab[] = {
+  { 't', N_("type"),               mu_c_string, get_type },
+  { 'p', N_("path"),               mu_c_string, get_path },
+  { 'U', N_("URL"),                mu_c_string, get_url },
+  { 's', N_("size"),               mu_c_off, get_size },
+  { 'c', N_("messages"),           mu_c_size, get_count },
+  { 'r', N_("recent messages"),    mu_c_size, get_recent },
+  { 'u', N_("first unseen"),       mu_c_size, get_unseen },
+  { 'v', N_("uidvalidity"),        mu_c_ulong, get_uidvalidity },
+  { 'n', N_("next uid"),           mu_c_size, get_uidnext },
+  { 'a', N_("access"),             mu_c_time, get_atime },
+  { 'A', N_("access"),             mu_c_time, get_atime, pr_c_time_h },
+  { 'f', N_("name"),               mu_c_string, get_name },
+  { 0 }
+};
+
+static struct mbox_property *
+propfmt (int fmt)
+{
+  struct mbox_property *p;
+  for (p = proptab; p->fmt; p++)
+    if (p->fmt == fmt)
+      return p;
+  return NULL;
+}
+
+static char const *
+fmtspec (char const *fmt, mu_mailbox_t mbx, const char *name)
+{
+  int c;
+  int title = 0;
+  struct mbox_property *prop;
+
+  if (!*++fmt)
+    {
+      mu_stream_write (mu_strout, fmt - 1, 1, NULL);
+      return fmt;
+    }
+  
+  c = *fmt++;
+
+  if (c == '%')
+    {
+      mu_stream_write (mu_strout, fmt - 1, 1, NULL);
+      return fmt;
+    }
+
+  if (c == ':')
+    {
+      if (*fmt == 0)
+       {
+         mu_stream_write (mu_strout, fmt - 2, 2, NULL);
+         return fmt;
+       }
+      c = *fmt++;
+      title = 1;
+    }
+  prop = propfmt (c);
+  if (prop)
+    {
+      int rc;
+      mu_c_storage_t cstor;
+      if (title)
+       mu_printf ("%s: ", gettext (prop->title));
+      rc = prop->fun (mbx, name, &cstor);
+      switch (rc)
+       {
+       case 0:
+         if (prop->prt)
+           prop->prt (&cstor);
+         else
+           mu_c_output (prop->type, &cstor);
+         if (prop->type == mu_c_string)
+           free (cstor.c_string);
+         break;
+
+       case MU_ERR_EMPTY_VFN:
+       case ENOSYS:
+         mu_printf (_("N/A"));
+         break;
+
+       default:
+         mu_printf ("[%s]", mu_strerror (rc));
+       }
+    }
+  else
+    mu_stream_write (mu_strout, "?", 1, NULL);
+  return fmt;
+}
+
+void
+format_stat (char const *fmt, mu_mailbox_t mbx, const char *name)
+{
+  int c;
+  
+  while (*fmt)
+    {
+      switch (*fmt)
+       {
+       case '%':
+         fmt = fmtspec (fmt, mbx, name);
+         break;
+         
+       case '\\':
+         if (fmt[1] && (c = mu_wordsplit_c_unquote_char (fmt[1])))
+           {
+             mu_printf ("%c", c);
+             fmt += 2;
+             break;
+           }
+         /* fall through */
+       default:
+         mu_stream_write (mu_strout, fmt, 1, NULL);
+         if (*fmt == '\n' && fmt[1] == 0)
+           return;
+         fmt++;
+       }
+    }
+  mu_printf ("\n");
+}
+
+int
+mutool_stat (int argc, char **argv)
+{
+  int rc;
+  mu_mailbox_t mbox;
+  const char *name;
+    
+  mu_register_all_mbox_formats ();
+  
+  mu_action_getopt (&argc, &argv, stat_options, stat_docstring, stat_args_doc);
+  if (argc > 1)
+    {
+      mu_error (_("too many arguments"));
+      return EX_USAGE;
+    }
+  name = argv[0];
+  
+  rc = mu_mailbox_create_default (&mbox, name);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_create_default", name, rc);
+      return EX_UNAVAILABLE;
+    }
+
+  rc = mu_mailbox_open (mbox, MU_STREAM_READ);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open", name, rc);
+      return EX_UNAVAILABLE;
+    }
+
+  if (!name)
+    {
+      mu_url_t url;
+      mu_mailbox_get_url (mbox, &url);
+      name = mu_url_to_string (url);
+    }
+
+  format_stat (format_string, mbox, name);
+
+  mu_mailbox_close (mbox);
+  mu_mailbox_destroy (&mbox);
+  return 0;
+}
+
+static int
+get_type (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  mu_url_t url;
+  int rc;
+  
+  rc = mu_mailbox_get_url (mbox, &url);
+  if (rc == 0)
+    rc = mu_url_aget_scheme (url, &cstor->c_string);
+  return rc;
+}
+
+static int
+get_path (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  int rc;
+  mu_url_t url;
+
+  rc = mu_mailbox_get_url (mbox, &url);
+  if (rc == 0)
+    rc = mu_url_aget_path (url, &cstor->c_string);
+  return rc;
+}
+
+static int
+get_url (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  mu_url_t url;
+  int rc;
+  
+  rc = mu_mailbox_get_url (mbox, &url);
+  if (rc == 0)
+    cstor->c_string = mu_strdup (mu_url_to_string (url));
+  return rc;
+}
+
+static int
+get_size (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  return mu_mailbox_get_size (mbox, &cstor->c_off);
+}
+
+static int
+get_count (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  return mu_mailbox_messages_count (mbox, &cstor->c_size);
+}
+
+static int
+get_recent (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  return mu_mailbox_messages_recent (mbox, &cstor->c_size);
+}
+
+static int
+get_unseen (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  return mu_mailbox_message_unseen (mbox, &cstor->c_size);
+}
+
+static int
+get_uidvalidity (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  return mu_mailbox_uidvalidity (mbox, &cstor->c_ulong);
+}
+
+static int
+get_uidnext (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  return mu_mailbox_uidnext (mbox, &cstor->c_size);
+}
+
+static int
+get_atime (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  return mu_mailbox_access_time (mbox, &cstor->c_time);
+}
+
+static int
+get_name (mu_mailbox_t mbox, char const *mbname, mu_c_storage_t *cstor)
+{
+  cstor->c_string = mu_strdup (mbname);
+  return 0;
+}
+
+/*
+  MU Setup: stat
+  mu-handler: mutool_stat
+  mu-docstring: stat_docstring
+  End MU Setup:
+*/
+
+  
+
+
+
+
+
+  
+  
+  


hooks/post-receive
-- 
GNU Mailutils



reply via email to

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