(rmail-preserve-inbox): New variable.
[bpt/emacs.git] / lib-src / movemail.c
CommitLineData
237e0016
RS
1/* movemail foo bar -- move file foo to file bar,
2 locking file foo the way /bin/mail respects.
7f75d5c6 3 Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
237e0016
RS
4
5This file is part of GNU Emacs.
6
93320c23
JA
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
39356651 9the Free Software Foundation; either version 2, or (at your option)
93320c23
JA
10any later version.
11
237e0016 12GNU Emacs is distributed in the hope that it will be useful,
93320c23
JA
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
237e0016 16
93320c23
JA
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
237e0016 21
63cf923d
RS
22/* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will
23 cause loss of mail* if you do it on a system that does not normally
24 use flock as its way of interlocking access to inbox files. The
25 setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the
26 system's own conventions. It is not a choice that is up to you.
08d0752f
RS
27
28 So, if your system uses lock files rather than flock, then the only way
29 you can get proper operation is to enable movemail to write lockfiles there.
30 This means you must either give that directory access modes
31 that permit everyone to write lockfiles in it, or you must make movemail
32 a setuid or setgid program. */
33
237e0016
RS
34/*
35 * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
36 *
88c40feb 37 * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP
237e0016
RS
38 * movemail will accept input filename arguments of the form
39 * "po:username". This will cause movemail to open a connection to
40 * a pop server running on $MAILHOST (environment variable). Movemail
41 * must be setuid to root in order to work with POP.
42 *
43 * New module: popmail.c
44 * Modified routines:
cfa191ff 45 * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ())
237e0016
RS
46 * after POP code.
47 * New routines in movemail.c:
48 * get_errmsg - return pointer to system error message
49 *
2e82e3c3
RS
50 * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies)
51 *
52 * Move all of the POP code into a separate file, "pop.c".
53 * Use strerror instead of get_errmsg.
54 *
237e0016
RS
55 */
56
3b9ee819
RS
57#define NO_SHORTNAMES /* Tell config not to load remap.h */
58#include <../src/config.h>
237e0016
RS
59#include <sys/types.h>
60#include <sys/stat.h>
61#include <sys/file.h>
e2f9d9af 62#include <stdio.h>
237e0016 63#include <errno.h>
8ca83cfd 64#include <../src/syswait.h>
2e82e3c3
RS
65#ifdef MAIL_USE_POP
66#include "pop.h"
67#endif
237e0016 68
91cf09ac
RS
69#ifdef MSDOS
70#undef access
71#endif /* MSDOS */
72
61946d67
RS
73#ifndef DIRECTORY_SEP
74#define DIRECTORY_SEP '/'
75#endif
76#ifndef IS_DIRECTORY_SEP
77#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
78#endif
79
7f75d5c6
RS
80#ifdef WINDOWSNT
81#undef access
82#undef unlink
83#define fork() 0
84#define sys_wait(var) (*(var) = 0)
85/* Unfortunately, Samba doesn't seem to properly lock Unix files even
86 though the locking call succeeds (and indeed blocks local access from
87 other NT programs). If you have direct file access using an NFS
88 client or something other than Samba, the locking call might work
89 properly - make sure it does before you enable this! */
90#define DISABLE_DIRECT_ACCESS
91#endif /* WINDOWSNT */
92
237e0016
RS
93#ifdef USG
94#include <fcntl.h>
95#include <unistd.h>
4ec9a77a
RS
96#ifndef F_OK
97#define F_OK 0
98#define X_OK 1
99#define W_OK 2
100#define R_OK 4
101#endif
237e0016
RS
102#endif /* USG */
103
29beb080
RS
104#ifdef HAVE_UNISTD_H
105#include <unistd.h>
106#endif
107
7f75d5c6 108#if defined (XENIX) || defined (WINDOWSNT)
237e0016
RS
109#include <sys/locking.h>
110#endif
111
63cf923d
RS
112#ifdef MAIL_USE_LOCKF
113#define MAIL_USE_SYSTEM_LOCK
114#endif
115
116#ifdef MAIL_USE_FLOCK
117#define MAIL_USE_SYSTEM_LOCK
118#endif
119
4293ba7f
RS
120#ifdef MAIL_USE_MMDF
121extern int lk_open (), lk_close ();
122#endif
123
a4deff3c
RS
124#if !defined (MAIL_USE_SYSTEM_LOCK) && !defined (MAIL_USE_MMDF) && \
125 defined (HAVE_LIBMAIL) && defined (HAVE_MAILLOCK_H)
126#include <maillock.h>
127/* We can't use maillock unless we know what directory system mail
128 files appear in. */
129#ifdef MAILDIR
130#define MAIL_USE_MAILLOCK
131static char *mail_spool_name ();
132#endif
133#endif
134
237e0016
RS
135/* Cancel substitutions made by config.h for Emacs. */
136#undef open
137#undef read
138#undef write
139#undef close
140
e97dd183 141#ifndef errno
237e0016 142extern int errno;
e97dd183 143#endif
e2f9d9af 144char *strerror ();
e2f9d9af
DM
145
146void fatal ();
147void error ();
148void pfatal_with_name ();
149void pfatal_and_delete ();
150char *concat ();
2583d6d7 151long *xmalloc ();
e2f9d9af
DM
152int popmail ();
153int pop_retr ();
154int mbx_write ();
155int mbx_delimit_begin ();
156int mbx_delimit_end ();
237e0016
RS
157
158/* Nonzero means this is name of a lock file to delete on fatal error. */
159char *delete_lockname;
160
e2f9d9af 161int
237e0016
RS
162main (argc, argv)
163 int argc;
164 char **argv;
165{
166 char *inname, *outname;
167 int indesc, outdesc;
237e0016 168 int nread;
8ca83cfd 169 WAITTYPE status;
237e0016 170
63cf923d 171#ifndef MAIL_USE_SYSTEM_LOCK
237e0016
RS
172 struct stat st;
173 long now;
174 int tem;
175 char *lockname, *p;
906ad89d 176 char *tempname;
237e0016 177 int desc;
63cf923d 178#endif /* not MAIL_USE_SYSTEM_LOCK */
237e0016 179
a4deff3c
RS
180#ifdef MAIL_USE_MAILLOCK
181 char *spool_name;
182#endif
183
237e0016
RS
184 delete_lockname = 0;
185
186 if (argc < 3)
e2f9d9af 187 {
7f75d5c6 188 fprintf (stderr, "Usage: movemail inbox destfile [POP-password]\n");
a4deff3c 189 exit (1);
e2f9d9af 190 }
237e0016
RS
191
192 inname = argv[1];
193 outname = argv[2];
194
4293ba7f
RS
195#ifdef MAIL_USE_MMDF
196 mmdf_init (argv[0]);
197#endif
198
af7bd34e
RS
199 if (*outname == 0)
200 fatal ("Destination file name is empty", 0);
201
b1ce62a8 202 /* Check access to output file. */
237e0016
RS
203 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
204 pfatal_with_name (outname);
205
8e6208c5 206 /* Also check that outname's directory is writable to the real uid. */
237e0016 207 {
91cf09ac 208 char *buf = (char *) xmalloc (strlen (outname) + 1);
e2f9d9af 209 char *p;
237e0016
RS
210 strcpy (buf, outname);
211 p = buf + strlen (buf);
7f75d5c6 212 while (p > buf && !IS_DIRECTORY_SEP (p[-1]))
237e0016
RS
213 *--p = 0;
214 if (p == buf)
215 *p++ = '.';
216 if (access (buf, W_OK) != 0)
217 pfatal_with_name (buf);
218 free (buf);
219 }
220
221#ifdef MAIL_USE_POP
12a0565a 222 if (!strncmp (inname, "po:", 3))
237e0016 223 {
b3112191 224 int status;
237e0016 225
7f75d5c6 226 status = popmail (inname + 3, outname, argc > 3 ? argv[3] : NULL);
237e0016
RS
227 exit (status);
228 }
229
cfa191ff 230 setuid (getuid ());
237e0016
RS
231#endif /* MAIL_USE_POP */
232
7f75d5c6
RS
233#ifndef DISABLE_DIRECT_ACCESS
234
b1ce62a8
RS
235 /* Check access to input file. */
236 if (access (inname, R_OK | W_OK) != 0)
237 pfatal_with_name (inname);
238
4293ba7f 239#ifndef MAIL_USE_MMDF
63cf923d 240#ifndef MAIL_USE_SYSTEM_LOCK
a4deff3c
RS
241#ifdef MAIL_USE_MAILLOCK
242 spool_name = mail_spool_name (inname);
243 if (! spool_name)
244#endif
237e0016 245 {
a4deff3c
RS
246 /* Use a lock file named after our first argument with .lock appended:
247 If it exists, the mail file is locked. */
248 /* Note: this locking mechanism is *required* by the mailer
249 (on systems which use it) to prevent loss of mail.
250
251 On systems that use a lock file, extracting the mail without locking
252 WILL occasionally cause loss of mail due to timing errors!
253
254 So, if creation of the lock file fails
255 due to access permission on the mail spool directory,
256 you simply MUST change the permission
257 and/or make movemail a setgid program
258 so it can create lock files properly.
259
260 You might also wish to verify that your system is one
261 which uses lock files for this purpose. Some systems use other methods.
262
263 If your system uses the `flock' system call for mail locking,
264 define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file
265 and recompile movemail. If the s- file for your system
266 should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report
267 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */
268
269 lockname = concat (inname, ".lock", "");
270 tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1);
271 strcpy (tempname, inname);
272 p = tempname + strlen (tempname);
273 while (p != tempname && !IS_DIRECTORY_SEP (p[-1]))
274 p--;
275 *p = 0;
276 strcpy (p, "EXXXXXX");
277 mktemp (tempname);
cfa191ff 278 unlink (tempname);
237e0016 279
a4deff3c 280 while (1)
237e0016 281 {
a4deff3c
RS
282 /* Create the lock file, but not under the lock file name. */
283 /* Give up if cannot do that. */
284 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666);
285 if (desc < 0)
286 {
287 char *message = (char *) xmalloc (strlen (tempname) + 50);
288 sprintf (message, "%s--see source file lib-src/movemail.c",
289 tempname);
290 pfatal_with_name (message);
291 }
292 close (desc);
293
294 tem = link (tempname, lockname);
295 unlink (tempname);
296 if (tem >= 0)
297 break;
298 sleep (1);
299
300 /* If lock file is five minutes old, unlock it.
301 Five minutes should be good enough to cope with crashes
302 and wedgitude, and long enough to avoid being fooled
303 by time differences between machines. */
304 if (stat (lockname, &st) >= 0)
305 {
306 now = time (0);
307 if (st.st_ctime < now - 300)
308 unlink (lockname);
309 }
237e0016 310 }
237e0016 311
a4deff3c
RS
312 delete_lockname = lockname;
313 }
63cf923d
RS
314#endif /* not MAIL_USE_SYSTEM_LOCK */
315#endif /* not MAIL_USE_MMDF */
237e0016 316
8ca83cfd
RS
317 if (fork () == 0)
318 {
25025815 319 int lockcount = 0;
a4deff3c
RS
320 int status = 0;
321#if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
322 long touched_lock, now;
323#endif
25025815 324
d5216c20 325 setuid (getuid ());
8ca83cfd 326
63cf923d
RS
327#ifndef MAIL_USE_MMDF
328#ifdef MAIL_USE_SYSTEM_LOCK
8ca83cfd 329 indesc = open (inname, O_RDWR);
63cf923d 330#else /* if not MAIL_USE_SYSTEM_LOCK */
8ca83cfd 331 indesc = open (inname, O_RDONLY);
63cf923d 332#endif /* not MAIL_USE_SYSTEM_LOCK */
8ca83cfd
RS
333#else /* MAIL_USE_MMDF */
334 indesc = lk_open (inname, O_RDONLY, 0, 0, 10);
4293ba7f
RS
335#endif /* MAIL_USE_MMDF */
336
8ca83cfd
RS
337 if (indesc < 0)
338 pfatal_with_name (inname);
237e0016 339
e397a017 340#if defined (BSD_SYSTEM) || defined (XENIX)
8ca83cfd
RS
341 /* In case movemail is setuid to root, make sure the user can
342 read the output file. */
343 /* This is desirable for all systems
344 but I don't want to assume all have the umask system call */
345 umask (umask (0) & 0333);
e397a017 346#endif /* BSD_SYSTEM || XENIX */
8ca83cfd
RS
347 outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
348 if (outdesc < 0)
349 pfatal_with_name (outname);
25025815
RS
350
351 /* This label exists so we can retry locking
352 after a delay, if it got EAGAIN or EBUSY. */
353 retry_lock:
354
355 /* Try to lock it. */
a4deff3c
RS
356#ifdef MAIL_USE_MAILLOCK
357 if (spool_name)
358 {
359 /* The "0 - " is to make it a negative number if maillock returns
360 non-zero. */
361 status = 0 - maillock (spool_name, 1);
362#ifdef HAVE_TOUCHLOCK
363 touched_lock = time (0);
364#endif
365 lockcount = 5;
366 }
367 else
368#endif /* MAIL_USE_MAILLOCK */
369 {
63cf923d
RS
370#ifdef MAIL_USE_SYSTEM_LOCK
371#ifdef MAIL_USE_LOCKF
a4deff3c 372 status = lockf (indesc, F_LOCK, 0);
63cf923d 373#else /* not MAIL_USE_LOCKF */
237e0016 374#ifdef XENIX
a4deff3c 375 status = locking (indesc, LK_RLCK, 0L);
7f75d5c6
RS
376#else
377#ifdef WINDOWSNT
a4deff3c 378 status = locking (indesc, LK_RLCK, -1L);
237e0016 379#else
a4deff3c 380 status = flock (indesc, LOCK_EX);
237e0016 381#endif
7f75d5c6 382#endif
63cf923d
RS
383#endif /* not MAIL_USE_LOCKF */
384#endif /* MAIL_USE_SYSTEM_LOCK */
a4deff3c 385 }
237e0016 386
25025815
RS
387 /* If it fails, retry up to 5 times
388 for certain failure codes. */
389 if (status < 0)
390 {
391 if (++lockcount <= 5)
392 {
393#ifdef EAGAIN
394 if (errno == EAGAIN)
395 {
396 sleep (1);
397 goto retry_lock;
398 }
399#endif
400#ifdef EBUSY
401 if (errno == EBUSY)
402 {
403 sleep (1);
404 goto retry_lock;
405 }
406#endif
407 }
408
409 pfatal_with_name (inname);
410 }
411
08564963 412 {
8ca83cfd
RS
413 char buf[1024];
414
415 while (1)
08564963 416 {
8ca83cfd
RS
417 nread = read (indesc, buf, sizeof buf);
418 if (nread != write (outdesc, buf, nread))
419 {
420 int saved_errno = errno;
421 unlink (outname);
422 errno = saved_errno;
423 pfatal_with_name (outname);
424 }
425 if (nread < sizeof buf)
426 break;
a4deff3c
RS
427#if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
428 if (spool_name)
429 {
430 now = time (0);
431 if (now - touched_lock > 60)
432 {
433 touchlock ();
434 touched_lock = now;
435 }
436 }
437#endif /* MAIL_USE_MAILLOCK */
08564963 438 }
08564963 439 }
237e0016 440
e397a017 441#ifdef BSD_SYSTEM
8ca83cfd
RS
442 if (fsync (outdesc) < 0)
443 pfatal_and_delete (outname);
237e0016
RS
444#endif
445
8ca83cfd
RS
446 /* Check to make sure no errors before we zap the inbox. */
447 if (close (outdesc) != 0)
448 pfatal_and_delete (outname);
237e0016 449
63cf923d 450#ifdef MAIL_USE_SYSTEM_LOCK
7f75d5c6 451#if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT)
8ca83cfd
RS
452 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
453 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
237e0016 454#else
8ca83cfd 455 ftruncate (indesc, 0L);
237e0016 456#endif /* STRIDE or XENIX */
63cf923d 457#endif /* MAIL_USE_SYSTEM_LOCK */
4293ba7f
RS
458
459#ifdef MAIL_USE_MMDF
8ca83cfd 460 lk_close (indesc, 0, 0, 0);
4293ba7f 461#else
8ca83cfd 462 close (indesc);
4293ba7f 463#endif
237e0016 464
63cf923d 465#ifndef MAIL_USE_SYSTEM_LOCK
e5f7ea68
RM
466 /* Delete the input file; if we can't, at least get rid of its
467 contents. */
e97dd183 468#ifdef MAIL_UNLINK_SPOOL
8ca83cfd
RS
469 /* This is generally bad to do, because it destroys the permissions
470 that were set on the file. Better to just empty the file. */
471 if (unlink (inname) < 0 && errno != ENOENT)
e97dd183 472#endif /* MAIL_UNLINK_SPOOL */
8ca83cfd 473 creat (inname, 0600);
63cf923d 474#endif /* not MAIL_USE_SYSTEM_LOCK */
8ca83cfd 475
a4deff3c
RS
476#ifdef MAIL_USE_MAILLOCK
477 /* This has to occur in the child, i.e., in the process that
478 acquired the lock! */
479 if (spool_name)
480 mailunlock ();
481#endif
8ca83cfd
RS
482 exit (0);
483 }
484
485 wait (&status);
486 if (!WIFEXITED (status))
487 exit (1);
488 else if (WRETCODE (status) != 0)
489 exit (WRETCODE (status));
490
63cf923d 491#if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
a4deff3c
RS
492#ifdef MAIL_USE_MAILLOCK
493 if (! spool_name)
494#endif /* MAIL_USE_MAILLOCK */
495 unlink (lockname);
63cf923d 496#endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
7f75d5c6
RS
497
498#endif /* ! DISABLE_DIRECT_ACCESS */
499
e2f9d9af 500 return 0;
237e0016 501}
a4deff3c
RS
502
503#ifdef MAIL_USE_MAILLOCK
504/* This function uses stat to confirm that the mail directory is
505 identical to the directory of the input file, rather than just
506 string-comparing the two paths, because one or both of them might
507 be symbolic links pointing to some other directory. */
508static char *
509mail_spool_name (inname)
510 char *inname;
511{
512 struct stat stat1, stat2;
513 char *indir, *fname;
514 int status;
515
516 if (! (fname = rindex (inname, '/')))
517 return NULL;
518
519 fname++;
520
521 if (stat (MAILDIR, &stat1) < 0)
522 return NULL;
523
524 indir = (char *) xmalloc (fname - inname + 1);
525 strncpy (indir, inname, fname - inname);
526 indir[fname-inname] = '\0';
527
528
529 status = stat (indir, &stat2);
530
531 free (indir);
532
533 if (status < 0)
534 return NULL;
535
536 if ((stat1.st_dev == stat2.st_dev) &&
537 (stat1.st_ino == stat2.st_ino))
538 return fname;
539
540 return NULL;
541}
542#endif /* MAIL_USE_MAILLOCK */
237e0016
RS
543\f
544/* Print error message and exit. */
545
e2f9d9af 546void
237e0016
RS
547fatal (s1, s2)
548 char *s1, *s2;
549{
550 if (delete_lockname)
551 unlink (delete_lockname);
552 error (s1, s2);
553 exit (1);
554}
555
556/* Print error message. `s1' is printf control string, `s2' is arg for it. */
557
e2f9d9af 558void
b1ce62a8
RS
559error (s1, s2, s3)
560 char *s1, *s2, *s3;
237e0016 561{
e2f9d9af
DM
562 fprintf (stderr, "movemail: ");
563 fprintf (stderr, s1, s2, s3);
564 fprintf (stderr, "\n");
237e0016
RS
565}
566
e2f9d9af 567void
237e0016
RS
568pfatal_with_name (name)
569 char *name;
570{
e2f9d9af 571 char *s = concat ("", strerror (errno), " for %s");
237e0016
RS
572 fatal (s, name);
573}
574
e2f9d9af 575void
cfa191ff
RS
576pfatal_and_delete (name)
577 char *name;
578{
e2f9d9af 579 char *s = concat ("", strerror (errno), " for %s");
cfa191ff
RS
580 unlink (name);
581 fatal (s, name);
582}
583
237e0016
RS
584/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
585
586char *
587concat (s1, s2, s3)
588 char *s1, *s2, *s3;
589{
590 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
591 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
592
593 strcpy (result, s1);
594 strcpy (result + len1, s2);
595 strcpy (result + len1 + len2, s3);
596 *(result + len1 + len2 + len3) = 0;
597
598 return result;
599}
600
601/* Like malloc but get fatal error if memory is exhausted. */
602
2583d6d7 603long *
237e0016 604xmalloc (size)
e97dd183 605 unsigned size;
237e0016 606{
2583d6d7 607 long *result = (long *) malloc (size);
237e0016
RS
608 if (!result)
609 fatal ("virtual memory exhausted", 0);
610 return result;
611}
612\f
613/* This is the guts of the interface to the Post Office Protocol. */
614
615#ifdef MAIL_USE_POP
616
7f75d5c6 617#ifndef WINDOWSNT
237e0016
RS
618#include <sys/socket.h>
619#include <netinet/in.h>
620#include <netdb.h>
7f75d5c6
RS
621#else
622#undef _WINSOCKAPI_
623#include <winsock.h>
624#endif
cecf0f21 625#include <pwd.h>
237e0016
RS
626
627#ifdef USG
628#include <fcntl.h>
629/* Cancel substitutions made by config.h for Emacs. */
630#undef open
631#undef read
632#undef write
633#undef close
634#endif /* USG */
635
636#define NOTOK (-1)
637#define OK 0
638#define DONE 1
639
640char *progname;
641FILE *sfi;
642FILE *sfo;
2e82e3c3
RS
643char ibuffer[BUFSIZ];
644char obuffer[BUFSIZ];
237e0016
RS
645char Errmsg[80];
646
7f75d5c6 647popmail (user, outfile, password)
b1ce62a8
RS
648 char *user;
649 char *outfile;
7f75d5c6 650 char *password;
237e0016 651{
b1ce62a8 652 int nmsgs, nbytes;
b1ce62a8
RS
653 register int i;
654 int mbfi;
655 FILE *mbf;
2e82e3c3
RS
656 char *getenv ();
657 int mbx_write ();
b32701a7 658 popserver server;
2e82e3c3 659 extern char *strerror ();
237e0016 660
7f75d5c6 661 server = pop_open (0, user, password, POP_NO_GETPASS);
2e82e3c3 662 if (! server)
b1ce62a8 663 {
2e82e3c3
RS
664 error (pop_error);
665 return (1);
237e0016
RS
666 }
667
2e82e3c3 668 if (pop_stat (server, &nmsgs, &nbytes))
b1ce62a8 669 {
2e82e3c3
RS
670 error (pop_error);
671 return (1);
237e0016
RS
672 }
673
b1ce62a8
RS
674 if (!nmsgs)
675 {
2e82e3c3
RS
676 pop_close (server);
677 return (0);
b1ce62a8
RS
678 }
679
680 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
681 if (mbfi < 0)
682 {
2e82e3c3
RS
683 pop_close (server);
684 error ("Error in open: %s, %s", strerror (errno), outfile);
685 return (1);
b1ce62a8
RS
686 }
687 fchown (mbfi, getuid (), -1);
688
7f75d5c6 689 if ((mbf = fdopen (mbfi, "wb")) == NULL)
b1ce62a8 690 {
2e82e3c3
RS
691 pop_close (server);
692 error ("Error in fdopen: %s", strerror (errno));
693 close (mbfi);
694 unlink (outfile);
695 return (1);
b1ce62a8
RS
696 }
697
698 for (i = 1; i <= nmsgs; i++)
699 {
700 mbx_delimit_begin (mbf);
2e82e3c3 701 if (pop_retr (server, i, mbx_write, mbf) != OK)
b1ce62a8 702 {
2e82e3c3 703 error (Errmsg);
b1ce62a8 704 close (mbfi);
2e82e3c3 705 return (1);
237e0016 706 }
b1ce62a8
RS
707 mbx_delimit_end (mbf);
708 fflush (mbf);
2e82e3c3
RS
709 if (ferror (mbf))
710 {
711 error ("Error in fflush: %s", strerror (errno));
712 pop_close (server);
713 close (mbfi);
714 return (1);
715 }
237e0016
RS
716 }
717
2e82e3c3
RS
718 /* On AFS, a call to write only modifies the file in the local
719 * workstation's AFS cache. The changes are not written to the server
720 * until a call to fsync or close is made. Users with AFS home
721 * directories have lost mail when over quota because these checks were
722 * not made in previous versions of movemail. */
723
e397a017 724#ifdef BSD_SYSTEM
cfa191ff
RS
725 if (fsync (mbfi) < 0)
726 {
2e82e3c3
RS
727 error ("Error in fsync: %s", strerror (errno));
728 return (1);
cfa191ff 729 }
340ff9de 730#endif
cfa191ff
RS
731
732 if (close (mbfi) == -1)
733 {
2e82e3c3
RS
734 error ("Error in close: %s", strerror (errno));
735 return (1);
cfa191ff
RS
736 }
737
b1ce62a8
RS
738 for (i = 1; i <= nmsgs; i++)
739 {
2e82e3c3 740 if (pop_delete (server, i))
b1ce62a8 741 {
2e82e3c3
RS
742 error (pop_error);
743 pop_close (server);
744 return (1);
237e0016
RS
745 }
746 }
747
2e82e3c3 748 if (pop_quit (server))
b1ce62a8 749 {
2e82e3c3
RS
750 error (pop_error);
751 return (1);
237e0016 752 }
237e0016 753
2e82e3c3 754 return (0);
237e0016
RS
755}
756
2e82e3c3 757pop_retr (server, msgno, action, arg)
b32701a7 758 popserver server;
a4deff3c 759 int (*action) ();
237e0016 760{
2e82e3c3
RS
761 extern char *strerror ();
762 char *line;
763 int ret;
237e0016 764
2e82e3c3 765 if (pop_retrieve_first (server, msgno, &line))
b1ce62a8 766 {
2e82e3c3
RS
767 strncpy (Errmsg, pop_error, sizeof (Errmsg));
768 Errmsg[sizeof (Errmsg)-1] = '\0';
769 return (NOTOK);
237e0016
RS
770 }
771
2e82e3c3 772 while (! (ret = pop_retrieve_next (server, &line)))
b1ce62a8 773 {
2e82e3c3
RS
774 if (! line)
775 break;
776
777 if ((*action)(line, arg) != OK)
b1ce62a8 778 {
2e82e3c3
RS
779 strcpy (Errmsg, strerror (errno));
780 pop_close (server);
781 return (NOTOK);
237e0016
RS
782 }
783 }
237e0016 784
2e82e3c3 785 if (ret)
b1ce62a8 786 {
2e82e3c3
RS
787 strncpy (Errmsg, pop_error, sizeof (Errmsg));
788 Errmsg[sizeof (Errmsg)-1] = '\0';
789 return (NOTOK);
237e0016
RS
790 }
791
2e82e3c3 792 return (OK);
237e0016
RS
793}
794
2e82e3c3
RS
795/* Do this as a macro instead of using strcmp to save on execution time. */
796#define IS_FROM_LINE(a) ((a[0] == 'F') \
797 && (a[1] == 'r') \
798 && (a[2] == 'o') \
799 && (a[3] == 'm') \
800 && (a[4] == ' '))
237e0016 801
2e82e3c3 802int
b1ce62a8
RS
803mbx_write (line, mbf)
804 char *line;
805 FILE *mbf;
237e0016 806{
2e82e3c3
RS
807 if (IS_FROM_LINE (line))
808 {
809 if (fputc ('>', mbf) == EOF)
810 return (NOTOK);
811 }
812 if (fputs (line, mbf) == EOF)
813 return (NOTOK);
814 if (fputc (0x0a, mbf) == EOF)
815 return (NOTOK);
816 return (OK);
237e0016
RS
817}
818
2e82e3c3 819int
b1ce62a8
RS
820mbx_delimit_begin (mbf)
821 FILE *mbf;
237e0016 822{
2e82e3c3
RS
823 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF)
824 return (NOTOK);
825 return (OK);
237e0016
RS
826}
827
b1ce62a8
RS
828mbx_delimit_end (mbf)
829 FILE *mbf;
237e0016 830{
2e82e3c3
RS
831 if (putc ('\037', mbf) == EOF)
832 return (NOTOK);
833 return (OK);
237e0016
RS
834}
835
836#endif /* MAIL_USE_POP */
e5f7ea68
RM
837\f
838#ifndef HAVE_STRERROR
839char *
840strerror (errnum)
841 int errnum;
842{
843 extern char *sys_errlist[];
844 extern int sys_nerr;
845
846 if (errnum >= 0 && errnum < sys_nerr)
847 return sys_errlist[errnum];
848 return (char *) "Unknown error";
849}
850
851#endif /* ! HAVE_STRERROR */