1 /* movemail foo bar -- move file foo to file bar,
2 locking file foo the way /bin/mail respects.
3 Copyright (C) 1986, 1992 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 1, 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 *will cause loss of mail*
22 if you do it on a system that does not normally use flock as its way of
23 interlocking access to inbox files. The setting of MAIL_USE_FLOCK
24 *must agree* with the system's own conventions.
25 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
51 #include <sys/types.h>
55 #define NO_SHORTNAMES /* Tell config not to load remap.h */
56 #include "../src/config.h"
70 #include <sys/locking.h>
74 extern int lk_open (), lk_close ();
77 /* Cancel substitutions made by config.h for Emacs. */
90 /* Nonzero means this is name of a lock file to delete on fatal error. */
91 char *delete_lockname
;
97 char *inname
, *outname
;
101 #ifndef MAIL_USE_FLOCK
108 #endif /* not MAIL_USE_FLOCK */
113 fatal ("two arguments required");
122 /* Check access to output file. */
123 if (access (outname
, F_OK
) == 0 && access (outname
, W_OK
) != 0)
124 pfatal_with_name (outname
);
126 /* Also check that outname's directory is writeable to the real uid. */
128 char *buf
= (char *) malloc (strlen (outname
) + 1);
130 strcpy (buf
, outname
);
131 p
= buf
+ strlen (buf
);
132 while (p
> buf
&& p
[-1] != '/')
136 if (access (buf
, W_OK
) != 0)
137 pfatal_with_name (buf
);
142 if (!bcmp (inname
, "po:", 3))
144 int status
; char *user
;
146 user
= (char *) rindex (inname
, ':') + 1;
147 status
= popmail (user
, outname
);
152 #endif /* MAIL_USE_POP */
154 /* Check access to input file. */
155 if (access (inname
, R_OK
| W_OK
) != 0)
156 pfatal_with_name (inname
);
158 #ifndef MAIL_USE_MMDF
159 #ifndef MAIL_USE_FLOCK
160 /* Use a lock file named /usr/spool/mail/$USER.lock:
161 If it exists, the mail file is locked. */
162 /* Note: this locking mechanism is *required* by the mailer
163 (on systems which use it) to prevent loss of mail.
165 On systems that use a lock file, extracting the mail without locking
166 WILL occasionally cause loss of mail due to timing errors!
168 So, if creation of the lock file fails
169 due to access permission on /usr/spool/mail,
170 you simply MUST change the permission
171 and/or make movemail a setgid program
172 so it can create lock files properly.
174 You might also wish to verify that your system is one
175 which uses lock files for this purpose. Some systems use other methods.
177 If your system uses the `flock' system call for mail locking,
178 define MAIL_USE_FLOCK in config.h or the s-*.h file
179 and recompile movemail. If the s- file for your system
180 should define MAIL_USE_FLOCK but does not, send a bug report
181 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
183 lockname
= concat (inname
, ".lock", "");
184 tempname
= strcpy (xmalloc (strlen (inname
)+1), inname
);
185 p
= tempname
+ strlen (tempname
);
186 while (p
!= tempname
&& p
[-1] != '/')
189 strcpy (p
, "EXXXXXX");
195 /* Create the lock file, but not under the lock file name. */
196 /* Give up if cannot do that. */
197 desc
= open (tempname
, O_WRONLY
| O_CREAT
, 0666);
199 pfatal_with_name ("lock file--see source file etc/movemail.c");
202 tem
= link (tempname
, lockname
);
208 /* If lock file is a minute old, unlock it. */
209 if (stat (lockname
, &st
) >= 0)
212 if (st
.st_ctime
< now
- 60)
217 delete_lockname
= lockname
;
218 #endif /* not MAIL_USE_FLOCK */
220 #ifdef MAIL_USE_FLOCK
221 indesc
= open (inname
, O_RDWR
);
222 #else /* if not MAIL_USE_FLOCK */
223 indesc
= open (inname
, O_RDONLY
);
224 #endif /* not MAIL_USE_FLOCK */
225 #else /* MAIL_USE_MMDF */
226 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
227 #endif /* MAIL_USE_MMDF */
230 pfatal_with_name (inname
);
232 #if defined (BSD) || defined (XENIX)
233 /* In case movemail is setuid to root, make sure the user can
234 read the output file. */
235 /* This is desirable for all systems
236 but I don't want to assume all have the umask system call */
237 umask (umask (0) & 0333);
238 #endif /* BSD or Xenix */
239 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
241 pfatal_with_name (outname
);
242 #ifdef MAIL_USE_FLOCK
244 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
246 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
248 #endif /* MAIL_USE_FLOCK */
255 nread
= read (indesc
, buf
, sizeof buf
);
256 if (nread
!= write (outdesc
, buf
, nread
))
258 int saved_errno
= errno
;
261 pfatal_with_name (outname
);
263 if (nread
< sizeof buf
)
269 if (fsync (outdesc
) < 0)
270 pfatal_and_delete (outname
);
273 /* Check to make sure no errors before we zap the inbox. */
274 if (close (outdesc
) != 0)
275 pfatal_and_delete (outname
);
277 #ifdef MAIL_USE_FLOCK
278 #if defined (STRIDE) || defined (XENIX)
279 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
280 close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
282 ftruncate (indesc
, 0L);
283 #endif /* STRIDE or XENIX */
284 #endif /* MAIL_USE_FLOCK */
287 lk_close (indesc
, 0, 0, 0);
292 #ifndef MAIL_USE_FLOCK
293 /* Delete the input file; if we can't, at least get rid of its contents. */
294 #ifdef MAIL_UNLINK_SPOOL
295 /* This is generally bad to do, because it destroys the permissions
296 that were set on the file. Better to just empty the file. */
297 if (unlink (inname
) < 0 && errno
!= ENOENT
)
298 #endif /* MAIL_UNLINK_SPOOL */
299 creat (inname
, 0600);
300 #ifndef MAIL_USE_MMDF
302 #endif /* not MAIL_USE_MMDF */
303 #endif /* not MAIL_USE_FLOCK */
307 /* Print error message and exit. */
313 unlink (delete_lockname
);
318 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
323 printf ("movemail: ");
328 pfatal_with_name (name
)
331 extern int errno
, sys_nerr
;
332 extern char *sys_errlist
[];
335 if (errno
< sys_nerr
)
336 s
= concat ("", sys_errlist
[errno
], " for %s");
338 s
= "cannot open %s";
342 pfatal_and_delete (name
)
345 extern int errno
, sys_nerr
;
346 extern char *sys_errlist
[];
349 if (errno
< sys_nerr
)
350 s
= concat ("", sys_errlist
[errno
], " for %s");
352 s
= "cannot open %s";
358 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
364 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
365 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
368 strcpy (result
+ len1
, s2
);
369 strcpy (result
+ len1
+ len2
, s3
);
370 *(result
+ len1
+ len2
+ len3
) = 0;
375 /* Like malloc but get fatal error if memory is exhausted. */
381 char *result
= malloc (size
);
383 fatal ("virtual memory exhausted", 0);
387 /* This is the guts of the interface to the Post Office Protocol. */
391 #include <sys/socket.h>
392 #include <netinet/in.h>
398 /* Cancel substitutions made by config.h for Emacs. */
414 static int debug
= 0;
420 popmail (user
, outfile
)
431 host
= getenv ("MAILHOST");
434 fatal ("no MAILHOST defined");
437 if (pop_init (host
) == NOTOK
)
442 if (getline (response
, sizeof response
, sfi
) != OK
)
447 if (pop_command ("USER %s", user
) == NOTOK
448 || pop_command ("RPOP %s", user
) == NOTOK
)
450 pop_command ("QUIT");
454 if (pop_stat (&nmsgs
, &nbytes
) == NOTOK
)
456 pop_command ("QUIT");
462 pop_command ("QUIT");
466 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
469 pop_command ("QUIT");
470 pfatal_and_delete (outfile
);
472 fchown (mbfi
, getuid (), -1);
474 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
476 pop_command ("QUIT");
477 pfatal_and_delete (outfile
);
480 for (i
= 1; i
<= nmsgs
; i
++)
482 mbx_delimit_begin (mbf
);
483 if (pop_retr (i
, mbx_write
, mbf
) != OK
)
485 pop_command ("QUIT");
490 mbx_delimit_end (mbf
);
494 if (fsync (mbfi
) < 0)
496 pop_command ("QUIT");
497 pfatal_and_delete (outfile
);
500 if (close (mbfi
) == -1)
502 pop_command ("QUIT");
503 pfatal_and_delete (outfile
);
506 for (i
= 1; i
<= nmsgs
; i
++)
508 if (pop_command ("DELE %d", i
) == NOTOK
)
510 /* Better to ignore this failure. */
514 pop_command ("QUIT");
521 register struct hostent
*hp
;
522 register struct servent
*sp
;
523 int lport
= IPPORT_RESERVED
- 1;
524 struct sockaddr_in sin
;
527 hp
= gethostbyname (host
);
530 sprintf (Errmsg
, "MAILHOST unknown: %s", host
);
534 sp
= getservbyname ("pop", "tcp");
537 strcpy (Errmsg
, "tcp/pop: unknown service");
541 sin
.sin_family
= hp
->h_addrtype
;
542 bcopy (hp
->h_addr
, (char *)&sin
.sin_addr
, hp
->h_length
);
543 sin
.sin_port
= sp
->s_port
;
544 s
= rresvport (&lport
);
547 sprintf (Errmsg
, "error creating socket: %s", get_errmsg ());
551 if (connect (s
, (char *)&sin
, sizeof sin
) < 0)
553 sprintf (Errmsg
, "error during connect: %s", get_errmsg ());
558 sfi
= fdopen (s
, "r");
559 sfo
= fdopen (s
, "w");
560 if (sfi
== NULL
|| sfo
== NULL
)
562 sprintf (Errmsg
, "error in fdopen: %s", get_errmsg ());
570 pop_command (fmt
, a
, b
, c
, d
)
576 sprintf (buf
, fmt
, a
, b
, c
, d
);
578 if (debug
) fprintf (stderr
, "---> %s\n", buf
);
579 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
581 if (getline (buf
, sizeof buf
, sfi
) != OK
)
583 strcpy (Errmsg
, buf
);
588 fprintf (stderr
, "<--- %s\n", buf
);
591 strcpy (Errmsg
, buf
);
601 pop_stat (nmsgs
, nbytes
)
607 fprintf (stderr
, "---> STAT\n");
608 if (putline ("STAT", Errmsg
, sfo
) == NOTOK
)
611 if (getline (buf
, sizeof buf
, sfi
) != OK
)
613 strcpy (Errmsg
, buf
);
617 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
620 strcpy (Errmsg
, buf
);
625 sscanf (buf
, "+OK %d %d", nmsgs
, nbytes
);
630 pop_retr (msgno
, action
, arg
)
635 sprintf (buf
, "RETR %d", msgno
);
636 if (debug
) fprintf (stderr
, "%s\n", buf
);
637 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
639 if (getline (buf
, sizeof buf
, sfi
) != OK
)
641 strcpy (Errmsg
, buf
);
647 switch (multiline (buf
, sizeof buf
, sfi
))
655 strcpy (Errmsg
, buf
);
670 while (--n
> 0 && (c
= fgetc (f
)) != EOF
)
671 if ((*p
++ = c
) == '\n') break;
675 strcpy (buf
, "error on connection");
679 if (c
== EOF
&& p
== buf
)
681 strcpy (buf
, "connection closed by foreign host");
686 if (*--p
== '\n') *p
= NULL
;
687 if (*--p
== '\r') *p
= NULL
;
691 multiline (buf
, n
, f
)
696 if (getline (buf
, n
, f
) != OK
)
700 if (*(buf
+1) == NULL
)
711 extern int errno
, sys_nerr
;
712 extern char *sys_errlist
[];
715 if (errno
< sys_nerr
)
716 s
= sys_errlist
[errno
];
722 putline (buf
, err
, f
)
727 fprintf (f
, "%s\r\n", buf
);
731 strcpy (err
, "lost connection");
737 mbx_write (line
, mbf
)
745 mbx_delimit_begin (mbf
)
748 fputs ("\f\n0, unseen,,\n", mbf
);
751 mbx_delimit_end (mbf
)
757 #endif /* MAIL_USE_POP */