]> code.delx.au - gnu-emacs/blob - lib-src/movemail.c
Merge from origin/emacs-24
[gnu-emacs] / 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-2015 Free Software
5 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 <stdbool.h>
63 #include <stdio.h>
64 #include <errno.h>
65 #include <time.h>
66
67 #include <getopt.h>
68 #include <unistd.h>
69 #include <fcntl.h>
70 #include <signal.h>
71 #include <string.h>
72 #include "syswait.h"
73 #ifdef MAIL_USE_POP
74 #include "pop.h"
75 #endif
76
77 #ifdef MSDOS
78 #undef access
79 #endif /* MSDOS */
80
81 #ifdef WINDOWSNT
82 #include "ntlib.h"
83 #undef access
84 #undef unlink
85 #define fork() 0
86 #define waitpid(child, var, flags) (*(var) = 0)
87 /* Unfortunately, Samba doesn't seem to properly lock Unix files even
88 though the locking call succeeds (and indeed blocks local access from
89 other NT programs). If you have direct file access using an NFS
90 client or something other than Samba, the locking call might work
91 properly - make sure it does before you enable this!
92
93 [18-Feb-97 andrewi] I now believe my comment above to be incorrect,
94 since it was based on a misunderstanding of how locking calls are
95 implemented and used on Unix. */
96 //#define DISABLE_DIRECT_ACCESS
97
98 #include <fcntl.h>
99 #endif /* WINDOWSNT */
100
101 #ifdef WINDOWSNT
102 #include <sys/locking.h>
103 #endif
104
105 /* If your system uses the `flock' or `lockf' system call for mail locking,
106 define MAIL_USE_SYSTEM_LOCK. If your system type should always define
107 MAIL_USE_LOCKF or MAIL_USE_FLOCK but configure does not do this,
108 please make a bug report. */
109
110 #ifdef MAIL_USE_LOCKF
111 #define MAIL_USE_SYSTEM_LOCK
112 #endif
113
114 #ifdef MAIL_USE_FLOCK
115 #define MAIL_USE_SYSTEM_LOCK
116 #endif
117
118 #ifdef MAIL_USE_MMDF
119 extern int lk_open (), lk_close ();
120 #endif
121
122 #if !defined (MAIL_USE_SYSTEM_LOCK) && !defined (MAIL_USE_MMDF) && \
123 (defined (HAVE_LIBMAIL) || defined (HAVE_LIBLOCKFILE)) && \
124 defined (HAVE_MAILLOCK_H)
125 #include <maillock.h>
126 /* We can't use maillock unless we know what directory system mail
127 files appear in. */
128 #ifdef MAILDIR
129 #define MAIL_USE_MAILLOCK
130 static char *mail_spool_name (char *);
131 #endif
132 #endif
133
134 static _Noreturn void fatal (const char *s1, const char *s2, const char *s3);
135 static void error (const char *s1, const char *s2, const char *s3);
136 static _Noreturn void pfatal_with_name (char *name);
137 static _Noreturn void pfatal_and_delete (char *name);
138 #ifdef MAIL_USE_POP
139 static int popmail (char *, char *, bool, char *, bool);
140 static bool pop_retr (popserver, int, FILE *);
141 static bool mbx_write (char *, int, FILE *);
142 static bool mbx_delimit_begin (FILE *);
143 static bool mbx_delimit_end (FILE *);
144 #endif
145
146 #if (defined MAIL_USE_MAILLOCK \
147 || (!defined DISABLE_DIRECT_ACCESS && !defined MAIL_USE_MMDF \
148 && !defined MAIL_USE_SYSTEM_LOCK))
149 /* Like malloc but get fatal error if memory is exhausted. */
150
151 static void *
152 xmalloc (size_t size)
153 {
154 void *result = malloc (size);
155 if (!result)
156 fatal ("virtual memory exhausted", 0, 0);
157 return result;
158 }
159 #endif
160
161 /* Nonzero means this is name of a lock file to delete on fatal error. */
162 static char *delete_lockname;
163
164 int
165 main (int argc, char **argv)
166 {
167 char *inname, *outname;
168 int indesc, outdesc;
169 ssize_t nread;
170 int wait_status;
171 int c;
172 bool preserve_mail = false;
173
174 #ifndef MAIL_USE_SYSTEM_LOCK
175 struct stat st;
176 int tem;
177 char *tempname;
178 size_t inname_len, inname_dirlen;
179 int desc;
180 #endif /* not MAIL_USE_SYSTEM_LOCK */
181
182 char *spool_name = 0;
183
184 #ifdef MAIL_USE_POP
185 bool pop_reverse_order = false;
186 # define ARGSTR "pr"
187 #else /* ! MAIL_USE_POP */
188 # define ARGSTR "p"
189 #endif /* MAIL_USE_POP */
190
191 uid_t real_gid = getgid ();
192 uid_t priv_gid = getegid ();
193
194 delete_lockname = 0;
195
196 while (0 <= (c = getopt (argc, argv, ARGSTR)))
197 {
198 switch (c) {
199 #ifdef MAIL_USE_POP
200 case 'r':
201 pop_reverse_order = true;
202 break;
203 #endif
204 case 'p':
205 preserve_mail = true;
206 break;
207 default:
208 return EXIT_FAILURE;
209 }
210 }
211
212 if (
213 #ifdef MAIL_USE_POP
214 (argc - optind < 2) || (argc - optind > 3)
215 #else
216 (argc - optind != 2)
217 #endif
218 )
219 {
220 #ifdef MAIL_USE_POP
221 fprintf (stderr, "Usage: movemail [-p] [-r] inbox destfile%s\n",
222 " [POP-password]");
223 #else
224 fprintf (stderr, "Usage: movemail [-p] inbox destfile%s\n", "");
225 #endif
226 return EXIT_FAILURE;
227 }
228
229 inname = argv[optind];
230 outname = argv[optind+1];
231
232 #ifdef MAIL_USE_MMDF
233 mmdf_init (argv[0]);
234 #endif
235
236 if (*outname == 0)
237 fatal ("Destination file name is empty", 0, 0);
238
239 #ifdef MAIL_USE_POP
240 if (!strncmp (inname, "po:", 3))
241 {
242 int status;
243
244 status = popmail (inname + 3, outname, preserve_mail,
245 (argc - optind == 3) ? argv[optind+2] : NULL,
246 pop_reverse_order);
247 return status;
248 }
249
250 if (setuid (getuid ()) < 0)
251 fatal ("Failed to drop privileges", 0, 0);
252
253 #endif /* MAIL_USE_POP */
254
255 #ifndef DISABLE_DIRECT_ACCESS
256
257 char *lockname = 0;
258
259 #ifndef MAIL_USE_MMDF
260 #ifndef MAIL_USE_SYSTEM_LOCK
261 #ifdef MAIL_USE_MAILLOCK
262 spool_name = mail_spool_name (inname);
263 #endif
264 if (! spool_name)
265 {
266 /* Use a lock file named after our first argument with .lock appended:
267 If it exists, the mail file is locked. */
268 /* Note: this locking mechanism is *required* by the mailer
269 (on systems which use it) to prevent loss of mail.
270
271 On systems that use a lock file, extracting the mail without locking
272 WILL occasionally cause loss of mail due to timing errors!
273
274 So, if creation of the lock file fails due to access
275 permission on the mail spool directory, you simply MUST
276 change the permission and/or make movemail a setgid program
277 so it can create lock files properly.
278
279 You might also wish to verify that your system is one which
280 uses lock files for this purpose. Some systems use other methods. */
281
282 inname_len = strlen (inname);
283 lockname = xmalloc (inname_len + sizeof ".lock");
284 strcpy (lockname, inname);
285 strcpy (lockname + inname_len, ".lock");
286 for (inname_dirlen = inname_len;
287 inname_dirlen && !IS_DIRECTORY_SEP (inname[inname_dirlen - 1]);
288 inname_dirlen--)
289 continue;
290 tempname = xmalloc (inname_dirlen + sizeof "EXXXXXX");
291
292 while (true)
293 {
294 /* Create the lock file, but not under the lock file name. */
295 /* Give up if cannot do that. */
296
297 memcpy (tempname, inname, inname_dirlen);
298 strcpy (tempname + inname_dirlen, "EXXXXXX");
299 desc = mkostemp (tempname, O_BINARY);
300 if (desc < 0)
301 {
302 int mkostemp_errno = errno;
303 error ("error while creating what would become the lock file",
304 0, 0);
305 errno = mkostemp_errno;
306 pfatal_with_name (tempname);
307 }
308 close (desc);
309
310 tem = link (tempname, lockname);
311
312 if (tem < 0 && errno != EEXIST)
313 pfatal_with_name (lockname);
314
315 unlink (tempname);
316 if (tem >= 0)
317 break;
318 sleep (1);
319
320 /* If lock file is five minutes old, unlock it.
321 Five minutes should be good enough to cope with crashes
322 and wedgitude, and long enough to avoid being fooled
323 by time differences between machines. */
324 if (stat (lockname, &st) >= 0)
325 {
326 time_t now = time (0);
327 if (st.st_ctime < now - 300)
328 {
329 unlink (lockname);
330 lockname = 0;
331 }
332 }
333 }
334
335 delete_lockname = lockname;
336 }
337 #endif /* not MAIL_USE_SYSTEM_LOCK */
338 #endif /* not MAIL_USE_MMDF */
339
340 #ifdef SIGCHLD
341 signal (SIGCHLD, SIG_DFL);
342 #endif
343
344 pid_t child = fork ();
345 if (child < 0)
346 fatal ("Error in fork; %s", strerror (errno), 0);
347
348 if (child == 0)
349 {
350 int lockcount = 0;
351 int status = 0;
352 #if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
353 time_t touched_lock IF_LINT (= 0);
354 #endif
355
356 if (setuid (getuid ()) < 0 || setregid (-1, real_gid) < 0)
357 fatal ("Failed to drop privileges", 0, 0);
358
359 #ifndef MAIL_USE_MMDF
360 #ifdef MAIL_USE_SYSTEM_LOCK
361 indesc = open (inname, O_RDWR | O_BINARY);
362 #else /* if not MAIL_USE_SYSTEM_LOCK */
363 indesc = open (inname, O_RDONLY | O_BINARY);
364 #endif /* not MAIL_USE_SYSTEM_LOCK */
365 #else /* MAIL_USE_MMDF */
366 indesc = lk_open (inname, O_RDONLY | O_BINARY, 0, 0, 10);
367 #endif /* MAIL_USE_MMDF */
368
369 if (indesc < 0)
370 pfatal_with_name (inname);
371
372 /* Make sure the user can read the output file. */
373 umask (umask (0) & 0377);
374
375 outdesc = open (outname, O_WRONLY | O_BINARY | O_CREAT | O_EXCL, 0666);
376 if (outdesc < 0)
377 pfatal_with_name (outname);
378
379 if (setregid (-1, priv_gid) < 0)
380 fatal ("Failed to regain privileges", 0, 0);
381
382 /* This label exists so we can retry locking
383 after a delay, if it got EAGAIN or EBUSY. */
384 retry_lock:
385
386 /* Try to lock it. */
387 #ifdef MAIL_USE_MAILLOCK
388 if (spool_name)
389 {
390 /* The "-" is to make it a negative number if maillock returns
391 non-zero. */
392 status = - maillock (spool_name, 1);
393 #ifdef HAVE_TOUCHLOCK
394 touched_lock = time (0);
395 #endif
396 lockcount = 5;
397 }
398 else
399 #endif /* MAIL_USE_MAILLOCK */
400 {
401 #ifdef MAIL_USE_SYSTEM_LOCK
402 #ifdef MAIL_USE_LOCKF
403 status = lockf (indesc, F_LOCK, 0);
404 #else /* not MAIL_USE_LOCKF */
405 #ifdef WINDOWSNT
406 status = locking (indesc, LK_RLCK, -1L);
407 #else
408 status = flock (indesc, LOCK_EX);
409 #endif
410 #endif /* not MAIL_USE_LOCKF */
411 #endif /* MAIL_USE_SYSTEM_LOCK */
412 }
413
414 /* If it fails, retry up to 5 times
415 for certain failure codes. */
416 if (status < 0)
417 {
418 if (++lockcount <= 5 && (errno == EAGAIN || errno == EBUSY))
419 {
420 sleep (1);
421 goto retry_lock;
422 }
423
424 pfatal_with_name (inname);
425 }
426
427 {
428 char buf[1024];
429
430 while (true)
431 {
432 nread = read (indesc, buf, sizeof buf);
433 if (nread < 0)
434 pfatal_with_name (inname);
435 if (nread != write (outdesc, buf, nread))
436 {
437 int saved_errno = errno;
438 unlink (outname);
439 errno = saved_errno;
440 pfatal_with_name (outname);
441 }
442 if (nread < sizeof buf)
443 break;
444 #if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
445 if (spool_name)
446 {
447 time_t now = time (0);
448 if (now - touched_lock > 60)
449 {
450 touchlock ();
451 touched_lock = now;
452 }
453 }
454 #endif /* MAIL_USE_MAILLOCK */
455 }
456 }
457
458 if (fsync (outdesc) != 0 && errno != EINVAL)
459 pfatal_and_delete (outname);
460
461 /* Prevent symlink attacks truncating other users' mailboxes */
462 if (setregid (-1, real_gid) < 0)
463 fatal ("Failed to drop privileges", 0, 0);
464
465 /* Check to make sure no errors before we zap the inbox. */
466 if (close (outdesc) != 0)
467 pfatal_and_delete (outname);
468
469 #ifdef MAIL_USE_SYSTEM_LOCK
470 if (! preserve_mail)
471 {
472 if (ftruncate (indesc, 0) != 0)
473 pfatal_with_name (inname);
474 }
475 #endif /* MAIL_USE_SYSTEM_LOCK */
476
477 #ifdef MAIL_USE_MMDF
478 lk_close (indesc, 0, 0, 0);
479 #else
480 close (indesc);
481 #endif
482
483 #ifndef MAIL_USE_SYSTEM_LOCK
484 if (! preserve_mail)
485 {
486 /* Delete the input file; if we can't, at least get rid of its
487 contents. */
488 #ifdef MAIL_UNLINK_SPOOL
489 /* This is generally bad to do, because it destroys the permissions
490 that were set on the file. Better to just empty the file. */
491 if (unlink (inname) < 0 && errno != ENOENT)
492 #endif /* MAIL_UNLINK_SPOOL */
493 creat (inname, 0600);
494 }
495 #endif /* not MAIL_USE_SYSTEM_LOCK */
496
497 /* End of mailbox truncation */
498 if (setregid (-1, priv_gid) < 0)
499 fatal ("Failed to regain privileges", 0, 0);
500
501 #ifdef MAIL_USE_MAILLOCK
502 /* This has to occur in the child, i.e., in the process that
503 acquired the lock! */
504 if (spool_name)
505 mailunlock ();
506 #endif
507 return EXIT_SUCCESS;
508 }
509
510 if (waitpid (child, &wait_status, 0) < 0)
511 fatal ("Error in waitpid; %s", strerror (errno), 0);
512 if (!WIFEXITED (wait_status))
513 return EXIT_FAILURE;
514 else if (WEXITSTATUS (wait_status) != 0)
515 return WEXITSTATUS (wait_status);
516
517 if (lockname)
518 unlink (lockname);
519
520 #endif /* ! DISABLE_DIRECT_ACCESS */
521
522 return EXIT_SUCCESS;
523 }
524
525 #ifdef MAIL_USE_MAILLOCK
526 /* This function uses stat to confirm that the mail directory is
527 identical to the directory of the input file, rather than just
528 string-comparing the two paths, because one or both of them might
529 be symbolic links pointing to some other directory. */
530 static char *
531 mail_spool_name (char *inname)
532 {
533 struct stat stat1, stat2;
534 char *indir, *fname;
535 int status;
536
537 if (! (fname = strrchr (inname, '/')))
538 return NULL;
539
540 fname++;
541
542 if (stat (MAILDIR, &stat1) < 0)
543 return NULL;
544
545 indir = xmalloc (fname - inname + 1);
546 memcpy (indir, inname, fname - inname);
547 indir[fname-inname] = '\0';
548
549
550 status = stat (indir, &stat2);
551
552 free (indir);
553
554 if (status < 0)
555 return NULL;
556
557 if (stat1.st_dev == stat2.st_dev
558 && stat1.st_ino == stat2.st_ino)
559 return fname;
560
561 return NULL;
562 }
563 #endif /* MAIL_USE_MAILLOCK */
564 \f
565 /* Print error message and exit. */
566
567 static void
568 fatal (const char *s1, const char *s2, const char *s3)
569 {
570 if (delete_lockname)
571 unlink (delete_lockname);
572 error (s1, s2, s3);
573 exit (EXIT_FAILURE);
574 }
575
576 /* Print error message. `s1' is printf control string, `s2' and `s3'
577 are args for it or null. */
578
579 static void
580 error (const char *s1, const char *s2, const char *s3)
581 {
582 fprintf (stderr, "movemail: ");
583 if (s3)
584 fprintf (stderr, s1, s2, s3);
585 else if (s2)
586 fprintf (stderr, s1, s2);
587 else
588 fprintf (stderr, "%s", s1);
589 fprintf (stderr, "\n");
590 }
591
592 static void
593 pfatal_with_name (char *name)
594 {
595 fatal ("%s for %s", strerror (errno), name);
596 }
597
598 static void
599 pfatal_and_delete (char *name)
600 {
601 char *s = strerror (errno);
602 unlink (name);
603 fatal ("%s for %s", s, name);
604 }
605 \f
606 /* This is the guts of the interface to the Post Office Protocol. */
607
608 #ifdef MAIL_USE_POP
609
610 #ifndef WINDOWSNT
611 #include <sys/socket.h>
612 #include <netinet/in.h>
613 #include <netdb.h>
614 #else
615 #undef _WINSOCKAPI_
616 #include <winsock.h>
617 #endif
618 #include <pwd.h>
619 #include <string.h>
620
621 /*
622 * The full valid syntax for a POP mailbox specification for movemail
623 * is "po:username:hostname". The ":hostname" is optional; if it is
624 * omitted, the MAILHOST environment variable will be consulted. Note
625 * that by the time popmail() is called the "po:" has been stripped
626 * off of the front of the mailbox name.
627 *
628 * If the mailbox is in the form "po:username:hostname", then it is
629 * modified by this function -- the second colon is replaced by a
630 * null.
631 *
632 * Return a value suitable for passing to `exit'.
633 */
634
635 static int
636 popmail (char *mailbox, char *outfile, bool preserve, char *password,
637 bool reverse_order)
638 {
639 int nmsgs, nbytes;
640 int i;
641 int mbfi;
642 FILE *mbf;
643 popserver server;
644 int start, end, increment;
645 char *user, *hostname;
646
647 user = mailbox;
648 if ((hostname = strchr (mailbox, ':')))
649 *hostname++ = '\0';
650
651 server = pop_open (hostname, user, password, POP_NO_GETPASS);
652 if (! server)
653 {
654 error ("Error connecting to POP server: %s", pop_error, 0);
655 return EXIT_FAILURE;
656 }
657
658 if (pop_stat (server, &nmsgs, &nbytes))
659 {
660 error ("Error getting message count from POP server: %s", pop_error, 0);
661 return EXIT_FAILURE;
662 }
663
664 if (!nmsgs)
665 {
666 pop_close (server);
667 return EXIT_SUCCESS;
668 }
669
670 mbfi = open (outfile, O_WRONLY | O_BINARY | O_CREAT | O_EXCL, 0666);
671 if (mbfi < 0)
672 {
673 pop_close (server);
674 error ("Error in open: %s, %s", strerror (errno), outfile);
675 return EXIT_FAILURE;
676 }
677
678 if (fchown (mbfi, getuid (), -1) != 0)
679 {
680 int fchown_errno = errno;
681 struct stat st;
682 if (fstat (mbfi, &st) != 0 || st.st_uid != getuid ())
683 {
684 pop_close (server);
685 error ("Error in fchown: %s, %s", strerror (fchown_errno), outfile);
686 return EXIT_FAILURE;
687 }
688 }
689
690 mbf = fdopen (mbfi, "wb");
691 if (!mbf)
692 {
693 pop_close (server);
694 error ("Error in fdopen: %s", strerror (errno), 0);
695 close (mbfi);
696 unlink (outfile);
697 return EXIT_FAILURE;
698 }
699
700 if (reverse_order)
701 {
702 start = nmsgs;
703 end = 1;
704 increment = -1;
705 }
706 else
707 {
708 start = 1;
709 end = nmsgs;
710 increment = 1;
711 }
712
713 for (i = start; i * increment <= end * increment; i += increment)
714 if (! (mbx_delimit_begin (mbf)
715 && pop_retr (server, i, mbf)
716 && mbx_delimit_end (mbf)
717 && fflush (mbf) == 0))
718 {
719 if (errno)
720 error ("Error in POP retrieving: %s", strerror (errno), 0);
721 pop_close (server);
722 fclose (mbf);
723 return EXIT_FAILURE;
724 }
725
726 if (fsync (mbfi) != 0 && errno != EINVAL)
727 {
728 error ("Error in fsync: %s", strerror (errno), 0);
729 fclose (mbf);
730 return EXIT_FAILURE;
731 }
732
733 if (fclose (mbf) != 0)
734 {
735 error ("Error in fclose: %s", strerror (errno), 0);
736 return EXIT_FAILURE;
737 }
738
739 if (! preserve)
740 for (i = 1; i <= nmsgs; i++)
741 {
742 if (pop_delete (server, i))
743 {
744 error ("Error from POP server: %s", pop_error, 0);
745 pop_close (server);
746 return EXIT_FAILURE;
747 }
748 }
749
750 if (pop_quit (server))
751 {
752 error ("Error from POP server: %s", pop_error, 0);
753 return EXIT_FAILURE;
754 }
755
756 return EXIT_SUCCESS;
757 }
758
759 static bool
760 pop_retr (popserver server, int msgno, FILE *arg)
761 {
762 char *line;
763 int ret;
764
765 if (pop_retrieve_first (server, msgno, &line))
766 {
767 error ("Error from POP server: %s", pop_error, 0);
768 errno = 0;
769 return false;
770 }
771
772 while ((ret = pop_retrieve_next (server, &line)) >= 0)
773 {
774 if (! line)
775 break;
776
777 if (! mbx_write (line, ret, arg))
778 {
779 int write_errno = errno;
780 pop_close (server);
781 errno = write_errno;
782 return false;
783 }
784 }
785
786 if (ret)
787 {
788 error ("Error from POP server: %s", pop_error, 0);
789 errno = 0;
790 return false;
791 }
792
793 return true;
794 }
795
796 static bool
797 mbx_write (char *line, int len, FILE *mbf)
798 {
799 #ifdef MOVEMAIL_QUOTE_POP_FROM_LINES
800 /* Do this as a macro instead of using strcmp to save on execution time. */
801 # define IS_FROM_LINE(a) ((a[0] == 'F') \
802 && (a[1] == 'r') \
803 && (a[2] == 'o') \
804 && (a[3] == 'm') \
805 && (a[4] == ' '))
806 if (IS_FROM_LINE (line))
807 {
808 if (fputc ('>', mbf) < 0)
809 return false;
810 }
811 #endif
812 if (line[0] == '\037')
813 {
814 if (fputs ("^_", mbf) < 0)
815 return false;
816 line++;
817 len--;
818 }
819 return fwrite (line, 1, len, mbf) == len && 0 <= fputc ('\n', mbf);
820 }
821
822 static bool
823 mbx_delimit_begin (FILE *mbf)
824 {
825 time_t now = time (NULL);
826 struct tm *ltime = localtime (&now);
827 if (!ltime)
828 return false;
829
830 char fromline[100];
831 if (! strftime (fromline, sizeof fromline,
832 "From movemail %a %b %e %T %Y\n", ltime))
833 {
834 errno = EOVERFLOW;
835 return false;
836 }
837 return 0 <= fputs (fromline, mbf);
838 }
839
840 static bool
841 mbx_delimit_end (FILE *mbf)
842 {
843 return 0 <= putc ('\n', mbf);
844 }
845
846 #endif /* MAIL_USE_POP */