1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2002-2021 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 /* MH refile command */
18
19 #include <mh.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <fcntl.h>
25
26 static char prog_doc[] = N_("File messages in other folders");
27 static char args_doc[] = N_("MSGLIST FOLDER [FOLDER...]");
28
29 int link_flag = 0;
30 int preserve_flag = 0;
31 char *source_file = NULL;
32 mu_list_t folder_name_list = NULL;
33 mu_list_t folder_mbox_list = NULL;
34
35 void
add_folder(const char * folder)36 add_folder (const char *folder)
37 {
38 if (!folder_name_list && mu_list_create (&folder_name_list))
39 {
40 mu_error (_("cannot create folder list"));
41 exit (1);
42 }
43 mu_list_append (folder_name_list, mu_strdup (folder));
44 }
45
46 static void
add_folder_option(struct mu_parseopt * po,struct mu_option * opt,const char * arg)47 add_folder_option (struct mu_parseopt *po, struct mu_option *opt,
48 const char *arg)
49 {
50 add_folder (arg);
51 }
52
53 static struct mu_option options[] = {
54 { "folder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
55 N_("specify folder to operate upon"),
56 mu_c_string, NULL, add_folder_option },
57 { "draft", 0, NULL, MU_OPTION_DEFAULT,
58 N_("use <mh-dir>/draft as the source message"),
59 mu_c_string, &source_file, NULL, "draft" },
60 { "copy", 0, NULL, MU_OPTION_DEFAULT,
61 N_("preserve the source folder copy"),
62 mu_c_bool, &link_flag },
63 { "link", 0, NULL, MU_OPTION_ALIAS },
64 { "preserve", 0, NULL, MU_OPTION_HIDDEN,
65 N_("try to preserve message sequence numbers"),
66 mu_c_bool, NULL, mh_opt_notimpl_warning },
67 { "source", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
68 N_("specify source folder; it will become the current folder after the program exits"),
69 mu_c_string, NULL, mh_opt_set_folder },
70 { "src", 0, NULL, MU_OPTION_ALIAS },
71 { "file", 0, N_("FILE"), MU_OPTION_DEFAULT,
72 N_("use FILE as the source message"),
73 mu_c_string, &source_file },
74 MU_OPTION_END
75 };
76
77 void
open_folders(void)78 open_folders (void)
79 {
80 int rc;
81 mu_iterator_t itr;
82
83 if (!folder_name_list)
84 {
85 mu_error (_("no folder specified"));
86 exit (1);
87 }
88
89 if ((rc = mu_list_create (&folder_mbox_list)) != 0)
90 {
91 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc);
92 exit (1);
93 }
94
95 if ((rc = mu_list_get_iterator (folder_name_list, &itr)) != 0)
96 {
97 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_get_iterator", NULL, rc);
98 exit (1);
99 }
100
101 for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
102 {
103 char *name = NULL;
104 mu_mailbox_t mbox;
105
106 mu_iterator_current (itr, (void **)&name);
107 mbox = mh_open_folder (name, MU_STREAM_RDWR|MU_STREAM_CREAT);
108 mu_list_append (folder_mbox_list, mbox);
109 free (name);
110 }
111 mu_iterator_destroy (&itr);
112 mu_list_destroy (&folder_name_list);
113 }
114
115 void
enumerate_folders(void (* f)(void *,mu_mailbox_t),void * data)116 enumerate_folders (void (*f) (void *, mu_mailbox_t), void *data)
117 {
118 mu_iterator_t itr;
119
120 if (mu_list_get_iterator (folder_mbox_list, &itr))
121 {
122 mu_error (_("cannot create iterator"));
123 exit (1);
124 }
125
126 for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
127 {
128 mu_mailbox_t mbox;
129 mu_iterator_current (itr, (void **)&mbox);
130 (*f) (data, mbox);
131 }
132 mu_iterator_destroy (&itr);
133 }
134
135 void
_close_folder(void * unused,mu_mailbox_t mbox)136 _close_folder (void *unused, mu_mailbox_t mbox)
137 {
138 mu_mailbox_close (mbox);
139 mu_mailbox_destroy (&mbox);
140 }
141
142 void
close_folders(void)143 close_folders (void)
144 {
145 enumerate_folders (_close_folder, NULL);
146 }
147
148 void
refile_folder(void * data,mu_mailbox_t mbox)149 refile_folder (void *data, mu_mailbox_t mbox)
150 {
151 mu_message_t msg = data;
152 int rc;
153
154 rc = mu_mailbox_append_message (mbox, msg);
155 if (rc)
156 {
157 mu_error (_("error appending message: %s"), mu_strerror (rc));
158 exit (1);
159 }
160 }
161
162 void
refile(mu_message_t msg)163 refile (mu_message_t msg)
164 {
165 enumerate_folders (refile_folder, msg);
166 }
167
168 int
refile_iterator(size_t num,mu_message_t msg,void * data)169 refile_iterator (size_t num, mu_message_t msg, void *data)
170 {
171 enumerate_folders (refile_folder, msg);
172 if (!link_flag)
173 {
174 mu_attribute_t attr;
175 mu_message_get_attribute (msg, &attr);
176 mu_attribute_set_deleted (attr);
177 }
178 return 0;
179 }
180
181 int
main(int argc,char ** argv)182 main (int argc, char **argv)
183 {
184 mu_msgset_t msgset;
185 mu_mailbox_t mbox;
186 int status, i, j;
187
188 mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL);
189 /* Collect any surplus folders */
190 for (i = j = 0; i < argc; i++)
191 {
192 if (argv[i][0] == '+')
193 add_folder (argv[i]);
194 else
195 argv[j++] = argv[i];
196 }
197 argv[j] = NULL;
198 argc = j;
199
200 open_folders ();
201
202 if (source_file)
203 {
204 mu_message_t msg;
205
206 if (argc > 0)
207 {
208 mu_error (_("both message set and source file given"));
209 exit (1);
210 }
211 msg = mh_file_to_message (mu_folder_directory (), source_file);
212 refile (msg);
213 if (!link_flag)
214 unlink (source_file);
215 status = 0;
216 }
217 else
218 {
219 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
220 mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
221
222 status = mu_msgset_foreach_message (msgset, refile_iterator, NULL);
223
224 mh_sequences_elim (msgset);
225
226 mu_mailbox_expunge (mbox);
227 mu_mailbox_close (mbox);
228 mu_mailbox_destroy (&mbox);
229 }
230
231 close_folders ();
232
233 return status;
234 }
235