Commit e6ae2852 e6ae2852edb142fcf84dc489715f8984843dfe0c by Sergey Poznyakoff

Implement a copy method in mailbox.

This method copies given messages (ificated by their sequence or UID
numbers) to the given mailbox. So far this is implemented only in
IMAP[S] folders.

The mh/inc utility uses this method to optionally move incorporated
messages to other folder (mailbox) instead of simply deleting them.

* include/mailutils/imap.h (mu_imap_response)
(mu_imap_response_code): New protos.
(MU_IMAP_CB_TAGGED_OK,MU_IMAP_CB_TAGGED_NO)
(MU_IMAP_CB_TAGGED_BAD): New callback codes.
* include/mailutils/mailbox.h (MU_MAILBOX_COPY_UID)
(MU_MAILBOX_COPY_CREAT): New constants.
(mu_mailbox_msgset_copy)
(mu_mailbox_message_copy): New protos.
* include/mailutils/sys/imap.h (resp_code): Rename to
response to avoid confusion. All uses updated.
(response_code): New member.
(_mu_imap_process_tagged_response): New proto.
* include/mailutils/sys/mailbox.h (_mu_mailbox) <_copy>: New member.
* libmailutils/mailbox/Makefile.am (libmailbox_la_SOURCES): Add copy.c
* libmailutils/mailbox/copy.c: New file.
* libproto/imap/err.c (mu_imap_response): New function.
(mu_imap_response_code): New function.
* libproto/imap/mbox.c (_imap_copy_to_mailbox)
(_mu_imap_mailbox_init): Implement _copy method.
* libproto/imap/resplist.c (IS_LBRACE,IS_RBRACE): Fix macros.
* libproto/imap/response.c (_mu_imap_response): Call
_mu_imap_process_tagged_response to process tagged responses.
* libproto/imap/resproc.c (parse_response_code): Bugfix: expected
']' was set off by one.
(resptab)<code>: New member.
(_mu_imap_process_tagged_response): New function.

* mh/inc.c (options, mh_option, opt_handler): New option --moveto.
(move_to_mailbox): New variable.
(main): If move_to_mailbox is set, move messages to that mailbox
instead of deleting them.
* mh/mh_getopt.h (mh_arg)<ARG_MOVETO>: New constant.

* NEWS: Update.

* include/mailutils/folder.h: Add a comment.
* libmailutils/mailbox/folder.c: Minor formatting change.
1 parent 1cf13b32
1 GNU mailutils NEWS -- history of user-visible changes. 2012-02-26 1 GNU mailutils NEWS -- history of user-visible changes. 2012-04-29
2 Copyright (C) 2002-2012 Free Software Foundation, Inc. 2 Copyright (C) 2002-2012 Free Software Foundation, Inc.
3 See the end of file for copying conditions. 3 See the end of file for copying conditions.
4 4
...@@ -116,6 +116,16 @@ See <http://mailutils.org/wiki/Timestamp_(Sieve_test)>. ...@@ -116,6 +116,16 @@ See <http://mailutils.org/wiki/Timestamp_(Sieve_test)>.
116 116
117 ** MH: improved compatibility with other implementations 117 ** MH: improved compatibility with other implementations
118 118
119 ** MH inc: new option --moveto
120
121 This option instructs the utility to move incorporated messages into
122 another folder instead of deleting them. It is implemented only for
123 input folders of type IMAP or IMAPS. A sample usage is:
124
125 inc -truncate -moveto Read -file imaps://imap.gmail.com
126
127 Note the `-truncate' option.
128
119 ** mailutils-config is deprecated. 129 ** mailutils-config is deprecated.
120 130
121 Use `mu cflags' and `mu ldflags' instead. The mailutils-config is 131 Use `mu cflags' and `mu ldflags' instead. The mailutils-config is
...@@ -202,6 +212,13 @@ transaction. ...@@ -202,6 +212,13 @@ transaction.
202 212
203 ** Support for Maildir and MH formats considerably improved. 213 ** Support for Maildir and MH formats considerably improved.
204 214
215 ** The mailbox object contains a `copy' method.
216
217 This method copies the requested set of messages into another
218 mailbox. It is accessed using the `mu_mailbox_msgset_copy' or
219 `mu_mailbox_message_copy' functions. So far it is implememented
220 only for IMAP and IMAPS mailboxes.
221
205 ** MIME support improved. 222 ** MIME support improved.
206 223
207 ** Debugging support considerably improved. 224 ** Debugging support considerably improved.
......
...@@ -61,7 +61,8 @@ extern int mu_folder_enumerate (mu_folder_t, const char *, ...@@ -61,7 +61,8 @@ extern int mu_folder_enumerate (mu_folder_t, const char *,
61 extern int mu_folder_lsub (mu_folder_t, const char *, const char *, 61 extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
62 mu_list_t *); 62 mu_list_t *);
63 63
64 /* Stream settings. */ 64 /* Stream settings. Don't use these functions.
65 FIXME: To be removed. */
65 extern int mu_folder_get_stream (mu_folder_t, mu_stream_t *) 66 extern int mu_folder_get_stream (mu_folder_t, mu_stream_t *)
66 __attribute__ ((deprecated)); 67 __attribute__ ((deprecated));
67 extern int mu_folder_get_streamref (mu_folder_t, mu_stream_t *); 68 extern int mu_folder_get_streamref (mu_folder_t, mu_stream_t *);
......
...@@ -133,6 +133,9 @@ int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier); ...@@ -133,6 +133,9 @@ int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier);
133 int mu_imap_trace (mu_imap_t imap, int op); 133 int mu_imap_trace (mu_imap_t imap, int op);
134 int mu_imap_trace_mask (mu_imap_t imap, int op, int lev); 134 int mu_imap_trace_mask (mu_imap_t imap, int op, int lev);
135 135
136 enum mu_imap_response mu_imap_response (mu_imap_t imap);
137 int mu_imap_response_code (mu_imap_t imap);
138
136 int mu_imap_strerror (mu_imap_t imap, const char **pstr); 139 int mu_imap_strerror (mu_imap_t imap, const char **pstr);
137 140
138 int mu_imap_session_state (mu_imap_t imap); 141 int mu_imap_session_state (mu_imap_t imap);
...@@ -178,21 +181,27 @@ extern struct mu_kwd _mu_imap_status_name_table[]; ...@@ -178,21 +181,27 @@ extern struct mu_kwd _mu_imap_status_name_table[];
178 #define MU_IMAP_CB_UIDNEXT 4 181 #define MU_IMAP_CB_UIDNEXT 4
179 #define MU_IMAP_CB_UIDVALIDITY 5 182 #define MU_IMAP_CB_UIDVALIDITY 5
180 183
181 /* The following callbacks correspond to server responses and take two 184 /* The following callbacks correspond to unsolicited server responses and
182 arguments: a response code (see MU_IMAP_RESPONSE, below) in SDAT, and 185 take two arguments: a response code (see MU_IMAP_RESPONSE, below) in
183 human-readable text string as returned by the server in PDAT. The 186 SDAT, and human-readable text string as returned by the server in PDAT.
184 latter can be NULL. */ 187 The latter can be NULL. */
185 #define MU_IMAP_CB_OK 6 188 #define MU_IMAP_CB_OK 6
186 #define MU_IMAP_CB_NO 7 189 #define MU_IMAP_CB_NO 7
187 #define MU_IMAP_CB_BAD 8 190 #define MU_IMAP_CB_BAD 8
188 #define MU_IMAP_CB_BYE 9 191 #define MU_IMAP_CB_BYE 9
189 #define MU_IMAP_CB_PREAUTH 10 192 #define MU_IMAP_CB_PREAUTH 10
190 193
194 /* These corresponde to the tagged server responses. The calling convention
195 is the same as above. */
196 #define MU_IMAP_CB_TAGGED_OK 11
197 #define MU_IMAP_CB_TAGGED_NO 12
198 #define MU_IMAP_CB_TAGGED_BAD 13
199
191 /* FETCH callback. Arguments: SDAT - message sequence number, PDAT - a 200 /* FETCH callback. Arguments: SDAT - message sequence number, PDAT - a
192 list (mu_list_t) of union mu_imap_fetch_response (see below). */ 201 list (mu_list_t) of union mu_imap_fetch_response (see below). */
193 #define MU_IMAP_CB_FETCH 11 202 #define MU_IMAP_CB_FETCH 14
194 203
195 #define _MU_IMAP_CB_MAX 12 204 #define _MU_IMAP_CB_MAX 15
196 205
197 typedef void (*mu_imap_callback_t) (void *, int code, size_t sdat, void *pdat); 206 typedef void (*mu_imap_callback_t) (void *, int code, size_t sdat, void *pdat);
198 207
...@@ -202,8 +211,6 @@ void mu_imap_register_callback_function (mu_imap_t imap, int code, ...@@ -202,8 +211,6 @@ void mu_imap_register_callback_function (mu_imap_t imap, int code,
202 mu_imap_callback_t callback, 211 mu_imap_callback_t callback,
203 void *data); 212 void *data);
204 213
205 #define MU_IMAP_RESPONSE_TAGGED 0x10
206
207 #define MU_IMAP_RESPONSE_UNKNOWN 0 214 #define MU_IMAP_RESPONSE_UNKNOWN 0
208 #define MU_IMAP_RESPONSE_ALERT 1 215 #define MU_IMAP_RESPONSE_ALERT 1
209 #define MU_IMAP_RESPONSE_BADCHARSET 2 216 #define MU_IMAP_RESPONSE_BADCHARSET 2
......
...@@ -42,7 +42,7 @@ extern int mu_mailbox_create_from_url (mu_mailbox_t *, mu_url_t); ...@@ -42,7 +42,7 @@ extern int mu_mailbox_create_from_url (mu_mailbox_t *, mu_url_t);
42 extern int mu_mailbox_create_from_record (mu_mailbox_t *pmbox, 42 extern int mu_mailbox_create_from_record (mu_mailbox_t *pmbox,
43 mu_record_t record, 43 mu_record_t record,
44 const char *name); 44 const char *name);
45 extern int mu_mailbox_create_default (mu_mailbox_t *, const char *); 45 extern int mu_mailbox_create_default (mu_mailbox_t *, const char *);
46 extern int mu_mailbox_create_at (mu_mailbox_t *pmbox, mu_folder_t folder, 46 extern int mu_mailbox_create_at (mu_mailbox_t *pmbox, mu_folder_t folder,
47 const char *name); 47 const char *name);
48 48
...@@ -119,6 +119,14 @@ extern int mu_mailbox_get_iterator (mu_mailbox_t mbx, ...@@ -119,6 +119,14 @@ extern int mu_mailbox_get_iterator (mu_mailbox_t mbx,
119 #define MU_MAILBOX_MSGNO_TO_UID 1 119 #define MU_MAILBOX_MSGNO_TO_UID 1
120 120
121 extern int mu_mailbox_translate (mu_mailbox_t, int, size_t, size_t *); 121 extern int mu_mailbox_translate (mu_mailbox_t, int, size_t, size_t *);
122
123 /* Copy message into a folder */
124 #define MU_MAILBOX_COPY_UID 0x01
125 #define MU_MAILBOX_COPY_CREAT 0x02
126
127 extern int mu_mailbox_msgset_copy (mu_mailbox_t, mu_msgset_t, const char *,
128 int);
129 extern int mu_mailbox_message_copy (mu_mailbox_t, size_t, const char *, int);
122 130
123 #ifdef __cplusplus 131 #ifdef __cplusplus
124 } 132 }
......
...@@ -85,8 +85,10 @@ struct _mu_imap ...@@ -85,8 +85,10 @@ struct _mu_imap
85 { 85 {
86 int flags; 86 int flags;
87 87
88 /* Holds the recect response code */ 88 /* Holds the recent response */
89 enum mu_imap_response resp_code; 89 enum mu_imap_response response;
90 /* The recent response code */
91 int response_code;
90 92
91 /* Error string (if any) */ 93 /* Error string (if any) */
92 char *errstr; 94 char *errstr;
...@@ -210,6 +212,7 @@ int _mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist); ...@@ -210,6 +212,7 @@ int _mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist);
210 int _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list, 212 int _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list,
211 mu_imap_response_action_t fun, 213 mu_imap_response_action_t fun,
212 void *data); 214 void *data);
215 int _mu_imap_process_tagged_response (mu_imap_t imap, mu_list_t resp);
213 216
214 int _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun, 217 int _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
215 void *data); 218 void *data);
......
...@@ -75,6 +75,7 @@ struct _mu_mailbox ...@@ -75,6 +75,7 @@ struct _mu_mailbox
75 int (*_get_uidls) (mu_mailbox_t, mu_list_t); 75 int (*_get_uidls) (mu_mailbox_t, mu_list_t);
76 76
77 int (*_translate) (mu_mailbox_t, int cmd, size_t, size_t *); 77 int (*_translate) (mu_mailbox_t, int cmd, size_t, size_t *);
78 int (*_copy) (mu_mailbox_t, mu_msgset_t, const char *, int);
78 }; 79 };
79 80
80 # ifdef __cplusplus 81 # ifdef __cplusplus
......
...@@ -24,6 +24,7 @@ libmailbox_la_SOURCES = \ ...@@ -24,6 +24,7 @@ libmailbox_la_SOURCES = \
24 attribute.c\ 24 attribute.c\
25 body.c\ 25 body.c\
26 bodystruct.c\ 26 bodystruct.c\
27 copy.c\
27 envelope.c\ 28 envelope.c\
28 folder.c\ 29 folder.c\
29 fsfolder.c\ 30 fsfolder.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2001, 2004-2005, 2007, 2009-2012 Free Software
3 Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library. If not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 #include <mailutils/types.h>
23 #include <mailutils/mailbox.h>
24 #include <mailutils/stream.h>
25 #include <mailutils/errno.h>
26 #include <mailutils/msgset.h>
27 #include <mailutils/sys/mailbox.h>
28
29 int
30 mu_mailbox_msgset_copy (mu_mailbox_t mbox, mu_msgset_t msgset,
31 const char *dest, int flags)
32 {
33 if (!mbox)
34 return EINVAL;
35 if (!mbox->_copy)
36 return ENOSYS;
37 return mbox->_copy (mbox, msgset, dest, flags);
38 }
39
40 int
41 mu_mailbox_message_copy (mu_mailbox_t mbox, size_t msgno,
42 const char *dest, int flags)
43 {
44 int rc;
45 mu_msgset_t msgset;
46 int mode;
47
48 if (!mbox)
49 return EINVAL;
50 if (!mbox->_copy)
51 return ENOSYS;
52
53 mode = flags & MU_MAILBOX_COPY_UID ? MU_MSGSET_UID : MU_MSGSET_NUM;
54 rc = mu_msgset_create (&msgset, mbox, mode);
55 if (rc)
56 return rc;
57 rc = mu_msgset_add_range (msgset, 1, 1, mode);
58 if (rc == 0)
59 rc = mbox->_copy (mbox, msgset, dest, flags);
60 mu_msgset_destroy (&msgset);
61 return rc;
62 }
...@@ -475,12 +475,13 @@ mu_folder_delete (mu_folder_t folder, const char *name) ...@@ -475,12 +475,13 @@ mu_folder_delete (mu_folder_t folder, const char *name)
475 mailbox and call mailbox delete (remove) method. This is necessary 475 mailbox and call mailbox delete (remove) method. This is necessary
476 because certain types of mailboxes share a common folder (e.g. mbox, 476 because certain types of mailboxes share a common folder (e.g. mbox,
477 maildir and mh all use filesystem folder), but have a different 477 maildir and mh all use filesystem folder), but have a different
478 internal structure. Supplying mu_folder_t with a knowledge of mailbox 478 internal structure. Supplying mu_folder_t with knowledge about
479 internals will harm separation of concerns. On the other hand, 479 mailbox internals will harm separation of concerns. On the other
480 removing something without looking into it may well yield undesired 480 hand, removing something without looking into it may well yield
481 results. For example, a MH mailbox can hold another mailboxes, i.e. 481 undesired results. For example, a MH mailbox can hold another
482 be a folder itself. Removing it blindly would result in removing 482 mailboxes, i.e. be a folder itself. Removing it blindly would
483 these mailboxes as well, which is clearly not indended. 483 result in removing these mailboxes as well, which is clearly not
484 indended.
484 485
485 To solve this folder and mailbox delete methods are tightly paired, 486 To solve this folder and mailbox delete methods are tightly paired,
486 but without looking into each-others internal mechanisms. */ 487 but without looking into each-others internal mechanisms. */
......
...@@ -121,7 +121,7 @@ mu_imap_append_stream_size (mu_imap_t imap, const char *mailbox, int flags, ...@@ -121,7 +121,7 @@ mu_imap_append_stream_size (mu_imap_t imap, const char *mailbox, int flags,
121 case MU_IMAP_CLIENT_APPEND_RX: 121 case MU_IMAP_CLIENT_APPEND_RX:
122 status = _mu_imap_response (imap, NULL, NULL); 122 status = _mu_imap_response (imap, NULL, NULL);
123 MU_IMAP_CHECK_EAGAIN (imap, status); 123 MU_IMAP_CHECK_EAGAIN (imap, status);
124 switch (imap->resp_code) 124 switch (imap->response)
125 { 125 {
126 case MU_IMAP_OK: 126 case MU_IMAP_OK:
127 status = 0; 127 status = 0;
......
...@@ -113,7 +113,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter) ...@@ -113,7 +113,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
113 NULL); 113 NULL);
114 imap->client_state = MU_IMAP_CLIENT_READY; 114 imap->client_state = MU_IMAP_CLIENT_READY;
115 MU_IMAP_CHECK_EAGAIN (imap, status); 115 MU_IMAP_CHECK_EAGAIN (imap, status);
116 if (imap->resp_code != MU_IMAP_OK) 116 if (imap->response != MU_IMAP_OK)
117 return MU_ERR_REPLY; 117 return MU_ERR_REPLY;
118 else 118 else
119 { 119 {
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
25 void 25 void
26 _mu_close_handler (mu_imap_t imap) 26 _mu_close_handler (mu_imap_t imap)
27 { 27 {
28 if (imap->resp_code == MU_IMAP_OK) 28 if (imap->response == MU_IMAP_OK)
29 imap->session_state = MU_IMAP_SESSION_AUTH; 29 imap->session_state = MU_IMAP_SESSION_AUTH;
30 } 30 }
31 31
......
...@@ -71,3 +71,21 @@ mu_imap_strerror (mu_imap_t imap, const char **pstr) ...@@ -71,3 +71,21 @@ mu_imap_strerror (mu_imap_t imap, const char **pstr)
71 *pstr = "(no recent reply)"; 71 *pstr = "(no recent reply)";
72 return MU_ERR_NOENT; 72 return MU_ERR_NOENT;
73 } 73 }
74
75 enum mu_imap_response
76 mu_imap_response (mu_imap_t imap)
77 {
78 if (!imap)
79 return MU_IMAP_BAD;
80 return imap->response;
81 }
82
83 int
84 mu_imap_response_code (mu_imap_t imap)
85 {
86 if (!imap)
87 return -1;
88 return imap->response_code;
89 }
90
91
......
...@@ -71,7 +71,7 @@ mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd) ...@@ -71,7 +71,7 @@ mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd)
71 MU_IMAP_CHECK_EAGAIN (imap, status); 71 MU_IMAP_CHECK_EAGAIN (imap, status);
72 if (cmd->tagged_handler) 72 if (cmd->tagged_handler)
73 cmd->tagged_handler (imap); 73 cmd->tagged_handler (imap);
74 switch (imap->resp_code) 74 switch (imap->response)
75 { 75 {
76 case MU_IMAP_OK: 76 case MU_IMAP_OK:
77 status = 0; 77 status = 0;
......
...@@ -126,7 +126,7 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc) ...@@ -126,7 +126,7 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc)
126 case MU_IMAP_CLIENT_ID_RX: 126 case MU_IMAP_CLIENT_ID_RX:
127 status = _mu_imap_response (imap, parse_id_reply, passoc); 127 status = _mu_imap_response (imap, parse_id_reply, passoc);
128 MU_IMAP_CHECK_EAGAIN (imap, status); 128 MU_IMAP_CHECK_EAGAIN (imap, status);
129 switch (imap->resp_code) 129 switch (imap->response)
130 { 130 {
131 case MU_IMAP_OK: 131 case MU_IMAP_OK:
132 status = 0; 132 status = 0;
......
...@@ -56,7 +56,7 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass) ...@@ -56,7 +56,7 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
56 status = _mu_imap_response (imap, NULL, NULL); 56 status = _mu_imap_response (imap, NULL, NULL);
57 imap->client_state = MU_IMAP_CLIENT_READY; 57 imap->client_state = MU_IMAP_CLIENT_READY;
58 MU_IMAP_CHECK_EAGAIN (imap, status); 58 MU_IMAP_CHECK_EAGAIN (imap, status);
59 switch (imap->resp_code) 59 switch (imap->response)
60 { 60 {
61 case MU_IMAP_OK: 61 case MU_IMAP_OK:
62 imap->session_state = MU_IMAP_SESSION_AUTH; 62 imap->session_state = MU_IMAP_SESSION_AUTH;
......
...@@ -1252,6 +1252,41 @@ _imap_mbx_is_updated (mu_mailbox_t mbox) ...@@ -1252,6 +1252,41 @@ _imap_mbx_is_updated (mu_mailbox_t mbox)
1252 return imbx->flags & _MU_IMAP_MBX_UPTODATE; 1252 return imbx->flags & _MU_IMAP_MBX_UPTODATE;
1253 } 1253 }
1254 1254
1255 static int
1256 _imap_copy_to_mailbox (mu_mailbox_t mbox, mu_msgset_t msgset,
1257 const char *mailbox, int flags)
1258 {
1259 struct _mu_imap_mailbox *imbx = mbox->data;
1260 mu_folder_t folder = mbox->folder;
1261 mu_imap_t imap = folder->data;
1262 int rc;
1263
1264 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
1265 (_("copying messages to mailbox %s"), mailbox));
1266 _imap_mbx_clrerr (imbx);
1267
1268 rc = mu_imap_copy (imap, flags & MU_MAILBOX_COPY_UID, msgset, mailbox);
1269 if (rc)
1270 {
1271 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1272 (_("mu_imap_copy: %s"), mu_strerror (rc)));
1273 if (rc)
1274 {
1275 if (mu_imap_response_code (imap) == MU_IMAP_RESPONSE_TRYCREATE)
1276 {
1277 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
1278 (_("creating mailbox %s"), mailbox));
1279 rc = mu_imap_mailbox_create (imap, mailbox);
1280 if (rc == 0)
1281 rc = mu_imap_copy (imap, flags & MU_MAILBOX_COPY_UID,
1282 msgset, mailbox);
1283 }
1284 }
1285 imbx->last_error = rc;
1286 }
1287 return rc;
1288 }
1289
1255 int 1290 int
1256 _mu_imap_mailbox_init (mu_mailbox_t mailbox) 1291 _mu_imap_mailbox_init (mu_mailbox_t mailbox)
1257 { 1292 {
...@@ -1279,6 +1314,7 @@ _mu_imap_mailbox_init (mu_mailbox_t mailbox) ...@@ -1279,6 +1314,7 @@ _mu_imap_mailbox_init (mu_mailbox_t mailbox)
1279 mailbox->_sync = _imap_mbx_sync; 1314 mailbox->_sync = _imap_mbx_sync;
1280 1315
1281 mailbox->_append_message = _imap_mbx_append_message; 1316 mailbox->_append_message = _imap_mbx_append_message;
1317 mailbox->_copy = _imap_copy_to_mailbox;
1282 1318
1283 return 0; 1319 return 0;
1284 } 1320 }
......
...@@ -55,8 +55,8 @@ _mu_imap_response_list_create (mu_imap_t imap, mu_list_t *plist) ...@@ -55,8 +55,8 @@ _mu_imap_response_list_create (mu_imap_t imap, mu_list_t *plist)
55 return 0; 55 return 0;
56 } 56 }
57 57
58 #define IS_LBRACE(p) ((p)[0] == '(') 58 #define IS_LBRACE(p) ((p)[0] == '(' && !(p)[1])
59 #define IS_RBRACE(p) ((p)[0] == ')') 59 #define IS_RBRACE(p) ((p)[0] == ')' && !(p)[1])
60 #define IS_NIL(p) (strcmp (p, "NIL") == 0) 60 #define IS_NIL(p) (strcmp (p, "NIL") == 0)
61 61
62 static struct imap_list_element * 62 static struct imap_list_element *
......
...@@ -27,13 +27,6 @@ ...@@ -27,13 +27,6 @@
27 #include <mailutils/errno.h> 27 #include <mailutils/errno.h>
28 #include <mailutils/sys/imap.h> 28 #include <mailutils/sys/imap.h>
29 29
30 static void
31 response_to_errstr (mu_imap_t imap, size_t argc, char **argv)
32 {
33 if (argc && strcmp (argv[argc-1], "]"))
34 _mu_imap_seterrstrz (imap, argv[argc-1]);
35 }
36
37 int 30 int
38 _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun, 31 _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
39 void *data) 32 void *data)
...@@ -83,29 +76,17 @@ _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun, ...@@ -83,29 +76,17 @@ _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
83 /*imap->client_state = MU_IMAP_CLIENT_ERROR;*/ 76 /*imap->client_state = MU_IMAP_CLIENT_ERROR;*/
84 status = MU_ERR_BADREPLY; 77 status = MU_ERR_BADREPLY;
85 } 78 }
86 else if (strcmp (wv[1], "OK") == 0) 79 else
87 {
88 imap->resp_code = MU_IMAP_OK;
89 response_to_errstr (imap, wc, wv);
90 }
91 else if (strcmp (wv[1], "NO") == 0)
92 {
93 imap->resp_code = MU_IMAP_NO;
94 response_to_errstr (imap, wc, wv);
95 }
96 else if (strcmp (wv[1], "BAD") == 0)
97 { 80 {
98 imap->resp_code = MU_IMAP_BAD; 81 mu_list_t list;
99 response_to_errstr (imap, wc, wv); 82 status = _mu_imap_untagged_response_to_list (imap, &list);
100 /* This may be so important that CB_BAD callback is 83 if (status == 0)
101 * overloaded to handle this case as well. 84 {
102 */ 85 if (_mu_imap_process_tagged_response (imap, list))
103 mu_imap_callback (imap, MU_IMAP_CB_BAD, 86 status = MU_ERR_BADREPLY;
104 MU_IMAP_RESPONSE_TAGGED, 87 mu_list_destroy (&list);
105 wc >= 1 ? wv[wc-1] : NULL); 88 }
106 } 89 }
107 else
108 status = MU_ERR_BADREPLY;
109 MU_IMAP_FSET (imap, MU_IMAP_RESP); 90 MU_IMAP_FSET (imap, MU_IMAP_RESP);
110 } 91 }
111 else 92 else
......
...@@ -72,7 +72,7 @@ parse_response_code (mu_imap_t imap, mu_list_t resp) ...@@ -72,7 +72,7 @@ parse_response_code (mu_imap_t imap, mu_list_t resp)
72 if (mu_kwd_xlat_name (mu_imap_response_codes, arg->v.string, &rcode)) 72 if (mu_kwd_xlat_name (mu_imap_response_codes, arg->v.string, &rcode))
73 return -1; 73 return -1;
74 74
75 arg = _mu_imap_list_at (resp, 4); 75 arg = _mu_imap_list_at (resp, 3);
76 if (!arg || !_mu_imap_list_element_is_string (arg, "]")) 76 if (!arg || !_mu_imap_list_element_is_string (arg, "]"))
77 return -1; 77 return -1;
78 } 78 }
...@@ -217,6 +217,7 @@ struct resptab ...@@ -217,6 +217,7 @@ struct resptab
217 { 217 {
218 char *name; 218 char *name;
219 mu_imap_response_action_t action; 219 mu_imap_response_action_t action;
220 int code;
220 }; 221 };
221 222
222 static struct resptab resptab[] = { 223 static struct resptab resptab[] = {
...@@ -350,5 +351,75 @@ _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list, ...@@ -350,5 +351,75 @@ _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list,
350 } 351 }
351 return 0; 352 return 0;
352 } 353 }
354
355 static void
356 default_tagged_response (mu_imap_t imap, int code, mu_list_t resp, void *data)
357 {
358 struct imap_list_element *arg;
359
360 if (mu_list_tail (resp, (void*) &arg) == 0 &&
361 arg->type == imap_eltype_string)
362 _mu_imap_seterrstrz (imap, arg->v.string);
363 imap->response_code = parse_response_code (imap, resp);
364 mu_imap_callback (imap, code, imap->response_code,
365 arg ? arg->v.string : NULL);
366 }
367
368 static void
369 ok_tagged_response (mu_imap_t imap, mu_list_t resp, void *data)
370 {
371 default_tagged_response (imap, MU_IMAP_CB_TAGGED_OK, resp, data);
372 }
373
374 static void
375 no_tagged_response (mu_imap_t imap, mu_list_t resp, void *data)
376 {
377 default_tagged_response (imap, MU_IMAP_CB_TAGGED_NO, resp, data);
378 }
379
380 static void
381 bad_tagged_response (mu_imap_t imap, mu_list_t resp, void *data)
382 {
383 default_tagged_response (imap, MU_IMAP_CB_TAGGED_BAD, resp, data);
384 }
385
386 static struct resptab tagged_resptab[] = {
387 { "OK", ok_tagged_response, MU_IMAP_OK },
388 { "NO", no_tagged_response, MU_IMAP_NO },
389 { "BAD", bad_tagged_response, MU_IMAP_BAD },
390 { NULL }
391 };
392
393 static int
394 _std_tagged_response (mu_imap_t imap, size_t count, mu_list_t resp)
395 {
396 struct resptab *rp;
397 struct imap_list_element *arg = _mu_imap_list_at (resp, 0);
398
399 if (!arg)
400 return 1;
401
402 if (arg->type == imap_eltype_string)
403 for (rp = tagged_resptab; rp->name; rp++)
404 {
405 if (mu_c_strcasecmp (rp->name, arg->v.string) == 0)
406 {
407 imap->response = rp->code;
408 rp->action (imap, resp, NULL);
409 return 0;
410 }
411 }
412 return 1;
413 }
414
415 int
416 _mu_imap_process_tagged_response (mu_imap_t imap, mu_list_t resp)
417 {
418 size_t count;
419
420 if (mu_list_count (resp, &count))
421 return 1;
422
423 return _std_tagged_response (imap, count, resp);
424 }
353 425
354
......
...@@ -113,7 +113,7 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable, ...@@ -113,7 +113,7 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
113 memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat)); 113 memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat));
114 status = _mu_imap_response (imap, _select_response_action, NULL); 114 status = _mu_imap_response (imap, _select_response_action, NULL);
115 MU_IMAP_CHECK_EAGAIN (imap, status); 115 MU_IMAP_CHECK_EAGAIN (imap, status);
116 switch (imap->resp_code) 116 switch (imap->response)
117 { 117 {
118 case MU_IMAP_OK: 118 case MU_IMAP_OK:
119 imap->session_state = MU_IMAP_SESSION_SELECTED; 119 imap->session_state = MU_IMAP_SESSION_SELECTED;
......
...@@ -60,7 +60,7 @@ mu_imap_starttls (mu_imap_t imap) ...@@ -60,7 +60,7 @@ mu_imap_starttls (mu_imap_t imap)
60 case MU_IMAP_CLIENT_STARTTLS_RX: 60 case MU_IMAP_CLIENT_STARTTLS_RX:
61 status = _mu_imap_response (imap, NULL, NULL); 61 status = _mu_imap_response (imap, NULL, NULL);
62 MU_IMAP_CHECK_EAGAIN (imap, status); 62 MU_IMAP_CHECK_EAGAIN (imap, status);
63 switch (imap->resp_code) 63 switch (imap->response)
64 { 64 {
65 case MU_IMAP_OK: 65 case MU_IMAP_OK:
66 status = mu_imapio_get_streams (imap->io, streams); 66 status = mu_imapio_get_streams (imap->io, streams);
......
...@@ -185,7 +185,7 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps) ...@@ -185,7 +185,7 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
185 185
186 status = _mu_imap_response (imap, _status_response_action, &sd); 186 status = _mu_imap_response (imap, _status_response_action, &sd);
187 MU_IMAP_CHECK_EAGAIN (imap, status); 187 MU_IMAP_CHECK_EAGAIN (imap, status);
188 switch (imap->resp_code) 188 switch (imap->response)
189 { 189 {
190 case MU_IMAP_OK: 190 case MU_IMAP_OK:
191 break; 191 break;
......
...@@ -67,7 +67,7 @@ mu_imap_store_flags (mu_imap_t imap, int uid, mu_msgset_t msgset, ...@@ -67,7 +67,7 @@ mu_imap_store_flags (mu_imap_t imap, int uid, mu_msgset_t msgset,
67 /* FIXME: Handle unsolicited responses */ 67 /* FIXME: Handle unsolicited responses */
68 status = _mu_imap_response (imap, NULL, NULL); 68 status = _mu_imap_response (imap, NULL, NULL);
69 MU_IMAP_CHECK_EAGAIN (imap, status); 69 MU_IMAP_CHECK_EAGAIN (imap, status);
70 switch (imap->resp_code) 70 switch (imap->response)
71 { 71 {
72 case MU_IMAP_OK: 72 case MU_IMAP_OK:
73 status = 0; 73 status = 0;
......
...@@ -42,6 +42,8 @@ static struct argp_option options[] = { ...@@ -42,6 +42,8 @@ static struct argp_option options[] = {
42 {"truncate", ARG_TRUNCATE, N_("BOOL"), OPTION_ARG_OPTIONAL, 42 {"truncate", ARG_TRUNCATE, N_("BOOL"), OPTION_ARG_OPTIONAL,
43 N_("truncate source mailbox after incorporating (default)")}, 43 N_("truncate source mailbox after incorporating (default)")},
44 {"notruncate", ARG_NOTRUNCATE, NULL, OPTION_HIDDEN, ""}, 44 {"notruncate", ARG_NOTRUNCATE, NULL, OPTION_HIDDEN, ""},
45 {"moveto", ARG_MOVETO, N_("MAILBOX"), 0,
46 N_("move incorporated messages to MAILBOX instead of deleting them") },
45 {"width", ARG_WIDTH, N_("NUMBER"), 0, 47 {"width", ARG_WIDTH, N_("NUMBER"), 0,
46 N_("set output width")}, 48 N_("set output width")},
47 {"quiet", ARG_QUIET, 0, 0, 49 {"quiet", ARG_QUIET, 0, 0,
...@@ -58,6 +60,7 @@ struct mh_option mh_option[] = { ...@@ -58,6 +60,7 @@ struct mh_option mh_option[] = {
58 { "form", MH_OPT_ARG, "format-file" }, 60 { "form", MH_OPT_ARG, "format-file" },
59 { "format", MH_OPT_ARG, "string" }, 61 { "format", MH_OPT_ARG, "string" },
60 { "truncate", MH_OPT_BOOL }, 62 { "truncate", MH_OPT_BOOL },
63 { "moveto", MH_OPT_ARG, "folder" },
61 { "width", MH_OPT_ARG, "number" }, 64 { "width", MH_OPT_ARG, "number" },
62 { "quiet" }, 65 { "quiet" },
63 { NULL } 66 { NULL }
...@@ -72,6 +75,7 @@ static int changecur = -1; ...@@ -72,6 +75,7 @@ static int changecur = -1;
72 static int truncate_source = -1; 75 static int truncate_source = -1;
73 static int quiet = 0; 76 static int quiet = 0;
74 static const char *append_folder; 77 static const char *append_folder;
78 static const char *move_to_mailbox;
75 79
76 static error_t 80 static error_t
77 opt_handler (int key, char *arg, struct argp_state *state) 81 opt_handler (int key, char *arg, struct argp_state *state)
...@@ -122,6 +126,10 @@ opt_handler (int key, char *arg, struct argp_state *state) ...@@ -122,6 +126,10 @@ opt_handler (int key, char *arg, struct argp_state *state)
122 case ARG_NOTRUNCATE: 126 case ARG_NOTRUNCATE:
123 truncate_source = 0; 127 truncate_source = 0;
124 break; 128 break;
129
130 case ARG_MOVETO:
131 move_to_mailbox = arg;
132 break;
125 133
126 case ARG_WIDTH: 134 case ARG_WIDTH:
127 width = strtoul (arg, NULL, 0); 135 width = strtoul (arg, NULL, 0);
...@@ -143,7 +151,8 @@ opt_handler (int key, char *arg, struct argp_state *state) ...@@ -143,7 +151,8 @@ opt_handler (int key, char *arg, struct argp_state *state)
143 } 151 }
144 152
145 void 153 void
146 list_message (mh_format_t *format, mu_mailbox_t mbox, size_t msgno, size_t width) 154 list_message (mh_format_t *format, mu_mailbox_t mbox, size_t msgno,
155 size_t width)
147 { 156 {
148 mu_message_t msg; 157 mu_message_t msg;
149 char *buf = NULL; 158 char *buf = NULL;
...@@ -275,6 +284,33 @@ main (int argc, char **argv) ...@@ -275,6 +284,33 @@ main (int argc, char **argv)
275 } 284 }
276 } 285 }
277 286
287 if (truncate_source && move_to_mailbox)
288 {
289 mu_msgset_t msgset;
290
291 rc = mu_msgset_create (&msgset, input, MU_MSGSET_NUM);
292 if (rc)
293 mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_create", NULL, rc);
294 else
295 {
296 rc = mu_msgset_add_range (msgset, 1, total, MU_MSGSET_NUM);
297 if (rc)
298 mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_add_range", NULL, rc);
299 else
300 {
301 rc = mu_mailbox_msgset_copy (input, msgset, move_to_mailbox,
302 MU_MAILBOX_COPY_CREAT);
303 if (rc)
304 {
305 mu_error (_("failed to move messages to %s: %s"),
306 move_to_mailbox, mu_strerror (rc));
307 truncate_source = 0;
308 }
309 }
310 mu_msgset_destroy (&msgset);
311 }
312 }
313
278 if (!changecur) 314 if (!changecur)
279 { 315 {
280 mu_property_t prop = mh_mailbox_get_property (output); 316 mu_property_t prop = mh_mailbox_get_property (output);
......
...@@ -91,7 +91,8 @@ enum mh_arg { ...@@ -91,7 +91,8 @@ enum mh_arg {
91 ARG_LINK, 91 ARG_LINK,
92 ARG_LIST, 92 ARG_LIST,
93 ARG_MIME, 93 ARG_MIME,
94 ARG_MOREPROC, 94 ARG_MOREPROC,
95 ARG_MOVETO,
95 ARG_MSGID, 96 ARG_MSGID,
96 ARG_NOALIAS, 97 ARG_NOALIAS,
97 ARG_NOAUDIT, 98 ARG_NOAUDIT,
......