mail: the "copy" command operates on files by default.
Last argument is treated as a mailbox only if it begins with a mailbox scheme (mbox://, maildir://, etc). * mail/copy.c (append_to_mailbox) (append_to_file): New functions. (mail_copy0): Depending on whether mailbox scheme is specified, call one of the above functions. * doc/texinfo/programs.texi (mail): Fix documentation of the copy command. * mail/testsuite/mail/write.exp: Update line/character counts for [Ss]ave commands.
Showing
3 changed files
with
202 additions
and
54 deletions
... | @@ -3236,11 +3236,18 @@ prints the message, immediately following last deleted one. | ... | @@ -3236,11 +3236,18 @@ prints the message, immediately following last deleted one. |
3236 | @table @samp | 3236 | @table @samp |
3237 | @item save [[@var{msglist}] @var{file}] | 3237 | @item save [[@var{msglist}] @var{file}] |
3238 | @itemx s [[@var{msglist}] @var{file}] | 3238 | @itemx s [[@var{msglist}] @var{file}] |
3239 | Takes a message list and a file name and appends each message in turn to | 3239 | Takes a message list and a file name or mailbox URL and appends each |
3240 | the end of the file. The name of file and number of characters appended | 3240 | message in turn to the end of that file or mailbox. Mailbox URLs |
3241 | to it is echoed on the terminal. Each saved message is marked for | 3241 | begin with mailbox type specifier, such as @samp{mbox://}, |
3242 | deletion as if with @code{delete} command, unless the variable | 3242 | @samp{maildir://}, etc. The name of file or mailbox and number of |
3243 | @code{keepsave} is set. | 3243 | lines and characters appended to it is echoed on the terminal. When |
3244 | writing to file, the numbers represent exact number of lines and | ||
3245 | characters appended to the file. When @var{file} specifies a mailbox, | ||
3246 | these numbers may differ by the amount of lines/characters needed to | ||
3247 | represent message envelope for that specific mailbox type. | ||
3248 | |||
3249 | Each saved message is marked for deletion as if with @code{delete} | ||
3250 | command, unless the variable @code{keepsave} is set. | ||
3244 | @item Save [@var{msglist}] | 3251 | @item Save [@var{msglist}] |
3245 | @itemx S [@var{msglist}] | 3252 | @itemx S [@var{msglist}] |
3246 | Like @code{save}, but the file to append messages to is named after the | 3253 | Like @code{save}, but the file to append messages to is named after the | ... | ... |
... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
16 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | 16 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ |
17 | 17 | ||
18 | #include "mail.h" | 18 | #include "mail.h" |
19 | #include <mailutils/locker.h> | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | * c[opy] [file] | 22 | * c[opy] [file] |
... | @@ -23,59 +24,33 @@ | ... | @@ -23,59 +24,33 @@ |
23 | * C[opy] [msglist] | 24 | * C[opy] [msglist] |
24 | */ | 25 | */ |
25 | 26 | ||
26 | /* | 27 | struct append_stat |
27 | * mail_copy0() is shared between mail_copy() and mail_save(). | ||
28 | * argc, argv -- argument count & vector | ||
29 | * mark -- whether we should mark the message as saved. | ||
30 | */ | ||
31 | int | ||
32 | mail_copy0 (int argc, char **argv, int mark) | ||
33 | { | 28 | { |
34 | mu_message_t msg; | 29 | size_t size; |
35 | mu_mailbox_t mbx; | 30 | size_t lines; |
36 | char *filename = NULL; | 31 | }; |
37 | msgset_t *msglist = NULL, *mp; | ||
38 | int sender = 0; | ||
39 | size_t total_size = 0, total_lines = 0, size; | ||
40 | int status; | ||
41 | |||
42 | if (mu_isupper (argv[0][0])) | ||
43 | sender = 1; | ||
44 | else if (argc >= 2) | ||
45 | filename = mail_expand_name (argv[--argc]); | ||
46 | else | ||
47 | filename = mu_strdup ("mbox"); | ||
48 | |||
49 | if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &msglist)) | ||
50 | { | ||
51 | if (filename) | ||
52 | free (filename); | ||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | if (sender) | ||
57 | filename = util_outfolder_name (util_get_sender (msglist->msg_part[0], 1)); | ||
58 | |||
59 | if (!filename) | ||
60 | { | ||
61 | msgset_free (msglist); | ||
62 | return 1; | ||
63 | } | ||
64 | 32 | ||
33 | static int | ||
34 | append_to_mailbox (char const *filename, msgset_t *msglist, int mark, | ||
35 | struct append_stat *totals) | ||
36 | { | ||
37 | int status; | ||
38 | mu_mailbox_t mbx; | ||
39 | msgset_t *mp; | ||
40 | size_t size; | ||
41 | mu_message_t msg; | ||
42 | |||
65 | if ((status = mu_mailbox_create_default (&mbx, filename)) != 0) | 43 | if ((status = mu_mailbox_create_default (&mbx, filename)) != 0) |
66 | { | 44 | { |
67 | mu_error (_("Cannot create mailbox %s: %s"), filename, | 45 | mu_error (_("Cannot create mailbox %s: %s"), filename, |
68 | mu_strerror (status)); | 46 | mu_strerror (status)); |
69 | free (filename); | ||
70 | msgset_free (msglist); | ||
71 | return 1; | 47 | return 1; |
72 | } | 48 | } |
73 | if ((status = mu_mailbox_open (mbx, MU_STREAM_WRITE | MU_STREAM_CREAT)) != 0) | 49 | if ((status = mu_mailbox_open (mbx, MU_STREAM_WRITE | MU_STREAM_CREAT)) != 0) |
74 | { | 50 | { |
75 | mu_error (_("Cannot open mailbox %s: %s"), filename, | 51 | mu_error (_("Cannot open mailbox %s: %s"), filename, |
76 | mu_strerror (status)); | 52 | mu_strerror (status)); |
77 | free (filename); | 53 | mu_mailbox_destroy (&mbx); |
78 | msgset_free (msglist); | ||
79 | return 1; | 54 | return 1; |
80 | } | 55 | } |
81 | 56 | ||
... | @@ -93,9 +68,9 @@ mail_copy0 (int argc, char **argv, int mark) | ... | @@ -93,9 +68,9 @@ mail_copy0 (int argc, char **argv, int mark) |
93 | } | 68 | } |
94 | 69 | ||
95 | mu_message_size (msg, &size); | 70 | mu_message_size (msg, &size); |
96 | total_size += size; | 71 | totals->size += size; |
97 | mu_message_lines (msg, &size); | 72 | mu_message_lines (msg, &size); |
98 | total_lines += size; | 73 | totals->lines += size; |
99 | 74 | ||
100 | if (mark) | 75 | if (mark) |
101 | { | 76 | { |
... | @@ -104,13 +79,179 @@ mail_copy0 (int argc, char **argv, int mark) | ... | @@ -104,13 +79,179 @@ mail_copy0 (int argc, char **argv, int mark) |
104 | mu_attribute_set_userflag (attr, MAIL_ATTRIBUTE_SAVED); | 79 | mu_attribute_set_userflag (attr, MAIL_ATTRIBUTE_SAVED); |
105 | } | 80 | } |
106 | } | 81 | } |
82 | |||
83 | mu_mailbox_close (mbx); | ||
84 | mu_mailbox_destroy (&mbx); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int | ||
89 | append_to_file (char const *filename, msgset_t *msglist, int mark, | ||
90 | struct append_stat *totals) | ||
91 | { | ||
92 | int status; | ||
93 | msgset_t *mp; | ||
94 | mu_stream_t ostr, mstr; | ||
95 | mu_off_t size; | ||
96 | size_t lines; | ||
97 | mu_message_t msg; | ||
98 | mu_locker_t locker; | ||
99 | |||
100 | status = mu_file_stream_create (&ostr, filename, | ||
101 | MU_STREAM_CREAT|MU_STREAM_APPEND); | ||
102 | if (status) | ||
103 | { | ||
104 | mu_error (_("Cannot open output file %s: %s"), | ||
105 | filename, mu_strerror (status)); | ||
106 | return 1; | ||
107 | } | ||
108 | |||
109 | status = mu_locker_create (&locker, filename, | ||
110 | MU_LOCKER_KERNEL|MU_LOCKER_RETRY); | ||
111 | if (status) | ||
112 | { | ||
113 | mu_error (_("Cannot create locker %s: %s"), | ||
114 | filename, mu_strerror (status)); | ||
115 | mu_stream_unref (ostr); | ||
116 | return 1; | ||
117 | } | ||
118 | mu_locker_lock_mode (locker, mu_lck_exc); | ||
119 | |||
120 | status = mu_locker_lock (locker); | ||
121 | if (status) | ||
122 | { | ||
123 | mu_error (_("Cannot lock %s: %s"), | ||
124 | filename, mu_strerror (status)); | ||
125 | mu_locker_destroy (&locker); | ||
126 | mu_stream_unref (ostr); | ||
127 | return 1; | ||
128 | } | ||
129 | |||
130 | for (mp = msglist; mp; mp = mp->next) | ||
131 | { | ||
132 | mu_envelope_t env; | ||
133 | const char *s, *d; | ||
134 | int n; | ||
135 | |||
136 | status = util_get_message (mbox, mp->msg_part[0], &msg); | ||
137 | if (status) | ||
138 | break; | ||
107 | 139 | ||
140 | status = mu_message_get_envelope (msg, &env); | ||
141 | if (status) | ||
142 | { | ||
143 | mu_error (_("Cannot get envelope: %s"), mu_strerror (status)); | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | status = mu_envelope_sget_sender (env, &s); | ||
148 | if (status) | ||
149 | { | ||
150 | mu_error (_("Cannot get envelope sender: %s"), mu_strerror (status)); | ||
151 | break; | ||
152 | } | ||
153 | |||
154 | status = mu_envelope_sget_date (env, &d); | ||
155 | if (status) | ||
156 | { | ||
157 | mu_error (_("Cannot get envelope date: %s"), mu_strerror (status)); | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | status = mu_stream_printf (ostr, "From %s %s\n%n", s, d, &n); | ||
162 | if (status) | ||
163 | { | ||
164 | mu_error (_("Write error: %s"), mu_strerror (status)); | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | totals->lines++; | ||
169 | totals->size += n; | ||
170 | |||
171 | status = mu_message_get_streamref (msg, &mstr); | ||
172 | if (status) | ||
173 | { | ||
174 | mu_error (_("Cannot get message: %s"), mu_strerror (status)); | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | status = mu_stream_copy (ostr, mstr, 0, &size); | ||
179 | if (status) | ||
180 | { | ||
181 | mu_error (_("Cannot append message: %s"), mu_strerror (status)); | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | mu_stream_unref (mstr); | ||
186 | |||
187 | mu_stream_write (ostr, "\n", 1, NULL); | ||
188 | |||
189 | totals->size += size + 1; | ||
190 | mu_message_lines (msg, &lines); | ||
191 | totals->lines += lines + 1; | ||
192 | |||
193 | if (mark) | ||
194 | { | ||
195 | mu_attribute_t attr; | ||
196 | mu_message_get_attribute (msg, &attr); | ||
197 | mu_attribute_set_userflag (attr, MAIL_ATTRIBUTE_SAVED); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | mu_stream_close (ostr); | ||
202 | mu_stream_unref (ostr); | ||
203 | |||
204 | mu_locker_unlock (locker); | ||
205 | mu_locker_destroy (&locker); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * mail_copy0() is shared between mail_copy() and mail_save(). | ||
212 | * argc, argv -- argument count & vector | ||
213 | * mark -- whether we should mark the message as saved. | ||
214 | */ | ||
215 | int | ||
216 | mail_copy0 (int argc, char **argv, int mark) | ||
217 | { | ||
218 | char *filename = NULL; | ||
219 | msgset_t *msglist = NULL; | ||
220 | int sender = 0; | ||
221 | struct append_stat totals = { 0, 0 }; | ||
222 | int status; | ||
223 | |||
224 | if (mu_isupper (argv[0][0])) | ||
225 | sender = 1; | ||
226 | else if (argc >= 2) | ||
227 | filename = mail_expand_name (argv[--argc]); | ||
228 | else | ||
229 | filename = mu_strdup ("mbox"); | ||
230 | |||
231 | if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &msglist)) | ||
232 | { | ||
233 | if (filename) | ||
234 | free (filename); | ||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | if (sender) | ||
239 | filename = util_outfolder_name (util_get_sender (msglist->msg_part[0], 1)); | ||
240 | |||
241 | if (!filename) | ||
242 | { | ||
243 | msgset_free (msglist); | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | if (mu_is_proto (filename)) | ||
248 | status = append_to_mailbox (filename, msglist, mark, &totals); | ||
249 | else | ||
250 | status = append_to_file (filename, msglist, mark, &totals); | ||
251 | |||
108 | if (status == 0) | 252 | if (status == 0) |
109 | mu_printf ("\"%s\" %3lu/%-5lu\n", filename, | 253 | mu_printf ("\"%s\" %3lu/%-5lu\n", filename, |
110 | (unsigned long) total_lines, (unsigned long) total_size); | 254 | (unsigned long) totals.lines, (unsigned long) totals.size); |
111 | |||
112 | mu_mailbox_close (mbx); | ||
113 | mu_mailbox_destroy (&mbx); | ||
114 | 255 | ||
115 | free (filename); | 256 | free (filename); |
116 | msgset_free (msglist); | 257 | msgset_free (msglist); | ... | ... |
... | @@ -66,7 +66,7 @@ mail_test "headers" \ | ... | @@ -66,7 +66,7 @@ mail_test "headers" \ |
66 | # Save messages to the third mailbox | 66 | # Save messages to the third mailbox |
67 | mail_command "set folder=\"$MU_FOLDER_DIR\"" | 67 | mail_command "set folder=\"$MU_FOLDER_DIR\"" |
68 | mail_test "save 1 2 +three" \ | 68 | mail_test "save 1 2 +three" \ |
69 | "\"$MU_FOLDER_DIR/three\" 28/968" | 69 | "\"$MU_FOLDER_DIR/three\" 32/1067" |
70 | 70 | ||
71 | mail_test "headers" \ | 71 | mail_test "headers" \ |
72 | ">* 1 Sergey Poznyakoff Tue Jul 16 12:11 12/390 MBOX"\ | 72 | ">* 1 Sergey Poznyakoff Tue Jul 16 12:11 12/390 MBOX"\ |
... | @@ -84,7 +84,7 @@ mail_test "headers" \ | ... | @@ -84,7 +84,7 @@ mail_test "headers" \ |
84 | # Test uppercase commands (Save and Copy) | 84 | # Test uppercase commands (Save and Copy) |
85 | mail_command "set outfolder=\"$MU_FOLDER_DIR\"" | 85 | mail_command "set outfolder=\"$MU_FOLDER_DIR\"" |
86 | mail_test "Save" \ | 86 | mail_test "Save" \ |
87 | "\"$MU_FOLDER_DIR/gray\" 12/390" | 87 | "\"$MU_FOLDER_DIR/gray\" 14/438" |
88 | 88 | ||
89 | mail_test "file \"$MU_FOLDER_DIR/gray\"" \ | 89 | mail_test "file \"$MU_FOLDER_DIR/gray\"" \ |
90 | "Held 2 messages in $MU_FOLDER_DIR/three" | 90 | "Held 2 messages in $MU_FOLDER_DIR/three" | ... | ... |
-
Please register or sign in to post a comment