Commit 455554b8 455554b8b04054e1db41b72426f7ee9d8579acf5 by Sergey Poznyakoff

API for formatting message sets on output

* libmailutils/msgset/print.c (mu_msgset_formats): New global.
(mu_stream_msgset_format): New function.
* include/mailutils/msgset.h (mu_msgset_format): New struct.
(mu_msgset_fmt_imap, mu_msgset_fmt_mh): New defines.
(MU_MSGSET_IGNORE_TRANSERR): New flag
(mu_msgset_copy, mu_msgset_translate): New protos.
(mu_stream_msgset_format, mu_msgset_imap_print): New protos.
(mu_msgset_print): Deprecate.
* libmailutils/imapio/sendmsgset.c: Use mu_msgset_imap_print
instead of mu_msgset_print.
* mu/libexec/imap.c: Likewise.
* libmailutils/msgset/Makefile.am: Add copy.c
* libmailutils/msgset/add.c (mu_msgset_add_range): Translate if
message set mode doesn't match the requested one.
* libmailutils/msgset/sub.c (mu_msgset_sub_range): Likewise.
* libmailutils/msgset/trans.c (_mu_msgset_translate_pair): Act
according to the mode argument.
(mu_msgset_translate): New function.
* libmailutils/tests/msgset.c: New option -mh
* mh/mh_sequence.c (write_sequence): Rewrite.
* testsuite/msgset.c: Optionally translate uids to msgnums and
vice-versa.
1 parent 1ddc81a1
......@@ -30,6 +30,25 @@ struct mu_msgrange
size_t msg_end;
};
struct mu_msgset_format
{
char *range; /* range separator (e.g., ":" for IMAP, "-" for MH) */
char *delim; /* delimiter (e.g., "," for IMAP, " " for MH) */
char *last; /* last message marker (e.g., "*" for IMAP, "last" for MH) */
char *empty; /* empty list representation ( "NIL", for IMAP, NULL for MH */
};
enum
{
MU_MSGSET_FMT_IMAP,
MU_MSGSET_FMT_MH
};
extern struct mu_msgset_format const mu_msgset_formats[];
typedef struct mu_msgset_format const *mu_msgset_format_t;
#define mu_msgset_fmt_imap (&mu_msgset_formats[MU_MSGSET_FMT_IMAP])
#define mu_msgset_fmt_mh (&mu_msgset_formats[MU_MSGSET_FMT_MH])
/* Message numbers start with 1. MU_MSGNO_LAST denotes the last
message. */
#define MU_MSGNO_LAST 0
......@@ -37,9 +56,15 @@ struct mu_msgrange
#define MU_MSGSET_NUM 0 /* Message set operates on sequence numbers */
#define MU_MSGSET_UID 1 /* Message set operates on UIDs */
#define MU_MSGSET_IGNORE_TRANSERR 0x10
#define MU_MSGSET_MODE_MASK 0x0f
int mu_msgset_create (mu_msgset_t *pmsgset, mu_mailbox_t mbox, int mode);
int mu_msgset_copy (mu_msgset_t src, mu_msgset_t dst);
int mu_msgset_translate (mu_msgset_t *dst, mu_msgset_t src, int flags);
int mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist);
int mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr);
......@@ -54,9 +79,21 @@ int mu_msgset_clear (mu_msgset_t set);
void mu_msgset_free (mu_msgset_t set);
void mu_msgset_destroy (mu_msgset_t *set);
int mu_msgset_parse_imap (mu_msgset_t set, int mode, const char *s, char **end);
int mu_msgset_parse_imap (mu_msgset_t set, int mode, const char *s,
char **end);
int mu_stream_msgset_format (mu_stream_t str,
struct mu_msgset_format const *fmt,
mu_msgset_t mset);
int mu_msgset_print (mu_stream_t str, mu_msgset_t msgset)
MU_DEPRECATED;
static inline int
mu_msgset_imap_print (mu_stream_t str, mu_msgset_t mset)
{
return mu_stream_msgset_format (str, mu_msgset_fmt_imap, mset);
}
int mu_msgset_print (mu_stream_t str, mu_msgset_t msgset);
int mu_msgset_locate (mu_msgset_t msgset, size_t n,
struct mu_msgrange const **prange);
......
......@@ -27,6 +27,7 @@ struct _mu_msgset
mu_list_t list; /* List of mu_msgrange structures */
mu_mailbox_t mbox; /* Associated mailbox */
int flags; /* Message set flags */
size_t format; /* Format index */
};
int _mu_msgset_translate_pair (mu_msgset_t mset, int mode,
......
......@@ -25,5 +25,5 @@
int
mu_imapio_send_msgset (mu_imapio_t io, mu_msgset_t msgset)
{
return mu_msgset_print (io->_imap_stream, msgset);
return mu_msgset_imap_print (io->_imap_stream, msgset);
}
......
......@@ -22,6 +22,7 @@ libmsgset_la_SOURCES = \
addset.c\
aggr.c\
clear.c\
copy.c\
create.c\
count.c\
getitr.c\
......
......@@ -41,12 +41,16 @@ mu_msgset_add_range (mu_msgset_t mset, size_t beg, size_t end, int mode)
return ENOMEM;
range->msg_beg = beg;
range->msg_end = end;
rc = _mu_msgset_translate_range (mset, mode, range);
if (mode != _MU_MSGSET_MODE (mset->flags))
{
rc = _mu_msgset_translate_range (mset, _MU_MSGSET_MODE (mset->flags),
range);
if (rc)
{
free (range);
return rc;
}
}
rc = mu_list_append (mset->list, range);
if (rc)
free (range);
......
......@@ -24,10 +24,26 @@
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
struct mu_msgset_format const mu_msgset_formats[] = {
[MU_MSGSET_FMT_IMAP] = {
.delim = ",",
.range = ":",
.last = "*",
.empty = "NIL"
},
[MU_MSGSET_FMT_MH] = {
.delim = " ",
.range = "-",
.last = "last"
}
};
struct print_env
{
mu_stream_t stream;
int cont;
struct mu_msgset_format const *fmt;
};
static int
......@@ -39,36 +55,59 @@ _msgrange_printer (void *item, void *data)
if (env->cont)
{
rc = mu_stream_write (env->stream, ",", 1, NULL);
rc = mu_stream_printf (env->stream, "%s", env->fmt->delim);
if (rc)
return rc;
}
else
env->cont = 1;
if (range->msg_beg == range->msg_end)
rc = mu_stream_printf (env->stream, "%lu", (unsigned long) range->msg_beg);
else if (range->msg_end == 0)
rc = mu_stream_printf (env->stream, "%lu:*",
(unsigned long) range->msg_beg);
rc = mu_stream_printf (env->stream, "%lu%s%s",
(unsigned long) range->msg_beg,
env->fmt->range,
env->fmt->last);
else if (range->msg_end == range->msg_beg + 1)
rc = mu_stream_printf (env->stream, "%lu%s%lu",
(unsigned long) range->msg_beg,
env->fmt->delim,
(unsigned long) range->msg_end);
else
rc = mu_stream_printf (env->stream, "%lu:%lu",
rc = mu_stream_printf (env->stream, "%lu%s%lu",
(unsigned long) range->msg_beg,
env->fmt->range,
(unsigned long) range->msg_end);
return rc;
}
int
mu_msgset_print (mu_stream_t str, mu_msgset_t mset)
mu_stream_msgset_format (mu_stream_t str, struct mu_msgset_format const *fmt,
mu_msgset_t mset)
{
struct print_env env;
int rc;
env.stream = str;
env.cont = 0;
env.fmt = fmt;
if (mu_list_is_empty (mset->list))
return mu_stream_printf (str, "%s", "nil");
{
if (env.fmt->empty)
return mu_stream_printf (str, "%s", env.fmt->empty);
return 0;
}
rc = mu_msgset_aggregate (mset);
if (rc)
return rc;
env.stream = str;
env.cont = 0;
return mu_list_foreach (mset->list, _msgrange_printer, &env);
}
int
mu_msgset_print (mu_stream_t str, mu_msgset_t mset)
{
return mu_stream_msgset_format (str, mu_msgset_fmt_imap, mset);
}
......
......@@ -129,11 +129,15 @@ mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t end, int mode)
beg = t;
}
rc = _mu_msgset_translate_pair (mset, mode, &beg, &end);
if (mode != _MU_MSGSET_MODE (mset->flags))
{
rc = _mu_msgset_translate_pair (mset, _MU_MSGSET_MODE (mset->flags),
&beg, &end);
if (rc == MU_ERR_NOENT)
return 0;
else if (rc)
return rc;
}
rc = mu_msgset_aggregate (mset);
if (rc)
......
......@@ -27,14 +27,14 @@ int
_mu_msgset_translate_pair (mu_msgset_t mset, int mode,
size_t *pbeg, size_t *pend)
{
if (mode != _MU_MSGSET_MODE (mset->flags) && mset->mbox)
if (mset->mbox)
{
int cmd, rc;
size_t n = 1;
size_t beg = *pbeg;
size_t end = *pend;
switch (_MU_MSGSET_MODE (mset->flags))
switch (mode)
{
case MU_MSGSET_NUM:
cmd = MU_MAILBOX_UID_TO_MSGNO;
......@@ -97,3 +97,74 @@ _mu_msgset_translate_range (mu_msgset_t mset, int mode, struct mu_msgrange *r)
return _mu_msgset_translate_pair (mset, mode, &r->msg_beg, &r->msg_end);
}
struct trans_closure
{
mu_msgset_t mset;
int flags;
};
static int
trans_range (void *item, void *data)
{
struct mu_msgrange const *range = item;
struct trans_closure *clos = data;
struct mu_msgrange *copy;
int rc;
copy = malloc (sizeof *copy);
if (!copy)
return errno;
*copy = *range;
rc = _mu_msgset_translate_range (clos->mset, _MU_MSGSET_MODE (clos->flags),
copy);
switch (rc)
{
case 0:
rc = mu_list_append (clos->mset->list, copy);
break;
case MU_ERR_NOENT:
if (clos->flags & MU_MSGSET_IGNORE_TRANSERR)
rc = 0;
/* fallthrough */
default:
free (copy);
}
return rc;
}
int
mu_msgset_translate (mu_msgset_t *dst, mu_msgset_t src, int flags)
{
int rc;
mu_msgset_t tmp;
rc = mu_msgset_create (&tmp, src->mbox, src->flags);
if (rc)
return rc;
tmp->format = src->format;
if (_MU_MSGSET_MODE (flags) == src->flags)
{
rc = mu_msgset_copy (src, tmp);
}
else
{
struct trans_closure tc;
tc.mset = tmp;
tc.flags = flags;
rc = mu_list_foreach (src->list, trans_range, &tc);
}
if (rc)
mu_msgset_destroy (&tmp);
else
*dst = tmp;
return rc;
}
......
......@@ -18,6 +18,8 @@
#include <stdlib.h>
#include <mailutils/mailutils.h>
mu_msgset_format_t format = mu_msgset_fmt_imap;
static void
parse_msgrange (char *arg, struct mu_msgrange *range)
{
......@@ -76,7 +78,7 @@ parse_msgset (const char *arg)
static void
print_all (mu_msgset_t msgset)
{
MU_ASSERT (mu_msgset_print (mu_strout, msgset));
MU_ASSERT (mu_stream_msgset_format (mu_strout, format, msgset));
mu_printf ("\n");
}
......@@ -111,13 +113,15 @@ main (int argc, char **argv)
if (strcmp (arg, "-h") == 0 || strcmp (arg, "-help") == 0)
{
mu_printf ("usage: %s [-msgset=SET] [-add=X[:Y]] [-del=X[:Y]] "
"[-addset=SET] [-delset=SET] [-first] [-last]...\n",
mu_printf ("usage: %s [-mh] [-msgset=SET] [-add=X[:Y]] [-del=X[:Y]] "
"[-addset=SET] [-delset=SET] [-first] [-last] ...\n",
mu_program_name);
return 0;
}
else if (strncmp (arg, "-msgset=", 8) == 0)
msgset_string = arg + 8;
else if (strcmp (arg, "-mh") == 0)
format = mu_msgset_fmt_mh;
else
break;
}
......
......@@ -440,9 +440,7 @@ main (int argc, char **argv)
mu_msgset_create (&unseen, NULL, MU_MSGSET_NUM);
mu_msgset_add_range (unseen, lastseen, incdat.lastmsg, MU_MSGSET_NUM);
mh_seq_add (incdat.output,
unseen_seq,
unseen, 0);
mh_seq_add (incdat.output, unseen_seq, unseen, 0);
mu_msgset_free (unseen);
}
......
......@@ -119,6 +119,7 @@ msgset_parser_init (struct msgset_parser *parser, mu_mailbox_t mbox,
mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_create", NULL, rc);
exit (1);
}
parser->argc = argc;
parser->argv = argv;
parser->curp = "";
......
......@@ -47,6 +47,8 @@ mh_seq_read (mu_mailbox_t mbox, const char *name, int flags)
static void
write_sequence (mu_mailbox_t mbox, const char *name, char *value, int private)
{
if (value && value[0] == 0)
value = NULL;
if (private)
{
char *p = private_sequence_name (name);
......@@ -63,96 +65,35 @@ delete_sequence (mu_mailbox_t mbox, const char *name, int private)
write_sequence (mbox, name, NULL, private);
}
struct format_closure
{
mu_stream_t stream;
mu_mailbox_t mailbox;
int delim;
};
static int
format_sequence (void *item, void *data)
{
struct mu_msgrange *r = item;
struct format_closure *clos = data;
int rc;
size_t beg, end;
if (clos->mailbox)
{
rc = mu_mailbox_translate (clos->mailbox,
MU_MAILBOX_MSGNO_TO_UID,
r->msg_beg, &beg);
if (rc)
return rc;
}
else
beg = r->msg_beg;
if (clos->delim)
mu_stream_write (clos->stream, " ", 1, NULL);
if (r->msg_beg == r->msg_end)
rc = mu_stream_printf (clos->stream, "%lu", (unsigned long) beg);
else
{
if (clos->mailbox)
{
rc = mu_mailbox_translate (clos->mailbox,
MU_MAILBOX_MSGNO_TO_UID,
r->msg_end, &end);
if (rc)
return rc;
}
else
end = r->msg_end;
if (beg + 1 == end)
rc = mu_stream_printf (clos->stream, "%lu %lu",
(unsigned long) beg,
(unsigned long) end);
else
rc = mu_stream_printf (clos->stream, "%lu-%lu",
(unsigned long) beg,
(unsigned long) end);
}
clos->delim = 1;
return rc;
}
static void
save_sequence (mu_mailbox_t mbox, const char *name, mu_msgset_t mset,
int flags)
{
mu_list_t list;
mu_msgset_get_list (mset, &list);
if (mu_list_is_empty (list))
write_sequence (mset->mbox, name, NULL, flags & SEQ_PRIVATE);
else
{
struct format_closure clos;
int rc;
mu_stream_t mstr;
mu_msgset_t outset;
mu_transport_t trans[2];
rc = mu_memory_stream_create (&clos.stream, MU_STREAM_RDWR);
rc = mu_msgset_translate (&outset, mset,
MU_MSGSET_UID|MU_MSGSET_IGNORE_TRANSERR);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_memory_stream_create", NULL, rc);
mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_translate", NULL, rc);
exit (1);
}
clos.mailbox = mset->mbox;
clos.delim = 0;
rc = mu_list_foreach (list, format_sequence, &clos);
rc = mu_memory_stream_create (&mstr, MU_STREAM_RDWR);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_foreach", NULL, rc);
mu_diag_funcall (MU_DIAG_ERROR, "mu_memory_stream_create", NULL, rc);
exit (1);
}
mu_stream_write (clos.stream, "", 1, NULL);
mu_stream_ioctl (clos.stream, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET,
trans);
mu_stream_msgset_format (mstr, mu_msgset_fmt_mh, outset);
mu_stream_write (mstr, "", 1, NULL);
mu_stream_ioctl (mstr, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, trans);
write_sequence (mbox, name, (char*)trans[0], flags & SEQ_PRIVATE);
mu_stream_unref (clos.stream);
}
mu_stream_unref (mstr);
mu_msgset_free (outset);
}
void
......
......@@ -1100,7 +1100,7 @@ com_search (int argc, char **argv)
return 0;
}
mu_printf ("%lu matches:", (unsigned long) count);
mu_msgset_print (mu_strout, mset);
mu_msgset_imap_print (mu_strout, mset);
mu_printf ("\n");
mu_msgset_free (mset);
......
......@@ -79,13 +79,16 @@ main (int argc, char **argv)
{
int i;
char *msgset_string = NULL;
mu_msgset_t msgset;
mu_msgset_t msgset, outset;
int create_mode = MU_MSGSET_NUM;
int parse_mode = MU_MSGSET_NUM;
int output_mode = MU_MSGSET_NUM;
int output_flags = 0;
mu_msgset_format_t format = mu_msgset_fmt_imap;
mu_mailbox_t mbox = NULL;
mu_set_program_name (argv[0]);
mu_registrar_record (mu_mbox_record);
mu_register_local_mbox_formats ();
for (i = 1; i < argc; i++)
{
char *arg = argv[i];
......@@ -114,6 +117,14 @@ main (int argc, char **argv)
MU_ASSERT (mu_mailbox_create (&mbox, arg + 9));
MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_READ));
}
else if (strcmp (arg, "-mh") == 0)
format = mu_msgset_fmt_mh;
else if (strcmp (arg, "-printuid") == 0)
output_mode = MU_MSGSET_UID;
else if (strcmp (arg, "-printnum") == 0)
output_mode = MU_MSGSET_NUM;
else if (strcmp (arg, "-ignore-error") == 0)
output_flags = MU_MSGSET_IGNORE_TRANSERR;
else
break;
}
......@@ -230,8 +241,11 @@ main (int argc, char **argv)
return 1;
}
}
MU_ASSERT (mu_msgset_print (mu_strout, msgset));
MU_ASSERT (mu_msgset_translate (&outset, msgset, output_mode|output_flags));
MU_ASSERT (mu_stream_msgset_format (mu_strout, format, outset));
mu_printf ("\n");
mu_msgset_free (outset);
mu_msgset_free (msgset);
return 0;
......