1 /* movemail foo bar -- move file foo to file bar,
2 locking file foo the way /bin/mail respects.
3 Copyright (C) 1986 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. */
22 * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
24 * Added POP (Post Office Protocol) service. When compiled -DPOP
25 * movemail will accept input filename arguments of the form
26 * "po:username". This will cause movemail to open a connection to
27 * a pop server running on $MAILHOST (environment variable). Movemail
28 * must be setuid to root in order to work with POP.
30 * New module: popmail.c
32 * main - added code within #ifdef MAIL_USE_POP; added setuid(getuid())
34 * New routines in movemail.c:
35 * get_errmsg - return pointer to system error message
39 #include <sys/types.h>
43 #define NO_SHORTNAMES /* Tell config not to load remap.h */
44 #include "../src/config.h"
58 #include <sys/locking.h>
62 extern int lk_open (), lk_close ();
65 /* Cancel substitutions made by config.h for Emacs. */
74 /* Nonzero means this is name of a lock file to delete on fatal error. */
75 char *delete_lockname
;
81 char *inname
, *outname
;
86 #ifndef MAIL_USE_FLOCK
93 #endif /* not MAIL_USE_FLOCK */
98 fatal ("two arguments required");
107 /* Check access to output file. */
108 if (access (outname
, F_OK
) == 0 && access (outname
, W_OK
) != 0)
109 pfatal_with_name (outname
);
111 /* Also check that outname's directory is writeable to the real uid. */
113 char *buf
= (char *) malloc (strlen (outname
) + 1);
115 strcpy (buf
, outname
);
116 p
= buf
+ strlen (buf
);
117 while (p
> buf
&& p
[-1] != '/')
121 if (access (buf
, W_OK
) != 0)
122 pfatal_with_name (buf
);
127 if (!bcmp (inname
, "po:", 3))
129 int status
; char *user
;
131 user
= (char *) rindex (inname
, ':') + 1;
132 status
= popmail (user
, outname
);
137 #endif /* MAIL_USE_POP */
139 /* Check access to input file. */
140 if (access (inname
, R_OK
| W_OK
) != 0)
141 pfatal_with_name (inname
);
143 #ifndef MAIL_USE_MMDF
144 #ifndef MAIL_USE_FLOCK
145 /* Use a lock file named /usr/spool/mail/$USER.lock:
146 If it exists, the mail file is locked. */
147 lockname
= concat (inname
, ".lock", "");
148 strcpy (tempname
, inname
);
149 p
= tempname
+ strlen (tempname
);
150 while (p
!= tempname
&& p
[-1] != '/')
153 strcpy (p
, "EXXXXXX");
155 (void) unlink (tempname
);
159 /* Create the lock file, but not under the lock file name. */
160 /* Give up if cannot do that. */
161 desc
= open (tempname
, O_WRONLY
| O_CREAT
, 0666);
163 pfatal_with_name (concat ("temporary file \"", tempname
, "\""));
166 tem
= link (tempname
, lockname
);
167 (void) unlink (tempname
);
172 /* If lock file is a minute old, unlock it. */
173 if (stat (lockname
, &st
) >= 0)
176 if (st
.st_ctime
< now
- 60)
177 (void) unlink (lockname
);
181 delete_lockname
= lockname
;
182 #endif /* not MAIL_USE_FLOCK */
184 #ifdef MAIL_USE_FLOCK
185 indesc
= open (inname
, O_RDWR
);
186 #else /* if not MAIL_USE_FLOCK */
187 indesc
= open (inname
, O_RDONLY
);
188 #endif /* not MAIL_USE_FLOCK */
189 #else /* MAIL_USE_MMDF */
190 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
191 #endif /* MAIL_USE_MMDF */
194 pfatal_with_name (inname
);
196 #if defined(BSD) || defined(XENIX)
197 /* In case movemail is setuid to root, make sure the user can
198 read the output file. */
199 /* This is desirable for all systems
200 but I don't want to assume all have the umask system call */
201 umask (umask (0) & 0333);
202 #endif /* BSD or Xenix */
203 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
205 pfatal_with_name (outname
);
206 #ifdef MAIL_USE_FLOCK
208 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
210 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
212 #endif /* MAIL_USE_FLOCK */
216 nread
= read (indesc
, buf
, sizeof buf
);
217 if (nread
!= write (outdesc
, buf
, nread
))
219 int saved_errno
= errno
;
220 (void) unlink (outname
);
222 pfatal_with_name (outname
);
224 if (nread
< sizeof buf
)
232 /* Check to make sure no errors before we zap the inbox. */
233 if (close (outdesc
) != 0)
235 int saved_errno
= errno
;
236 (void) unlink (outname
);
238 pfatal_with_name (outname
);
241 #ifdef MAIL_USE_FLOCK
242 #if defined(STRIDE) || defined(XENIX)
243 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
244 (void) close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
246 (void) ftruncate (indesc
, 0L);
247 #endif /* STRIDE or XENIX */
248 #endif /* MAIL_USE_FLOCK */
251 lk_close (indesc
, 0, 0, 0);
256 #ifndef MAIL_USE_FLOCK
257 /* Delete the input file; if we can't, at least get rid of its contents. */
258 if (unlink (inname
) < 0)
260 creat (inname
, 0666);
261 #ifndef MAIL_USE_MMDF
263 #endif /* not MAIL_USE_MMDF */
264 #endif /* not MAIL_USE_FLOCK */
268 /* Print error message and exit. */
274 unlink (delete_lockname
);
279 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
284 printf ("movemail: ");
289 pfatal_with_name (name
)
292 extern int errno
, sys_nerr
;
293 extern char *sys_errlist
[];
296 if (errno
< sys_nerr
)
297 s
= concat ("", sys_errlist
[errno
], " for %s");
299 s
= "cannot open %s";
303 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
309 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
310 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
313 strcpy (result
+ len1
, s2
);
314 strcpy (result
+ len1
+ len2
, s3
);
315 *(result
+ len1
+ len2
+ len3
) = 0;
320 /* Like malloc but get fatal error if memory is exhausted. */
326 int result
= malloc (size
);
328 fatal ("virtual memory exhausted", 0);
332 /* This is the guts of the interface to the Post Office Protocol. */
336 #include <sys/socket.h>
337 #include <netinet/in.h>
343 /* Cancel substitutions made by config.h for Emacs. */
359 static int debug
= 0;
365 popmail (user
, outfile
)
376 host
= getenv ("MAILHOST");
379 fatal ("no MAILHOST defined");
382 if (pop_init (host
) == NOTOK
)
388 if (getline (response
, sizeof response
, sfi
) != OK
)
394 if (pop_command ("USER %s", user
) == NOTOK
395 || pop_command ("RPOP %s", user
) == NOTOK
)
398 pop_command ("QUIT");
402 if (pop_stat (&nmsgs
, &nbytes
) == NOTOK
)
405 pop_command ("QUIT");
411 pop_command ("QUIT");
415 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
418 pop_command ("QUIT");
419 error ("Error in open: %s, %s", get_errmsg (), outfile
);
422 fchown (mbfi
, getuid (), -1);
424 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
426 pop_command ("QUIT");
427 error ("Error in fdopen: %s", get_errmsg ());
433 for (i
= 1; i
<= nmsgs
; i
++)
435 mbx_delimit_begin (mbf
);
436 if (pop_retr (i
, mbx_write
, mbf
) != OK
)
439 pop_command ("QUIT");
443 mbx_delimit_end (mbf
);
447 for (i
= 1; i
<= nmsgs
; i
++)
449 if (pop_command ("DELE %d", i
) == NOTOK
)
452 pop_command ("QUIT");
458 pop_command ("QUIT");
466 register struct hostent
*hp
;
467 register struct servent
*sp
;
468 int lport
= IPPORT_RESERVED
- 1;
469 struct sockaddr_in sin
;
472 hp
= gethostbyname (host
);
475 sprintf (Errmsg
, "MAILHOST unknown: %s", host
);
479 sp
= getservbyname ("pop", "tcp");
482 strcpy (Errmsg
, "tcp/pop: unknown service");
486 sin
.sin_family
= hp
->h_addrtype
;
487 bcopy (hp
->h_addr
, (char *)&sin
.sin_addr
, hp
->h_length
);
488 sin
.sin_port
= sp
->s_port
;
489 s
= rresvport (&lport
);
492 sprintf (Errmsg
, "error creating socket: %s", get_errmsg ());
496 if (connect (s
, (char *)&sin
, sizeof sin
) < 0)
498 sprintf (Errmsg
, "error during connect: %s", get_errmsg ());
503 sfi
= fdopen (s
, "r");
504 sfo
= fdopen (s
, "w");
505 if (sfi
== NULL
|| sfo
== NULL
)
507 sprintf (Errmsg
, "error in fdopen: %s", get_errmsg ());
515 pop_command (fmt
, a
, b
, c
, d
)
521 sprintf (buf
, fmt
, a
, b
, c
, d
);
523 if (debug
) fprintf (stderr
, "---> %s\n", buf
);
524 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
526 if (getline (buf
, sizeof buf
, sfi
) != OK
)
528 strcpy (Errmsg
, buf
);
532 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
535 strcpy (Errmsg
, buf
);
545 pop_stat (nmsgs
, nbytes
)
550 if (debug
) fprintf (stderr
, "---> STAT\n");
551 if (putline ("STAT", Errmsg
, sfo
) == NOTOK
) return NOTOK
;
553 if (getline (buf
, sizeof buf
, sfi
) != OK
)
555 strcpy (Errmsg
, buf
);
559 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
562 strcpy (Errmsg
, buf
);
567 sscanf (buf
, "+OK %d %d", nmsgs
, nbytes
);
572 pop_retr (msgno
, action
, arg
)
577 sprintf (buf
, "RETR %d", msgno
);
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
);
589 switch (multiline (buf
, sizeof buf
, sfi
))
597 strcpy (Errmsg
, buf
);
612 while (--n
> 0 && (c
= fgetc (f
)) != EOF
)
613 if ((*p
++ = c
) == '\n') break;
617 strcpy (buf
, "error on connection");
621 if (c
== EOF
&& p
== buf
)
623 strcpy (buf
, "connection closed by foreign host");
628 if (*--p
== '\n') *p
= NULL
;
629 if (*--p
== '\r') *p
= NULL
;
633 multiline (buf
, n
, f
)
638 if (getline (buf
, n
, f
) != OK
) return NOTOK
;
641 if (*(buf
+1) == NULL
)
656 extern int errno
, sys_nerr
;
657 extern char *sys_errlist
[];
660 if (errno
< sys_nerr
)
661 s
= sys_errlist
[errno
];
667 putline (buf
, err
, f
)
672 fprintf (f
, "%s\r\n", buf
);
676 strcpy (err
, "lost connection");
682 mbx_write (line
, mbf
)
690 mbx_delimit_begin (mbf
)
693 fputs ("\f\n0, unseen,,\n", mbf
);
696 mbx_delimit_end (mbf
)
702 #endif /* MAIL_USE_POP */