Commit 46b844cf 46b844cf0c0623dd370573ce6da21dd8aa6fd907 by Sergey Poznyakoff

Provide a library function for translating message UIDs to numbers and vice versa.

* include/mailutils/mailbox.h (MU_MAILBOX_UID_TO_MSGNO)
(MU_MAILBOX_MSGNO_TO_UID): New defines.
(mu_mailbox_translate): New proto.
* include/mailutils/sys/mailbox.h (_mu_mailbox) <_translate>: New
method.
* libmailutils/mailbox/mailbox.c (mu_mailbox_translate): New
function.
* libproto/mh/mbox.c (mh_translate): New function.  Implements
the _translate method.
* mh/mh_msgset.c (mh_uid_to_msgno, mh_msgno_to_uid): Remove.  All
callers updated to use mu_mailbox_translate instead.
(mh_search_message): Remove.
(mh_get_message): Rewrite using mu_mailbox_translate.

* mh/comp.c (copy_message): Check return from mu_mailbox_get_message.
* mh/mh_init.c (mh_draft_message): Rewrite using mu_url_sget_path.
* mh/tests/comp.at: Test draftfolder functionality.
1 parent e34d8c16
......@@ -116,6 +116,12 @@ extern int mu_mailbox_unlock (mu_mailbox_t mbox);
extern int mu_mailbox_get_iterator (mu_mailbox_t mbx,
mu_iterator_t *piterator);
/* ID translation */
#define MU_MAILBOX_UID_TO_MSGNO 0
#define MU_MAILBOX_MSGNO_TO_UID 1
extern int mu_mailbox_translate (mu_mailbox_t, int, size_t, size_t *);
#ifdef __cplusplus
}
......
......@@ -74,6 +74,8 @@ struct _mu_mailbox
int (*_quick_get_message) (mu_mailbox_t, mu_message_qid_t, mu_message_t *);
int (*_get_uidls) (mu_mailbox_t, mu_list_t);
int (*_translate) (mu_mailbox_t, int cmd, size_t, size_t *);
};
# ifdef __cplusplus
......
......@@ -167,7 +167,7 @@ amd_msg_bsearch (struct _amd_data *amd, mu_off_t first, mu_off_t last,
/* Search for message MSG in the message array of AMD.
If found, return 0 and store index of the located entry in the
variable PRET. Otherwise, return 1 and place into PRET index of
variable PRET. Otherwise, return 1 and store in PRET the index of
the array element that is less than MSG (in the sense of
amd->msg_cmp)
Index returned in PRET is 1-based, so *PRET == 0 means that MSG
......
......@@ -829,4 +829,116 @@ mu_mailbox_get_uidls (mu_mailbox_t mbox, mu_list_t *plist)
return status;
}
/* Auxiliary function. Performs binary search for a message with the
given UID number */
static int
_uid_bsearch (mu_mailbox_t mbox, size_t start, size_t stop, size_t uid,
size_t *msgno)
{
mu_message_t mid_msg = NULL;
size_t num = 0, middle;
int rc;
middle = (start + stop) / 2;
rc = mu_mailbox_get_message (mbox, middle, &mid_msg);
if (rc)
return rc;
rc = mu_message_get_uid (mid_msg, &num);
if (rc)
return rc;
if (num == uid)
{
*msgno = middle;
return 0;
}
if (start >= stop)
return MU_ERR_NOENT;
if (num > uid)
return _uid_bsearch (mbox, start, middle - 1, uid, msgno);
else /*if (num < seqno)*/
return _uid_bsearch (mbox, middle + 1, stop, uid, msgno);
}
static int
_search_message_uid (mu_mailbox_t mbox, size_t uid, size_t *result)
{
int rc;
size_t num, count;
mu_message_t msg;
rc = mu_mailbox_get_message (mbox, 1, &msg);
if (rc)
return rc;
rc = mu_message_get_uid (msg, &num);
if (rc)
return rc;
if (uid < num)
return MU_ERR_NOENT;
else if (uid == num)
{
*result = 1;
return 0;
}
rc = mu_mailbox_messages_count (mbox, &count);
if (rc)
return rc;
rc = mu_mailbox_get_message (mbox, count, &msg);
if (rc)
return rc;
rc = mu_message_get_uid (msg, &num);
if (rc)
return rc;
if (uid > num)
return MU_ERR_NOENT;
else if (uid == num)
{
*result = count;
return 0;
}
return _uid_bsearch (mbox, 1, count, uid, result);
}
/* Translat message UIDs to message numbers and vice versa. */
int
mu_mailbox_translate (mu_mailbox_t mbox, int cmd, size_t from, size_t *to)
{
int rc = ENOSYS;
mu_message_t msg;
if (mbox == NULL)
return MU_ERR_MBX_NULL;
if (to == NULL)
return EINVAL;
if (mbox->flags & MU_STREAM_QACCESS)
return MU_ERR_BADOP;
if (mbox->_translate)
rc = mbox->_translate (mbox, cmd, from, to);
if (rc == ENOSYS)
{
switch (cmd)
{
case MU_MAILBOX_UID_TO_MSGNO:
rc = _search_message_uid (mbox, from, to);
break;
case MU_MAILBOX_MSGNO_TO_UID:
rc = mu_mailbox_get_message (mbox, from, &msg);
if (rc)
return rc;
rc = mu_message_get_uid (msg, to);
break;
default:
break;
}
}
return rc;
}
......
......@@ -51,6 +51,7 @@
#include <mailutils/debug.h>
#include <mailutils/envelope.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/locker.h>
#include <mailutils/message.h>
......@@ -380,6 +381,39 @@ mh_get_property (mu_mailbox_t mailbox, mu_property_t *pprop)
return 0;
}
static int
mh_translate (mu_mailbox_t mbox, int cmd, size_t from, size_t *to)
{
struct _amd_data *amd = mbox->data;
struct _mh_message msg, *mp;
size_t n;
/* Make sure the mailbox has been scanned */
mu_mailbox_messages_count (mbox, &n);
switch (cmd)
{
case MU_MAILBOX_UID_TO_MSGNO:
msg.seq_number = from;
if (amd_msg_lookup (amd, (struct _amd_message*) &msg, &n))
return MU_ERR_NOENT;
*to = n;
break;
case MU_MAILBOX_MSGNO_TO_UID:
mp = (struct _mh_message *) _amd_get_message (amd, from);
if (!mp)
return MU_ERR_NOENT;
*to = mp->seq_number;
break;
default:
return ENOSYS;
}
return 0;
}
......@@ -407,6 +441,7 @@ _mailbox_mh_init (mu_mailbox_t mailbox)
amd->remove = mh_remove;
mailbox->_get_property = mh_get_property;
mailbox->_translate = mh_translate;
return 0;
}
......
......@@ -161,7 +161,13 @@ copy_message (mu_mailbox_t mbox, size_t n, const char *file)
mu_stream_t out;
int rc;
mu_mailbox_get_message (mbox, n, &msg);
rc = mu_mailbox_get_message (mbox, n, &msg);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
exit (1);
}
mu_message_get_streamref (msg, &in);
if ((rc = mu_file_stream_create (&out,
......
......@@ -970,15 +970,14 @@ mh_draft_message (const char *name, const char *msgspec, char **pname)
mu_url_t url;
size_t uid;
int rc;
const char *urlstr;
mu_mailbox_t mbox;
const char *path;
mbox = mh_open_folder (name, 0);
if (!mbox)
return 1;
mu_mailbox_get_url (mbox, &url);
urlstr = mu_url_to_string (url);
if (strcmp (msgspec, "new") == 0)
{
......@@ -986,8 +985,11 @@ mh_draft_message (const char *name, const char *msgspec, char **pname)
rc = mu_mailbox_uidnext (mbox, &uid);
if (rc)
mu_error (_("cannot obtain sequence number for the new message: %s"),
mu_strerror (rc));
{
mu_error (_("cannot obtain sequence number for the new message: %s"),
mu_strerror (rc));
exit (1);
}
mu_mailbox_get_property (mbox, &prop);
mu_property_set_value (prop, "cur", mu_umaxtostr (0, uid), 1);
}
......@@ -1008,21 +1010,13 @@ mh_draft_message (const char *name, const char *msgspec, char **pname)
}
mh_msgset_free (&msgset);
}
if (rc == 0)
mu_url_sget_path (url, &path);
rc = mu_asprintf (pname, "%s/%lu", path, (unsigned long) uid);
if (rc)
{
const char *dir;
const char *msg;
size_t len;
dir = urlstr + 3; /* FIXME */
msg = mu_umaxtostr (0, uid);
len = strlen (dir) + 1 + strlen (msg) + 1;
*pname = xmalloc (len);
strcpy (*pname, dir);
strcat (*pname, "/");
strcat (*pname, msg);
mu_diag_funcall (MU_DIAG_ERROR, "mu_asprintf", NULL, rc);
exit (1);
}
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
......
......@@ -19,27 +19,6 @@
#include <mh.h>
int
mh_uid_to_msgno (mu_mailbox_t mbox, size_t uid, size_t *msgno)
{
size_t num = mh_get_message (mbox, uid, NULL);
if (num == 0)
return MU_ERR_NOENT;
*msgno = num;
return 0;
}
int
mh_msgno_to_uid (mu_mailbox_t mbox, size_t msgno, size_t *uid)
{
mu_message_t msg;
int rc = mu_mailbox_get_message (mbox, msgno, &msg);
if (rc)
return rc;
return mu_message_get_uid (msg, uid);
}
void
mh_msgset_init (mh_msgset_t *msgset)
{
......@@ -196,75 +175,6 @@ mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
}
msgset->flags |= MH_MSGSET_UID;
}
/* Auxiliary function. Performs binary search for a message with the
given sequence number */
static size_t
mh_search_message (mu_mailbox_t mbox, size_t start, size_t stop,
size_t seqno, mu_message_t *mesg)
{
mu_message_t mid_msg = NULL;
size_t num = 0, middle;
middle = (start + stop) / 2;
if (mu_mailbox_get_message (mbox, middle, &mid_msg)
|| mh_message_number (mid_msg, &num))
return 0;
if (num == seqno)
{
if (mesg)
*mesg = mid_msg;
return middle;
}
if (start >= stop)
return 0;
if (num > seqno)
return mh_search_message (mbox, start, middle-1, seqno, mesg);
else /*if (num < seqno)*/
return mh_search_message (mbox, middle+1, stop, seqno, mesg);
}
/* Retrieve the message with the given sequence number.
Returns ordinal number of the message in the mailbox if found,
zero otherwise. The retrieved message is stored in the location
pointed to by mesg, unless it is NULL. */
size_t
mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
{
size_t num, count;
mu_message_t msg;
if (mu_mailbox_get_message (mbox, 1, &msg)
|| mh_message_number (msg, &num))
return 0;
if (seqno < num)
return 0;
else if (seqno == num)
{
if (mesg)
*mesg = msg;
return 1;
}
if (mu_mailbox_messages_count (mbox, &count)
|| mu_mailbox_get_message (mbox, count, &msg)
|| mh_message_number (msg, &num))
return 0;
if (seqno > num)
return 0;
else if (seqno == num)
{
if (mesg)
*mesg = msg;
return count;
}
return mh_search_message (mbox, 1, count, seqno, mesg);
}
struct msgset_parser
......@@ -415,7 +325,7 @@ msgset_cur (mu_mailbox_t mbox, size_t *pnum)
{
size_t num;
mh_mailbox_get_cur (mbox, &num);
return mh_uid_to_msgno (mbox, num, pnum);
return mu_mailbox_translate (mbox, MU_MAILBOX_UID_TO_MSGNO, num, pnum);
}
static int
......@@ -518,7 +428,8 @@ parse_term (struct msgset_parser *parser, int seq)
if (endp != parser->curp)
msgset_abort (term);
if (mh_uid_to_msgno (parser->mbox, num, &parser->number))
if (mu_mailbox_translate (parser->mbox, MU_MAILBOX_UID_TO_MSGNO,
num, &parser->number))
{
parser->validuid = 0;
parser->number = num;
......@@ -617,7 +528,8 @@ parse_range (struct msgset_parser *parser)
{
size_t total, lastuid;
msgset_last (parser->mbox, &total);
mh_msgno_to_uid (parser->mbox, total, &lastuid);
mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
total, &lastuid);
if (start > lastuid)
{
if (!parser->sign)
......@@ -647,7 +559,9 @@ parse_range (struct msgset_parser *parser)
size_t total;
msgset_last (parser->mbox, &total);
mh_msgno_to_uid (parser->mbox, total, &lastuid);
mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
total, &lastuid);
if (parser->number > lastuid)
parser->number = total;
else if (!validuid)
......@@ -659,7 +573,8 @@ parse_range (struct msgset_parser *parser)
{
size_t total;
msgset_last (parser->mbox, &total);
mh_msgno_to_uid (parser->mbox, total, &lastuid);
mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
total, &lastuid);
}
if (start > lastuid && !parser->validuid)
emptyrange_abort (parser->argv[-1]);
......@@ -720,3 +635,29 @@ mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
mh_msgset_optimize (msgset);
}
/* Retrieve the message with the given sequence number.
Returns ordinal number of the message in the mailbox if found,
zero otherwise. The retrieved message is stored in the location
pointed to by mesg, unless it is NULL. */
size_t
mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
{
int rc;
size_t num;
if (mu_mailbox_translate (mbox, MU_MAILBOX_UID_TO_MSGNO, seqno, &num))
return 0;
if (mesg)
{
rc = mu_mailbox_get_message (mbox, num, mesg);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
exit (1);
}
}
return num;
}
......
......@@ -143,6 +143,61 @@ Subject: test input
message body
])
MH_CHECK([comp -draftfolder],[comp05 comp-draftfolder],[
mkdir Mail/drafts
dir=`pwd`
echo 'quit' | compcmd -draftfolder drafts | sed "s|$dir/*||;s| *$||"
cat Mail/drafts/1
],
[0],
[-- Editor invocation: Mail/drafts/1
-- Input file:
To:
cc:
Subject:
--------
-- Input file end
What now? draft left on "Mail/drafts/1".
To:
cc:
Subject:
--------
Seen by mhed
])
MH_CHECK([comp +draftfolder -use],[comp06 comp-draftfolder-use],[
mkdir Mail/drafts
AT_DATA([Mail/drafts/1],[From: gray
To: root
Subject: test input
message body
])
echo "cur: 1" > Mail/drafts/.mh_sequences
dir=`pwd`
echo 'quit' | compcmd -draftfolder drafts -use| sed "s|$dir/*||;s| *$||"
cat Mail/drafts/1
],
[0],
[-- Editor invocation: Mail/drafts/1
-- Input file:
From: gray
To: root
Subject: test input
message body
-- Input file end
What now? draft left on "Mail/drafts/1".
From: gray
To: root
Subject: test input
message body
Seen by mhed
])
m4_popdef([compcmd])
m4_popdef([MH_KEYWORDS])
......