]>
code.delx.au - gnu-emacs/blob - lib-src/movemail.c
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 /* Note: this locking mechanism is *required* by the mailer
148 (on systems which use it) to prevent loss of mail.
150 On systems that use a lock file, extracting the mail without locking
151 WILL occasionally cause loss of mail due to timing errors!
153 So, if creation of the lock file fails
154 due to access permission on /usr/spool/mail,
155 you simply MUST change the permission
156 and/or make movemail a setgid program
157 so it can create lock files properly.
159 You might also wish to verify that your system is one
160 which uses lock files for this purpose. Some systems use other methods.
162 If your system uses the `flock' system call for mail locking,
163 define MAIL_USE_FLOCK in config.h or the s-*.h file
164 and recompile movemail. If the s- file for your system
165 should define MAIL_USE_FLOCK but does not, send a bug report
166 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
168 lockname
= concat (inname
, ".lock", "");
169 strcpy (tempname
, inname
);
170 p
= tempname
+ strlen (tempname
);
171 while (p
!= tempname
&& p
[-1] != '/')
174 strcpy (p
, "EXXXXXX");
176 (void) unlink (tempname
);
180 /* Create the lock file, but not under the lock file name. */
181 /* Give up if cannot do that. */
182 desc
= open (tempname
, O_WRONLY
| O_CREAT
, 0666);
184 pfatal_with_name ("lock file--see source file etc/movemail.c");
187 tem
= link (tempname
, lockname
);
188 (void) unlink (tempname
);
193 /* If lock file is a minute old, unlock it. */
194 if (stat (lockname
, &st
) >= 0)
197 if (st
.st_ctime
< now
- 60)
198 (void) unlink (lockname
);
202 delete_lockname
= lockname
;
203 #endif /* not MAIL_USE_FLOCK */
205 #ifdef MAIL_USE_FLOCK
206 indesc
= open (inname
, O_RDWR
);
207 #else /* if not MAIL_USE_FLOCK */
208 indesc
= open (inname
, O_RDONLY
);
209 #endif /* not MAIL_USE_FLOCK */
210 #else /* MAIL_USE_MMDF */
211 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
212 #endif /* MAIL_USE_MMDF */
215 pfatal_with_name (inname
);
217 #if defined(BSD) || defined(XENIX)
218 /* In case movemail is setuid to root, make sure the user can
219 read the output file. */
220 /* This is desirable for all systems
221 but I don't want to assume all have the umask system call */
222 umask (umask (0) & 0333);
223 #endif /* BSD or Xenix */
224 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
226 pfatal_with_name (outname
);
227 #ifdef MAIL_USE_FLOCK
229 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
231 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
233 #endif /* MAIL_USE_FLOCK */
237 nread
= read (indesc
, buf
, sizeof buf
);
238 if (nread
!= write (outdesc
, buf
, nread
))
240 int saved_errno
= errno
;
241 (void) unlink (outname
);
243 pfatal_with_name (outname
);
245 if (nread
< sizeof buf
)
253 /* Check to make sure no errors before we zap the inbox. */
254 if (close (outdesc
) != 0)
256 int saved_errno
= errno
;
257 (void) unlink (outname
);
259 pfatal_with_name (outname
);
262 #ifdef MAIL_USE_FLOCK
263 #if defined(STRIDE) || defined(XENIX)
264 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
265 (void) close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
267 (void) ftruncate (indesc
, 0L);
268 #endif /* STRIDE or XENIX */
269 #endif /* MAIL_USE_FLOCK */
272 lk_close (indesc
, 0, 0, 0);
277 #ifndef MAIL_USE_FLOCK
278 /* Delete the input file; if we can't, at least get rid of its contents. */
279 if (unlink (inname
) < 0)
281 creat (inname
, 0666);
282 #ifndef MAIL_USE_MMDF
284 #endif /* not MAIL_USE_MMDF */
285 #endif /* not MAIL_USE_FLOCK */
289 /* Print error message and exit. */
295 unlink (delete_lockname
);
300 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
305 printf ("movemail: ");
310 pfatal_with_name (name
)
313 extern int errno
, sys_nerr
;
314 extern char *sys_errlist
[];
317 if (errno
< sys_nerr
)
318 s
= concat ("", sys_errlist
[errno
], " for %s");
320 s
= "cannot open %s";
324 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
330 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
331 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
334 strcpy (result
+ len1
, s2
);
335 strcpy (result
+ len1
+ len2
, s3
);
336 *(result
+ len1
+ len2
+ len3
) = 0;
341 /* Like malloc but get fatal error if memory is exhausted. */
347 int result
= malloc (size
);
349 fatal ("virtual memory exhausted", 0);
353 /* This is the guts of the interface to the Post Office Protocol. */
357 #include <sys/socket.h>
358 #include <netinet/in.h>
364 /* Cancel substitutions made by config.h for Emacs. */
380 static int debug
= 0;
386 popmail (user
, outfile
)
397 host
= getenv ("MAILHOST");
400 fatal ("no MAILHOST defined");
403 if (pop_init (host
) == NOTOK
)
409 if (getline (response
, sizeof response
, sfi
) != OK
)
415 if (pop_command ("USER %s", user
) == NOTOK
416 || pop_command ("RPOP %s", user
) == NOTOK
)
419 pop_command ("QUIT");
423 if (pop_stat (&nmsgs
, &nbytes
) == NOTOK
)
426 pop_command ("QUIT");
432 pop_command ("QUIT");
436 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
439 pop_command ("QUIT");
440 error ("Error in open: %s, %s", get_errmsg (), outfile
);
443 fchown (mbfi
, getuid (), -1);
445 if ((mbf
= fdopen (mbfi
, "w")) == NULL
)
447 pop_command ("QUIT");
448 error ("Error in fdopen: %s", get_errmsg ());
454 for (i
= 1; i
<= nmsgs
; i
++)
456 mbx_delimit_begin (mbf
);
457 if (pop_retr (i
, mbx_write
, mbf
) != OK
)
460 pop_command ("QUIT");
464 mbx_delimit_end (mbf
);
468 for (i
= 1; i
<= nmsgs
; i
++)
470 if (pop_command ("DELE %d", i
) == NOTOK
)
473 pop_command ("QUIT");
479 pop_command ("QUIT");
487 register struct hostent
*hp
;
488 register struct servent
*sp
;
489 int lport
= IPPORT_RESERVED
- 1;
490 struct sockaddr_in sin
;
493 hp
= gethostbyname (host
);
496 sprintf (Errmsg
, "MAILHOST unknown: %s", host
);
500 sp
= getservbyname ("pop", "tcp");
503 strcpy (Errmsg
, "tcp/pop: unknown service");
507 sin
.sin_family
= hp
->h_addrtype
;
508 bcopy (hp
->h_addr
, (char *)&sin
.sin_addr
, hp
->h_length
);
509 sin
.sin_port
= sp
->s_port
;
510 s
= rresvport (&lport
);
513 sprintf (Errmsg
, "error creating socket: %s", get_errmsg ());
517 if (connect (s
, (char *)&sin
, sizeof sin
) < 0)
519 sprintf (Errmsg
, "error during connect: %s", get_errmsg ());
524 sfi
= fdopen (s
, "r");
525 sfo
= fdopen (s
, "w");
526 if (sfi
== NULL
|| sfo
== NULL
)
528 sprintf (Errmsg
, "error in fdopen: %s", get_errmsg ());
536 pop_command (fmt
, a
, b
, c
, d
)
542 sprintf (buf
, fmt
, a
, b
, c
, d
);
544 if (debug
) fprintf (stderr
, "---> %s\n", buf
);
545 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
547 if (getline (buf
, sizeof buf
, sfi
) != OK
)
549 strcpy (Errmsg
, buf
);
553 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
556 strcpy (Errmsg
, buf
);
566 pop_stat (nmsgs
, nbytes
)
571 if (debug
) fprintf (stderr
, "---> STAT\n");
572 if (putline ("STAT", Errmsg
, sfo
) == NOTOK
) return NOTOK
;
574 if (getline (buf
, sizeof buf
, sfi
) != OK
)
576 strcpy (Errmsg
, buf
);
580 if (debug
) fprintf (stderr
, "<--- %s\n", buf
);
583 strcpy (Errmsg
, buf
);
588 sscanf (buf
, "+OK %d %d", nmsgs
, nbytes
);
593 pop_retr (msgno
, action
, arg
)
598 sprintf (buf
, "RETR %d", msgno
);
599 if (debug
) fprintf (stderr
, "%s\n", buf
);
600 if (putline (buf
, Errmsg
, sfo
) == NOTOK
) return NOTOK
;
602 if (getline (buf
, sizeof buf
, sfi
) != OK
)
604 strcpy (Errmsg
, buf
);
610 switch (multiline (buf
, sizeof buf
, sfi
))
618 strcpy (Errmsg
, buf
);
633 while (--n
> 0 && (c
= fgetc (f
)) != EOF
)
634 if ((*p
++ = c
) == '\n') break;
638 strcpy (buf
, "error on connection");
642 if (c
== EOF
&& p
== buf
)
644 strcpy (buf
, "connection closed by foreign host");
649 if (*--p
== '\n') *p
= NULL
;
650 if (*--p
== '\r') *p
= NULL
;
654 multiline (buf
, n
, f
)
659 if (getline (buf
, n
, f
) != OK
) return NOTOK
;
662 if (*(buf
+1) == NULL
)
677 extern int errno
, sys_nerr
;
678 extern char *sys_errlist
[];
681 if (errno
< sys_nerr
)
682 s
= sys_errlist
[errno
];
688 putline (buf
, err
, f
)
693 fprintf (f
, "%s\r\n", buf
);
697 strcpy (err
, "lost connection");
703 mbx_write (line
, mbf
)
711 mbx_delimit_begin (mbf
)
714 fputs ("\f\n0, unseen,,\n", mbf
);
717 mbx_delimit_end (mbf
)
723 #endif /* MAIL_USE_POP */