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