Merge from emacs-24; up to 2012-11-15T23:31:37Z!dancol@dancol.org
[bpt/emacs.git] / lib-src / movemail.c
1 /* movemail foo bar -- move file foo to file bar,
2 locking file foo the way /bin/mail respects.
3
4 Copyright (C) 1986, 1992-1994, 1996, 1999, 2001-2012
5 Free Software Foundation, Inc.
6
7 This file is part of GNU Emacs.
8
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21
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/lockf 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 #include <config.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <sys/file.h>
62 #include <stdio.h>
63 #include <errno.h>
64 #include <time.h>
65
66 #include <getopt.h>
67 #include <unistd.h>
68 #include <fcntl.h>
69 #include <string.h>
70 #include "syswait.h"
71 #ifdef MAIL_USE_POP
72 #include "pop.h"
73 #endif
74
75 #ifdef MSDOS
76 #undef access
77 #endif /* MSDOS */
78
79 #ifdef WINDOWSNT
80 #include "ntlib.h"
81 #undef access
82 #undef unlink
83 #define fork() 0
84 #define 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
91 [18-Feb-97 andrewi] I now believe my comment above to be incorrect,
92 since it was based on a misunderstanding of how locking calls are
93 implemented and used on Unix. */
94 //#define DISABLE_DIRECT_ACCESS
95
96 #include <fcntl.h>
97 #endif /* WINDOWSNT */
98
99 #ifndef F_OK
100 #define F_OK 0
101 #define X_OK 1
102 #define W_OK 2
103 #define R_OK 4
104 #endif
105
106 #ifdef WINDOWSNT
107 #include <sys/locking.h>
108 #endif
109
110 /* If your system uses the `flock' or `lockf' system call for mail locking,
111 define MAIL_USE_SYSTEM_LOCK. If your system type should always define
112 MAIL_USE_LOCKF or MAIL_USE_FLOCK but configure does not do this,
113 please make a bug report. */
114
115 #ifdef MAIL_USE_LOCKF
116 #define MAIL_USE_SYSTEM_LOCK
117 #endif
118
119 #ifdef MAIL_USE_FLOCK
120 #define MAIL_USE_SYSTEM_LOCK
121 #endif
122
123 #ifdef MAIL_USE_MMDF
124 extern int lk_open (), lk_close ();
125 #endif
126
127 #if !defined (MAIL_USE_SYSTEM_LOCK) && !defined (MAIL_USE_MMDF) && \
128 (defined (HAVE_LIBMAIL) || defined (HAVE_LIBLOCKFILE)) && \
129 defined (HAVE_MAILLOCK_H)
130 #include <maillock.h>
131 /* We can't use maillock unless we know what directory system mail
132 files appear in. */
133 #ifdef MAILDIR
134 #define MAIL_USE_MAILLOCK
135 static char *mail_spool_name (char *);
136 #endif
137 #endif
138
139 static _Noreturn void fatal (const char *s1, const char *s2, const char *s3);
140 static void error (const char *s1, const char *s2, const char *s3);
141 static _Noreturn void pfatal_with_name (char *name);
142 static _Noreturn void pfatal_and_delete (char *name);
143 #ifdef MAIL_USE_POP
144 static int popmail (char *mailbox, char *outfile, int preserve, char *password, int reverse_order);
145 static int pop_retr (popserver server, int msgno, FILE *arg);
146 static int mbx_write (char *line, int len, FILE *mbf);
147 static int mbx_delimit_begin (FILE *mbf);
148 static int mbx_delimit_end (FILE *mbf);
149 #endif
150
151 #if (defined MAIL_USE_MAILLOCK \
152 || (!defined DISABLE_DIRECT_ACCESS && !defined MAIL_USE_MMDF \
153 && !defined MAIL_USE_SYSTEM_LOCK))
154 /* Like malloc but get fatal error if memory is exhausted. */
155
156 static void *
157 xmalloc (size_t size)
158 {
159 void *result = malloc (size);
160 if (!result)
161 fatal ("virtual memory exhausted", 0, 0);
162 return result;
163 }
164 #endif
165
166 /* Nonzero means this is name of a lock file to delete on fatal error. */
167 static char *delete_lockname;
168
169 int
170 main (int argc, char **argv)
171 {
172 char *inname, *outname;
173 int indesc, outdesc;
174 ssize_t nread;
175 int wait_status;
176 int c, preserve_mail = 0;
177
178 #ifndef MAIL_USE_SYSTEM_LOCK
179 struct stat st;
180 int tem;
181 char *lockname;
182 char *tempname;
183 size_t inname_len, inname_dirlen;
184 int desc;
185 #endif /* not MAIL_USE_SYSTEM_LOCK */
186
187 #ifdef MAIL_USE_MAILLOCK
188 char *spool_name;
189 #endif
190
191 #ifdef MAIL_USE_POP
192 int pop_reverse_order = 0;
193 # define ARGSTR "pr"
194 #else /* ! MAIL_USE_POP */
195 # define ARGSTR "p"
196 #endif /* MAIL_USE_POP */
197
198 uid_t real_gid = getgid ();
199 uid_t priv_gid = getegid ();
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] [-r] 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 #ifdef MAIL_USE_POP
252 if (!strncmp (inname, "po:", 3))
253 {
254 int status;
255
256 status = popmail (inname + 3, outname, preserve_mail,
257 (argc - optind == 3) ? argv[optind+2] : NULL,
258 pop_reverse_order);
259 exit (status);
260 }
261
262 if (setuid (getuid ()) < 0)
263 fatal ("Failed to drop privileges", 0, 0);
264
265 #endif /* MAIL_USE_POP */
266
267 #ifndef DISABLE_DIRECT_ACCESS
268 #ifndef MAIL_USE_MMDF
269 #ifndef MAIL_USE_SYSTEM_LOCK
270 #ifdef MAIL_USE_MAILLOCK
271 spool_name = mail_spool_name (inname);
272 if (spool_name)
273 {
274 #ifdef lint
275 lockname = 0;
276 #endif
277 }
278 else
279 #endif
280 {
281 /* Use a lock file named after our first argument with .lock appended:
282 If it exists, the mail file is locked. */
283 /* Note: this locking mechanism is *required* by the mailer
284 (on systems which use it) to prevent loss of mail.
285
286 On systems that use a lock file, extracting the mail without locking
287 WILL occasionally cause loss of mail due to timing errors!
288
289 So, if creation of the lock file fails due to access
290 permission on the mail spool directory, you simply MUST
291 change the permission and/or make movemail a setgid program
292 so it can create lock files properly.
293
294 You might also wish to verify that your system is one which
295 uses lock files for this purpose. Some systems use other methods. */
296
297 inname_len = strlen (inname);
298 lockname = xmalloc (inname_len + sizeof ".lock");
299 strcpy (lockname, inname);
300 strcpy (lockname + inname_len, ".lock");
301 for (inname_dirlen = inname_len;
302 inname_dirlen && !IS_DIRECTORY_SEP (inname[inname_dirlen - 1]);
303 inname_dirlen--)
304 continue;
305 tempname = xmalloc (inname_dirlen + sizeof "EXXXXXX");
306
307 while (1)
308 {
309 /* Create the lock file, but not under the lock file name. */
310 /* Give up if cannot do that. */
311
312 memcpy (tempname, inname, inname_dirlen);
313 strcpy (tempname + inname_dirlen, "EXXXXXX");
314 #ifdef HAVE_MKSTEMP
315 desc = mkstemp (tempname);
316 #else
317 mktemp (tempname);
318 if (!*tempname)
319 desc = -1;
320 else
321 {
322 unlink (tempname);
323 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0600);
324 }
325 #endif
326 if (desc < 0)
327 {
328 int mkstemp_errno = errno;
329 error ("error while creating what would become the lock file",
330 0, 0);
331 errno = mkstemp_errno;
332 pfatal_with_name (tempname);
333 }
334 close (desc);
335
336 tem = link (tempname, lockname);
337
338 #ifdef EPERM
339 if (tem < 0 && errno == EPERM)
340 fatal ("Unable to create hard link between %s and %s",
341 tempname, lockname);
342 #endif
343
344 unlink (tempname);
345 if (tem >= 0)
346 break;
347 sleep (1);
348
349 /* If lock file is five minutes old, unlock it.
350 Five minutes should be good enough to cope with crashes
351 and wedgitude, and long enough to avoid being fooled
352 by time differences between machines. */
353 if (stat (lockname, &st) >= 0)
354 {
355 time_t now = time (0);
356 if (st.st_ctime < now - 300)
357 unlink (lockname);
358 }
359 }
360
361 delete_lockname = lockname;
362 }
363 #endif /* not MAIL_USE_SYSTEM_LOCK */
364 #endif /* not MAIL_USE_MMDF */
365
366 if (fork () == 0)
367 {
368 int lockcount = 0;
369 int status = 0;
370 #if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
371 time_t touched_lock;
372 # ifdef lint
373 touched_lock = 0;
374 # endif
375 #endif
376
377 if (setuid (getuid ()) < 0 || setregid (-1, real_gid) < 0)
378 fatal ("Failed to drop privileges", 0, 0);
379
380 #ifndef MAIL_USE_MMDF
381 #ifdef MAIL_USE_SYSTEM_LOCK
382 indesc = open (inname, O_RDWR);
383 #else /* if not MAIL_USE_SYSTEM_LOCK */
384 indesc = open (inname, O_RDONLY);
385 #endif /* not MAIL_USE_SYSTEM_LOCK */
386 #else /* MAIL_USE_MMDF */
387 indesc = lk_open (inname, O_RDONLY, 0, 0, 10);
388 #endif /* MAIL_USE_MMDF */
389
390 if (indesc < 0)
391 pfatal_with_name (inname);
392
393 #ifdef BSD_SYSTEM
394 /* In case movemail is setuid to root, make sure the user can
395 read the output file. */
396 /* This is desirable for all systems
397 but I don't want to assume all have the umask system call */
398 umask (umask (0) & 0333);
399 #endif /* BSD_SYSTEM */
400 outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
401 if (outdesc < 0)
402 pfatal_with_name (outname);
403
404 if (setregid (-1, priv_gid) < 0)
405 fatal ("Failed to regain privileges", 0, 0);
406
407 /* This label exists so we can retry locking
408 after a delay, if it got EAGAIN or EBUSY. */
409 retry_lock:
410
411 /* Try to lock it. */
412 #ifdef MAIL_USE_MAILLOCK
413 if (spool_name)
414 {
415 /* The "0 - " is to make it a negative number if maillock returns
416 non-zero. */
417 status = 0 - maillock (spool_name, 1);
418 #ifdef HAVE_TOUCHLOCK
419 touched_lock = time (0);
420 #endif
421 lockcount = 5;
422 }
423 else
424 #endif /* MAIL_USE_MAILLOCK */
425 {
426 #ifdef MAIL_USE_SYSTEM_LOCK
427 #ifdef MAIL_USE_LOCKF
428 status = lockf (indesc, F_LOCK, 0);
429 #else /* not MAIL_USE_LOCKF */
430 #ifdef WINDOWSNT
431 status = locking (indesc, LK_RLCK, -1L);
432 #else
433 status = flock (indesc, LOCK_EX);
434 #endif
435 #endif /* not MAIL_USE_LOCKF */
436 #endif /* MAIL_USE_SYSTEM_LOCK */
437 }
438
439 /* If it fails, retry up to 5 times
440 for certain failure codes. */
441 if (status < 0)
442 {
443 if (++lockcount <= 5)
444 {
445 #ifdef EAGAIN
446 if (errno == EAGAIN)
447 {
448 sleep (1);
449 goto retry_lock;
450 }
451 #endif
452 #ifdef EBUSY
453 if (errno == EBUSY)
454 {
455 sleep (1);
456 goto retry_lock;
457 }
458 #endif
459 }
460
461 pfatal_with_name (inname);
462 }
463
464 {
465 char buf[1024];
466
467 while (1)
468 {
469 nread = read (indesc, buf, sizeof buf);
470 if (nread < 0)
471 pfatal_with_name (inname);
472 if (nread != write (outdesc, buf, nread))
473 {
474 int saved_errno = errno;
475 unlink (outname);
476 errno = saved_errno;
477 pfatal_with_name (outname);
478 }
479 if (nread < sizeof buf)
480 break;
481 #if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
482 if (spool_name)
483 {
484 time_t now = time (0);
485 if (now - touched_lock > 60)
486 {
487 touchlock ();
488 touched_lock = now;
489 }
490 }
491 #endif /* MAIL_USE_MAILLOCK */
492 }
493 }
494
495 #ifdef BSD_SYSTEM
496 if (fsync (outdesc) < 0)
497 pfatal_and_delete (outname);
498 #endif
499
500 /* Prevent symlink attacks truncating other users' mailboxes */
501 if (setregid (-1, real_gid) < 0)
502 fatal ("Failed to drop privileges", 0, 0);
503
504 /* Check to make sure no errors before we zap the inbox. */
505 if (close (outdesc) != 0)
506 pfatal_and_delete (outname);
507
508 #ifdef MAIL_USE_SYSTEM_LOCK
509 if (! preserve_mail)
510 {
511 if (ftruncate (indesc, 0L) != 0)
512 pfatal_with_name (inname);
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 /* End of mailbox truncation */
537 if (setregid (-1, priv_gid) < 0)
538 fatal ("Failed to regain privileges", 0, 0);
539
540 #ifdef MAIL_USE_MAILLOCK
541 /* This has to occur in the child, i.e., in the process that
542 acquired the lock! */
543 if (spool_name)
544 mailunlock ();
545 #endif
546 exit (EXIT_SUCCESS);
547 }
548
549 wait (&wait_status);
550 if (!WIFEXITED (wait_status))
551 exit (EXIT_FAILURE);
552 else if (WEXITSTATUS (wait_status) != 0)
553 exit (WEXITSTATUS (wait_status));
554
555 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
556 #ifdef MAIL_USE_MAILLOCK
557 if (! spool_name)
558 #endif /* MAIL_USE_MAILLOCK */
559 unlink (lockname);
560 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
561
562 #endif /* ! DISABLE_DIRECT_ACCESS */
563
564 return EXIT_SUCCESS;
565 }
566
567 #ifdef MAIL_USE_MAILLOCK
568 /* This function uses stat to confirm that the mail directory is
569 identical to the directory of the input file, rather than just
570 string-comparing the two paths, because one or both of them might
571 be symbolic links pointing to some other directory. */
572 static char *
573 mail_spool_name (char *inname)
574 {
575 struct stat stat1, stat2;
576 char *indir, *fname;
577 int status;
578
579 if (! (fname = strrchr (inname, '/')))
580 return NULL;
581
582 fname++;
583
584 if (stat (MAILDIR, &stat1) < 0)
585 return NULL;
586
587 indir = xmalloc (fname - inname + 1);
588 memcpy (indir, inname, fname - inname);
589 indir[fname-inname] = '\0';
590
591
592 status = stat (indir, &stat2);
593
594 free (indir);
595
596 if (status < 0)
597 return NULL;
598
599 if (stat1.st_dev == stat2.st_dev
600 && stat1.st_ino == stat2.st_ino)
601 return fname;
602
603 return NULL;
604 }
605 #endif /* MAIL_USE_MAILLOCK */
606 \f
607 /* Print error message and exit. */
608
609 static void
610 fatal (const char *s1, const char *s2, const char *s3)
611 {
612 if (delete_lockname)
613 unlink (delete_lockname);
614 error (s1, s2, s3);
615 exit (EXIT_FAILURE);
616 }
617
618 /* Print error message. `s1' is printf control string, `s2' and `s3'
619 are args for it or null. */
620
621 static void
622 error (const char *s1, const char *s2, const char *s3)
623 {
624 fprintf (stderr, "movemail: ");
625 if (s3)
626 fprintf (stderr, s1, s2, s3);
627 else if (s2)
628 fprintf (stderr, s1, s2);
629 else
630 fprintf (stderr, "%s", s1);
631 fprintf (stderr, "\n");
632 }
633
634 static void
635 pfatal_with_name (char *name)
636 {
637 fatal ("%s for %s", strerror (errno), name);
638 }
639
640 static void
641 pfatal_and_delete (char *name)
642 {
643 char *s = strerror (errno);
644 unlink (name);
645 fatal ("%s for %s", s, name);
646 }
647 \f
648 /* This is the guts of the interface to the Post Office Protocol. */
649
650 #ifdef MAIL_USE_POP
651
652 #ifndef WINDOWSNT
653 #include <sys/socket.h>
654 #include <netinet/in.h>
655 #include <netdb.h>
656 #else
657 #undef _WINSOCKAPI_
658 #include <winsock.h>
659 #endif
660 #include <pwd.h>
661 #include <string.h>
662
663 #define NOTOK (-1)
664 #define OK 0
665
666 static char Errmsg[200]; /* POP errors, at least, can exceed
667 the original length of 80. */
668
669 /*
670 * The full valid syntax for a POP mailbox specification for movemail
671 * is "po:username:hostname". The ":hostname" is optional; if it is
672 * omitted, the MAILHOST environment variable will be consulted. Note
673 * that by the time popmail() is called the "po:" has been stripped
674 * off of the front of the mailbox name.
675 *
676 * If the mailbox is in the form "po:username:hostname", then it is
677 * modified by this function -- the second colon is replaced by a
678 * null.
679 *
680 * Return a value suitable for passing to `exit'.
681 */
682
683 static int
684 popmail (char *mailbox, char *outfile, int preserve, char *password, int reverse_order)
685 {
686 int nmsgs, nbytes;
687 register int i;
688 int mbfi;
689 FILE *mbf;
690 char *getenv (const char *);
691 popserver server;
692 int start, end, increment;
693 char *user, *hostname;
694
695 user = mailbox;
696 if ((hostname = strchr (mailbox, ':')))
697 *hostname++ = '\0';
698
699 server = pop_open (hostname, user, password, POP_NO_GETPASS);
700 if (! server)
701 {
702 error ("Error connecting to POP server: %s", pop_error, 0);
703 return EXIT_FAILURE;
704 }
705
706 if (pop_stat (server, &nmsgs, &nbytes))
707 {
708 error ("Error getting message count from POP server: %s", pop_error, 0);
709 return EXIT_FAILURE;
710 }
711
712 if (!nmsgs)
713 {
714 pop_close (server);
715 return EXIT_SUCCESS;
716 }
717
718 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
719 if (mbfi < 0)
720 {
721 pop_close (server);
722 error ("Error in open: %s, %s", strerror (errno), outfile);
723 return EXIT_FAILURE;
724 }
725
726 if (fchown (mbfi, getuid (), -1) != 0)
727 {
728 int fchown_errno = errno;
729 struct stat st;
730 if (fstat (mbfi, &st) != 0 || st.st_uid != getuid ())
731 {
732 pop_close (server);
733 error ("Error in fchown: %s, %s", strerror (fchown_errno), outfile);
734 return EXIT_FAILURE;
735 }
736 }
737
738 if ((mbf = fdopen (mbfi, "wb")) == NULL)
739 {
740 pop_close (server);
741 error ("Error in fdopen: %s", strerror (errno), 0);
742 close (mbfi);
743 unlink (outfile);
744 return EXIT_FAILURE;
745 }
746
747 if (reverse_order)
748 {
749 start = nmsgs;
750 end = 1;
751 increment = -1;
752 }
753 else
754 {
755 start = 1;
756 end = nmsgs;
757 increment = 1;
758 }
759
760 for (i = start; i * increment <= end * increment; i += increment)
761 {
762 mbx_delimit_begin (mbf);
763 if (pop_retr (server, i, mbf) != OK)
764 {
765 error ("%s", Errmsg, 0);
766 close (mbfi);
767 return EXIT_FAILURE;
768 }
769 mbx_delimit_end (mbf);
770 fflush (mbf);
771 if (ferror (mbf))
772 {
773 error ("Error in fflush: %s", strerror (errno), 0);
774 pop_close (server);
775 close (mbfi);
776 return EXIT_FAILURE;
777 }
778 }
779
780 /* On AFS, a call to write only modifies the file in the local
781 * workstation's AFS cache. The changes are not written to the server
782 * until a call to fsync or close is made. Users with AFS home
783 * directories have lost mail when over quota because these checks were
784 * not made in previous versions of movemail. */
785
786 #ifdef BSD_SYSTEM
787 if (fsync (mbfi) < 0)
788 {
789 error ("Error in fsync: %s", strerror (errno), 0);
790 return EXIT_FAILURE;
791 }
792 #endif
793
794 if (close (mbfi) == -1)
795 {
796 error ("Error in close: %s", strerror (errno), 0);
797 return EXIT_FAILURE;
798 }
799
800 if (! preserve)
801 for (i = 1; i <= nmsgs; i++)
802 {
803 if (pop_delete (server, i))
804 {
805 error ("Error from POP server: %s", pop_error, 0);
806 pop_close (server);
807 return EXIT_FAILURE;
808 }
809 }
810
811 if (pop_quit (server))
812 {
813 error ("Error from POP server: %s", pop_error, 0);
814 return EXIT_FAILURE;
815 }
816
817 return EXIT_SUCCESS;
818 }
819
820 static int
821 pop_retr (popserver server, int msgno, FILE *arg)
822 {
823 char *line;
824 int ret;
825
826 if (pop_retrieve_first (server, msgno, &line))
827 {
828 snprintf (Errmsg, sizeof Errmsg, "Error from POP server: %s", pop_error);
829 return (NOTOK);
830 }
831
832 while ((ret = pop_retrieve_next (server, &line)) >= 0)
833 {
834 if (! line)
835 break;
836
837 if (mbx_write (line, ret, arg) != OK)
838 {
839 strcpy (Errmsg, strerror (errno));
840 pop_close (server);
841 return (NOTOK);
842 }
843 }
844
845 if (ret)
846 {
847 snprintf (Errmsg, sizeof Errmsg, "Error from POP server: %s", pop_error);
848 return (NOTOK);
849 }
850
851 return (OK);
852 }
853
854 static int
855 mbx_write (char *line, int len, FILE *mbf)
856 {
857 #ifdef MOVEMAIL_QUOTE_POP_FROM_LINES
858 /* Do this as a macro instead of using strcmp to save on execution time. */
859 # define IS_FROM_LINE(a) ((a[0] == 'F') \
860 && (a[1] == 'r') \
861 && (a[2] == 'o') \
862 && (a[3] == 'm') \
863 && (a[4] == ' '))
864 if (IS_FROM_LINE (line))
865 {
866 if (fputc ('>', mbf) == EOF)
867 return (NOTOK);
868 }
869 #endif
870 if (line[0] == '\037')
871 {
872 if (fputs ("^_", mbf) == EOF)
873 return (NOTOK);
874 line++;
875 len--;
876 }
877 if (fwrite (line, 1, len, mbf) != len)
878 return (NOTOK);
879 if (fputc (0x0a, mbf) == EOF)
880 return (NOTOK);
881 return (OK);
882 }
883
884 static int
885 mbx_delimit_begin (FILE *mbf)
886 {
887 time_t now;
888 struct tm *ltime;
889 char fromline[40] = "From movemail ";
890
891 now = time (NULL);
892 ltime = localtime (&now);
893
894 strcat (fromline, asctime (ltime));
895
896 if (fputs (fromline, mbf) == EOF)
897 return (NOTOK);
898 return (OK);
899 }
900
901 static int
902 mbx_delimit_end (FILE *mbf)
903 {
904 if (putc ('\n', mbf) == EOF)
905 return (NOTOK);
906 return (OK);
907 }
908
909 #endif /* MAIL_USE_POP */