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[];