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