Mercurial > hg > xemacs-beta
comparison lib-src/movemail.c @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | de805c49cfc1 |
children | 11054d720c21 |
comparison
equal
deleted
inserted
replaced
411:12e008d41344 | 412:697ef44129c6 |
---|---|
1 /* movemail foo bar -- move file foo to file bar, | 1 /* movemail foo bar -- move file foo to file bar, |
2 locking file foo. | 2 locking file foo the way /bin/mail respects. |
3 Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. | 3 Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. |
4 | 4 |
5 This file is part of XEmacs. | 5 This file is part of GNU Emacs. |
6 | 6 |
7 XEmacs is free software; you can redistribute it and/or modify it | 7 GNU Emacs is free software; you can redistribute it and/or modify |
8 under the terms of the GNU General Public License as published by the | 8 it under the terms of the GNU General Public License as published by |
9 Free Software Foundation; either version 2, or (at your option) any | 9 the Free Software Foundation; either version 2, or (at your option) |
10 later version. | 10 any later version. |
11 | 11 |
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | 12 GNU Emacs is distributed in the hope that it will be useful, |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 13 but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 for more details. | 15 GNU General Public License for more details. |
16 | 16 |
17 You should have received a copy of the GNU General Public License | 17 You should have received a copy of the GNU General Public License |
18 along with XEmacs; see the file COPYING. If not, write to | 18 along with GNU Emacs; see the file COPYING. If not, write to |
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
20 Boston, MA 02111-1307, USA. | 20 Boston, MA 02111-1307, USA. */ |
21 | 21 |
22 Please mail bugs and suggestions to the XEmacs maintainer. | 22 /* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will |
23 */ | 23 cause loss of mail* if you do it on a system that does not normally |
24 | 24 use flock as its way of interlocking access to inbox files. The |
25 /* Important notice: | 25 setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the |
26 * | 26 system's own conventions. It is not a choice that is up to you. |
27 * You *must* coordinate the locking method used by movemail with that | 27 |
28 * used by your mail delivery agent, as well as that of the other mail | 28 So, if your system uses lock files rather than flock, then the only way |
29 * user agents on your system. movemail allows you to do this at run | 29 you can get proper operation is to enable movemail to write lockfiles there. |
30 * time via the -m flag. Moreover, it uses a default determined by | 30 This means you must either give that directory access modes |
31 * the MAIL_LOCK_DOT, MAIL_LOCK_LOCKF, MAIL_LOCK_FLOCK, | 31 that permit everyone to write lockfiles in it, or you must make movemail |
32 * MAIL_LOCK_LOCKING, and MAIL_LOCK_MMDF preprocessor settings. | 32 a setuid or setgid program. */ |
33 */ | |
34 | |
35 /* | |
36 * Mike Sperber <sperber@informatik.uni-tuebingen.de> reorganized | |
37 * everything that has to with locking in December 1999. | |
38 */ | |
39 | 33 |
40 /* | 34 /* |
41 * Modified January, 1986 by Michael R. Gretzinger (Project Athena) | 35 * Modified January, 1986 by Michael R. Gretzinger (Project Athena) |
42 * | 36 * |
43 * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP | 37 * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP |
60 * | 54 * |
61 */ | 55 */ |
62 | 56 |
63 #define NO_SHORTNAMES /* Tell config not to load remap.h */ | 57 #define NO_SHORTNAMES /* Tell config not to load remap.h */ |
64 #define DONT_ENCAPSULATE | 58 #define DONT_ENCAPSULATE |
65 #include <config.h> | 59 #include <../src/config.h> |
66 #include <sys/types.h> | 60 #include <sys/types.h> |
67 #include <sys/stat.h> | 61 #include <sys/stat.h> |
68 #include <stdio.h> | 62 #include <stdio.h> |
69 #include <errno.h> | 63 #include <errno.h> |
70 #include "../src/sysfile.h" | 64 #include "../src/sysfile.h" |
71 #include "../src/syswait.h" | 65 #include "../src/syswait.h" |
72 #ifndef WIN32_NATIVE | 66 #ifndef WINDOWSNT |
73 #include "../src/systime.h" | 67 #include "../src/systime.h" |
74 #endif | 68 #endif |
75 #include <stdlib.h> | 69 #include <stdlib.h> |
76 #include <string.h> | 70 #include <string.h> |
77 #include "getopt.h" | 71 #include "getopt.h" |
85 | 79 |
86 #ifndef HAVE_STRERROR | 80 #ifndef HAVE_STRERROR |
87 char * strerror (int errnum); | 81 char * strerror (int errnum); |
88 #endif /* HAVE_STRERROR */ | 82 #endif /* HAVE_STRERROR */ |
89 | 83 |
84 #ifdef MSDOS | |
85 #undef access | |
86 #endif /* MSDOS */ | |
87 | |
90 #ifndef DIRECTORY_SEP | 88 #ifndef DIRECTORY_SEP |
91 #define DIRECTORY_SEP '/' | 89 #define DIRECTORY_SEP '/' |
92 #endif | 90 #endif |
93 #ifndef IS_DIRECTORY_SEP | 91 #ifndef IS_DIRECTORY_SEP |
94 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) | 92 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) |
95 #endif | 93 #endif |
96 | 94 |
97 #ifdef WIN32_NATIVE | 95 #ifdef WINDOWSNT |
98 #undef access | 96 #undef access |
99 #undef unlink | 97 #undef unlink |
100 #define fork() 0 | 98 #define fork() 0 |
101 #define sys_wait(var) (*(var) = 0) | 99 #define sys_wait(var) (*(var) = 0) |
102 /* Unfortunately, Samba doesn't seem to properly lock Unix files even | 100 /* Unfortunately, Samba doesn't seem to properly lock Unix files even |
104 other NT programs). If you have direct file access using an NFS | 102 other NT programs). If you have direct file access using an NFS |
105 client or something other than Samba, the locking call might work | 103 client or something other than Samba, the locking call might work |
106 properly - make sure it does before you enable this! */ | 104 properly - make sure it does before you enable this! */ |
107 #define DISABLE_DIRECT_ACCESS | 105 #define DISABLE_DIRECT_ACCESS |
108 #include <io.h> | 106 #include <io.h> |
109 #endif /* WIN32_NATIVE */ | 107 #endif /* WINDOWSNT */ |
110 | 108 |
111 #if defined (HAVE_UNISTD_H) | 109 #if defined (HAVE_UNISTD_H) || defined (USG) |
112 #include <unistd.h> | 110 #include <unistd.h> |
113 #endif /* unistd.h */ | 111 #endif /* unistd.h */ |
114 #ifndef F_OK | 112 #ifndef F_OK |
115 #define F_OK 0 | 113 #define F_OK 0 |
116 #define X_OK 1 | 114 #define X_OK 1 |
117 #define W_OK 2 | 115 #define W_OK 2 |
118 #define R_OK 4 | 116 #define R_OK 4 |
119 #endif /* No F_OK */ | 117 #endif /* No F_OK */ |
120 | 118 |
121 #if defined (HAVE_FCNTL_H) | 119 #if defined (HAVE_FCNTL_H) || defined (USG) |
122 #include <fcntl.h> | 120 #include <fcntl.h> |
123 #endif /* fcntl.h */ | 121 #endif /* fcntl.h */ |
124 | 122 |
125 #ifdef HAVE_LOCKING | 123 #if defined (XENIX) || defined (WINDOWSNT) |
126 #include <sys/locking.h> | 124 #include <sys/locking.h> |
127 #endif | 125 #endif |
128 | 126 |
129 #ifdef HAVE_MMDF | 127 #ifdef MAIL_USE_LOCKF |
128 #define MAIL_USE_SYSTEM_LOCK | |
129 #endif | |
130 | |
131 #ifdef MAIL_USE_FLOCK | |
132 #define MAIL_USE_SYSTEM_LOCK | |
133 #endif | |
134 | |
135 #ifdef MAIL_USE_MMDF | |
130 extern int lk_open (), lk_close (); | 136 extern int lk_open (), lk_close (); |
131 #endif | 137 #endif |
132 | 138 |
133 /* Cancel substitutions made by config.h for Emacs. */ | 139 /* Cancel substitutions made by config.h for Emacs. */ |
134 #undef open | 140 #undef open |
136 #undef write | 142 #undef write |
137 #undef close | 143 #undef close |
138 | 144 |
139 static void fatal (char *, char*); | 145 static void fatal (char *, char*); |
140 static void error (char *, char *, char *); | 146 static void error (char *, char *, char *); |
141 static void usage(int); | |
142 static void pfatal_with_name (char *); | 147 static void pfatal_with_name (char *); |
143 static void pfatal_and_delete (char *); | 148 static void pfatal_and_delete (char *); |
144 static char *concat (char *, char *, char *); | 149 static char *concat (char *, char *, char *); |
145 static long *xmalloc (unsigned int); | 150 static long *xmalloc (unsigned int); |
146 #ifdef MAIL_USE_POP | 151 #ifdef MAIL_USE_POP |
147 static int popmail (char *, char *, char *); | 152 static int popmail (char *, char *, char *); |
148 static int pop_retr (popserver server, int msgno, | 153 static int pop_retr (popserver server, int msgno, int (*action)(), void *arg); |
149 int (*action)(char *, FILE *), FILE *arg); | |
150 static int mbx_write (char *, FILE *); | 154 static int mbx_write (char *, FILE *); |
151 static int mbx_delimit_begin (FILE *); | 155 static int mbx_delimit_begin (FILE *); |
152 static int mbx_delimit_end (FILE *); | 156 static int mbx_delimit_end (FILE *); |
153 static struct re_pattern_buffer* compile_regex (char* regexp_pattern); | 157 static struct re_pattern_buffer* compile_regex (char* regexp_pattern); |
154 static int pop_search_top (popserver server, int msgno, int lines, | 158 static int pop_search_top (popserver server, int msgno, int lines, |
155 struct re_pattern_buffer* regexp); | 159 struct re_pattern_buffer* regexp); |
156 #endif | 160 #endif |
161 | |
162 /* Nonzero means this is name of a lock file to delete on fatal error. */ | |
163 char *delete_lockname; | |
157 | 164 |
158 int verbose=0; | 165 int verbose=0; |
159 #ifdef MAIL_USE_POP | 166 #ifdef MAIL_USE_POP |
160 int reverse=0; | 167 int reverse=0; |
161 int keep_messages=0; | 168 int keep_messages=0; |
174 { "reverse-pop-order", no_argument, NULL, 'x' }, | 181 { "reverse-pop-order", no_argument, NULL, 'x' }, |
175 { "keep-messages", no_argument, NULL, 'k' }, | 182 { "keep-messages", no_argument, NULL, 'k' }, |
176 { "regex", required_argument, NULL, 'r' }, | 183 { "regex", required_argument, NULL, 'r' }, |
177 { "match-lines", required_argument, NULL, 'l' }, | 184 { "match-lines", required_argument, NULL, 'l' }, |
178 #endif | 185 #endif |
179 { "lock-method", required_argument, NULL, 'm' }, | |
180 { "help", no_argument, NULL, 'h' }, | |
181 { "verbose", no_argument, NULL, 'v' }, | 186 { "verbose", no_argument, NULL, 'v' }, |
182 { 0 } | 187 { 0 } |
183 }; | 188 }; |
184 | |
185 #define DOTLOCKING 0 | |
186 #define FLOCKING 1 | |
187 #define LOCKFING 2 | |
188 #define MMDF 3 | |
189 #define LOCKING 4 | |
190 | |
191 #if defined(MAIL_LOCK_FLOCK) && defined(HAVE_FLOCK) | |
192 #define DEFAULT_LOCKING FLOCKING | |
193 #elif defined(MAIL_LOCK_LOCKF) && defined(HAVE_LOCKF) | |
194 #define DEFAULT_LOCKING LOCKFING | |
195 #elif defined(MAIL_LOCK_MMDF) && defined(HAVE_MMDF) | |
196 #define DEFAULT_LOCKING MMDF | |
197 #elif defined(MAIL_LOCK_LOCKING) && defined(HAVE_LOCKING) | |
198 #define DEFAULT_LOCKING LOCKING | |
199 #else | |
200 #define DEFAULT_LOCKING DOTLOCKING | |
201 #endif | |
202 | |
203 #ifndef DISABLE_DIRECT_ACCESS | |
204 static void lock_dot(char *); | |
205 #endif | |
206 static void unlock_dot(char *); | |
207 static int parse_lock_method(char *); | |
208 static char *unparse_lock_method(int); | |
209 | 189 |
210 int | 190 int |
211 main (int argc, char *argv[]) | 191 main (int argc, char *argv[]) |
212 { | 192 { |
213 char *inname=0, *outname=0, *poppass=0; | 193 char *inname=0, *outname=0, *poppass=0; |
215 int indesc, outdesc; | 195 int indesc, outdesc; |
216 int nread; | 196 int nread; |
217 int status; | 197 int status; |
218 #endif | 198 #endif |
219 | 199 |
220 int lock_method = DEFAULT_LOCKING; | 200 #ifndef MAIL_USE_SYSTEM_LOCK |
221 | 201 struct stat st; |
222 char *maybe_lock_env; | 202 long now; |
223 | 203 int tem; |
224 maybe_lock_env = getenv("EMACSLOCKMETHOD"); | 204 char *lockname, *p; |
225 if (maybe_lock_env) | 205 char *tempname; |
226 { | 206 int desc; |
227 printf("maybe-lock_env: %s\n", maybe_lock_env); | 207 #endif /* not MAIL_USE_SYSTEM_LOCK */ |
228 lock_method = parse_lock_method(maybe_lock_env); | 208 |
229 } | 209 delete_lockname = 0; |
230 | 210 |
231 for (;;) | 211 while (1) |
232 { | 212 { |
233 #ifdef MAIL_USE_POP | 213 #ifdef MAIL_USE_POP |
234 char* optstring = "i:o:m:p:l:r:xvhk"; | 214 char* optstring = "i:o:p:l:r:xvk"; |
235 #else | 215 #else |
236 char* optstring = "i:o:m:vh"; | 216 char* optstring = "i:o:v"; |
237 #endif | 217 #endif |
238 int opt = getopt_long (argc, argv, optstring, longopts, 0); | 218 int opt = getopt_long (argc, argv, optstring, longopts, 0); |
239 | 219 |
240 if (opt == EOF) | 220 if (opt == EOF) |
241 break; | 221 break; |
272 | 252 |
273 case 'r': /* regular expression */ | 253 case 'r': /* regular expression */ |
274 regexp_pattern = compile_regex (optarg); | 254 regexp_pattern = compile_regex (optarg); |
275 break; | 255 break; |
276 #endif | 256 #endif |
277 | 257 case 'v': verbose = 1; break; |
278 case 'm': | |
279 lock_method = parse_lock_method(optarg); | |
280 break; | |
281 case 'h': | |
282 usage(lock_method); | |
283 exit(0); | |
284 case 'v': | |
285 verbose = 1; | |
286 break; | |
287 } | 258 } |
288 } | 259 } |
289 | 260 |
290 while (optind < argc) | 261 while (optind < argc) |
291 { | 262 { |
298 optind++; | 269 optind++; |
299 } | 270 } |
300 | 271 |
301 if (!inname || !outname) | 272 if (!inname || !outname) |
302 { | 273 { |
303 usage(lock_method); | 274 fprintf (stderr, "Usage: movemail [-rvxk] [-l lines ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); |
304 exit(1); | 275 exit(1); |
305 } | 276 } |
306 | 277 |
307 #ifdef HAVE_MMDF | 278 #ifdef MAIL_USE_MMDF |
308 if (lock_method == MMDF) | 279 mmdf_init (argv[0]); |
309 mmdf_init (argv[0]); | |
310 #endif | 280 #endif |
311 | 281 |
312 if (*outname == 0) | 282 if (*outname == 0) |
313 fatal ("Destination file name is empty", 0); | 283 fatal ("Destination file name is empty", 0); |
314 | 284 |
315 VERBOSE(("checking access to output file\n")); | |
316 /* Check access to output file. */ | 285 /* Check access to output file. */ |
317 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) | 286 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) |
318 pfatal_with_name (outname); | 287 pfatal_with_name (outname); |
319 | 288 |
320 /* Also check that outname's directory is writable to the real uid. */ | 289 /* Also check that outname's directory is writable to the real uid. */ |
337 { | 306 { |
338 int retcode = popmail (inname + 3, outname, poppass); | 307 int retcode = popmail (inname + 3, outname, poppass); |
339 exit (retcode); | 308 exit (retcode); |
340 } | 309 } |
341 | 310 |
342 #ifndef WIN32_NATIVE | 311 #ifndef WINDOWSNT |
343 setuid (getuid ()); | 312 setuid (getuid ()); |
344 #endif | 313 #endif |
345 #endif /* MAIL_USE_POP */ | 314 #endif /* MAIL_USE_POP */ |
346 | 315 |
347 #ifndef DISABLE_DIRECT_ACCESS | 316 #ifndef DISABLE_DIRECT_ACCESS |
348 | 317 |
349 /* Check access to input file. */ | 318 /* Check access to input file. */ |
350 if (access (inname, R_OK | W_OK) != 0) | 319 if (access (inname, R_OK | W_OK) != 0) |
351 pfatal_with_name (inname); | 320 pfatal_with_name (inname); |
352 | 321 |
322 #ifndef MAIL_USE_MMDF | |
323 #ifndef MAIL_USE_SYSTEM_LOCK | |
324 /* Use a lock file named after our first argument with .lock appended: | |
325 If it exists, the mail file is locked. */ | |
326 /* Note: this locking mechanism is *required* by the mailer | |
327 (on systems which use it) to prevent loss of mail. | |
328 | |
329 On systems that use a lock file, extracting the mail without locking | |
330 WILL occasionally cause loss of mail due to timing errors! | |
331 | |
332 So, if creation of the lock file fails | |
333 due to access permission on the mail spool directory, | |
334 you simply MUST change the permission | |
335 and/or make movemail a setgid program | |
336 so it can create lock files properly. | |
337 | |
338 You might also wish to verify that your system is one | |
339 which uses lock files for this purpose. Some systems use other methods. | |
340 | |
341 If your system uses the `flock' system call for mail locking, | |
342 define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file | |
343 and recompile movemail. If the s- file for your system | |
344 should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report | |
345 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */ | |
346 | |
347 lockname = concat (inname, ".lock", ""); | |
348 tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); | |
349 strcpy (tempname, inname); | |
350 p = tempname + strlen (tempname); | |
351 while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) | |
352 p--; | |
353 *p = 0; | |
354 strcpy (p, "EXXXXXX"); | |
355 mktemp (tempname); | |
356 unlink (tempname); | |
357 | |
358 while (1) | |
359 { | |
360 /* Create the lock file, but not under the lock file name. */ | |
361 /* Give up if cannot do that. */ | |
362 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
363 if (desc < 0) | |
364 { | |
365 char *message = (char *) xmalloc (strlen (tempname) + 50); | |
366 sprintf (message, "%s--see source file lib-src/movemail.c", | |
367 tempname); | |
368 pfatal_with_name (message); | |
369 } | |
370 close (desc); | |
371 | |
372 tem = link (tempname, lockname); | |
373 unlink (tempname); | |
374 if (tem >= 0) | |
375 break; | |
376 sleep (1); | |
377 | |
378 /* If lock file is five minutes old, unlock it. | |
379 Five minutes should be good enough to cope with crashes | |
380 and wedgitude, and long enough to avoid being fooled | |
381 by time differences between machines. */ | |
382 if (stat (lockname, &st) >= 0) | |
383 { | |
384 now = time (0); | |
385 if (st.st_ctime < now - 300) | |
386 unlink (lockname); | |
387 } | |
388 } | |
389 | |
390 delete_lockname = lockname; | |
391 #endif /* not MAIL_USE_SYSTEM_LOCK */ | |
392 #endif /* not MAIL_USE_MMDF */ | |
353 | 393 |
354 if (fork () == 0) | 394 if (fork () == 0) |
355 { | 395 { |
356 setuid (getuid ()); | 396 setuid (getuid ()); |
357 | 397 |
358 VERBOSE(("opening input file\n")); | 398 #ifndef MAIL_USE_MMDF |
359 | 399 #ifdef MAIL_USE_SYSTEM_LOCK |
360 switch (lock_method) | 400 indesc = open (inname, O_RDWR); |
361 { | 401 #else /* if not MAIL_USE_SYSTEM_LOCK */ |
362 case DOTLOCKING: | 402 indesc = open (inname, O_RDONLY); |
363 indesc = open (inname, O_RDONLY); | 403 #endif /* not MAIL_USE_SYSTEM_LOCK */ |
364 break; | 404 #else /* MAIL_USE_MMDF */ |
365 #ifdef HAVE_LOCKF | 405 indesc = lk_open (inname, O_RDONLY, 0, 0, 10); |
366 case LOCKFING: | 406 #endif /* MAIL_USE_MMDF */ |
367 indesc = open (inname, O_RDWR); | |
368 break; | |
369 #endif | |
370 #ifdef HAVE_FLOCK | |
371 case FLOCKING: | |
372 indesc = open (inname, O_RDWR); | |
373 break; | |
374 #endif | |
375 #ifdef HAVE_LOCKING | |
376 case LOCKING: | |
377 indesc = open (inname, O_RDWR); | |
378 break; | |
379 #endif | |
380 #ifdef HAVE_MMDF | |
381 case MMDF: | |
382 indesc = lk_open (inname, O_RDONLY, 0, 0, 10); | |
383 break; | |
384 #endif | |
385 default: abort(); | |
386 } | |
387 | 407 |
388 if (indesc < 0) | 408 if (indesc < 0) |
389 pfatal_with_name (inname); | 409 pfatal_with_name (inname); |
390 | 410 |
391 #ifdef HAVE_UMASK | 411 #if defined (BSD) || defined (XENIX) |
392 /* In case movemail is setuid to root, make sure the user can | 412 /* In case movemail is setuid to root, make sure the user can |
393 read the output file. */ | 413 read the output file. */ |
414 /* This is desirable for all systems | |
415 but I don't want to assume all have the umask system call */ | |
394 umask (umask (0) & 0333); | 416 umask (umask (0) & 0333); |
395 #endif | 417 #endif /* BSD or Xenix */ |
396 | |
397 outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); | 418 outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); |
398 if (outdesc < 0) | 419 if (outdesc < 0) |
399 pfatal_with_name (outname); | 420 pfatal_with_name (outname); |
400 | 421 #ifdef MAIL_USE_SYSTEM_LOCK |
401 VERBOSE(("locking input file\n")); | 422 #ifdef MAIL_USE_LOCKF |
402 | 423 if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname); |
403 switch (lock_method) | 424 #else /* not MAIL_USE_LOCKF */ |
404 { | 425 #ifdef XENIX |
405 #ifdef HAVE_LOCKF | 426 if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); |
406 case LOCKFING: | 427 #else |
407 if (lockf (indesc, F_LOCK, 0) < 0) | 428 #ifdef WINDOWSNT |
408 pfatal_with_name (inname); | 429 if (locking (indesc, LK_RLCK, -1L) < 0) pfatal_with_name (inname); |
409 break; | 430 #else |
410 #endif | 431 if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); |
411 #ifdef HAVE_FLOCK | 432 #endif |
412 case FLOCKING: | 433 #endif |
413 if (flock (indesc, LOCK_EX) < 0) | 434 #endif /* not MAIL_USE_LOCKF */ |
414 pfatal_with_name (inname); | 435 #endif /* MAIL_USE_SYSTEM_LOCK */ |
415 break; | 436 |
416 #endif | |
417 #ifdef HAVE_LOCKING | |
418 case LOCKING: | |
419 if (locking (indesc, LK_RLCK, -1L) < 0) | |
420 pfatal_with_name (inname); | |
421 break; | |
422 #endif | |
423 case DOTLOCKING: | |
424 lock_dot(inname); | |
425 break; | |
426 } | |
427 | |
428 VERBOSE(("copying input file to output file\n")); | |
429 | |
430 { | 437 { |
431 char buf[1024]; | 438 char buf[1024]; |
432 | 439 |
433 while (1) | 440 while (1) |
434 { | 441 { |
443 if (nread < sizeof buf) | 450 if (nread < sizeof buf) |
444 break; | 451 break; |
445 } | 452 } |
446 } | 453 } |
447 | 454 |
448 #ifdef HAVE_FSYNC | 455 #ifdef BSD |
449 if (fsync (outdesc) < 0) | 456 if (fsync (outdesc) < 0) |
450 pfatal_and_delete (outname); | 457 pfatal_and_delete (outname); |
451 #endif | 458 #endif |
452 | 459 |
453 /* Check to make sure no errors before we zap the inbox. */ | 460 /* Check to make sure no errors before we zap the inbox. */ |
454 if (close (outdesc) != 0) | 461 if (close (outdesc) != 0) |
455 pfatal_and_delete (outname); | 462 pfatal_and_delete (outname); |
456 | 463 |
457 VERBOSE(("deleting or truncating input file\n")); | 464 #ifdef MAIL_USE_SYSTEM_LOCK |
458 | 465 #if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT) |
459 switch (lock_method) | 466 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ |
460 { | 467 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); |
461 case LOCKFING: | |
462 case FLOCKING: | |
463 case LOCKING: | |
464 #ifdef HAVE_FTRUNCATE | |
465 ftruncate (indesc, 0L); | |
466 #else | 468 #else |
467 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); | 469 ftruncate (indesc, 0L); |
468 #endif | 470 #endif /* STRIDE or XENIX */ |
469 close (indesc); | 471 #endif /* MAIL_USE_SYSTEM_LOCK */ |
470 break; | 472 |
471 #ifdef HAVE_MMDF | 473 #ifdef MAIL_USE_MMDF |
472 case MMDF: | 474 lk_close (indesc, 0, 0, 0); |
473 lk_close (indesc, 0, 0, 0); | 475 #else |
474 break; | 476 close (indesc); |
475 #endif | 477 #endif |
476 case DOTLOCKING: | 478 |
477 creat (inname, 0600); | 479 #ifndef MAIL_USE_SYSTEM_LOCK |
478 break; | 480 /* Delete the input file; if we can't, at least get rid of its |
479 } | 481 contents. */ |
482 #ifdef MAIL_UNLINK_SPOOL | |
483 /* This is generally bad to do, because it destroys the permissions | |
484 that were set on the file. Better to just empty the file. */ | |
485 if (unlink (inname) < 0 && errno != ENOENT) | |
486 #endif /* MAIL_UNLINK_SPOOL */ | |
487 creat (inname, 0600); | |
488 #endif /* not MAIL_USE_SYSTEM_LOCK */ | |
480 | 489 |
481 exit (0); | 490 exit (0); |
482 } | 491 } |
483 | 492 |
484 wait (&status); | 493 wait (&status); |
485 if (!WIFEXITED (status)) | 494 if (!WIFEXITED (status)) |
486 exit (1); | 495 exit (1); |
487 else if (WEXITSTATUS (status) != 0) | 496 else if (WEXITSTATUS (status) != 0) |
488 exit (WEXITSTATUS (status)); | 497 exit (WEXITSTATUS (status)); |
489 | 498 |
490 if (lock_method == DOTLOCKING) | 499 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK) |
491 unlock_dot(inname); | 500 unlink (lockname); |
492 | 501 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */ |
493 #endif /* not DISABLE_DIRECT_ACCESS */ | 502 |
503 #endif /* ! DISABLE_DIRECT_ACCESS */ | |
494 | 504 |
495 return 0; | 505 return 0; |
496 } | 506 } |
497 | 507 |
498 static void | |
499 usage(int lock_method) | |
500 { | |
501 printf ("Usage: movemail [-rvxkh] [-l lines ] [-m method ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); | |
502 printf("where method is one of: dot"); | |
503 #ifdef HAVE_LOCKF | |
504 printf(", lockf"); | |
505 #endif | |
506 #ifdef HAVE_FLOCK | |
507 printf(", flock"); | |
508 #endif | |
509 #ifdef HAVE_MMDF | |
510 printf(", mmdf"); | |
511 #endif | |
512 #ifdef HAVE_LOCKING | |
513 printf(", locking"); | |
514 #endif | |
515 printf("\nDefault is: %s\n", unparse_lock_method(lock_method)); | |
516 | |
517 } | |
518 | |
519 static char * | |
520 unparse_lock_method(int lock_method) | |
521 { | |
522 switch (lock_method) | |
523 { | |
524 case DOTLOCKING: return "dot"; | |
525 case FLOCKING: return "flock"; | |
526 case LOCKFING: return "lockf"; | |
527 case LOCKING: return "locking"; | |
528 case MMDF: return "mmdf"; | |
529 default: abort();return 0; | |
530 } | |
531 } | |
532 | |
533 static int | |
534 parse_lock_method(char *method_name) | |
535 { | |
536 if (!strcmp("dot", method_name) || !strcmp("file", method_name)) | |
537 return DOTLOCKING; | |
538 #ifdef HAVE_LOCKF | |
539 else if (!strcmp("lockf", method_name)) | |
540 return LOCKFING; | |
541 #endif | |
542 #ifdef HAVE_FLOCK | |
543 else if (!strcmp("flock", method_name)) | |
544 return FLOCKING; | |
545 #endif | |
546 #ifdef HAVE_MMDF | |
547 else if (!strcmp("mmdf", method_name)) | |
548 return MMDF; | |
549 #endif | |
550 #ifdef HAVE_LOCKING | |
551 else if (!strcmp("locking", method_name)) | |
552 return LOCKING; | |
553 #endif | |
554 else | |
555 fatal("invalid lock method: %s", method_name); | |
556 return 0; /* unreached */ | |
557 } | |
558 | |
559 static char * | |
560 dot_filename(char *filename) | |
561 { | |
562 return concat (filename, ".lock", ""); | |
563 } | |
564 | |
565 static char *dotlock_filename = NULL; | |
566 | |
567 #ifndef DISABLE_DIRECT_ACCESS | |
568 static void | |
569 lock_dot(char *filename) | |
570 { | |
571 struct stat st; | |
572 long now; | |
573 int tem; | |
574 char *lockname, *p; | |
575 char *tempname; | |
576 int desc; | |
577 | |
578 dotlock_filename = (char *) xmalloc(strlen(filename) + 1); | |
579 | |
580 /* Use a lock file named after our first argument with .lock appended: | |
581 If it exists, the mail file is locked. */ | |
582 | |
583 lockname = dot_filename(filename); | |
584 tempname = (char *) xmalloc (strlen (filename) + strlen ("EXXXXXX") + 1); | |
585 strcpy (tempname, filename); | |
586 p = tempname + strlen (tempname); | |
587 while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) | |
588 p--; | |
589 *p = 0; | |
590 strcpy (p, "EXXXXXX"); | |
591 mktemp (tempname); | |
592 unlink (tempname); | |
593 | |
594 for (;;) | |
595 { | |
596 /* Create the lock file, but not under the lock file name. */ | |
597 /* Give up if cannot do that. */ | |
598 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
599 if (desc < 0) | |
600 { | |
601 char *message = (char *) xmalloc (strlen (tempname) + 50); | |
602 sprintf (message, "%s--see source file lib-src/movemail.c", | |
603 tempname); | |
604 pfatal_with_name (message); | |
605 } | |
606 close (desc); | |
607 | |
608 tem = link (tempname, lockname); | |
609 unlink (tempname); | |
610 if (tem >= 0) | |
611 break; | |
612 sleep (1); | |
613 | |
614 /* If lock file is five minutes old, unlock it. | |
615 Five minutes should be good enough to cope with crashes | |
616 and wedgitude, and long enough to avoid being fooled | |
617 by time differences between machines. */ | |
618 if (stat (lockname, &st) >= 0) | |
619 { | |
620 now = time (0); | |
621 if (st.st_ctime < now - 300) | |
622 unlink (lockname); | |
623 } | |
624 } | |
625 strcpy(dotlock_filename, filename); | |
626 } | |
627 #endif /* not DISABLE_DIRECT_ACCESS */ | |
628 | |
629 static void | |
630 unlock_dot(char *filename) | |
631 { | |
632 unlink(dot_filename(filename)); | |
633 } | |
634 | |
635 static void | |
636 maybe_unlock_dot(void) | |
637 { | |
638 if (dotlock_filename) | |
639 unlock_dot(dotlock_filename); | |
640 } | |
641 | |
642 /* Print error message and exit. */ | 508 /* Print error message and exit. */ |
643 | 509 |
644 static void | 510 static void |
645 fatal (char *s1, char *s2) | 511 fatal (char *s1, char *s2) |
646 { | 512 { |
647 maybe_unlock_dot(); | 513 if (delete_lockname) |
514 unlink (delete_lockname); | |
648 error (s1, s2, NULL); | 515 error (s1, s2, NULL); |
649 exit (1); | 516 exit (1); |
650 } | 517 } |
651 | 518 |
652 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ | 519 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ |
698 long *result = (long *) malloc (size); | 565 long *result = (long *) malloc (size); |
699 if (!result) | 566 if (!result) |
700 fatal ("virtual memory exhausted", 0); | 567 fatal ("virtual memory exhausted", 0); |
701 return result; | 568 return result; |
702 } | 569 } |
703 | 570 |
704 /* This is the guts of the interface to the Post Office Protocol. */ | 571 /* This is the guts of the interface to the Post Office Protocol. */ |
705 | 572 |
706 #ifdef MAIL_USE_POP | 573 #ifdef MAIL_USE_POP |
707 | 574 |
708 #ifndef WIN32_NATIVE | 575 #ifndef WINDOWSNT |
709 #include <sys/socket.h> | 576 #include <sys/socket.h> |
710 #include <netinet/in.h> | 577 #include <netinet/in.h> |
711 #include <netdb.h> | 578 #include <netdb.h> |
712 #else | 579 #else |
713 #undef _WINSOCKAPI_ | 580 #undef _WINSOCKAPI_ |
714 #include <winsock.h> | 581 #include <winsock.h> |
715 #endif | 582 #endif |
716 #include <stdio.h> | 583 #include <stdio.h> |
717 #include "../src/syspwd.h" | 584 #include <pwd.h> |
718 | 585 |
719 #define POP_ERROR (-1) | 586 #define POP_ERROR (-1) |
720 #define POP_RETRIEVED (0) | 587 #define POP_RETRIEVED (0) |
721 #define POP_DONE (1) | 588 #define POP_DONE (1) |
722 | 589 |
735 int mbfi; | 602 int mbfi; |
736 short* retrieved_list; | 603 short* retrieved_list; |
737 FILE *mbf; | 604 FILE *mbf; |
738 popserver server; | 605 popserver server; |
739 | 606 |
740 VERBOSE(("opening server\n")); | 607 VERBOSE(("opening server\r")); |
741 server = pop_open (0, user, password, POP_NO_GETPASS); | 608 server = pop_open (0, user, password, POP_NO_GETPASS); |
742 if (! server) | 609 if (! server) |
743 { | 610 { |
744 error (pop_error, NULL, NULL); | 611 error (pop_error, NULL, NULL); |
745 return (1); | 612 return (1); |
746 } | 613 } |
747 | 614 |
748 VERBOSE(("stat'ing messages\n")); | 615 VERBOSE(("stat'ing messages\r")); |
749 if (pop_stat (server, &nmsgs, &nbytes)) | 616 if (pop_stat (server, &nmsgs, &nbytes)) |
750 { | 617 { |
751 error (pop_error, NULL, NULL); | 618 error (pop_error, NULL, NULL); |
752 return (1); | 619 return (1); |
753 } | 620 } |
768 { | 635 { |
769 pop_close (server); | 636 pop_close (server); |
770 error ("Error in open: %s, %s", strerror (errno), outfile); | 637 error ("Error in open: %s, %s", strerror (errno), outfile); |
771 return (1); | 638 return (1); |
772 } | 639 } |
773 #if !defined(CYGWIN) && !defined(WIN32_NATIVE) | 640 #if !defined(__CYGWIN32__) && !defined(WINDOWSNT) |
774 fchown (mbfi, getuid (), (gid_t) -1); | 641 fchown (mbfi, getuid (), -1); |
775 #endif | 642 #endif |
776 | 643 |
777 if ((mbf = fdopen (mbfi, "wb")) == NULL) | 644 if ((mbf = fdopen (mbfi, "wb")) == NULL) |
778 { | 645 { |
779 pop_close (server); | 646 pop_close (server); |
784 } | 651 } |
785 | 652 |
786 for (idx = 0; idx < nmsgs; idx++) | 653 for (idx = 0; idx < nmsgs; idx++) |
787 { | 654 { |
788 i = reverse ? nmsgs - idx : idx + 1; | 655 i = reverse ? nmsgs - idx : idx + 1; |
789 VERBOSE(("checking message %d \n", i)); | 656 VERBOSE(("checking message %d \r", i)); |
790 | 657 |
791 if (!regexp_pattern | 658 if (!regexp_pattern |
792 || | 659 || |
793 pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) | 660 pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) |
794 { | 661 { |
795 VERBOSE(("retrieving message %d \n", i)); | 662 VERBOSE(("retrieving message %d \r", i)); |
796 mbx_delimit_begin (mbf); | 663 mbx_delimit_begin (mbf); |
797 if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) | 664 if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) |
798 { | 665 { |
799 error (Errmsg, NULL, NULL); | 666 error (Errmsg, NULL, NULL); |
800 close (mbfi); | 667 close (mbfi); |
819 * workstation's AFS cache. The changes are not written to the server | 686 * workstation's AFS cache. The changes are not written to the server |
820 * until a call to fsync or close is made. Users with AFS home | 687 * until a call to fsync or close is made. Users with AFS home |
821 * directories have lost mail when over quota because these checks were | 688 * directories have lost mail when over quota because these checks were |
822 * not made in previous versions of movemail. */ | 689 * not made in previous versions of movemail. */ |
823 | 690 |
824 #ifdef HAVE_FSYNC | 691 #ifdef BSD |
825 if (fsync (mbfi) < 0) | 692 if (fsync (mbfi) < 0) |
826 { | 693 { |
827 error ("Error in fsync: %s", strerror (errno), NULL); | 694 error ("Error in fsync: %s", strerror (errno), NULL); |
828 return (1); | 695 return (1); |
829 } | 696 } |
839 { | 706 { |
840 for (i = 1; i <= nmsgs; i++) | 707 for (i = 1; i <= nmsgs; i++) |
841 { | 708 { |
842 if (retrieved_list[i] == 1) | 709 if (retrieved_list[i] == 1) |
843 { | 710 { |
844 VERBOSE(("deleting message %d \n", i)); | 711 VERBOSE(("deleting message %d \r", i)); |
845 if (pop_delete (server, i)) | 712 if (pop_delete (server, i)) |
846 { | 713 { |
847 error (pop_error, NULL, NULL); | 714 error (pop_error, NULL, NULL); |
848 pop_close (server); | 715 pop_close (server); |
849 return (1); | 716 return (1); |
861 | 728 |
862 return (0); | 729 return (0); |
863 } | 730 } |
864 | 731 |
865 static int | 732 static int |
866 pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), FILE *arg) | 733 pop_retr (popserver server, int msgno, int (*action)(), void *arg) |
867 { | 734 { |
868 char *line; | 735 char *line; |
869 int ret; | 736 int ret; |
870 | 737 |
871 if (pop_retrieve_first (server, msgno, &line)) | 738 if (pop_retrieve_first (server, msgno, &line)) |
1007 } | 874 } |
1008 | 875 |
1009 | 876 |
1010 | 877 |
1011 #endif /* MAIL_USE_POP */ | 878 #endif /* MAIL_USE_POP */ |
1012 | 879 |
1013 #ifndef HAVE_STRERROR | 880 #ifndef HAVE_STRERROR |
1014 char * | 881 char * |
1015 strerror (int errnum) | 882 strerror (int errnum) |
1016 { | 883 { |
1017 extern char *sys_errlist[]; | 884 extern char *sys_errlist[]; |