movemail.c 15.4 KB
Newer Older
Richard M. Stallman's avatar
Richard M. Stallman committed
1 2
/* movemail foo bar -- move file foo to file bar,
   locking file foo the way /bin/mail respects.
3
   Copyright (C) 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
4 5 6

This file is part of GNU Emacs.

Joseph Arceneaux's avatar
Joseph Arceneaux committed
7 8
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
Joseph Arceneaux's avatar
Joseph Arceneaux committed
10 11
any later version.

Richard M. Stallman's avatar
Richard M. Stallman committed
12
GNU Emacs is distributed in the hope that it will be useful,
Joseph Arceneaux's avatar
Joseph Arceneaux committed
13 14 15
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
Richard M. Stallman's avatar
Richard M. Stallman committed
16

Joseph Arceneaux's avatar
Joseph Arceneaux committed
17 18 19
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
20

21 22 23 24 25
/* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will
   cause loss of mail* if you do it on a system that does not normally
   use flock as its way of interlocking access to inbox files.  The
   setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the
   system's own conventions.  It is not a choice that is up to you.
26 27 28 29 30 31 32

   So, if your system uses lock files rather than flock, then the only way
   you can get proper operation is to enable movemail to write lockfiles there.
   This means you must either give that directory access modes
   that permit everyone to write lockfiles in it, or you must make movemail
   a setuid or setgid program.  */

Richard M. Stallman's avatar
Richard M. Stallman committed
33 34 35 36 37 38 39 40 41 42 43
/*
 * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
 *
 * Added POP (Post Office Protocol) service.  When compiled -DPOP
 * movemail will accept input filename arguments of the form
 * "po:username".  This will cause movemail to open a connection to
 * a pop server running on $MAILHOST (environment variable).  Movemail
 * must be setuid to root in order to work with POP.
 * 
 * New module: popmail.c
 * Modified routines:
44
 *	main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ())
Richard M. Stallman's avatar
Richard M. Stallman committed
45 46 47 48
 *		after POP code. 
 * New routines in movemail.c:
 *	get_errmsg - return pointer to system error message
 *
49 50 51 52 53
 * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies)
 *
 * Move all of the POP code into a separate file, "pop.c".
 * Use strerror instead of get_errmsg.
 *
Richard M. Stallman's avatar
Richard M. Stallman committed
54 55
 */

56 57
#define NO_SHORTNAMES   /* Tell config not to load remap.h */
#include <../src/config.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
58 59 60
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
61
#include <stdio.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
62
#include <errno.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
63
#include <../src/syswait.h>
64 65 66
#ifdef MAIL_USE_POP
#include "pop.h"
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
67

68 69 70 71
#ifdef MSDOS
#undef access
#endif /* MSDOS */

Richard M. Stallman's avatar
Richard M. Stallman committed
72 73 74
#ifdef USG
#include <fcntl.h>
#include <unistd.h>
75 76 77 78 79 80
#ifndef F_OK
#define F_OK 0
#define X_OK 1
#define W_OK 2
#define R_OK 4
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
81 82
#endif /* USG */

83 84 85 86
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

Richard M. Stallman's avatar
Richard M. Stallman committed
87 88 89 90
#ifdef XENIX
#include <sys/locking.h>
#endif

91 92 93 94 95 96 97 98
#ifdef MAIL_USE_LOCKF
#define MAIL_USE_SYSTEM_LOCK
#endif

#ifdef MAIL_USE_FLOCK
#define MAIL_USE_SYSTEM_LOCK
#endif

99 100 101 102
#ifdef MAIL_USE_MMDF
extern int lk_open (), lk_close ();
#endif

Richard M. Stallman's avatar
Richard M. Stallman committed
103 104 105 106 107 108
/* Cancel substitutions made by config.h for Emacs.  */
#undef open
#undef read
#undef write
#undef close

David J. MacKenzie's avatar
David J. MacKenzie committed
109
#ifndef errno
Richard M. Stallman's avatar
Richard M. Stallman committed
110
extern int errno;
David J. MacKenzie's avatar
David J. MacKenzie committed
111
#endif
112 113 114 115 116 117 118
char *strerror ();

void fatal ();
void error ();
void pfatal_with_name ();
void pfatal_and_delete ();
char *concat ();
119
long *xmalloc ();
120 121 122 123 124
int popmail ();
int pop_retr ();
int mbx_write ();
int mbx_delimit_begin ();
int mbx_delimit_end ();
Richard M. Stallman's avatar
Richard M. Stallman committed
125 126 127 128

/* Nonzero means this is name of a lock file to delete on fatal error.  */
char *delete_lockname;

129
int
Richard M. Stallman's avatar
Richard M. Stallman committed
130 131 132 133 134 135 136
main (argc, argv)
     int argc;
     char **argv;
{
  char *inname, *outname;
  int indesc, outdesc;
  int nread;
Richard M. Stallman's avatar
Richard M. Stallman committed
137
  WAITTYPE status;
Richard M. Stallman's avatar
Richard M. Stallman committed
138

139
#ifndef MAIL_USE_SYSTEM_LOCK
Richard M. Stallman's avatar
Richard M. Stallman committed
140 141 142 143
  struct stat st;
  long now;
  int tem;
  char *lockname, *p;
144
  char *tempname;
Richard M. Stallman's avatar
Richard M. Stallman committed
145
  int desc;
146
#endif /* not MAIL_USE_SYSTEM_LOCK */
Richard M. Stallman's avatar
Richard M. Stallman committed
147 148 149 150

  delete_lockname = 0;

  if (argc < 3)
151 152 153 154
    {
      fprintf (stderr, "Usage: movemail inbox destfile");
      exit(1);
    }
Richard M. Stallman's avatar
Richard M. Stallman committed
155 156 157 158

  inname = argv[1];
  outname = argv[2];

159 160 161 162
#ifdef MAIL_USE_MMDF
  mmdf_init (argv[0]);
#endif

163
  /* Check access to output file.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
164 165 166 167 168
  if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
    pfatal_with_name (outname);

  /* Also check that outname's directory is writeable to the real uid.  */
  {
169
    char *buf = (char *) xmalloc (strlen (outname) + 1);
170
    char *p;
Richard M. Stallman's avatar
Richard M. Stallman committed
171 172 173 174 175 176 177 178 179 180 181 182
    strcpy (buf, outname);
    p = buf + strlen (buf);
    while (p > buf && p[-1] != '/')
      *--p = 0;
    if (p == buf)
      *p++ = '.';
    if (access (buf, W_OK) != 0)
      pfatal_with_name (buf);
    free (buf);
  }

#ifdef MAIL_USE_POP
183
  if (!strncmp (inname, "po:", 3))
Richard M. Stallman's avatar
Richard M. Stallman committed
184 185 186
    {
      int status; char *user;

187 188 189 190
      for (user = &inname[strlen (inname) - 1]; user >= inname; user--)
	if (*user == ':')
	  break;

191
      user++;
Richard M. Stallman's avatar
Richard M. Stallman committed
192 193 194 195
      status = popmail (user, outname);
      exit (status);
    }

196
  setuid (getuid ());
Richard M. Stallman's avatar
Richard M. Stallman committed
197 198
#endif /* MAIL_USE_POP */

199 200 201 202
  /* Check access to input file.  */
  if (access (inname, R_OK | W_OK) != 0)
    pfatal_with_name (inname);

203
#ifndef MAIL_USE_MMDF
204
#ifndef MAIL_USE_SYSTEM_LOCK
Richard M. Stallman's avatar
Richard M. Stallman committed
205 206
  /* Use a lock file named /usr/spool/mail/$USER.lock:
     If it exists, the mail file is locked.  */
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
  /* Note: this locking mechanism is *required* by the mailer
     (on systems which use it) to prevent loss of mail.

     On systems that use a lock file, extracting the mail without locking
     WILL occasionally cause loss of mail due to timing errors!

     So, if creation of the lock file fails
     due to access permission on /usr/spool/mail,
     you simply MUST change the permission
     and/or make movemail a setgid program
     so it can create lock files properly.

     You might also wish to verify that your system is one
     which uses lock files for this purpose.  Some systems use other methods.

     If your system uses the `flock' system call for mail locking,
223
     define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file
224
     and recompile movemail.  If the s- file for your system
225
     should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report
226 227
     to bug-gnu-emacs@prep.ai.mit.edu so we can fix it.  */

Richard M. Stallman's avatar
Richard M. Stallman committed
228
  lockname = concat (inname, ".lock", "");
229 230
  tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1);
  strcpy (tempname, inname);
Richard M. Stallman's avatar
Richard M. Stallman committed
231 232 233 234 235 236
  p = tempname + strlen (tempname);
  while (p != tempname && p[-1] != '/')
    p--;
  *p = 0;
  strcpy (p, "EXXXXXX");
  mktemp (tempname);
237
  unlink (tempname);
Richard M. Stallman's avatar
Richard M. Stallman committed
238 239 240 241 242

  while (1)
    {
      /* Create the lock file, but not under the lock file name.  */
      /* Give up if cannot do that.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
243
      desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666);
Richard M. Stallman's avatar
Richard M. Stallman committed
244
      if (desc < 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
245
	pfatal_with_name ("lock file--see source file lib-src/movemail.c");
Richard M. Stallman's avatar
Richard M. Stallman committed
246 247 248
      close (desc);

      tem = link (tempname, lockname);
249
      unlink (tempname);
Richard M. Stallman's avatar
Richard M. Stallman committed
250 251 252 253
      if (tem >= 0)
	break;
      sleep (1);

254 255 256 257
      /* If lock file is five minutes old, unlock it.
	 Five minutes should be good enough to cope with crashes
	 and wedgitude, and long enough to avoid being fooled
	 by time differences between machines.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
258 259 260
      if (stat (lockname, &st) >= 0)
	{
	  now = time (0);
261
	  if (st.st_ctime < now - 300)
262
	    unlink (lockname);
Richard M. Stallman's avatar
Richard M. Stallman committed
263 264 265 266
	}
    }

  delete_lockname = lockname;
267 268
#endif /* not MAIL_USE_SYSTEM_LOCK */
#endif /* not MAIL_USE_MMDF */
Richard M. Stallman's avatar
Richard M. Stallman committed
269

Richard M. Stallman's avatar
Richard M. Stallman committed
270 271
  if (fork () == 0)
    {
Karl Heuer's avatar
Karl Heuer committed
272
      setuid (getuid ());
Richard M. Stallman's avatar
Richard M. Stallman committed
273

274 275
#ifndef MAIL_USE_MMDF
#ifdef MAIL_USE_SYSTEM_LOCK
Richard M. Stallman's avatar
Richard M. Stallman committed
276
      indesc = open (inname, O_RDWR);
277
#else  /* if not MAIL_USE_SYSTEM_LOCK */
Richard M. Stallman's avatar
Richard M. Stallman committed
278
      indesc = open (inname, O_RDONLY);
279
#endif /* not MAIL_USE_SYSTEM_LOCK */
Richard M. Stallman's avatar
Richard M. Stallman committed
280 281
#else  /* MAIL_USE_MMDF */
      indesc = lk_open (inname, O_RDONLY, 0, 0, 10);
282 283
#endif /* MAIL_USE_MMDF */

Richard M. Stallman's avatar
Richard M. Stallman committed
284 285
      if (indesc < 0)
	pfatal_with_name (inname);
Richard M. Stallman's avatar
Richard M. Stallman committed
286

287
#if defined (BSD) || defined (XENIX)
Richard M. Stallman's avatar
Richard M. Stallman committed
288 289 290 291 292
      /* In case movemail is setuid to root, make sure the user can
	 read the output file.  */
      /* This is desirable for all systems
	 but I don't want to assume all have the umask system call */
      umask (umask (0) & 0333);
Richard M. Stallman's avatar
Richard M. Stallman committed
293
#endif /* BSD or Xenix */
Richard M. Stallman's avatar
Richard M. Stallman committed
294 295 296
      outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
      if (outdesc < 0)
	pfatal_with_name (outname);
297 298 299 300
#ifdef MAIL_USE_SYSTEM_LOCK
#ifdef MAIL_USE_LOCKF
      if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname);
#else /* not MAIL_USE_LOCKF */
Richard M. Stallman's avatar
Richard M. Stallman committed
301
#ifdef XENIX
Richard M. Stallman's avatar
Richard M. Stallman committed
302
      if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname);
Richard M. Stallman's avatar
Richard M. Stallman committed
303
#else
Richard M. Stallman's avatar
Richard M. Stallman committed
304
      if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname);
Richard M. Stallman's avatar
Richard M. Stallman committed
305
#endif
306 307
#endif /* not MAIL_USE_LOCKF */
#endif /* MAIL_USE_SYSTEM_LOCK */
Richard M. Stallman's avatar
Richard M. Stallman committed
308

Jim Blandy's avatar
Jim Blandy committed
309
      {
Richard M. Stallman's avatar
Richard M. Stallman committed
310 311 312
	char buf[1024];

	while (1)
Jim Blandy's avatar
Jim Blandy committed
313
	  {
Richard M. Stallman's avatar
Richard M. Stallman committed
314 315 316 317 318 319 320 321 322 323
	    nread = read (indesc, buf, sizeof buf);
	    if (nread != write (outdesc, buf, nread))
	      {
		int saved_errno = errno;
		unlink (outname);
		errno = saved_errno;
		pfatal_with_name (outname);
	      }
	    if (nread < sizeof buf)
	      break;
Jim Blandy's avatar
Jim Blandy committed
324 325
	  }
      }
Richard M. Stallman's avatar
Richard M. Stallman committed
326 327

#ifdef BSD
Richard M. Stallman's avatar
Richard M. Stallman committed
328 329
      if (fsync (outdesc) < 0)
	pfatal_and_delete (outname);
Richard M. Stallman's avatar
Richard M. Stallman committed
330 331
#endif

Richard M. Stallman's avatar
Richard M. Stallman committed
332 333 334
      /* Check to make sure no errors before we zap the inbox.  */
      if (close (outdesc) != 0)
	pfatal_and_delete (outname);
Richard M. Stallman's avatar
Richard M. Stallman committed
335

336
#ifdef MAIL_USE_SYSTEM_LOCK
337
#if defined (STRIDE) || defined (XENIX)
Richard M. Stallman's avatar
Richard M. Stallman committed
338 339
      /* Stride, xenix have file locking, but no ftruncate.  This mess will do. */
      close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
Richard M. Stallman's avatar
Richard M. Stallman committed
340
#else
Richard M. Stallman's avatar
Richard M. Stallman committed
341
      ftruncate (indesc, 0L);
Richard M. Stallman's avatar
Richard M. Stallman committed
342
#endif /* STRIDE or XENIX */
343
#endif /* MAIL_USE_SYSTEM_LOCK */
344 345

#ifdef MAIL_USE_MMDF
Richard M. Stallman's avatar
Richard M. Stallman committed
346
      lk_close (indesc, 0, 0, 0);
347
#else
Richard M. Stallman's avatar
Richard M. Stallman committed
348
      close (indesc);
349
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
350

351
#ifndef MAIL_USE_SYSTEM_LOCK
352 353
      /* Delete the input file; if we can't, at least get rid of its
	 contents.  */
David J. MacKenzie's avatar
David J. MacKenzie committed
354
#ifdef MAIL_UNLINK_SPOOL
Richard M. Stallman's avatar
Richard M. Stallman committed
355 356 357
      /* This is generally bad to do, because it destroys the permissions
	 that were set on the file.  Better to just empty the file.  */
      if (unlink (inname) < 0 && errno != ENOENT)
David J. MacKenzie's avatar
David J. MacKenzie committed
358
#endif /* MAIL_UNLINK_SPOOL */
Richard M. Stallman's avatar
Richard M. Stallman committed
359
	creat (inname, 0600);
360
#endif /* not MAIL_USE_SYSTEM_LOCK */
Richard M. Stallman's avatar
Richard M. Stallman committed
361 362 363 364 365 366 367 368 369 370

      exit (0);
    }

  wait (&status);
  if (!WIFEXITED (status))
    exit (1);
  else if (WRETCODE (status) != 0)
    exit (WRETCODE (status));

371
#if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
372
  unlink (lockname);
373
#endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
374
  return 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
375 376 377 378
}

/* Print error message and exit.  */

379
void
Richard M. Stallman's avatar
Richard M. Stallman committed
380 381 382 383 384 385 386 387 388 389 390
fatal (s1, s2)
     char *s1, *s2;
{
  if (delete_lockname)
    unlink (delete_lockname);
  error (s1, s2);
  exit (1);
}

/* Print error message.  `s1' is printf control string, `s2' is arg for it. */

391
void
392 393
error (s1, s2, s3)
     char *s1, *s2, *s3;
Richard M. Stallman's avatar
Richard M. Stallman committed
394
{
395 396 397
  fprintf (stderr, "movemail: ");
  fprintf (stderr, s1, s2, s3);
  fprintf (stderr, "\n");
Richard M. Stallman's avatar
Richard M. Stallman committed
398 399
}

400
void
Richard M. Stallman's avatar
Richard M. Stallman committed
401 402 403
pfatal_with_name (name)
     char *name;
{
404
  char *s = concat ("", strerror (errno), " for %s");
Richard M. Stallman's avatar
Richard M. Stallman committed
405 406 407
  fatal (s, name);
}

408
void
409 410 411
pfatal_and_delete (name)
     char *name;
{
412
  char *s = concat ("", strerror (errno), " for %s");
413 414 415 416
  unlink (name);
  fatal (s, name);
}

Richard M. Stallman's avatar
Richard M. Stallman committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */

char *
concat (s1, s2, s3)
     char *s1, *s2, *s3;
{
  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  char *result = (char *) xmalloc (len1 + len2 + len3 + 1);

  strcpy (result, s1);
  strcpy (result + len1, s2);
  strcpy (result + len1 + len2, s3);
  *(result + len1 + len2 + len3) = 0;

  return result;
}

/* Like malloc but get fatal error if memory is exhausted.  */

436
long *
Richard M. Stallman's avatar
Richard M. Stallman committed
437
xmalloc (size)
David J. MacKenzie's avatar
David J. MacKenzie committed
438
     unsigned size;
Richard M. Stallman's avatar
Richard M. Stallman committed
439
{
440
  long *result = (long *) malloc (size);
Richard M. Stallman's avatar
Richard M. Stallman committed
441 442 443 444 445 446 447 448 449 450 451 452 453
  if (!result)
    fatal ("virtual memory exhausted", 0);
  return result;
}

/* This is the guts of the interface to the Post Office Protocol.  */

#ifdef MAIL_USE_POP

#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
454
#include <pwd.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471

#ifdef USG
#include <fcntl.h>
/* Cancel substitutions made by config.h for Emacs.  */
#undef open
#undef read
#undef write
#undef close
#endif /* USG */

#define NOTOK (-1)
#define OK 0
#define DONE 1

char *progname;
FILE *sfi;
FILE *sfo;
472 473
char ibuffer[BUFSIZ];
char obuffer[BUFSIZ];
Richard M. Stallman's avatar
Richard M. Stallman committed
474 475
char Errmsg[80];

476 477 478
popmail (user, outfile)
     char *user;
     char *outfile;
Richard M. Stallman's avatar
Richard M. Stallman committed
479
{
480 481 482 483
  int nmsgs, nbytes;
  register int i;
  int mbfi;
  FILE *mbf;
484 485
  char *getenv ();
  int mbx_write ();
486
  popserver server;
487
  extern char *strerror ();
Richard M. Stallman's avatar
Richard M. Stallman committed
488

489 490
  server = pop_open (0, user, 0, POP_NO_GETPASS);
  if (! server)
491
    {
492 493
      error (pop_error);
      return (1);
Richard M. Stallman's avatar
Richard M. Stallman committed
494 495
    }

496
  if (pop_stat (server, &nmsgs, &nbytes))
497
    {
498 499
      error (pop_error);
      return (1);
Richard M. Stallman's avatar
Richard M. Stallman committed
500 501
    }

502 503
  if (!nmsgs)
    {
504 505
      pop_close (server);
      return (0);
506 507 508 509 510
    }

  mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
  if (mbfi < 0)
    {
511 512 513
      pop_close (server);
      error ("Error in open: %s, %s", strerror (errno), outfile);
      return (1);
514 515 516 517 518
    }
  fchown (mbfi, getuid (), -1);

  if ((mbf = fdopen (mbfi, "w")) == NULL)
    {
519 520 521 522 523
      pop_close (server);
      error ("Error in fdopen: %s", strerror (errno));
      close (mbfi);
      unlink (outfile);
      return (1);
524 525 526 527 528
    }

  for (i = 1; i <= nmsgs; i++)
    {
      mbx_delimit_begin (mbf);
529
      if (pop_retr (server, i, mbx_write, mbf) != OK)
530
	{
531
	  error (Errmsg);
532
	  close (mbfi);
533
	  return (1);
Richard M. Stallman's avatar
Richard M. Stallman committed
534
	}
535 536
      mbx_delimit_end (mbf);
      fflush (mbf);
537 538 539 540 541 542 543
      if (ferror (mbf))
	{
	  error ("Error in fflush: %s", strerror (errno));
	  pop_close (server);
	  close (mbfi);
	  return (1);
	}
Richard M. Stallman's avatar
Richard M. Stallman committed
544 545
    }

546 547 548 549 550 551
  /* On AFS, a call to write only modifies the file in the local
   *     workstation's AFS cache.  The changes are not written to the server
   *      until a call to fsync or close is made.  Users with AFS home
   *      directories have lost mail when over quota because these checks were
   *      not made in previous versions of movemail. */

552
#ifdef BSD
553 554
  if (fsync (mbfi) < 0)
    {
555 556
      error ("Error in fsync: %s", strerror (errno));
      return (1);
557
    }
558
#endif
559 560 561

  if (close (mbfi) == -1)
    {
562 563
      error ("Error in close: %s", strerror (errno));
      return (1);
564 565
    }

566 567
  for (i = 1; i <= nmsgs; i++)
    {
568
      if (pop_delete (server, i))
569
	{
570 571 572
	  error (pop_error);
	  pop_close (server);
	  return (1);
Richard M. Stallman's avatar
Richard M. Stallman committed
573 574 575
	}
    }

576
  if (pop_quit (server))
577
    {
578 579
      error (pop_error);
      return (1);
Richard M. Stallman's avatar
Richard M. Stallman committed
580 581
    }
    
582
  return (0);
Richard M. Stallman's avatar
Richard M. Stallman committed
583 584
}

585
pop_retr (server, msgno, action, arg)
586
     popserver server;
587
     int (*action)();
Richard M. Stallman's avatar
Richard M. Stallman committed
588
{
589 590 591
  extern char *strerror ();
  char *line;
  int ret;
Richard M. Stallman's avatar
Richard M. Stallman committed
592

593
  if (pop_retrieve_first (server, msgno, &line))
594
    {
595 596 597
      strncpy (Errmsg, pop_error, sizeof (Errmsg));
      Errmsg[sizeof (Errmsg)-1] = '\0';
      return (NOTOK);
Richard M. Stallman's avatar
Richard M. Stallman committed
598 599
    }

600
  while (! (ret = pop_retrieve_next (server, &line)))
601
    {
602 603 604 605
      if (! line)
	break;

      if ((*action)(line, arg) != OK)
606
	{
607 608 609
	  strcpy (Errmsg, strerror (errno));
	  pop_close (server);
	  return (NOTOK);
Richard M. Stallman's avatar
Richard M. Stallman committed
610 611 612
	}
    }

613
  if (ret)
614
    {
615 616 617
      strncpy (Errmsg, pop_error, sizeof (Errmsg));
      Errmsg[sizeof (Errmsg)-1] = '\0';
      return (NOTOK);
Richard M. Stallman's avatar
Richard M. Stallman committed
618 619
    }

620
  return (OK);
Richard M. Stallman's avatar
Richard M. Stallman committed
621 622
}

623 624 625 626 627 628
/* Do this as a macro instead of using strcmp to save on execution time. */
#define IS_FROM_LINE(a) ((a[0] == 'F') \
			 && (a[1] == 'r') \
			 && (a[2] == 'o') \
			 && (a[3] == 'm') \
			 && (a[4] == ' '))
Richard M. Stallman's avatar
Richard M. Stallman committed
629

630
int
631 632 633
mbx_write (line, mbf)
     char *line;
     FILE *mbf;
Richard M. Stallman's avatar
Richard M. Stallman committed
634
{
635 636 637 638 639 640 641 642 643 644
  if (IS_FROM_LINE (line))
    {
      if (fputc ('>', mbf) == EOF)
	return (NOTOK);
    }
  if (fputs (line, mbf) == EOF) 
    return (NOTOK);
  if (fputc (0x0a, mbf) == EOF)
    return (NOTOK);
  return (OK);
Richard M. Stallman's avatar
Richard M. Stallman committed
645 646
}

647
int
648 649
mbx_delimit_begin (mbf)
     FILE *mbf;
Richard M. Stallman's avatar
Richard M. Stallman committed
650
{
651 652 653
  if (fputs ("\f\n0, unseen,,\n", mbf) == EOF)
    return (NOTOK);
  return (OK);
Richard M. Stallman's avatar
Richard M. Stallman committed
654 655
}

656 657
mbx_delimit_end (mbf)
     FILE *mbf;
Richard M. Stallman's avatar
Richard M. Stallman committed
658
{
659 660 661
  if (putc ('\037', mbf) == EOF)
    return (NOTOK);
  return (OK);
Richard M. Stallman's avatar
Richard M. Stallman committed
662 663 664
}

#endif /* MAIL_USE_POP */
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679

#ifndef HAVE_STRERROR
char *
strerror (errnum)
     int errnum;
{
  extern char *sys_errlist[];
  extern int sys_nerr;

  if (errnum >= 0 && errnum < sys_nerr)
    return sys_errlist[errnum];
  return (char *) "Unknown error";
}

#endif /* ! HAVE_STRERROR */