2 ** refile.c -- move or link message(s) from a source folder
3 ** -- into one or more destination folders
5 ** This code is Copyright (c) 2002, by the authors of nmh. See the
6 ** COPYRIGHT file in the root directory of the nmh distribution for
7 ** complete copyright information.
15 static struct swit switches[] = {
33 { "rmmproc program", 0 },
43 static char maildir[BUFSIZ];
53 static void opnfolds (struct st_fold *, int);
54 static void clsfolds (struct st_fold *, int);
55 static void remove_files (int, char **);
56 static int m_file (char *, struct st_fold *, int, int, int);
60 main (int argc, char **argv)
62 int linkf = 0, preserve = 0, filep = 0;
63 int foldp = 0, unlink_msgs = 0;
65 char *cp, *folder = NULL, buf[BUFSIZ];
66 char **argp, **arguments;
67 char *filevec[NFOLDERS + 2];
68 char **files = &filevec[1]; /* leave room for remove_files:vec[0] */
69 struct st_fold folders[NFOLDERS + 1];
70 struct msgs_array msgs = { 0, 0, NULL };
74 setlocale(LC_ALL, "");
76 invo_name = r1bindex (argv[0], '/');
78 /* read user profile/context */
81 arguments = getarguments (invo_name, argc, argv, 1);
87 while ((cp = *argp++)) {
89 switch (smatch (++cp, switches)) {
91 ambigsw (cp, switches);
94 adios (NULL, "-%s unknown\n", cp);
97 snprintf (buf, sizeof(buf), "%s [msgs] [switches] +folder ...", invo_name);
98 print_help (buf, switches, 1);
101 print_version(invo_name);
127 adios (NULL, "only one source folder at a time!");
128 if (!(cp = *argp++) || *cp == '-')
129 adios (NULL, "missing argument to %s", argp[-2]);
130 folder = path (*cp == '+' || *cp == '@' ?
136 if (filep > NFOLDERS)
137 adios (NULL, "only %d files allowed!",
139 if (!(cp = *argp++) || *cp == '-')
140 adios (NULL, "missing argument to %s",
142 files[filep++] = path (cp, TFILE);
146 if (!(rmmproc = *argp++) || *rmmproc == '-')
147 adios (NULL, "missing argument to %s",
155 if (*cp == '+' || *cp == '@') {
156 if (foldp > NFOLDERS)
157 adios (NULL, "only %d folders allowed!",
159 folders[foldp++].f_name =
162 app_msgarg(&msgs, cp);
165 if (!context_find ("path"))
166 free (path ("./", TFOLDER));
168 adios (NULL, "no folder specified");
171 if (!msgs.size && !foldp && !filep && (cp = getenv ("mhdraft")) && *cp)
176 ** We are refiling a file to the folders
179 if (folder || msgs.size)
180 adios (NULL, "use -file or some messages, not both");
181 opnfolds (folders, foldp);
182 for (i = 0; i < filep; i++)
183 if (m_file (files[i], folders, foldp, preserve, 0))
185 /* If -nolink, then "remove" files */
187 remove_files (filep, filevec);
192 app_msgarg(&msgs, "cur");
194 folder = getfolder (1);
195 strncpy (maildir, m_maildir (folder), sizeof(maildir));
197 if (chdir (maildir) == NOTOK)
198 adios (maildir, "unable to change directory to");
200 /* read source folder and create message structure */
201 if (!(mp = folder_read (folder)))
202 adios (NULL, "unable to read folder %s", folder);
204 /* check for empty folder */
206 adios (NULL, "no messages in %s", folder);
208 /* parse the message range/sequence/name and set SELECTED */
209 for (msgnum = 0; msgnum < msgs.size; msgnum++)
210 if (!m_convert (mp, msgs.msgs[msgnum]))
212 seq_setprev (mp); /* set the previous-sequence */
214 /* create folder structures for each destination folder */
215 opnfolds (folders, foldp);
217 /* Link all the selected messages into destination folders.
219 ** This causes the add hook to be run for messages that are
220 ** linked into another folder. The refile hook is run for
221 ** messages that are moved to another folder.
223 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
224 if (is_selected (mp, msgnum)) {
225 cp = getcpy (m_name (msgnum));
226 if (m_file (cp, folders, foldp, preserve, !linkf))
233 ** This is a hack. If we are using an external rmmproc,
234 ** then save the current folder to the context file,
235 ** so the external rmmproc will remove files from the correct
236 ** directory. This should be moved to folder_delmsgs().
239 context_replace (pfolder, folder);
245 ** If -nolink, then "remove" messages from source folder.
247 ** Note that folder_delmsgs does not call the delete hook
248 ** because the message has already been handled above.
251 folder_delmsgs (mp, unlink_msgs, 1);
254 clsfolds (folders, foldp);
256 if (mp->hghsel != mp->curmsg
257 && (mp->numsel != mp->nummsg || linkf))
258 seq_setcur (mp, mp->hghsel);
259 seq_save (mp); /* synchronize message sequences */
261 context_replace (pfolder, folder); /* update current folder */
262 context_save (); /* save the context file */
263 folder_free (mp); /* free folder structure */
270 ** Read all the destination folders and
271 ** create folder structures for all of them.
275 opnfolds (struct st_fold *folders, int nfolders)
277 char nmaildir[BUFSIZ];
278 register struct st_fold *fp, *ep;
279 register struct msgs *mp;
281 for (fp = folders, ep = folders + nfolders; fp < ep; fp++) {
282 chdir (m_maildir (""));
283 strncpy (nmaildir, m_maildir (fp->f_name), sizeof(nmaildir));
285 create_folder (nmaildir, 0, done);
287 if (chdir (nmaildir) == NOTOK)
288 adios (nmaildir, "unable to change directory to");
289 if (!(mp = folder_read (fp->f_name)))
290 adios (NULL, "unable to read folder %s", fp->f_name);
301 ** Set the Previous-Sequence and then sychronize the
302 ** sequence file, for each destination folder.
306 clsfolds (struct st_fold *folders, int nfolders)
308 register struct st_fold *fp, *ep;
309 register struct msgs *mp;
311 for (fp = folders, ep = folders + nfolders; fp < ep; fp++) {
320 ** If you have a "rmmproc" defined, we called that
321 ** to remove all the specified files. If "rmmproc"
322 ** is not defined, then just unlink the files.
326 remove_files (int filep, char **files)
331 /* If rmmproc is defined, we use that */
333 vec = files++; /* vec[0] = filevec[0] */
334 files[filep] = NULL; /* NULL terminate list */
337 vec[0] = r1bindex (rmmproc, '/');
338 execvp (rmmproc, vec);
339 adios (rmmproc, "unable to exec");
342 /* Else just unlink the files */
343 files++; /* advance past filevec[0] */
344 for (i = 0; i < filep; i++) {
345 if (unlink (files[i]) == NOTOK)
346 admonish (files[i], "unable to unlink");
352 ** Link (or copy) the message into each of
353 ** the destination folders.
357 m_file (char *msgfile, struct st_fold *folders, int nfolders, int preserve,
361 struct st_fold *fp, *ep;
363 for (fp = folders, ep = folders + nfolders; fp < ep; fp++) {
364 if ((msgnum = folder_addmsg (&fp->f_mp, msgfile, 1, 0,
365 preserve, nfolders == 1 && refile, maildir))