1 /* movemail foo bar -- move file foo to file bar,
2 locking file foo the way /bin/mail respects.
3 Copyright (C) 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
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
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 /* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will
22 cause loss of mail* if you do it on a system that does not normally
23 use flock as its way of interlocking access to inbox files. The
24 setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the
25 system's own conventions. It is not a choice that is up to you.
27 So, if your system uses lock files rather than flock, then the only way
28 you can get proper operation is to enable movemail to write lockfiles there.
29 This means you must either give that directory access modes
30 that permit everyone to write lockfiles in it, or you must make movemail
31 a setuid or setgid program. */
34 * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
36 * Added POP (Post Office Protocol) service. When compiled -DPOP
37 * movemail will accept input filename arguments of the form
38 * "po:username". This will cause movemail to open a connection to
39 * a pop server running on $MAILHOST (environment variable). Movemail
40 * must be setuid to root in order to work with POP.
42 * New module: popmail.c
44 * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ())
46 * New routines in movemail.c:
47 * get_errmsg - return pointer to system error message
49 * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies)
51 * Move all of the POP code into a separate file, "pop.c".
52 * Use strerror instead of get_errmsg.
56 #define NO_SHORTNAMES /* Tell config not to load remap.h */
57 #include <../src/config.h>
58 #include <sys/types.h>
63 #include <../src/syswait.h>
88 #include <sys/locking.h>
92 #define MAIL_USE_SYSTEM_LOCK
96 #define MAIL_USE_SYSTEM_LOCK
100 extern int lk_open (), lk_close ();
103 /* Cancel substitutions made by config.h for Emacs. */
116 void pfatal_with_name ();
117 void pfatal_and_delete ();
123 int mbx_delimit_begin ();
124 int mbx_delimit_end ();
126 /* Nonzero means this is name of a lock file to delete on fatal error. */
127 char *delete_lockname
;
134 char *inname
, *outname
;
139 #ifndef MAIL_USE_SYSTEM_LOCK
146 #endif /* not MAIL_USE_SYSTEM_LOCK */
152 fprintf (stderr
, "Usage: movemail inbox destfile\n");
163 /* Check access to output file. */
164 if (access (outname
, F_OK
) == 0 && access (outname
, W_OK
) != 0)
165 pfatal_with_name (outname
);
167 /* Also check that outname's directory is writeable to the real uid. */
169 char *buf
= (char *) xmalloc (strlen (outname
) + 1);
171 strcpy (buf
, outname
);
172 p
= buf
+ strlen (buf
);
173 while (p
> buf
&& p
[-1] != '/')
177 if (access (buf
, W_OK
) != 0)
178 pfatal_with_name (buf
);
183 if (!strncmp (inname
, "po:", 3))
187 status
= popmail (inname
+ 3, outname
);
192 #endif /* MAIL_USE_POP */
194 /* Check access to input file. */
195 if (access (inname
, R_OK
| W_OK
) != 0)
196 pfatal_with_name (inname
);
198 #ifndef MAIL_USE_MMDF
199 #ifndef MAIL_USE_SYSTEM_LOCK
200 /* Use a lock file named after our first argument with .lock appended:
201 If it exists, the mail file is locked. */
202 /* Note: this locking mechanism is *required* by the mailer
203 (on systems which use it) to prevent loss of mail.
205 On systems that use a lock file, extracting the mail without locking
206 WILL occasionally cause loss of mail due to timing errors!
208 So, if creation of the lock file fails
209 due to access permission on the mail spool directory,
210 you simply MUST change the permission
211 and/or make movemail a setgid program
212 so it can create lock files properly.
214 You might also wish to verify that your system is one
215 which uses lock files for this purpose. Some systems use other methods.
217 If your system uses the `flock' system call for mail locking,
218 define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file
219 and recompile movemail. If the s- file for your system
220 should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report
221 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
223 lockname
= concat (inname
, ".lock", "");
224 tempname
= (char *) xmalloc (strlen (inname
) + strlen ("EXXXXXX") + 1);
225 strcpy (tempname
, inname
);
226 p
= tempname
+ strlen (tempname
);
227 while (p
!= tempname
&& p
[-1] != '/')
230 strcpy (p
, "EXXXXXX");
236 /* Create the lock file, but not under the lock file name. */
237 /* Give up if cannot do that. */
238 desc
= open (tempname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
240 pfatal_with_name ("lock file--see source file lib-src/movemail.c");
243 tem
= link (tempname
, lockname
);
249 /* If lock file is five minutes old, unlock it.
250 Five minutes should be good enough to cope with crashes
251 and wedgitude, and long enough to avoid being fooled
252 by time differences between machines. */
253 if (stat (lockname
, &st
) >= 0)
256 if (st
.st_ctime
< now
- 300)
261 delete_lockname
= lockname
;
262 #endif /* not MAIL_USE_SYSTEM_LOCK */
263 #endif /* not MAIL_USE_MMDF */
269 #ifndef MAIL_USE_MMDF
270 #ifdef MAIL_USE_SYSTEM_LOCK
271 indesc
= open (inname
, O_RDWR
);
272 #else /* if not MAIL_USE_SYSTEM_LOCK */
273 indesc
= open (inname
, O_RDONLY
);
274 #endif /* not MAIL_USE_SYSTEM_LOCK */
275 #else /* MAIL_USE_MMDF */
276 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
277 #endif /* MAIL_USE_MMDF */
280 pfatal_with_name (inname
);
282 #if defined (BSD) || defined (XENIX)
283 /* In case movemail is setuid to root, make sure the user can
284 read the output file. */
285 /* This is desirable for all systems
286 but I don't want to assume all have the umask system call */
287 umask (umask (0) & 0333);
288 #endif /* BSD or Xenix */
289 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
291 pfatal_with_name (outname
);
292 #ifdef MAIL_USE_SYSTEM_LOCK
293 #ifdef MAIL_USE_LOCKF
294 if (lockf (indesc
, F_LOCK
, 0) < 0) pfatal_with_name (inname
);
295 #else /* not MAIL_USE_LOCKF */
297 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
299 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
301 #endif /* not MAIL_USE_LOCKF */
302 #endif /* MAIL_USE_SYSTEM_LOCK */
309 nread
= read (indesc
, buf
, sizeof buf
);
310 if (nread
!= write (outdesc
, buf
, nread
))
312 int saved_errno
= errno
;
315 pfatal_with_name (outname
);
317 if (nread
< sizeof buf
)
323 if (fsync (outdesc
) < 0)
324 pfatal_and_delete (outname
);
327 /* Check to make sure no errors before we zap the inbox. */
328 if (close (outdesc
) != 0)
329 pfatal_and_delete (outname
);
331 #ifdef MAIL_USE_SYSTEM_LOCK
332 #if defined (STRIDE) || defined (XENIX)
333 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
334 close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
336 ftruncate (indesc
, 0L);
337 #endif /* STRIDE or XENIX */
338 #endif /* MAIL_USE_SYSTEM_LOCK */
341 lk_close (indesc
, 0, 0, 0);
346 #ifndef MAIL_USE_SYSTEM_LOCK
347 /* Delete the input file; if we can't, at least get rid of its
349 #ifdef MAIL_UNLINK_SPOOL
350 /* This is generally bad to do, because it destroys the permissions
351 that were set on the file. Better to just empty the file. */
352 if (unlink (inname
) < 0 && errno
!= ENOENT
)
353 #endif /* MAIL_UNLINK_SPOOL */
354 creat (inname
, 0600);
355 #endif /* not MAIL_USE_SYSTEM_LOCK */
361 if (!WIFEXITED (status
))
363 else if (WRETCODE (status
) != 0)
364 exit (WRETCODE (status
));
366 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
368 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
372 /* Print error message and exit. */
379 unlink (delete_lockname
);
384 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
390 fprintf (stderr
, "movemail: ");
391 fprintf (stderr
, s1
, s2
, s3
);
392 fprintf (stderr
, "\n");
396 pfatal_with_name (name
)
399 char *s
= concat ("", strerror (errno
), " for %s");
404 pfatal_and_delete (name
)
407 char *s
= concat ("", strerror (errno
), " for %s");
412 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
418 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
419 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
422 strcpy (result
+ len1
, s2
);
423 strcpy (result
+ len1
+ len2
, s3
);
424 *(result
+ len1
+ len2
+ len3
) = 0;
429 /* Like malloc but get fatal error if memory is exhausted. */
435 long *result
= (long *) malloc (size
);
437 fatal ("virtual memory exhausted", 0);
441 /* This is the guts of the interface to the Post Office Protocol. */
445 #include <sys/socket.h>
446 #include <netinet/in.h>
453 /* Cancel substitutions made by config.h for Emacs. */
467 char ibuffer
[BUFSIZ
];
468 char obuffer
[BUFSIZ
];
471 popmail (user
, outfile
)
482 extern char *strerror ();
484 server
= pop_open (0, user
, 0, POP_NO_GETPASS
);
491 if (pop_stat (server
, &nmsgs
, &nbytes
))
503 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
507 error ("Error in open: %s, %s", strerror (errno
), outfile
);
510 fchown (mbfi
, getuid (), -1);
512 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
515 error ("Error in fdopen: %s", strerror (errno
));
521 for (i
= 1; i
<= nmsgs
; i
++)
523 mbx_delimit_begin (mbf
);
524 if (pop_retr (server
, i
, mbx_write
, mbf
) != OK
)
530 mbx_delimit_end (mbf
);
534 error ("Error in fflush: %s", strerror (errno
));
541 /* On AFS, a call to write only modifies the file in the local
542 * workstation's AFS cache. The changes are not written to the server
543 * until a call to fsync or close is made. Users with AFS home
544 * directories have lost mail when over quota because these checks were
545 * not made in previous versions of movemail. */
548 if (fsync (mbfi
) < 0)
550 error ("Error in fsync: %s", strerror (errno
));
555 if (close (mbfi
) == -1)
557 error ("Error in close: %s", strerror (errno
));
561 for (i
= 1; i
<= nmsgs
; i
++)
563 if (pop_delete (server
, i
))
571 if (pop_quit (server
))
580 pop_retr (server
, msgno
, action
, arg
)
584 extern char *strerror ();
588 if (pop_retrieve_first (server
, msgno
, &line
))
590 strncpy (Errmsg
, pop_error
, sizeof (Errmsg
));
591 Errmsg
[sizeof (Errmsg
)-1] = '\0';
595 while (! (ret
= pop_retrieve_next (server
, &line
)))
600 if ((*action
)(line
, arg
) != OK
)
602 strcpy (Errmsg
, strerror (errno
));
610 strncpy (Errmsg
, pop_error
, sizeof (Errmsg
));
611 Errmsg
[sizeof (Errmsg
)-1] = '\0';
618 /* Do this as a macro instead of using strcmp to save on execution time. */
619 #define IS_FROM_LINE(a) ((a[0] == 'F') \
626 mbx_write (line
, mbf
)
630 if (IS_FROM_LINE (line
))
632 if (fputc ('>', mbf
) == EOF
)
635 if (fputs (line
, mbf
) == EOF
)
637 if (fputc (0x0a, mbf
) == EOF
)
643 mbx_delimit_begin (mbf
)
646 if (fputs ("\f\n0, unseen,,\n", mbf
) == EOF
)
651 mbx_delimit_end (mbf
)
654 if (putc ('\037', mbf
) == EOF
)
659 #endif /* MAIL_USE_POP */
661 #ifndef HAVE_STRERROR
666 extern char *sys_errlist
[];
669 if (errnum
>= 0 && errnum
< sys_nerr
)
670 return sys_errlist
[errnum
];
671 return (char *) "Unknown error";
674 #endif /* ! HAVE_STRERROR */