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");
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))
185 int status
; char *user
;
187 for (user
= &inname
[strlen (inname
) - 1]; user
>= inname
; user
--)
192 status
= popmail (user
, outname
);
197 #endif /* MAIL_USE_POP */
199 /* Check access to input file. */
200 if (access (inname
, R_OK
| W_OK
) != 0)
201 pfatal_with_name (inname
);
203 #ifndef MAIL_USE_MMDF
204 #ifndef MAIL_USE_SYSTEM_LOCK
205 /* Use a lock file named /usr/spool/mail/$USER.lock:
206 If it exists, the mail file is locked. */
207 /* Note: this locking mechanism is *required* by the mailer
208 (on systems which use it) to prevent loss of mail.
210 On systems that use a lock file, extracting the mail without locking
211 WILL occasionally cause loss of mail due to timing errors!
213 So, if creation of the lock file fails
214 due to access permission on /usr/spool/mail,
215 you simply MUST change the permission
216 and/or make movemail a setgid program
217 so it can create lock files properly.
219 You might also wish to verify that your system is one
220 which uses lock files for this purpose. Some systems use other methods.
222 If your system uses the `flock' system call for mail locking,
223 define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file
224 and recompile movemail. If the s- file for your system
225 should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report
226 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
228 lockname
= concat (inname
, ".lock", "");
229 tempname
= (char *) xmalloc (strlen (inname
) + strlen ("EXXXXXX") + 1);
230 strcpy (tempname
, inname
);
231 p
= tempname
+ strlen (tempname
);
232 while (p
!= tempname
&& p
[-1] != '/')
235 strcpy (p
, "EXXXXXX");
241 /* Create the lock file, but not under the lock file name. */
242 /* Give up if cannot do that. */
243 desc
= open (tempname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
245 pfatal_with_name ("lock file--see source file lib-src/movemail.c");
248 tem
= link (tempname
, lockname
);
254 /* If lock file is a minute old, unlock it. */
255 if (stat (lockname
, &st
) >= 0)
258 if (st
.st_ctime
< now
- 60)
263 delete_lockname
= lockname
;
264 #endif /* not MAIL_USE_SYSTEM_LOCK */
265 #endif /* not MAIL_USE_MMDF */
271 #ifndef MAIL_USE_MMDF
272 #ifdef MAIL_USE_SYSTEM_LOCK
273 indesc
= open (inname
, O_RDWR
);
274 #else /* if not MAIL_USE_SYSTEM_LOCK */
275 indesc
= open (inname
, O_RDONLY
);
276 #endif /* not MAIL_USE_SYSTEM_LOCK */
277 #else /* MAIL_USE_MMDF */
278 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
279 #endif /* MAIL_USE_MMDF */
282 pfatal_with_name (inname
);
284 #if defined (BSD) || defined (XENIX)
285 /* In case movemail is setuid to root, make sure the user can
286 read the output file. */
287 /* This is desirable for all systems
288 but I don't want to assume all have the umask system call */
289 umask (umask (0) & 0333);
290 #endif /* BSD or Xenix */
291 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
293 pfatal_with_name (outname
);
294 #ifdef MAIL_USE_SYSTEM_LOCK
295 #ifdef MAIL_USE_LOCKF
296 if (lockf (indesc
, F_LOCK
, 0) < 0) pfatal_with_name (inname
);
297 #else /* not MAIL_USE_LOCKF */
299 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
301 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
303 #endif /* not MAIL_USE_LOCKF */
304 #endif /* MAIL_USE_SYSTEM_LOCK */
311 nread
= read (indesc
, buf
, sizeof buf
);
312 if (nread
!= write (outdesc
, buf
, nread
))
314 int saved_errno
= errno
;
317 pfatal_with_name (outname
);
319 if (nread
< sizeof buf
)
325 if (fsync (outdesc
) < 0)
326 pfatal_and_delete (outname
);
329 /* Check to make sure no errors before we zap the inbox. */
330 if (close (outdesc
) != 0)
331 pfatal_and_delete (outname
);
333 #ifdef MAIL_USE_SYSTEM_LOCK
334 #if defined (STRIDE) || defined (XENIX)
335 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
336 close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
338 ftruncate (indesc
, 0L);
339 #endif /* STRIDE or XENIX */
340 #endif /* MAIL_USE_SYSTEM_LOCK */
343 lk_close (indesc
, 0, 0, 0);
348 #ifndef MAIL_USE_SYSTEM_LOCK
349 /* Delete the input file; if we can't, at least get rid of its
351 #ifdef MAIL_UNLINK_SPOOL
352 /* This is generally bad to do, because it destroys the permissions
353 that were set on the file. Better to just empty the file. */
354 if (unlink (inname
) < 0 && errno
!= ENOENT
)
355 #endif /* MAIL_UNLINK_SPOOL */
356 creat (inname
, 0600);
357 #endif /* not MAIL_USE_SYSTEM_LOCK */
363 if (!WIFEXITED (status
))
365 else if (WRETCODE (status
) != 0)
366 exit (WRETCODE (status
));
368 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
370 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
374 /* Print error message and exit. */
381 unlink (delete_lockname
);
386 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
392 fprintf (stderr
, "movemail: ");
393 fprintf (stderr
, s1
, s2
, s3
);
394 fprintf (stderr
, "\n");
398 pfatal_with_name (name
)
401 char *s
= concat ("", strerror (errno
), " for %s");
406 pfatal_and_delete (name
)
409 char *s
= concat ("", strerror (errno
), " for %s");
414 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
420 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
421 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
424 strcpy (result
+ len1
, s2
);
425 strcpy (result
+ len1
+ len2
, s3
);
426 *(result
+ len1
+ len2
+ len3
) = 0;
431 /* Like malloc but get fatal error if memory is exhausted. */
437 char *result
= (char *) malloc (size
);
439 fatal ("virtual memory exhausted", 0);
443 /* This is the guts of the interface to the Post Office Protocol. */
447 #include <sys/socket.h>
448 #include <netinet/in.h>
455 /* Cancel substitutions made by config.h for Emacs. */
469 char ibuffer
[BUFSIZ
];
470 char obuffer
[BUFSIZ
];
473 popmail (user
, outfile
)
484 extern char *strerror ();
486 server
= pop_open (0, user
, 0, POP_NO_GETPASS
);
493 if (pop_stat (server
, &nmsgs
, &nbytes
))
505 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
509 error ("Error in open: %s, %s", strerror (errno
), outfile
);
512 fchown (mbfi
, getuid (), -1);
514 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
517 error ("Error in fdopen: %s", strerror (errno
));
523 for (i
= 1; i
<= nmsgs
; i
++)
525 mbx_delimit_begin (mbf
);
526 if (pop_retr (server
, i
, mbx_write
, mbf
) != OK
)
532 mbx_delimit_end (mbf
);
536 error ("Error in fflush: %s", strerror (errno
));
543 /* On AFS, a call to write only modifies the file in the local
544 * workstation's AFS cache. The changes are not written to the server
545 * until a call to fsync or close is made. Users with AFS home
546 * directories have lost mail when over quota because these checks were
547 * not made in previous versions of movemail. */
550 if (fsync (mbfi
) < 0)
552 error ("Error in fsync: %s", strerror (errno
));
557 if (close (mbfi
) == -1)
559 error ("Error in close: %s", strerror (errno
));
563 for (i
= 1; i
<= nmsgs
; i
++)
565 if (pop_delete (server
, i
))
573 if (pop_quit (server
))
582 pop_retr (server
, msgno
, action
, arg
)
586 extern char *strerror ();
590 if (pop_retrieve_first (server
, msgno
, &line
))
592 strncpy (Errmsg
, pop_error
, sizeof (Errmsg
));
593 Errmsg
[sizeof (Errmsg
)-1] = '\0';
597 while (! (ret
= pop_retrieve_next (server
, &line
)))
602 if ((*action
)(line
, arg
) != OK
)
604 strcpy (Errmsg
, strerror (errno
));
612 strncpy (Errmsg
, pop_error
, sizeof (Errmsg
));
613 Errmsg
[sizeof (Errmsg
)-1] = '\0';
620 /* Do this as a macro instead of using strcmp to save on execution time. */
621 #define IS_FROM_LINE(a) ((a[0] == 'F') \
628 mbx_write (line
, mbf
)
632 if (IS_FROM_LINE (line
))
634 if (fputc ('>', mbf
) == EOF
)
637 if (fputs (line
, mbf
) == EOF
)
639 if (fputc (0x0a, mbf
) == EOF
)
645 mbx_delimit_begin (mbf
)
648 if (fputs ("\f\n0, unseen,,\n", mbf
) == EOF
)
653 mbx_delimit_end (mbf
)
656 if (putc ('\037', mbf
) == EOF
)
661 #endif /* MAIL_USE_POP */
663 #ifndef HAVE_STRERROR
668 extern char *sys_errlist
[];
671 if (errnum
>= 0 && errnum
< sys_nerr
)
672 return sys_errlist
[errnum
];
673 return (char *) "Unknown error";
676 #endif /* ! HAVE_STRERROR */