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); ...@@ -116,6 +116,12 @@ extern int mu_mailbox_unlock (mu_mailbox_t mbox);
116 116
117 extern int mu_mailbox_get_iterator (mu_mailbox_t mbx, 117 extern int mu_mailbox_get_iterator (mu_mailbox_t mbx,
118 mu_iterator_t *piterator); 118 mu_iterator_t *piterator);
119
120 /* ID translation */
121 #define MU_MAILBOX_UID_TO_MSGNO 0
122 #define MU_MAILBOX_MSGNO_TO_UID 1
123
124 extern int mu_mailbox_translate (mu_mailbox_t, int, size_t, size_t *);
119 125
120 #ifdef __cplusplus 126 #ifdef __cplusplus
121 } 127 }
......
...@@ -74,6 +74,8 @@ struct _mu_mailbox ...@@ -74,6 +74,8 @@ struct _mu_mailbox
74 74
75 int (*_quick_get_message) (mu_mailbox_t, mu_message_qid_t, mu_message_t *); 75 int (*_quick_get_message) (mu_mailbox_t, mu_message_qid_t, mu_message_t *);
76 int (*_get_uidls) (mu_mailbox_t, mu_list_t); 76 int (*_get_uidls) (mu_mailbox_t, mu_list_t);
77
78 int (*_translate) (mu_mailbox_t, int cmd, size_t, size_t *);
77 }; 79 };
78 80
79 # ifdef __cplusplus 81 # ifdef __cplusplus
......
...@@ -167,7 +167,7 @@ amd_msg_bsearch (struct _amd_data *amd, mu_off_t first, mu_off_t last, ...@@ -167,7 +167,7 @@ amd_msg_bsearch (struct _amd_data *amd, mu_off_t first, mu_off_t last,
167 167
168 /* Search for message MSG in the message array of AMD. 168 /* Search for message MSG in the message array of AMD.
169 If found, return 0 and store index of the located entry in the 169 If found, return 0 and store index of the located entry in the
170 variable PRET. Otherwise, return 1 and place into PRET index of 170 variable PRET. Otherwise, return 1 and store in PRET the index of
171 the array element that is less than MSG (in the sense of 171 the array element that is less than MSG (in the sense of
172 amd->msg_cmp) 172 amd->msg_cmp)
173 Index returned in PRET is 1-based, so *PRET == 0 means that MSG 173 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) ...@@ -829,4 +829,116 @@ mu_mailbox_get_uidls (mu_mailbox_t mbox, mu_list_t *plist)
829 return status; 829 return status;
830 } 830 }
831 831
832
833 /* Auxiliary function. Performs binary search for a message with the
834 given UID number */
835 static int
836 _uid_bsearch (mu_mailbox_t mbox, size_t start, size_t stop, size_t uid,
837 size_t *msgno)
838 {
839 mu_message_t mid_msg = NULL;
840 size_t num = 0, middle;
841 int rc;
842
843 middle = (start + stop) / 2;
844 rc = mu_mailbox_get_message (mbox, middle, &mid_msg);
845 if (rc)
846 return rc;
847 rc = mu_message_get_uid (mid_msg, &num);
848 if (rc)
849 return rc;
850
851 if (num == uid)
852 {
853 *msgno = middle;
854 return 0;
855 }
856
857 if (start >= stop)
858 return MU_ERR_NOENT;
859
860 if (num > uid)
861 return _uid_bsearch (mbox, start, middle - 1, uid, msgno);
862 else /*if (num < seqno)*/
863 return _uid_bsearch (mbox, middle + 1, stop, uid, msgno);
864 }
865
866 static int
867 _search_message_uid (mu_mailbox_t mbox, size_t uid, size_t *result)
868 {
869 int rc;
870 size_t num, count;
871 mu_message_t msg;
872
873 rc = mu_mailbox_get_message (mbox, 1, &msg);
874 if (rc)
875 return rc;
876 rc = mu_message_get_uid (msg, &num);
877 if (rc)
878 return rc;
879 if (uid < num)
880 return MU_ERR_NOENT;
881 else if (uid == num)
882 {
883 *result = 1;
884 return 0;
885 }
886
887 rc = mu_mailbox_messages_count (mbox, &count);
888 if (rc)
889 return rc;
890 rc = mu_mailbox_get_message (mbox, count, &msg);
891 if (rc)
892 return rc;
893 rc = mu_message_get_uid (msg, &num);
894 if (rc)
895 return rc;
896
897 if (uid > num)
898 return MU_ERR_NOENT;
899 else if (uid == num)
900 {
901 *result = count;
902 return 0;
903 }
904 return _uid_bsearch (mbox, 1, count, uid, result);
905 }
906
907 /* Translat message UIDs to message numbers and vice versa. */
908 int
909 mu_mailbox_translate (mu_mailbox_t mbox, int cmd, size_t from, size_t *to)
910 {
911 int rc = ENOSYS;
912 mu_message_t msg;
913
914 if (mbox == NULL)
915 return MU_ERR_MBX_NULL;
916 if (to == NULL)
917 return EINVAL;
918 if (mbox->flags & MU_STREAM_QACCESS)
919 return MU_ERR_BADOP;
920
921 if (mbox->_translate)
922 rc = mbox->_translate (mbox, cmd, from, to);
923 if (rc == ENOSYS)
924 {
925 switch (cmd)
926 {
927 case MU_MAILBOX_UID_TO_MSGNO:
928 rc = _search_message_uid (mbox, from, to);
929 break;
930
931 case MU_MAILBOX_MSGNO_TO_UID:
932 rc = mu_mailbox_get_message (mbox, from, &msg);
933 if (rc)
934 return rc;
935 rc = mu_message_get_uid (msg, to);
936 break;
832 937
938 default:
939 break;
940 }
941 }
942 return rc;
943 }
944
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
51 #include <mailutils/debug.h> 51 #include <mailutils/debug.h>
52 #include <mailutils/envelope.h> 52 #include <mailutils/envelope.h>
53 #include <mailutils/error.h> 53 #include <mailutils/error.h>
54 #include <mailutils/errno.h>
54 #include <mailutils/header.h> 55 #include <mailutils/header.h>
55 #include <mailutils/locker.h> 56 #include <mailutils/locker.h>
56 #include <mailutils/message.h> 57 #include <mailutils/message.h>
...@@ -380,6 +381,39 @@ mh_get_property (mu_mailbox_t mailbox, mu_property_t *pprop) ...@@ -380,6 +381,39 @@ mh_get_property (mu_mailbox_t mailbox, mu_property_t *pprop)
380 return 0; 381 return 0;
381 } 382 }
382 383
384
385
386 static int
387 mh_translate (mu_mailbox_t mbox, int cmd, size_t from, size_t *to)
388 {
389 struct _amd_data *amd = mbox->data;
390 struct _mh_message msg, *mp;
391 size_t n;
392
393 /* Make sure the mailbox has been scanned */
394 mu_mailbox_messages_count (mbox, &n);
395
396 switch (cmd)
397 {
398 case MU_MAILBOX_UID_TO_MSGNO:
399 msg.seq_number = from;
400 if (amd_msg_lookup (amd, (struct _amd_message*) &msg, &n))
401 return MU_ERR_NOENT;
402 *to = n;
403 break;
404
405 case MU_MAILBOX_MSGNO_TO_UID:
406 mp = (struct _mh_message *) _amd_get_message (amd, from);
407 if (!mp)
408 return MU_ERR_NOENT;
409 *to = mp->seq_number;
410 break;
411
412 default:
413 return ENOSYS;
414 }
415 return 0;
416 }
383 417
384 418
385 419
...@@ -407,6 +441,7 @@ _mailbox_mh_init (mu_mailbox_t mailbox) ...@@ -407,6 +441,7 @@ _mailbox_mh_init (mu_mailbox_t mailbox)
407 amd->remove = mh_remove; 441 amd->remove = mh_remove;
408 442
409 mailbox->_get_property = mh_get_property; 443 mailbox->_get_property = mh_get_property;
444 mailbox->_translate = mh_translate;
410 445
411 return 0; 446 return 0;
412 } 447 }
......
...@@ -161,7 +161,13 @@ copy_message (mu_mailbox_t mbox, size_t n, const char *file) ...@@ -161,7 +161,13 @@ copy_message (mu_mailbox_t mbox, size_t n, const char *file)
161 mu_stream_t out; 161 mu_stream_t out;
162 int rc; 162 int rc;
163 163
164 mu_mailbox_get_message (mbox, n, &msg); 164 rc = mu_mailbox_get_message (mbox, n, &msg);
165 if (rc)
166 {
167 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
168 exit (1);
169 }
170
165 mu_message_get_streamref (msg, &in); 171 mu_message_get_streamref (msg, &in);
166 172
167 if ((rc = mu_file_stream_create (&out, 173 if ((rc = mu_file_stream_create (&out,
......
...@@ -970,15 +970,14 @@ mh_draft_message (const char *name, const char *msgspec, char **pname) ...@@ -970,15 +970,14 @@ mh_draft_message (const char *name, const char *msgspec, char **pname)
970 mu_url_t url; 970 mu_url_t url;
971 size_t uid; 971 size_t uid;
972 int rc; 972 int rc;
973 const char *urlstr;
974 mu_mailbox_t mbox; 973 mu_mailbox_t mbox;
975 974 const char *path;
975
976 mbox = mh_open_folder (name, 0); 976 mbox = mh_open_folder (name, 0);
977 if (!mbox) 977 if (!mbox)
978 return 1; 978 return 1;
979 979
980 mu_mailbox_get_url (mbox, &url); 980 mu_mailbox_get_url (mbox, &url);
981 urlstr = mu_url_to_string (url);
982 981
983 if (strcmp (msgspec, "new") == 0) 982 if (strcmp (msgspec, "new") == 0)
984 { 983 {
...@@ -986,8 +985,11 @@ mh_draft_message (const char *name, const char *msgspec, char **pname) ...@@ -986,8 +985,11 @@ mh_draft_message (const char *name, const char *msgspec, char **pname)
986 985
987 rc = mu_mailbox_uidnext (mbox, &uid); 986 rc = mu_mailbox_uidnext (mbox, &uid);
988 if (rc) 987 if (rc)
989 mu_error (_("cannot obtain sequence number for the new message: %s"), 988 {
990 mu_strerror (rc)); 989 mu_error (_("cannot obtain sequence number for the new message: %s"),
990 mu_strerror (rc));
991 exit (1);
992 }
991 mu_mailbox_get_property (mbox, &prop); 993 mu_mailbox_get_property (mbox, &prop);
992 mu_property_set_value (prop, "cur", mu_umaxtostr (0, uid), 1); 994 mu_property_set_value (prop, "cur", mu_umaxtostr (0, uid), 1);
993 } 995 }
...@@ -1008,21 +1010,13 @@ mh_draft_message (const char *name, const char *msgspec, char **pname) ...@@ -1008,21 +1010,13 @@ mh_draft_message (const char *name, const char *msgspec, char **pname)
1008 } 1010 }
1009 mh_msgset_free (&msgset); 1011 mh_msgset_free (&msgset);
1010 } 1012 }
1011 1013
1012 if (rc == 0) 1014 mu_url_sget_path (url, &path);
1015 rc = mu_asprintf (pname, "%s/%lu", path, (unsigned long) uid);
1016 if (rc)
1013 { 1017 {
1014 const char *dir; 1018 mu_diag_funcall (MU_DIAG_ERROR, "mu_asprintf", NULL, rc);
1015 const char *msg; 1019 exit (1);
1016 size_t len;
1017
1018 dir = urlstr + 3; /* FIXME */
1019
1020 msg = mu_umaxtostr (0, uid);
1021 len = strlen (dir) + 1 + strlen (msg) + 1;
1022 *pname = xmalloc (len);
1023 strcpy (*pname, dir);
1024 strcat (*pname, "/");
1025 strcat (*pname, msg);
1026 } 1020 }
1027 mu_mailbox_close (mbox); 1021 mu_mailbox_close (mbox);
1028 mu_mailbox_destroy (&mbox); 1022 mu_mailbox_destroy (&mbox);
......
...@@ -19,27 +19,6 @@ ...@@ -19,27 +19,6 @@
19 19
20 #include <mh.h> 20 #include <mh.h>
21 21
22 int
23 mh_uid_to_msgno (mu_mailbox_t mbox, size_t uid, size_t *msgno)
24 {
25 size_t num = mh_get_message (mbox, uid, NULL);
26 if (num == 0)
27 return MU_ERR_NOENT;
28 *msgno = num;
29 return 0;
30 }
31
32 int
33 mh_msgno_to_uid (mu_mailbox_t mbox, size_t msgno, size_t *uid)
34 {
35 mu_message_t msg;
36 int rc = mu_mailbox_get_message (mbox, msgno, &msg);
37 if (rc)
38 return rc;
39 return mu_message_get_uid (msg, uid);
40 }
41
42
43 void 22 void
44 mh_msgset_init (mh_msgset_t *msgset) 23 mh_msgset_init (mh_msgset_t *msgset)
45 { 24 {
...@@ -196,75 +175,6 @@ mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset) ...@@ -196,75 +175,6 @@ mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
196 } 175 }
197 msgset->flags |= MH_MSGSET_UID; 176 msgset->flags |= MH_MSGSET_UID;
198 } 177 }
199
200 /* Auxiliary function. Performs binary search for a message with the
201 given sequence number */
202 static size_t
203 mh_search_message (mu_mailbox_t mbox, size_t start, size_t stop,
204 size_t seqno, mu_message_t *mesg)
205 {
206 mu_message_t mid_msg = NULL;
207 size_t num = 0, middle;
208
209 middle = (start + stop) / 2;
210 if (mu_mailbox_get_message (mbox, middle, &mid_msg)
211 || mh_message_number (mid_msg, &num))
212 return 0;
213
214 if (num == seqno)
215 {
216 if (mesg)
217 *mesg = mid_msg;
218 return middle;
219 }
220
221 if (start >= stop)
222 return 0;
223
224 if (num > seqno)
225 return mh_search_message (mbox, start, middle-1, seqno, mesg);
226 else /*if (num < seqno)*/
227 return mh_search_message (mbox, middle+1, stop, seqno, mesg);
228 }
229
230 /* Retrieve the message with the given sequence number.
231 Returns ordinal number of the message in the mailbox if found,
232 zero otherwise. The retrieved message is stored in the location
233 pointed to by mesg, unless it is NULL. */
234
235 size_t
236 mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
237 {
238 size_t num, count;
239 mu_message_t msg;
240
241 if (mu_mailbox_get_message (mbox, 1, &msg)
242 || mh_message_number (msg, &num))
243 return 0;
244 if (seqno < num)
245 return 0;
246 else if (seqno == num)
247 {
248 if (mesg)
249 *mesg = msg;
250 return 1;
251 }
252
253 if (mu_mailbox_messages_count (mbox, &count)
254 || mu_mailbox_get_message (mbox, count, &msg)
255 || mh_message_number (msg, &num))
256 return 0;
257 if (seqno > num)
258 return 0;
259 else if (seqno == num)
260 {
261 if (mesg)
262 *mesg = msg;
263 return count;
264 }
265
266 return mh_search_message (mbox, 1, count, seqno, mesg);
267 }
268 178
269 179
270 struct msgset_parser 180 struct msgset_parser
...@@ -415,7 +325,7 @@ msgset_cur (mu_mailbox_t mbox, size_t *pnum) ...@@ -415,7 +325,7 @@ msgset_cur (mu_mailbox_t mbox, size_t *pnum)
415 { 325 {
416 size_t num; 326 size_t num;
417 mh_mailbox_get_cur (mbox, &num); 327 mh_mailbox_get_cur (mbox, &num);
418 return mh_uid_to_msgno (mbox, num, pnum); 328 return mu_mailbox_translate (mbox, MU_MAILBOX_UID_TO_MSGNO, num, pnum);
419 } 329 }
420 330
421 static int 331 static int
...@@ -518,7 +428,8 @@ parse_term (struct msgset_parser *parser, int seq) ...@@ -518,7 +428,8 @@ parse_term (struct msgset_parser *parser, int seq)
518 if (endp != parser->curp) 428 if (endp != parser->curp)
519 msgset_abort (term); 429 msgset_abort (term);
520 430
521 if (mh_uid_to_msgno (parser->mbox, num, &parser->number)) 431 if (mu_mailbox_translate (parser->mbox, MU_MAILBOX_UID_TO_MSGNO,
432 num, &parser->number))
522 { 433 {
523 parser->validuid = 0; 434 parser->validuid = 0;
524 parser->number = num; 435 parser->number = num;
...@@ -617,7 +528,8 @@ parse_range (struct msgset_parser *parser) ...@@ -617,7 +528,8 @@ parse_range (struct msgset_parser *parser)
617 { 528 {
618 size_t total, lastuid; 529 size_t total, lastuid;
619 msgset_last (parser->mbox, &total); 530 msgset_last (parser->mbox, &total);
620 mh_msgno_to_uid (parser->mbox, total, &lastuid); 531 mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
532 total, &lastuid);
621 if (start > lastuid) 533 if (start > lastuid)
622 { 534 {
623 if (!parser->sign) 535 if (!parser->sign)
...@@ -647,7 +559,9 @@ parse_range (struct msgset_parser *parser) ...@@ -647,7 +559,9 @@ parse_range (struct msgset_parser *parser)
647 size_t total; 559 size_t total;
648 560
649 msgset_last (parser->mbox, &total); 561 msgset_last (parser->mbox, &total);
650 mh_msgno_to_uid (parser->mbox, total, &lastuid); 562 mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
563 total, &lastuid);
564
651 if (parser->number > lastuid) 565 if (parser->number > lastuid)
652 parser->number = total; 566 parser->number = total;
653 else if (!validuid) 567 else if (!validuid)
...@@ -659,7 +573,8 @@ parse_range (struct msgset_parser *parser) ...@@ -659,7 +573,8 @@ parse_range (struct msgset_parser *parser)
659 { 573 {
660 size_t total; 574 size_t total;
661 msgset_last (parser->mbox, &total); 575 msgset_last (parser->mbox, &total);
662 mh_msgno_to_uid (parser->mbox, total, &lastuid); 576 mu_mailbox_translate (parser->mbox, MU_MAILBOX_MSGNO_TO_UID,
577 total, &lastuid);
663 } 578 }
664 if (start > lastuid && !parser->validuid) 579 if (start > lastuid && !parser->validuid)
665 emptyrange_abort (parser->argv[-1]); 580 emptyrange_abort (parser->argv[-1]);
...@@ -720,3 +635,29 @@ mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, ...@@ -720,3 +635,29 @@ mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
720 635
721 mh_msgset_optimize (msgset); 636 mh_msgset_optimize (msgset);
722 } 637 }
638
639
640 /* Retrieve the message with the given sequence number.
641 Returns ordinal number of the message in the mailbox if found,
642 zero otherwise. The retrieved message is stored in the location
643 pointed to by mesg, unless it is NULL. */
644
645 size_t
646 mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
647 {
648 int rc;
649 size_t num;
650
651 if (mu_mailbox_translate (mbox, MU_MAILBOX_UID_TO_MSGNO, seqno, &num))
652 return 0;
653 if (mesg)
654 {
655 rc = mu_mailbox_get_message (mbox, num, mesg);
656 if (rc)
657 {
658 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
659 exit (1);
660 }
661 }
662 return num;
663 }
......
...@@ -143,6 +143,61 @@ Subject: test input ...@@ -143,6 +143,61 @@ Subject: test input
143 message body 143 message body
144 ]) 144 ])
145 145
146 MH_CHECK([comp -draftfolder],[comp05 comp-draftfolder],[
147 mkdir Mail/drafts
148 dir=`pwd`
149 echo 'quit' | compcmd -draftfolder drafts | sed "s|$dir/*||;s| *$||"
150 cat Mail/drafts/1
151 ],
152 [0],
153 [-- Editor invocation: Mail/drafts/1
154 -- Input file:
155 To:
156 cc:
157 Subject:
158 --------
159 -- Input file end
160 What now? draft left on "Mail/drafts/1".
161 To:
162 cc:
163 Subject:
164 --------
165 Seen by mhed
166 ])
167
168 MH_CHECK([comp +draftfolder -use],[comp06 comp-draftfolder-use],[
169 mkdir Mail/drafts
170 AT_DATA([Mail/drafts/1],[From: gray
171 To: root
172 Subject: test input
173
174 message body
175 ])
176 echo "cur: 1" > Mail/drafts/.mh_sequences
177
178 dir=`pwd`
179 echo 'quit' | compcmd -draftfolder drafts -use| sed "s|$dir/*||;s| *$||"
180 cat Mail/drafts/1
181 ],
182 [0],
183 [-- Editor invocation: Mail/drafts/1
184 -- Input file:
185 From: gray
186 To: root
187 Subject: test input
188
189 message body
190 -- Input file end
191 What now? draft left on "Mail/drafts/1".
192 From: gray
193 To: root
194 Subject: test input
195
196 message body
197 Seen by mhed
198 ])
199
200
146 m4_popdef([compcmd]) 201 m4_popdef([compcmd])
147 m4_popdef([MH_KEYWORDS]) 202 m4_popdef([MH_KEYWORDS])
148 203
......