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 (!bcmp (inname
, "po:", 3))
145 int status
; char *user
;
147 user
= (char *) rindex (inname
, ':') + 1;
148 status
= popmail (user
, outname
);
153 #endif /* MAIL_USE_POP */
155 /* Check access to input file. */
156 if (access (inname
, R_OK
| W_OK
) != 0)
157 pfatal_with_name (inname
);
159 #ifndef MAIL_USE_MMDF
160 #ifndef MAIL_USE_FLOCK
161 /* Use a lock file named /usr/spool/mail/$USER.lock:
162 If it exists, the mail file is locked. */
163 /* Note: this locking mechanism is *required* by the mailer
164 (on systems which use it) to prevent loss of mail.
166 On systems that use a lock file, extracting the mail without locking
167 WILL occasionally cause loss of mail due to timing errors!
169 So, if creation of the lock file fails
170 due to access permission on /usr/spool/mail,
171 you simply MUST change the permission
172 and/or make movemail a setgid program
173 so it can create lock files properly.
175 You might also wish to verify that your system is one
176 which uses lock files for this purpose. Some systems use other methods.
178 If your system uses the `flock' system call for mail locking,
179 define MAIL_USE_FLOCK in config.h or the s-*.h file
180 and recompile movemail. If the s- file for your system
181 should define MAIL_USE_FLOCK but does not, send a bug report
182 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
184 lockname
= concat (inname
, ".lock", "");
185 tempname
= strcpy (xmalloc (strlen (inname
)+1), inname
);
186 p
= tempname
+ strlen (tempname
);
187 while (p
!= tempname
&& p
[-1] != '/')
190 strcpy (p
, "EXXXXXX");
196 /* Create the lock file, but not under the lock file name. */
197 /* Give up if cannot do that. */
198 desc
= open (tempname
, O_WRONLY
| O_CREAT
, 0666);
200 pfatal_with_name ("lock file--see source file etc/movemail.c");
203 tem
= link (tempname
, lockname
);
209 /* If lock file is a minute old, unlock it. */
210 if (stat (lockname
, &st
) >= 0)
213 if (st
.st_ctime
< now
- 60)
218 delete_lockname
= lockname
;
219 #endif /* not MAIL_USE_FLOCK */
221 #ifdef MAIL_USE_FLOCK
222 indesc
= open (inname
, O_RDWR
);
223 #else /* if not MAIL_USE_FLOCK */
224 indesc
= open (inname
, O_RDONLY
);
225 #endif /* not MAIL_USE_FLOCK */
226 #else /* MAIL_USE_MMDF */
227 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
228 #endif /* MAIL_USE_MMDF */
231 pfatal_with_name (inname
);
233 #if defined (BSD) || defined (XENIX)
234 /* In case movemail is setuid to root, make sure the user can
235 read the output file. */
236 /* This is desirable for all systems
237 but I don't want to assume all have the umask system call */
238 umask (umask (0) & 0333);
239 #endif /* BSD or Xenix */
240 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
242 pfatal_with_name (outname
);
243 #ifdef MAIL_USE_FLOCK
245 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
247 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
249 #endif /* MAIL_USE_FLOCK */
256 nread
= read (indesc
, buf
, sizeof buf
);
257 if (nread
!= write (outdesc
, buf
, nread
))
259 int saved_errno
= errno
;
262 pfatal_with_name (outname
);
264 if (nread
< sizeof buf
)
270 if (fsync (outdesc
) < 0)
271 pfatal_and_delete (outname
);
274 /* Check to make sure no errors before we zap the inbox. */
275 if (close (outdesc
) != 0)
276 pfatal_and_delete (outname
);
278 #ifdef MAIL_USE_FLOCK
279 #if defined (STRIDE) || defined (XENIX)
280 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
281 close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
283 ftruncate (indesc
, 0L);
284 #endif /* STRIDE or XENIX */
285 #endif /* MAIL_USE_FLOCK */
288 lk_close (indesc
, 0, 0, 0);
293 #ifndef MAIL_USE_FLOCK
294 /* Delete the input file; if we can't, at least get rid of its contents. */
295 #ifdef MAIL_UNLINK_SPOOL
296 /* This is generally bad to do, because it destroys the permissions
297 that were set on the file. Better to just empty the file. */
298 if (unlink (inname
) < 0 && errno
!= ENOENT
)
299 #endif /* MAIL_UNLINK_SPOOL */
300 creat (inname
, 0600);
301 #ifndef MAIL_USE_MMDF
303 #endif /* not MAIL_USE_MMDF */
304 #endif /* not MAIL_USE_FLOCK */
308 /* Print error message and exit. */
314 unlink (delete_lockname
);
319 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
324 printf ("movemail: ");
329 pfatal_with_name (name
)
332 extern int errno
, sys_nerr
;
333 extern char *sys_errlist
[];
336 if (errno
< sys_nerr
)
337 s
= concat ("", sys_errlist
[errno
], " for %s");
339 s
= "cannot open %s";
343 pfatal_and_delete (name
)
346 extern int errno
, sys_nerr
;
347 extern char *sys_errlist
[];
350 if (errno
< sys_nerr
)
351 s
= concat ("", sys_errlist
[errno
], " for %s");
353 s
= "cannot open %s";
359 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
365 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
366 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
369 strcpy (result
+ len1
, s2
);
370 strcpy (result
+ len1
+ len2
, s3
);
371 *(result
+ len1
+ len2
+ len3
) = 0;
376 /* Like malloc but get fatal error if memory is exhausted. */
382 char *result
= malloc (size
);
384 fatal ("virtual memory exhausted", 0);
388 /* This is the guts of the interface to the Post Office Protocol. */
392 #include <sys/socket.h>
393 #include <netinet/in.h>
400 /* Cancel substitutions made by config.h for Emacs. */
416 static int debug
= 0;
422 popmail (user
, outfile
)
432 struct passwd
*pw
= (struct passwd
*) getpwuid (getuid ());
434 fatal ("cannot determine user name");
436 host
= getenv ("MAILHOST");
439 fatal ("no MAILHOST defined");
442 if (pop_init (host
) == NOTOK
)
447 if (getline (response
, sizeof response
, sfi
) != OK
)
452 if (pop_command ("USER %s", user
) == NOTOK
453 || pop_command ("RPOP %s", pw
->pw_name
) == NOTOK
)
455 pop_command ("QUIT");
459 if (pop_stat (&nmsgs
, &nbytes
) == NOTOK
)
461 pop_command ("QUIT");
467 pop_command ("QUIT");
471 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
474 pop_command ("QUIT");
475 pfatal_and_delete (outfile
);
477 fchown (mbfi
, getuid (), -1);
479 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
481 pop_command ("QUIT");
482 pfatal_and_delete (outfile
);
485 for (i
= 1; i
<= nmsgs
; i
++)
487 mbx_delimit_begin (mbf
);
488 if (pop_retr (i
, mbx_write
, mbf
) != OK
)
490 pop_command ("QUIT");
495 mbx_delimit_end (mbf
);
499 if (fsync (mbfi
) < 0)
501 pop_command ("QUIT");
502 pfatal_and_delete (outfile
);
505 if (close (mbfi
) == -1)
507 pop_command ("QUIT");
508 pfatal_and_delete (outfile
);
511 for (i
= 1; i
<= nmsgs
; i
++)
513 if (pop_command ("DELE %d", i
) == NOTOK
)
515 /* Better to ignore this failure. */
519 pop_command ("QUIT");
526 register struct hostent
*hp
;
527 register struct servent
*sp
;
528 int lport
= IPPORT_RESERVED
- 1;
529 struct sockaddr_in sin
;
532 hp
= gethostbyname (host
);
535 sprintf (Errmsg
, "MAILHOST unknown: %s", host
);
539 sp
= getservbyname ("pop", "tcp");
542 strcpy (Errmsg
, "tcp/pop: unknown service");
546 sin
.sin_family
= hp
->h_addrtype
;
547 bcopy (hp
->h_addr
, (char *)&sin
.sin_addr
, hp
->h_length
);
548 sin
.sin_port
= sp
->s_port
;
549 s
= rresvport (&lport
);
552 sprintf (Errmsg
, "error creating socket: %s", get_errmsg ());
556 if (connect (s
, (char *)&sin
, sizeof sin
) < 0)
558 sprintf (Errmsg
, "error during connect: %s", get_errmsg ());
563 sfi
= fdopen (s
, "r");
564 sfo
= fdopen (s
, "w");
565 if (sfi
== NULL
|| sfo
== NULL
)
567 sprintf (Errmsg
, "error in fdopen: %s", get_errmsg ());
575 pop_command (fmt
, a
, b
, c
, d
)
581 sprintf (buf
, fmt
, a
, b
, c
, d
);
583 if (debug
) fprintf (stderr
, "---> %s\n", buf
);
584 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
586 if (getline (buf
, sizeof buf
, sfi
) != OK
)
588 strcpy (Errmsg
, buf
);
593 fprintf (stderr
, "<--- %s\n", buf
);
596 strcpy (Errmsg
, buf
);
606 pop_stat (nmsgs
, nbytes
)
612 fprintf (stderr
, "---> STAT\n");
613 if (putline ("STAT", Errmsg
, sfo
) == NOTOK
)
616 if (getline (buf
, sizeof buf
, sfi
) != OK
)
618 strcpy (Errmsg
, buf
);
622 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
625 strcpy (Errmsg
, buf
);
630 sscanf (buf
, "+OK %d %d", nmsgs
, nbytes
);
635 pop_retr (msgno
, action
, arg
)
640 sprintf (buf
, "RETR %d", msgno
);
641 if (debug
) fprintf (stderr
, "%s\n", buf
);
642 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
644 if (getline (buf
, sizeof buf
, sfi
) != OK
)
646 strcpy (Errmsg
, buf
);
652 switch (multiline (buf
, sizeof buf
, sfi
))
660 strcpy (Errmsg
, buf
);
675 while (--n
> 0 && (c
= fgetc (f
)) != EOF
)
676 if ((*p
++ = c
) == '\n') break;
680 strcpy (buf
, "error on connection");
684 if (c
== EOF
&& p
== buf
)
686 strcpy (buf
, "connection closed by foreign host");
691 if (*--p
== '\n') *p
= NULL
;
692 if (*--p
== '\r') *p
= NULL
;
696 multiline (buf
, n
, f
)
701 if (getline (buf
, n
, f
) != OK
)
705 if (*(buf
+1) == NULL
)
716 extern int errno
, sys_nerr
;
717 extern char *sys_errlist
[];
720 if (errno
< sys_nerr
)
721 s
= sys_errlist
[errno
];
727 putline (buf
, err
, f
)
732 fprintf (f
, "%s\r\n", buf
);
736 strcpy (err
, "lost connection");
742 mbx_write (line
, mbf
)
750 mbx_delimit_begin (mbf
)
753 fputs ("\f\n0, unseen,,\n", mbf
);
756 mbx_delimit_end (mbf
)
762 #endif /* MAIL_USE_POP */