]>
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 distributed in the hope that it will be useful,
8 but without any warranty. No author or distributor
9 accepts responsibility to anyone for the consequences of using it
10 or for whether it serves any particular purpose or works at all,
11 unless he says so in writing.
13 Everyone is granted permission to copy, modify and redistribute
14 GNU Emacs, but only under the conditions described in the
15 document "GNU Emacs copying permission notice". An exact copy
16 of the document is supposed to have been given to you along with
17 GNU Emacs so that you can know how you may redistribute it all.
18 It should be in a file named COPYING. Among other things, the
19 copyright notice and this notice must be preserved on all copies. */
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 input and output file. */
108 if (access (inname
, R_OK
| W_OK
) != 0)
109 pfatal_with_name (inname
);
110 if (access (outname
, F_OK
) == 0 && access (outname
, W_OK
) != 0)
111 pfatal_with_name (outname
);
113 /* Also check that outname's directory is writeable to the real uid. */
115 char *buf
= (char *) malloc (strlen (outname
) + 1);
117 strcpy (buf
, outname
);
118 p
= buf
+ strlen (buf
);
119 while (p
> buf
&& p
[-1] != '/')
123 if (access (buf
, W_OK
) != 0)
124 pfatal_with_name (buf
);
129 if (!bcmp (inname
, "po:", 3))
131 int status
; char *user
;
133 user
= (char *) rindex (inname
, ':') + 1;
134 status
= popmail (user
, outname
);
139 #endif /* MAIL_USE_POP */
141 #ifndef MAIL_USE_MMDF
142 #ifndef MAIL_USE_FLOCK
143 /* Use a lock file named /usr/spool/mail/$USER.lock:
144 If it exists, the mail file is locked. */
145 lockname
= concat (inname
, ".lock", "");
146 strcpy (tempname
, inname
);
147 p
= tempname
+ strlen (tempname
);
148 while (p
!= tempname
&& p
[-1] != '/')
151 strcpy (p
, "EXXXXXX");
153 (void) unlink (tempname
);
157 /* Create the lock file, but not under the lock file name. */
158 /* Give up if cannot do that. */
159 desc
= open (tempname
, O_WRONLY
| O_CREAT
, 0666);
161 pfatal_with_name (concat ("temporary file \"", tempname
, "\""));
164 tem
= link (tempname
, lockname
);
165 (void) unlink (tempname
);
170 /* If lock file is a minute old, unlock it. */
171 if (stat (lockname
, &st
) >= 0)
174 if (st
.st_ctime
< now
- 60)
175 (void) unlink (lockname
);
179 delete_lockname
= lockname
;
180 #endif /* not MAIL_USE_FLOCK */
182 #ifdef MAIL_USE_FLOCK
183 indesc
= open (inname
, O_RDWR
);
184 #else /* if not MAIL_USE_FLOCK */
185 indesc
= open (inname
, O_RDONLY
);
186 #endif /* not MAIL_USE_FLOCK */
187 #else /* MAIL_USE_MMDF */
188 indesc
= lk_open (inname
, O_RDONLY
, 0, 0, 10);
189 #endif /* MAIL_USE_MMDF */
192 pfatal_with_name (inname
);
194 #if defined(BSD) || defined(XENIX)
195 /* In case movemail is setuid to root, make sure the user can
196 read the output file. */
197 /* This is desirable for all systems
198 but I don't want to assume all have the umask system call */
199 umask (umask (0) & 0333);
200 #endif /* BSD or Xenix */
201 outdesc
= open (outname
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
203 pfatal_with_name (outname
);
204 #ifdef MAIL_USE_FLOCK
206 if (locking (indesc
, LK_RLCK
, 0L) < 0) pfatal_with_name (inname
);
208 if (flock (indesc
, LOCK_EX
) < 0) pfatal_with_name (inname
);
210 #endif /* MAIL_USE_FLOCK */
214 nread
= read (indesc
, buf
, sizeof buf
);
215 if (nread
!= write (outdesc
, buf
, nread
))
217 int saved_errno
= errno
;
218 (void) unlink (outname
);
220 pfatal_with_name (outname
);
222 if (nread
< sizeof buf
)
230 /* Check to make sure no errors before we zap the inbox. */
231 if (close (outdesc
) != 0)
233 int saved_errno
= errno
;
234 (void) unlink (outname
);
236 pfatal_with_name (outname
);
239 #ifdef MAIL_USE_FLOCK
240 #if defined(STRIDE) || defined(XENIX)
241 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
242 (void) close (open (inname
, O_CREAT
| O_TRUNC
| O_RDWR
, 0666));
244 (void) ftruncate (indesc
, 0L);
245 #endif /* STRIDE or XENIX */
246 #endif /* MAIL_USE_FLOCK */
249 lk_close (indesc
, 0, 0, 0);
254 #ifndef MAIL_USE_FLOCK
255 /* Delete the input file; if we can't, at least get rid of its contents. */
256 if (unlink (inname
) < 0)
258 creat (inname
, 0666);
259 #ifndef MAIL_USE_MMDF
261 #endif /* not MAIL_USE_MMDF */
262 #endif /* not MAIL_USE_FLOCK */
266 /* Print error message and exit. */
272 unlink (delete_lockname
);
277 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
282 printf ("movemail: ");
287 pfatal_with_name (name
)
290 extern int errno
, sys_nerr
;
291 extern char *sys_errlist
[];
294 if (errno
< sys_nerr
)
295 s
= concat ("", sys_errlist
[errno
], " for %s");
297 s
= "cannot open %s";
301 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
307 int len1
= strlen (s1
), len2
= strlen (s2
), len3
= strlen (s3
);
308 char *result
= (char *) xmalloc (len1
+ len2
+ len3
+ 1);
311 strcpy (result
+ len1
, s2
);
312 strcpy (result
+ len1
+ len2
, s3
);
313 *(result
+ len1
+ len2
+ len3
) = 0;
318 /* Like malloc but get fatal error if memory is exhausted. */
324 int result
= malloc (size
);
326 fatal ("virtual memory exhausted", 0);
330 /* This is the guts of the interface to the Post Office Protocol. */
334 #include <sys/socket.h>
335 #include <netinet/in.h>
341 /* Cancel substitutions made by config.h for Emacs. */
357 static int debug
= 0;
359 popmail(user
, outfile
)
373 host
= getenv("MAILHOST");
375 fatal("no MAILHOST defined");
378 if (pop_init(host
) == NOTOK
) {
383 if (getline(response
, sizeof response
, sfi
) != OK
) {
388 if (pop_command("USER %s", user
) == NOTOK
||
389 pop_command("RPOP %s", user
) == NOTOK
) {
395 if (pop_stat(&nmsgs
, &nbytes
) == NOTOK
) {
407 mbfi
= open (outfile
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
411 error("Error in open: %s, %s", get_errmsg(), outfile
);
414 fchown(mbfi
, getuid(), -1);
416 if ((mbf
= fdopen(mbfi
, "w")) == NULL
)
419 error("Error in fdopen: %s", get_errmsg());
425 for (i
= 1; i
<= nmsgs
; i
++) {
426 mbx_delimit_begin(mbf
);
427 if (pop_retr(i
, mbx_write
, mbf
) != OK
) {
433 mbx_delimit_end(mbf
);
437 for (i
= 1; i
<= nmsgs
; i
++) {
438 if (pop_command("DELE %d", i
) == NOTOK
) {
454 register struct hostent
*hp
;
455 register struct servent
*sp
;
456 int lport
= IPPORT_RESERVED
- 1;
457 struct sockaddr_in sin
;
461 hp
= gethostbyname(host
);
463 sprintf(Errmsg
, "MAILHOST unknown: %s", host
);
467 sp
= getservbyname("pop", "tcp");
469 strcpy(Errmsg
, "tcp/pop: unknown service");
473 sin
.sin_family
= hp
->h_addrtype
;
474 bcopy(hp
->h_addr
, (char *)&sin
.sin_addr
, hp
->h_length
);
475 sin
.sin_port
= sp
->s_port
;
476 s
= rresvport(&lport
);
478 sprintf(Errmsg
, "error creating socket: %s", get_errmsg());
482 if (connect(s
, (char *)&sin
, sizeof sin
) < 0) {
483 sprintf(Errmsg
, "error during connect: %s", get_errmsg());
488 sfi
= fdopen(s
, "r");
489 sfo
= fdopen(s
, "w");
490 if (sfi
== NULL
|| sfo
== NULL
) {
491 sprintf(Errmsg
, "error in fdopen: %s", get_errmsg());
499 pop_command(fmt
, a
, b
, c
, d
)
505 sprintf(buf
, fmt
, a
, b
, c
, d
);
507 if (debug
) fprintf(stderr
, "---> %s\n", buf
);
508 if (putline(buf
, Errmsg
, sfo
) == NOTOK
) return(NOTOK
);
510 if (getline(buf
, sizeof buf
, sfi
) != OK
) {
515 if (debug
) fprintf(stderr
, "<--- %s\n", buf
);
525 pop_stat(nmsgs
, nbytes
)
530 if (debug
) fprintf(stderr
, "---> STAT\n");
531 if (putline("STAT", Errmsg
, sfo
) == NOTOK
) return(NOTOK
);
533 if (getline(buf
, sizeof buf
, sfi
) != OK
) {
538 if (debug
) fprintf(stderr
, "<--- %s\n", buf
);
543 sscanf(buf
, "+OK %d %d", nmsgs
, nbytes
);
548 pop_retr(msgno
, action
, arg
)
553 sprintf(buf
, "RETR %d", msgno
);
554 if (debug
) fprintf(stderr
, "%s\n", buf
);
555 if (putline(buf
, Errmsg
, sfo
) == NOTOK
) return(NOTOK
);
557 if (getline(buf
, sizeof buf
, sfi
) != OK
) {
563 switch (multiline(buf
, sizeof buf
, sfi
)) {
585 while (--n
> 0 && (c
= fgetc(f
)) != EOF
)
586 if ((*p
++ = c
) == '\n') break;
589 strcpy(buf
, "error on connection");
593 if (c
== EOF
&& p
== buf
) {
594 strcpy(buf
, "connection closed by foreign host");
599 if (*--p
== '\n') *p
= NULL
;
600 if (*--p
== '\r') *p
= NULL
;
609 if (getline(buf
, n
, f
) != OK
) return (NOTOK
);
611 if (*(buf
+1) == NULL
) {
623 extern int errno
, sys_nerr
;
624 extern char *sys_errlist
[];
627 if (errno
< sys_nerr
)
628 s
= sys_errlist
[errno
];
639 fprintf(f
, "%s\r\n", buf
);
642 strcpy(err
, "lost connection");
656 mbx_delimit_begin(mbf
)
659 fputs("\f\n0,unseen,,\n", mbf
);
668 #endif /* MAIL_USE_POP */