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 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>
57 #include <../src/syswait.h>
75 #include <sys/locking.h>
79 extern int lk_open (), lk_close ();
82 /* Cancel substitutions made by config.h for Emacs. */
94 /* Nonzero means this is name of a lock file to delete on fatal error. */
95 char *delete_lockname
;
101 char *inname
, *outname
;
106 #ifndef MAIL_USE_FLOCK
113 #endif /* not MAIL_USE_FLOCK */
118 fatal ("two arguments required");
127 /* Check access to output file. */
128 if (access (outname
, F_OK
) == 0 && access (outname
, W_OK
) != 0)
129 pfatal_with_name (outname
);
131 /* Also check that outname's directory is writeable to the real uid. */
133 char *buf
= (char *) xmalloc (strlen (outname
) + 1);
135 strcpy (buf
, outname
);
136 p
= buf
+ strlen (buf
);
137 while (p
> buf
&& p
[-1] != '/')
141 if (access (buf
, W_OK
) != 0)
142 pfatal_with_name (buf
);
147 if (!strncmp (inname
, "po:", 3))
149 int status
; char *user
;
151 for (user
= &inname
[strlen (inname
) - 1]; user
>= inname
; user
--)
155 status
= popmail (user
, outname
);
160 #endif /* MAIL_USE_POP */
162 /* Check access to input file. */
163 if (access (inname
, R_OK
| W_OK
) != 0)
164 pfatal_with_name (inname
);
166 #ifndef MAIL_USE_MMDF
167 #ifndef MAIL_USE_FLOCK
168 /* Use a lock file named /usr/spool/mail/$USER.lock:
169 If it exists, the mail file is locked. */
170 /* Note: this locking mechanism is *required* by the mailer
171 (on systems which use it) to prevent loss of mail.
173 On systems that use a lock file, extracting the mail without locking
174 WILL occasionally cause loss of mail due to timing errors!
176 So, if creation of the lock file fails
177 due to access permission on /usr/spool/mail,
178 you simply MUST change the permission
179 and/or make movemail a setgid program
180 so it can create lock files properly.
182 You might also wish to verify that your system is one
183 which uses lock files for this purpose. Some systems use other methods.
185 If your system uses the `flock' system call for mail locking,
186 define MAIL_USE_FLOCK in config.h or the s-*.h file
187 and recompile movemail. If the s- file for your system
188 should define MAIL_USE_FLOCK but does not, send a bug report
189 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
191 lockname
= concat (inname
, ".lock", "");
192 tempname
= (char *) xmalloc (strlen (inname
) + strlen ("EXXXXXX") + 1);
193 strcpy (tempname
, inname
);
194 p
= tempname
+ strlen (tempname
);
195 while (p
!= tempname
&& p
[-1] != '/')
198 strcpy (p
, "EXXXXXX");
204 /* Create the lock file, but not under the lock file name. */
205 /* Give up if cannot do that. */
206 desc
= open (tempname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
208 pfatal_with_name ("lock file--see source file lib-src/movemail.c");
211 tem
= link (tempname
, lockname
);
217 /* If lock file is a minute old, unlock it. */
218 if (stat (lockname
, &st
) >= 0)
221 if (st
.st_ctime
< now
- 60)
226 delete_lockname
= lockname
;
227 #endif /* not MAIL_USE_FLOCK */
233 #ifdef MAIL_USE_FLOCK
234 indesc
= open (inname
, O_RDWR
);
235 #else /* if not MAIL_USE_FLOCK */
236 indesc
= open (inname
, O_RDONLY
);
237 #endif /* not MAIL_USE_FLOCK */
238 #else /* MAIL_USE_MMDF */
239 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
240 #endif /* MAIL_USE_MMDF */
243 pfatal_with_name (inname
);
245 #if defined (BSD) || defined (XENIX)
246 /* In case movemail is setuid to root, make sure the user can
247 read the output file. */
248 /* This is desirable for all systems
249 but I don't want to assume all have the umask system call */
250 umask (umask (0) & 0333);
251 #endif /* BSD or Xenix */
252 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
254 pfatal_with_name (outname
);
255 #ifdef MAIL_USE_FLOCK
257 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
259 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
261 #endif /* MAIL_USE_FLOCK */
268 nread
= read (indesc
, buf
, sizeof buf
);
269 if (nread
!= write (outdesc
, buf
, nread
))
271 int saved_errno
= errno
;
274 pfatal_with_name (outname
);
276 if (nread
< sizeof buf
)
282 if (fsync (outdesc
) < 0)
283 pfatal_and_delete (outname
);
286 /* Check to make sure no errors before we zap the inbox. */
287 if (close (outdesc
) != 0)
288 pfatal_and_delete (outname
);
290 #ifdef MAIL_USE_FLOCK
291 #if defined (STRIDE) || defined (XENIX)
292 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
293 close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
295 ftruncate (indesc
, 0L);
296 #endif /* STRIDE or XENIX */
297 #endif /* MAIL_USE_FLOCK */
300 lk_close (indesc
, 0, 0, 0);
305 #ifndef MAIL_USE_FLOCK
306 /* Delete the input file; if we can't, at least get rid of its contents. */
307 #ifdef MAIL_UNLINK_SPOOL
308 /* This is generally bad to do, because it destroys the permissions
309 that were set on the file. Better to just empty the file. */
310 if (unlink (inname
) < 0 && errno
!= ENOENT
)
311 #endif /* MAIL_UNLINK_SPOOL */
312 creat (inname
, 0600);
318 if (!WIFEXITED (status
))
320 else if (WRETCODE (status
) != 0)
321 exit (WRETCODE (status
));
323 #ifndef MAIL_USE_MMDF
325 #endif /* not MAIL_USE_MMDF */
326 #endif /* not MAIL_USE_FLOCK */
330 /* Print error message and exit. */
336 unlink (delete_lockname
);
341 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
346 printf ("movemail: ");
351 pfatal_with_name (name
)
354 extern int errno
, sys_nerr
;
355 extern char *sys_errlist
[];
358 if (errno
< sys_nerr
)
359 s
= concat ("", sys_errlist
[errno
], " for %s");
361 s
= "cannot open %s";
365 pfatal_and_delete (name
)
368 extern int errno
, sys_nerr
;
369 extern char *sys_errlist
[];
372 if (errno
< sys_nerr
)
373 s
= concat ("", sys_errlist
[errno
], " for %s");
375 s
= "cannot open %s";
381 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
387 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
388 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
391 strcpy (result
+ len1
, s2
);
392 strcpy (result
+ len1
+ len2
, s3
);
393 *(result
+ len1
+ len2
+ len3
) = 0;
398 /* Like malloc but get fatal error if memory is exhausted. */
404 char *result
= (char *) malloc (size
);
406 fatal ("virtual memory exhausted", 0);
410 /* This is the guts of the interface to the Post Office Protocol. */
414 #include <sys/socket.h>
415 #include <netinet/in.h>
422 /* Cancel substitutions made by config.h for Emacs. */
438 static int debug
= 0;
444 popmail (user
, outfile
)
454 struct passwd
*pw
= (struct passwd
*) getpwuid (getuid ());
456 fatal ("cannot determine user name");
458 host
= getenv ("MAILHOST");
461 fatal ("no MAILHOST defined");
464 if (pop_init (host
) == NOTOK
)
469 if (getline (response
, sizeof response
, sfi
) != OK
)
474 if (pop_command ("USER %s", user
) == NOTOK
475 || pop_command ("RPOP %s", pw
->pw_name
) == NOTOK
)
477 pop_command ("QUIT");
481 if (pop_stat (&nmsgs
, &nbytes
) == NOTOK
)
483 pop_command ("QUIT");
489 pop_command ("QUIT");
493 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
496 pop_command ("QUIT");
497 pfatal_and_delete (outfile
);
499 fchown (mbfi
, getuid (), -1);
501 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
503 pop_command ("QUIT");
504 pfatal_and_delete (outfile
);
507 for (i
= 1; i
<= nmsgs
; i
++)
509 mbx_delimit_begin (mbf
);
510 if (pop_retr (i
, mbx_write
, mbf
) != OK
)
512 pop_command ("QUIT");
517 mbx_delimit_end (mbf
);
521 if (fsync (mbfi
) < 0)
523 pop_command ("QUIT");
524 pfatal_and_delete (outfile
);
527 if (close (mbfi
) == -1)
529 pop_command ("QUIT");
530 pfatal_and_delete (outfile
);
533 for (i
= 1; i
<= nmsgs
; i
++)
535 if (pop_command ("DELE %d", i
) == NOTOK
)
537 /* Better to ignore this failure. */
541 pop_command ("QUIT");
548 register struct hostent
*hp
;
549 register struct servent
*sp
;
550 int lport
= IPPORT_RESERVED
- 1;
551 struct sockaddr_in sin
;
554 hp
= gethostbyname (host
);
557 sprintf (Errmsg
, "MAILHOST unknown: %s", host
);
561 sp
= getservbyname ("pop", "tcp");
564 strcpy (Errmsg
, "tcp/pop: unknown service");
568 sin
.sin_family
= hp
->h_addrtype
;
569 bcopy (hp
->h_addr
, (char *)&sin
.sin_addr
, hp
->h_length
);
570 sin
.sin_port
= sp
->s_port
;
571 s
= rresvport (&lport
);
574 sprintf (Errmsg
, "error creating socket: %s", get_errmsg ());
578 if (connect (s
, (char *)&sin
, sizeof sin
) < 0)
580 sprintf (Errmsg
, "error during connect: %s", get_errmsg ());
585 sfi
= fdopen (s
, "r");
586 sfo
= fdopen (s
, "w");
587 if (sfi
== NULL
|| sfo
== NULL
)
589 sprintf (Errmsg
, "error in fdopen: %s", get_errmsg ());
597 pop_command (fmt
, a
, b
, c
, d
)
603 sprintf (buf
, fmt
, a
, b
, c
, d
);
605 if (debug
) fprintf (stderr
, "---> %s\n", buf
);
606 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
608 if (getline (buf
, sizeof buf
, sfi
) != OK
)
610 strcpy (Errmsg
, buf
);
615 fprintf (stderr
, "<--- %s\n", buf
);
618 strcpy (Errmsg
, buf
);
628 pop_stat (nmsgs
, nbytes
)
634 fprintf (stderr
, "---> STAT\n");
635 if (putline ("STAT", Errmsg
, sfo
) == NOTOK
)
638 if (getline (buf
, sizeof buf
, sfi
) != OK
)
640 strcpy (Errmsg
, buf
);
644 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
647 strcpy (Errmsg
, buf
);
652 sscanf (buf
, "+OK %d %d", nmsgs
, nbytes
);
657 pop_retr (msgno
, action
, arg
)
662 sprintf (buf
, "RETR %d", msgno
);
663 if (debug
) fprintf (stderr
, "%s\n", buf
);
664 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
666 if (getline (buf
, sizeof buf
, sfi
) != OK
)
668 strcpy (Errmsg
, buf
);
674 switch (multiline (buf
, sizeof buf
, sfi
))
682 strcpy (Errmsg
, buf
);
697 while (--n
> 0 && (c
= fgetc (f
)) != EOF
)
698 if ((*p
++ = c
) == '\n') break;
702 strcpy (buf
, "error on connection");
706 if (c
== EOF
&& p
== buf
)
708 strcpy (buf
, "connection closed by foreign host");
713 if (*--p
== '\n') *p
= NULL
;
714 if (*--p
== '\r') *p
= NULL
;
718 multiline (buf
, n
, f
)
723 if (getline (buf
, n
, f
) != OK
)
727 if (*(buf
+1) == NULL
)
738 extern int errno
, sys_nerr
;
739 extern char *sys_errlist
[];
742 if (errno
< sys_nerr
)
743 s
= sys_errlist
[errno
];
749 putline (buf
, err
, f
)
754 fprintf (f
, "%s\r\n", buf
);
758 strcpy (err
, "lost connection");
764 mbx_write (line
, mbf
)
772 mbx_delimit_begin (mbf
)
775 fputs ("\f\n0, unseen,,\n", mbf
);
778 mbx_delimit_end (mbf
)
784 #endif /* MAIL_USE_POP */