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