comparison lib-src/movemail.c @ 398:74fd4e045ea6 r21-2-29

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