1 /* movemail foo bar -- move file foo to file bar,
3 Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
5 Copyright (C) 2005 Johann "Myrkraverk" Oskarsson <johann@myrkraverk.com>
7 This file is part of SXEmacs.
9 SXEmacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 SXEmacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 Please mail bugs and suggestions to the SXEmacs maintainer.
27 * You *must* coordinate the locking method used by movemail with that
28 * used by your mail delivery agent, as well as that of the other mail
29 * user agents on your system. movemail allows you to do this at run
30 * time via the -m flag. Moreover, it uses a default determined by
31 * the MAIL_LOCK_DOT, MAIL_LOCK_LOCKF, MAIL_LOCK_FLOCK,
32 * MAIL_LOCK_LOCKING, and MAIL_LOCK_MMDF preprocessor settings.
36 * Mike Sperber <sperber@informatik.uni-tuebingen.de> reorganized
37 * everything that has to with locking in December 1999.
41 * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
43 * Added POP (Post Office Protocol) service. When compiled
44 * -DMAIL_USE_POP movemail will accept input filename arguments of the
45 * form "po:username". This will cause movemail to open a connection
46 * to a pop server running on $MAILHOST (environment variable).
47 * Movemail must be setuid to root in order to work with POP.
49 * New module: popmail.c
51 * main - added code within #ifdef MAIL_USE_POP; added setuid
52 * (getuid ()) after POP code.
53 * New routines in movemail.c:
54 * get_errmsg - return pointer to system error message
56 * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies)
58 * Move all of the POP code into a separate file, "pop.c".
59 * Use strerror instead of get_errmsg.
63 #define NO_SHORTNAMES /* Tell config not to load remap.h */
64 #define DONT_ENCAPSULATE
66 #include <sys/types.h>
70 #include "../src/sysfile.h"
71 #include "../src/syswait.h"
72 #include "../src/systime.h"
80 #include "../src/regex.h"
86 extern int optind, opterr;
89 char *strerror(int errnum);
90 #endif /* HAVE_STRERROR */
93 #define DIRECTORY_SEP '/'
95 #ifndef IS_DIRECTORY_SEP
96 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
99 #if defined (HAVE_UNISTD_H)
101 #endif /* unistd.h */
109 #if defined (HAVE_FCNTL_H)
114 #include <sys/locking.h>
118 extern int lk_open(), lk_close();
121 /* Cancel substitutions made by config.h for Emacs. */
127 static void fatal(char *, char *);
128 static void error(const char *, const char *, const char *);
129 static void usage(int);
130 static void pfatal_with_name(char *);
131 static void pfatal_and_delete(char *);
132 static char *concat(char *, char *, char *);
133 static long *xmalloc(unsigned int);
135 static int popmail(char *, char *, char *);
136 static int pop_retr(popserver server, int msgno,
137 int (*action) (char *, FILE *), FILE * arg);
138 static int mbx_write(char *, FILE *);
139 static int mbx_delimit_begin(FILE *);
140 static int mbx_delimit_end(FILE *);
141 static struct re_pattern_buffer *compile_regex(char *regexp_pattern);
142 static int pop_search_top(popserver server, int msgno, int lines,
143 struct re_pattern_buffer *regexp);
147 #define xstrncpy(d_,s_,l_) \
151 strncat((dst_),(s_),(l_)-1); \
157 int keep_messages = 0;
158 struct re_pattern_buffer *regexp_pattern = 0;
159 int match_lines = 10;
162 #define VERBOSE(x) if (verbose) { printf x; fflush(stdout); }
164 #ifdef HAVE_GETOPT_LONG
165 struct option longopts[] = {
166 {"inbox", required_argument, NULL, 'i'},
167 {"outfile", required_argument, NULL, 'o'},
169 {"password", required_argument, NULL, 'p'},
170 {"reverse-pop-order", no_argument, NULL, 'x'},
171 {"keep-messages", no_argument, NULL, 'k'},
172 {"regex", required_argument, NULL, 'r'},
173 {"match-lines", required_argument, NULL, 'l'},
175 {"lock-method", required_argument, NULL, 'm'},
176 {"help", no_argument, NULL, 'h'},
177 {"verbose", no_argument, NULL, 'v'},
188 #if defined(MAIL_LOCK_FLOCK) && defined(HAVE_FLOCK)
189 #define DEFAULT_LOCKING FLOCKING
190 #elif defined(MAIL_LOCK_LOCKF) && defined(HAVE_LOCKF)
191 #define DEFAULT_LOCKING LOCKFING
192 #elif defined(MAIL_LOCK_MMDF) && defined(HAVE_MMDF)
193 #define DEFAULT_LOCKING MMDF
194 #elif defined(MAIL_LOCK_LOCKING) && defined(HAVE_LOCKING)
195 #define DEFAULT_LOCKING LOCKING
197 #define DEFAULT_LOCKING DOTLOCKING
200 #ifndef DISABLE_DIRECT_ACCESS
201 static void lock_dot(char *);
203 static void unlock_dot(char *);
204 static int parse_lock_method(char *);
205 static char *unparse_lock_method(int);
207 int main(int argc, char *argv[])
209 char *inname = 0, *outname = 0;
210 #if defined MAIL_USE_POP
212 #endif /* MAIL_USE_POP */
213 #ifndef DISABLE_DIRECT_ACCESS
219 int lock_method = DEFAULT_LOCKING;
221 char *maybe_lock_env;
223 maybe_lock_env = getenv("EMACSLOCKMETHOD");
224 if (maybe_lock_env) {
225 printf("maybe-lock_env: %s\n", maybe_lock_env);
226 lock_method = parse_lock_method(maybe_lock_env);
231 char *optstring = "i:o:m:p:l:r:xvhk";
233 char *optstring = "i:o:m:vh";
237 int opt = getopt_long(argc, argv, optstring, longopts, 0);
239 int opt = getopt(argc, argv, optstring);
241 # error "movemail cannot be built without getopt, preferably getopt_long"
249 case 1: /* one of the standard arguments seen */
252 } else if (!outname) {
254 #if defined MAIL_USE_POP
257 #endif /* MAIL_USE_POP */
261 case 'i': /* infile */
265 case 'o': /* outfile */
269 case 'p': /* pop password */
278 case 'l': /* lines to match */
279 match_lines = atoi(optarg);
282 case 'r': /* regular expression */
283 regexp_pattern = compile_regex(optarg);
288 lock_method = parse_lock_method(optarg);
301 while (optind < argc) {
302 assert(argv[optind] != NULL);
304 inname = argv[optind];
305 } else if (!outname) {
306 outname = argv[optind];
307 #if defined MAIL_USE_POP
309 poppass = argv[optind];
310 #endif /* MAIL_USE_POP */
315 if (!inname || !outname) {
320 if (lock_method == MMDF)
325 fatal("Destination file name is empty", 0);
327 /* Also check that outname's directory is writable to the real uid. */
329 char *buf = (char *)xmalloc(strlen(outname) + 1);
331 strcpy(buf, outname);
332 cp = buf + strlen(buf);
333 while (cp > buf && !IS_DIRECTORY_SEP(cp[-1]))
337 if (access(buf, W_OK) != 0)
338 pfatal_with_name(buf);
343 if (!strncmp(inname, "po:", 3)) {
344 int retcode = popmail(inname + 3, outname, poppass);
348 #endif /* MAIL_USE_POP */
350 #ifndef DISABLE_DIRECT_ACCESS
356 VERBOSE(("opening input file\n"));
358 switch (lock_method) {
360 indesc = open(inname, O_RDONLY);
364 indesc = open(inname, O_RDWR);
369 indesc = open(inname, O_RDWR);
374 indesc = open(inname, O_RDWR);
379 indesc = lk_open(inname, O_RDONLY, 0, 0, 10);
387 pfatal_with_name(inname);
390 /* In case movemail is setuid to root, make sure the user can
391 read the output file. */
392 umask(umask(0) & 0333);
395 outdesc = open(outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
397 pfatal_with_name(outname);
399 VERBOSE(("locking input file\n"));
401 switch (lock_method) {
404 if (lockf(indesc, F_LOCK, 0) < 0)
405 pfatal_with_name(inname);