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. */
91 /* Nonzero means this is name of a lock file to delete on fatal error. */
92 char *delete_lockname
;
98 char *inname
, *outname
;
102 #ifndef MAIL_USE_FLOCK
109 #endif /* not MAIL_USE_FLOCK */
114 fatal ("two arguments required");
123 /* Check access to output file. */
124 if (access (outname
, F_OK
) == 0 && access (outname
, W_OK
) != 0)
125 pfatal_with_name (outname
);
127 /* Also check that outname's directory is writeable to the real uid. */
129 char *buf
= (char *) malloc (strlen (outname
) + 1);
131 strcpy (buf
, outname
);
132 p
= buf
+ strlen (buf
);
133 while (p
> buf
&& p
[-1] != '/')
137 if (access (buf
, W_OK
) != 0)
138 pfatal_with_name (buf
);
143 if (!strncmp (inname
, "po:", 3))
145 int status
; char *user
;
147 for (user
= &inname
[strlen (inname
) - 1]; user
>= inname
; user
--)
151 status
= popmail (user
, outname
);
156 #endif /* MAIL_USE_POP */
158 /* Check access to input file. */
159 if (access (inname
, R_OK
| W_OK
) != 0)
160 pfatal_with_name (inname
);
162 #ifndef MAIL_USE_MMDF
163 #ifndef MAIL_USE_FLOCK
164 /* Use a lock file named /usr/spool/mail/$USER.lock:
165 If it exists, the mail file is locked. */
166 /* Note: this locking mechanism is *required* by the mailer
167 (on systems which use it) to prevent loss of mail.
169 On systems that use a lock file, extracting the mail without locking
170 WILL occasionally cause loss of mail due to timing errors!
172 So, if creation of the lock file fails
173 due to access permission on /usr/spool/mail,
174 you simply MUST change the permission
175 and/or make movemail a setgid program
176 so it can create lock files properly.
178 You might also wish to verify that your system is one
179 which uses lock files for this purpose. Some systems use other methods.
181 If your system uses the `flock' system call for mail locking,
182 define MAIL_USE_FLOCK in config.h or the s-*.h file
183 and recompile movemail. If the s- file for your system
184 should define MAIL_USE_FLOCK but does not, send a bug report
185 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
187 lockname
= concat (inname
, ".lock", "");
188 tempname
= strcpy (xmalloc (strlen (inname
)+1), inname
);
189 p
= tempname
+ strlen (tempname
);
190 while (p
!= tempname
&& p
[-1] != '/')
193 strcpy (p
, "EXXXXXX");
199 /* Create the lock file, but not under the lock file name. */
200 /* Give up if cannot do that. */
201 desc
= open (tempname
, O_WRONLY
| O_CREAT
, 0666);
203 pfatal_with_name ("lock file--see source file etc/movemail.c");
206 tem
= link (tempname
, lockname
);
212 /* If lock file is a minute old, unlock it. */
213 if (stat (lockname
, &st
) >= 0)
216 if (st
.st_ctime
< now
- 60)
221 delete_lockname
= lockname
;
222 #endif /* not MAIL_USE_FLOCK */
224 #ifdef MAIL_USE_FLOCK
225 indesc
= open (inname
, O_RDWR
);
226 #else /* if not MAIL_USE_FLOCK */
227 indesc
= open (inname
, O_RDONLY
);
228 #endif /* not MAIL_USE_FLOCK */
229 #else /* MAIL_USE_MMDF */
230 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
231 #endif /* MAIL_USE_MMDF */
234 pfatal_with_name (inname
);
236 #if defined (BSD) || defined (XENIX)
237 /* In case movemail is setuid to root, make sure the user can
238 read the output file. */
239 /* This is desirable for all systems
240 but I don't want to assume all have the umask system call */
241 umask (umask (0) & 0333);
242 #endif /* BSD or Xenix */
243 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
245 pfatal_with_name (outname
);
246 #ifdef MAIL_USE_FLOCK
248 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
250 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
252 #endif /* MAIL_USE_FLOCK */
259 nread
= read (indesc
, buf
, sizeof buf
);
260 if (nread
!= write (outdesc
, buf
, nread
))
262 int saved_errno
= errno
;
265 pfatal_with_name (outname
);
267 if (nread
< sizeof buf
)
273 if (fsync (outdesc
) < 0)
274 pfatal_and_delete (outname
);
277 /* Check to make sure no errors before we zap the inbox. */
278 if (close (outdesc
) != 0)
279 pfatal_and_delete (outname
);
281 #ifdef MAIL_USE_FLOCK
282 #if defined (STRIDE) || defined (XENIX)
283 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
284 close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
286 ftruncate (indesc
, 0L);
287 #endif /* STRIDE or XENIX */
288 #endif /* MAIL_USE_FLOCK */
291 lk_close (indesc
, 0, 0, 0);
296 #ifndef MAIL_USE_FLOCK
297 /* Delete the input file; if we can't, at least get rid of its contents. */
298 #ifdef MAIL_UNLINK_SPOOL
299 /* This is generally bad to do, because it destroys the permissions
300 that were set on the file. Better to just empty the file. */
301 if (unlink (inname
) < 0 && errno
!= ENOENT
)
302 #endif /* MAIL_UNLINK_SPOOL */
303 creat (inname
, 0600);
304 #ifndef MAIL_USE_MMDF
306 #endif /* not MAIL_USE_MMDF */
307 #endif /* not MAIL_USE_FLOCK */
311 /* Print error message and exit. */
317 unlink (delete_lockname
);
322 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
327 printf ("movemail: ");
332 pfatal_with_name (name
)
335 extern int errno
, sys_nerr
;
336 extern char *sys_errlist
[];
339 if (errno
< sys_nerr
)
340 s
= concat ("", sys_errlist
[errno
], " for %s");
342 s
= "cannot open %s";
346 pfatal_and_delete (name
)
349 extern int errno
, sys_nerr
;
350 extern char *sys_errlist
[];
353 if (errno
< sys_nerr
)
354 s
= concat ("", sys_errlist
[errno
], " for %s");
356 s
= "cannot open %s";
362 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
368 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
369 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
372 strcpy (result
+ len1
, s2
);
373 strcpy (result
+ len1
+ len2
, s3
);
374 *(result
+ len1
+ len2
+ len3
) = 0;
379 /* Like malloc but get fatal error if memory is exhausted. */
385 char *result
= malloc (size
);
387 fatal ("virtual memory exhausted", 0);
391 /* This is the guts of the interface to the Post Office Protocol. */
395 #include <sys/socket.h>
396 #include <netinet/in.h>
403 /* Cancel substitutions made by config.h for Emacs. */
419 static int debug
= 0;
425 popmail (user
, outfile
)
435 struct passwd
*pw
= (struct passwd
*) getpwuid (getuid ());
437 fatal ("cannot determine user name");
439 host
= getenv ("MAILHOST");
442 fatal ("no MAILHOST defined");
445 if (pop_init (host
) == NOTOK
)
450 if (getline (response
, sizeof response
, sfi
) != OK
)
455 if (pop_command ("USER %s", user
) == NOTOK
456 || pop_command ("RPOP %s", pw
->pw_name
) == NOTOK
)
458 pop_command ("QUIT");
462 if (pop_stat (&nmsgs
, &nbytes
) == NOTOK
)
464 pop_command ("QUIT");
470 pop_command ("QUIT");
474 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
477 pop_command ("QUIT");
478 pfatal_and_delete (outfile
);
480 fchown (mbfi
, getuid (), -1);
482 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
484 pop_command ("QUIT");
485 pfatal_and_delete (outfile
);
488 for (i
= 1; i
<= nmsgs
; i
++)
490 mbx_delimit_begin (mbf
);
491 if (pop_retr (i
, mbx_write
, mbf
) != OK
)
493 pop_command ("QUIT");
498 mbx_delimit_end (mbf
);
502 if (fsync (mbfi
) < 0)
504 pop_command ("QUIT");
505 pfatal_and_delete (outfile
);
508 if (close (mbfi
) == -1)
510 pop_command ("QUIT");
511 pfatal_and_delete (outfile
);
514 for (i
= 1; i
<= nmsgs
; i
++)
516 if (pop_command ("DELE %d", i
) == NOTOK
)
518 /* Better to ignore this failure. */
522 pop_command ("QUIT");
529 register struct hostent
*hp
;
530 register struct servent
*sp
;
531 int lport
= IPPORT_RESERVED
- 1;
532 struct sockaddr_in sin
;
535 hp
= gethostbyname (host
);
538 sprintf (Errmsg
, "MAILHOST unknown: %s", host
);
542 sp
= getservbyname ("pop", "tcp");
545 strcpy (Errmsg
, "tcp/pop: unknown service");
549 sin
.sin_family
= hp
->h_addrtype
;
550 bcopy (hp
->h_addr
, (char *)&sin
.sin_addr
, hp
->h_length
);
551 sin
.sin_port
= sp
->s_port
;
552 s
= rresvport (&lport
);
555 sprintf (Errmsg
, "error creating socket: %s", get_errmsg ());
559 if (connect (s
, (char *)&sin
, sizeof sin
) < 0)
561 sprintf (Errmsg
, "error during connect: %s", get_errmsg ());
566 sfi
= fdopen (s
, "r");
567 sfo
= fdopen (s
, "w");
568 if (sfi
== NULL
|| sfo
== NULL
)
570 sprintf (Errmsg
, "error in fdopen: %s", get_errmsg ());
578 pop_command (fmt
, a
, b
, c
, d
)
584 sprintf (buf
, fmt
, a
, b
, c
, d
);
586 if (debug
) fprintf (stderr
, "---> %s\n", buf
);
587 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
589 if (getline (buf
, sizeof buf
, sfi
) != OK
)
591 strcpy (Errmsg
, buf
);
596 fprintf (stderr
, "<--- %s\n", buf
);
599 strcpy (Errmsg
, buf
);
609 pop_stat (nmsgs
, nbytes
)
615 fprintf (stderr
, "---> STAT\n");
616 if (putline ("STAT", Errmsg
, sfo
) == NOTOK
)
619 if (getline (buf
, sizeof buf
, sfi
) != OK
)
621 strcpy (Errmsg
, buf
);
625 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
628 strcpy (Errmsg
, buf
);
633 sscanf (buf
, "+OK %d %d", nmsgs
, nbytes
);
638 pop_retr (msgno
, action
, arg
)
643 sprintf (buf
, "RETR %d", msgno
);
644 if (debug
) fprintf (stderr
, "%s\n", buf
);
645 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
647 if (getline (buf
, sizeof buf
, sfi
) != OK
)
649 strcpy (Errmsg
, buf
);
655 switch (multiline (buf
, sizeof buf
, sfi
))
663 strcpy (Errmsg
, buf
);
678 while (--n
> 0 && (c
= fgetc (f
)) != EOF
)
679 if ((*p
++ = c
) == '\n') break;
683 strcpy (buf
, "error on connection");
687 if (c
== EOF
&& p
== buf
)
689 strcpy (buf
, "connection closed by foreign host");
694 if (*--p
== '\n') *p
= NULL
;
695 if (*--p
== '\r') *p
= NULL
;
699 multiline (buf
, n
, f
)
704 if (getline (buf
, n
, f
) != OK
)
708 if (*(buf
+1) == NULL
)
719 extern int errno
, sys_nerr
;
720 extern char *sys_errlist
[];
723 if (errno
< sys_nerr
)
724 s
= sys_errlist
[errno
];
730 putline (buf
, err
, f
)
735 fprintf (f
, "%s\r\n", buf
);
739 strcpy (err
, "lost connection");
745 mbx_write (line
, mbf
)
753 mbx_delimit_begin (mbf
)
756 fputs ("\f\n0, unseen,,\n", mbf
);
759 mbx_delimit_end (mbf
)
765 #endif /* MAIL_USE_POP */