Commit 8571d58b 8571d58b012a8c920073d9b9d139547dd44bd42a by Sergey Poznyakoff

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
1 parent 48bfe14e
......@@ -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
@node mailutils stat
@subsection 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.
@example
$ 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
@end 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{%}.
@dfn{Backslash 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:
@table @asis
@item %f
Name of the mailbox as supplied in the command line. If
@command{mailutils stat} was used without explicit mailbox argument,
@samp{%f} is equivalent to @samp{%U}.
@item %t
Type of the mailbox (@samp{mbox}, @samp{maildir}, etc.). The
description string is @samp{type}.
@item %p
Path to the mailbox. In case of remote mailboxes, it is the path
part of the mailbox URL. Description string: @samp{path}.
@item %U
URL of the mailbox. Description string: @samp{URL}.
@item %s
Size of the mailbox in octets. Description string: @samp{size}.
@item %c
Number of messages in the mailbox. Description string:
@samp{messages}.
@item %r
Number of recent (unread) messages in the mailbox. Description string:
@samp{recent messages}.
@item %u
Index of the first unseen message. Description string: @samp{first unseen}.
@item %v
The UIDVALIDITY value. Description string: @samp{uidvalidity}.
@item %n
The UID value which will be assigned to the new message to be
incorporated into the mailbox. Description string: @samp{next uid}.
@item %a
Access time of the mailbox, as a number of seconds since the epoch.
@item %A
Access time of the mailbox in human-readable format.
@end table
@node mailutils query
@subsection mailutils query
The @command{mailutils query} command queries values from Mailutils
......
......@@ -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);
......
......@@ -59,6 +59,7 @@ MODULES = \
$(POP_C)\
query.c\
send.c\
stat.c\
$(SMTP_C)\
wicket.c
......
/* 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:
*/