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