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