(store_in_keymap): Add `static' to declaration.
[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.
4ee9629e 3 Copyright (C) 1986, 92, 93, 94, 96, 1999 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 57#define NO_SHORTNAMES /* Tell config not to load remap.h */
752fb472 58#include <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 81#ifdef WINDOWSNT
677a7bcf 82#include "ntlib.h"
7f75d5c6
RS
83#undef access
84#undef unlink
85#define fork() 0
4822b2e5 86#define wait(var) (*(var) = 0)
7f75d5c6
RS
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
677a7bcf
RS
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
677a7bcf 98#include <fcntl.h>
7f75d5c6
RS
99#endif /* WINDOWSNT */
100
237e0016
RS
101#ifdef USG
102#include <fcntl.h>
103#include <unistd.h>
4ec9a77a
RS
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
237e0016
RS
110#endif /* USG */
111
29beb080
RS
112#ifdef HAVE_UNISTD_H
113#include <unistd.h>
114#endif
115
7f75d5c6 116#if defined (XENIX) || defined (WINDOWSNT)
237e0016
RS
117#include <sys/locking.h>
118#endif
119
63cf923d
RS
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
4293ba7f
RS
128#ifdef MAIL_USE_MMDF
129extern int lk_open (), lk_close ();
130#endif
131
a4deff3c
RS
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
139static char *mail_spool_name ();
140#endif
141#endif
142
e97dd183 143#ifndef errno
237e0016 144extern int errno;
e97dd183 145#endif
e2f9d9af 146char *strerror ();
c4009c1f 147extern char *rindex ();
e2f9d9af
DM
148
149void fatal ();
150void error ();
151void pfatal_with_name ();
152void pfatal_and_delete ();
153char *concat ();
2583d6d7 154long *xmalloc ();
e2f9d9af
DM
155int popmail ();
156int pop_retr ();
157int mbx_write ();
158int mbx_delimit_begin ();
159int mbx_delimit_end ();
237e0016
RS
160
161/* Nonzero means this is name of a lock file to delete on fatal error. */
162char *delete_lockname;
163
e2f9d9af 164int
237e0016
RS
165main (argc, argv)
166 int argc;
167 char **argv;
168{
169 char *inname, *outname;
170 int indesc, outdesc;
237e0016 171 int nread;
8ca83cfd 172 WAITTYPE status;
fea4325c 173 int c, preserve_mail = 0;
237e0016 174
63cf923d 175#ifndef MAIL_USE_SYSTEM_LOCK
237e0016
RS
176 struct stat st;
177 long now;
178 int tem;
179 char *lockname, *p;
906ad89d 180 char *tempname;
237e0016 181 int desc;
63cf923d 182#endif /* not MAIL_USE_SYSTEM_LOCK */
237e0016 183
a4deff3c
RS
184#ifdef MAIL_USE_MAILLOCK
185 char *spool_name;
186#endif
187
a2997b0f
KH
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
9112a2a9
AI
195#ifdef WINDOWSNT
196 /* Ensure all file i/o is in binary mode. */
197 _fmode = _O_BINARY;
198#endif
199
237e0016
RS
200 delete_lockname = 0;
201
a2997b0f 202 while ((c = getopt (argc, argv, ARGSTR)) != EOF)
e2f9d9af 203 {
fea4325c 204 switch (c) {
a2997b0f
KH
205#ifdef MAIL_USE_POP
206 case 'r':
207 pop_reverse_order = 1;
208 break;
209#endif
fea4325c
RS
210 case 'p':
211 preserve_mail++;
212 break;
213 default:
0d66b6f3 214 exit(1);
fea4325c
RS
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 {
0d66b6f3 226 fprintf (stderr, "Usage: movemail [-p] inbox destfile%s\n",
fea4325c 227#ifdef MAIL_USE_POP
0d66b6f3 228 " [POP-password]"
fea4325c 229#else
0d66b6f3 230 ""
fea4325c
RS
231#endif
232 );
a4deff3c 233 exit (1);
e2f9d9af 234 }
237e0016 235
fea4325c
RS
236 inname = argv[optind];
237 outname = argv[optind+1];
237e0016 238
4293ba7f
RS
239#ifdef MAIL_USE_MMDF
240 mmdf_init (argv[0]);
241#endif
242
af7bd34e
RS
243 if (*outname == 0)
244 fatal ("Destination file name is empty", 0);
245
b1ce62a8 246 /* Check access to output file. */
237e0016
RS
247 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
248 pfatal_with_name (outname);
249
8e6208c5 250 /* Also check that outname's directory is writable to the real uid. */
237e0016 251 {
91cf09ac 252 char *buf = (char *) xmalloc (strlen (outname) + 1);
e2f9d9af 253 char *p;
237e0016
RS
254 strcpy (buf, outname);
255 p = buf + strlen (buf);
7f75d5c6 256 while (p > buf && !IS_DIRECTORY_SEP (p[-1]))
237e0016
RS
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
12a0565a 266 if (!strncmp (inname, "po:", 3))
237e0016 267 {
b3112191 268 int status;
237e0016 269
fea4325c 270 status = popmail (inname + 3, outname, preserve_mail,
a2997b0f
KH
271 (argc - optind == 3) ? argv[optind+2] : NULL,
272 pop_reverse_order);
237e0016
RS
273 exit (status);
274 }
275
cfa191ff 276 setuid (getuid ());
237e0016
RS
277#endif /* MAIL_USE_POP */
278
7f75d5c6
RS
279#ifndef DISABLE_DIRECT_ACCESS
280
b1ce62a8
RS
281 /* Check access to input file. */
282 if (access (inname, R_OK | W_OK) != 0)
283 pfatal_with_name (inname);
284
4293ba7f 285#ifndef MAIL_USE_MMDF
63cf923d 286#ifndef MAIL_USE_SYSTEM_LOCK
a4deff3c
RS
287#ifdef MAIL_USE_MAILLOCK
288 spool_name = mail_spool_name (inname);
289 if (! spool_name)
290#endif
237e0016 291 {
a4deff3c
RS
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);
cfa191ff 324 unlink (tempname);
237e0016 325
a4deff3c 326 while (1)
237e0016 327 {
a4deff3c
RS
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);
4b265472 334 sprintf (message, "creating %s, which would become the lock file",
a4deff3c
RS
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 }
237e0016 356 }
237e0016 357
a4deff3c
RS
358 delete_lockname = lockname;
359 }
63cf923d
RS
360#endif /* not MAIL_USE_SYSTEM_LOCK */
361#endif /* not MAIL_USE_MMDF */
237e0016 362
8ca83cfd
RS
363 if (fork () == 0)
364 {
25025815 365 int lockcount = 0;
a4deff3c
RS
366 int status = 0;
367#if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
368 long touched_lock, now;
369#endif
25025815 370
d5216c20 371 setuid (getuid ());
8ca83cfd 372
63cf923d
RS
373#ifndef MAIL_USE_MMDF
374#ifdef MAIL_USE_SYSTEM_LOCK
8ca83cfd 375 indesc = open (inname, O_RDWR);
63cf923d 376#else /* if not MAIL_USE_SYSTEM_LOCK */
8ca83cfd 377 indesc = open (inname, O_RDONLY);
63cf923d 378#endif /* not MAIL_USE_SYSTEM_LOCK */
8ca83cfd
RS
379#else /* MAIL_USE_MMDF */
380 indesc = lk_open (inname, O_RDONLY, 0, 0, 10);
4293ba7f
RS
381#endif /* MAIL_USE_MMDF */
382
8ca83cfd
RS
383 if (indesc < 0)
384 pfatal_with_name (inname);
237e0016 385
e397a017 386#if defined (BSD_SYSTEM) || defined (XENIX)
8ca83cfd
RS
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);
e397a017 392#endif /* BSD_SYSTEM || XENIX */
8ca83cfd
RS
393 outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
394 if (outdesc < 0)
395 pfatal_with_name (outname);
25025815
RS
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. */
a4deff3c
RS
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 {
63cf923d
RS
416#ifdef MAIL_USE_SYSTEM_LOCK
417#ifdef MAIL_USE_LOCKF
a4deff3c 418 status = lockf (indesc, F_LOCK, 0);
63cf923d 419#else /* not MAIL_USE_LOCKF */
237e0016 420#ifdef XENIX
a4deff3c 421 status = locking (indesc, LK_RLCK, 0L);
7f75d5c6
RS
422#else
423#ifdef WINDOWSNT
a4deff3c 424 status = locking (indesc, LK_RLCK, -1L);
237e0016 425#else
a4deff3c 426 status = flock (indesc, LOCK_EX);
237e0016 427#endif
7f75d5c6 428#endif
63cf923d
RS
429#endif /* not MAIL_USE_LOCKF */
430#endif /* MAIL_USE_SYSTEM_LOCK */
a4deff3c 431 }
237e0016 432
25025815
RS
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
08564963 458 {
8ca83cfd
RS
459 char buf[1024];
460
461 while (1)
08564963 462 {
8ca83cfd
RS
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;
a4deff3c
RS
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 */
08564963 484 }
08564963 485 }
237e0016 486
e397a017 487#ifdef BSD_SYSTEM
8ca83cfd
RS
488 if (fsync (outdesc) < 0)
489 pfatal_and_delete (outname);
237e0016
RS
490#endif
491
8ca83cfd
RS
492 /* Check to make sure no errors before we zap the inbox. */
493 if (close (outdesc) != 0)
494 pfatal_and_delete (outname);
237e0016 495
63cf923d 496#ifdef MAIL_USE_SYSTEM_LOCK
fea4325c
RS
497 if (! preserve_mail)
498 {
3288d108 499#if defined (STRIDE) || defined (XENIX)
fea4325c
RS
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));
237e0016 503#else
fea4325c 504 ftruncate (indesc, 0L);
237e0016 505#endif /* STRIDE or XENIX */
b1cb2966 506 }
63cf923d 507#endif /* MAIL_USE_SYSTEM_LOCK */
4293ba7f
RS
508
509#ifdef MAIL_USE_MMDF
8ca83cfd 510 lk_close (indesc, 0, 0, 0);
4293ba7f 511#else
8ca83cfd 512 close (indesc);
4293ba7f 513#endif
237e0016 514
63cf923d 515#ifndef MAIL_USE_SYSTEM_LOCK
fea4325c
RS
516 if (! preserve_mail)
517 {
518 /* Delete the input file; if we can't, at least get rid of its
519 contents. */
e97dd183 520#ifdef MAIL_UNLINK_SPOOL
fea4325c
RS
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)
e97dd183 524#endif /* MAIL_UNLINK_SPOOL */
fea4325c
RS
525 creat (inname, 0600);
526 }
63cf923d 527#endif /* not MAIL_USE_SYSTEM_LOCK */
8ca83cfd 528
a4deff3c
RS
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
8ca83cfd
RS
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
63cf923d 544#if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
a4deff3c
RS
545#ifdef MAIL_USE_MAILLOCK
546 if (! spool_name)
547#endif /* MAIL_USE_MAILLOCK */
548 unlink (lockname);
63cf923d 549#endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
7f75d5c6
RS
550
551#endif /* ! DISABLE_DIRECT_ACCESS */
552
e2f9d9af 553 return 0;
237e0016 554}
a4deff3c
RS
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. */
561static char *
562mail_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
c4009c1f
RS
589 if (stat1.st_dev == stat2.st_dev
590 && stat1.st_ino == stat2.st_ino)
a4deff3c
RS
591 return fname;
592
593 return NULL;
594}
595#endif /* MAIL_USE_MAILLOCK */
237e0016
RS
596\f
597/* Print error message and exit. */
598
e2f9d9af 599void
237e0016
RS
600fatal (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
e2f9d9af 611void
b1ce62a8
RS
612error (s1, s2, s3)
613 char *s1, *s2, *s3;
237e0016 614{
e2f9d9af
DM
615 fprintf (stderr, "movemail: ");
616 fprintf (stderr, s1, s2, s3);
617 fprintf (stderr, "\n");
237e0016
RS
618}
619
e2f9d9af 620void
237e0016
RS
621pfatal_with_name (name)
622 char *name;
623{
e2f9d9af 624 char *s = concat ("", strerror (errno), " for %s");
237e0016
RS
625 fatal (s, name);
626}
627
e2f9d9af 628void
cfa191ff
RS
629pfatal_and_delete (name)
630 char *name;
631{
e2f9d9af 632 char *s = concat ("", strerror (errno), " for %s");
cfa191ff
RS
633 unlink (name);
634 fatal (s, name);
635}
636
237e0016
RS
637/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
638
639char *
640concat (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
2583d6d7 656long *
237e0016 657xmalloc (size)
e97dd183 658 unsigned size;
237e0016 659{
2583d6d7 660 long *result = (long *) malloc (size);
237e0016
RS
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
7f75d5c6 670#ifndef WINDOWSNT
237e0016
RS
671#include <sys/socket.h>
672#include <netinet/in.h>
673#include <netdb.h>
7f75d5c6
RS
674#else
675#undef _WINSOCKAPI_
676#include <winsock.h>
677#endif
cecf0f21 678#include <pwd.h>
237e0016 679
237e0016
RS
680#define NOTOK (-1)
681#define OK 0
682#define DONE 1
683
684char *progname;
685FILE *sfi;
686FILE *sfo;
2e82e3c3
RS
687char ibuffer[BUFSIZ];
688char obuffer[BUFSIZ];
752fb472
DL
689char Errmsg[200]; /* POP errors, at least, can exceed
690 the original length of 80. */
237e0016 691
476b2799
GM
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
704popmail (mailbox, outfile, preserve, password, reverse_order)
705 char *mailbox;
b1ce62a8 706 char *outfile;
fea4325c 707 int preserve;
7f75d5c6 708 char *password;
a2997b0f 709 int reverse_order;
237e0016 710{
b1ce62a8 711 int nmsgs, nbytes;
b1ce62a8
RS
712 register int i;
713 int mbfi;
714 FILE *mbf;
2e82e3c3 715 char *getenv ();
b32701a7 716 popserver server;
a2997b0f 717 int start, end, increment;
476b2799
GM
718 char *user, *hostname;
719
720 user = mailbox;
721 if ((hostname = index(mailbox, ':')))
722 *hostname++ = '\0';
237e0016 723
476b2799 724 server = pop_open (hostname, user, password, POP_NO_GETPASS);
2e82e3c3 725 if (! server)
b1ce62a8 726 {
9b956af2 727 error ("Error connecting to POP server: %s", pop_error);
2e82e3c3 728 return (1);
237e0016
RS
729 }
730
2e82e3c3 731 if (pop_stat (server, &nmsgs, &nbytes))
b1ce62a8 732 {
9b956af2 733 error ("Error getting message count from POP server: %s", pop_error);
2e82e3c3 734 return (1);
237e0016
RS
735 }
736
b1ce62a8
RS
737 if (!nmsgs)
738 {
2e82e3c3
RS
739 pop_close (server);
740 return (0);
b1ce62a8
RS
741 }
742
743 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
744 if (mbfi < 0)
745 {
2e82e3c3
RS
746 pop_close (server);
747 error ("Error in open: %s, %s", strerror (errno), outfile);
748 return (1);
b1ce62a8
RS
749 }
750 fchown (mbfi, getuid (), -1);
751
7f75d5c6 752 if ((mbf = fdopen (mbfi, "wb")) == NULL)
b1ce62a8 753 {
2e82e3c3
RS
754 pop_close (server);
755 error ("Error in fdopen: %s", strerror (errno));
756 close (mbfi);
757 unlink (outfile);
758 return (1);
b1ce62a8
RS
759 }
760
a2997b0f
KH
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)
b1ce62a8
RS
775 {
776 mbx_delimit_begin (mbf);
ff804ff5 777 if (pop_retr (server, i, mbf) != OK)
b1ce62a8 778 {
2e82e3c3 779 error (Errmsg);
b1ce62a8 780 close (mbfi);
2e82e3c3 781 return (1);
237e0016 782 }
b1ce62a8
RS
783 mbx_delimit_end (mbf);
784 fflush (mbf);
2e82e3c3
RS
785 if (ferror (mbf))
786 {
787 error ("Error in fflush: %s", strerror (errno));
788 pop_close (server);
789 close (mbfi);
790 return (1);
791 }
237e0016
RS
792 }
793
2e82e3c3
RS
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
e397a017 800#ifdef BSD_SYSTEM
cfa191ff
RS
801 if (fsync (mbfi) < 0)
802 {
2e82e3c3
RS
803 error ("Error in fsync: %s", strerror (errno));
804 return (1);
cfa191ff 805 }
340ff9de 806#endif
cfa191ff
RS
807
808 if (close (mbfi) == -1)
809 {
2e82e3c3
RS
810 error ("Error in close: %s", strerror (errno));
811 return (1);
cfa191ff
RS
812 }
813
fea4325c
RS
814 if (! preserve)
815 for (i = 1; i <= nmsgs; i++)
816 {
817 if (pop_delete (server, i))
818 {
9b956af2 819 error ("Error from POP server: %s", pop_error);
fea4325c
RS
820 pop_close (server);
821 return (1);
822 }
823 }
237e0016 824
2e82e3c3 825 if (pop_quit (server))
b1ce62a8 826 {
9b956af2 827 error ("Error from POP server: %s", pop_error);
2e82e3c3 828 return (1);
237e0016 829 }
237e0016 830
2e82e3c3 831 return (0);
237e0016
RS
832}
833
ff804ff5
KH
834int
835pop_retr (server, msgno, arg)
b32701a7 836 popserver server;
ff804ff5 837 FILE *arg;
237e0016 838{
2e82e3c3
RS
839 extern char *strerror ();
840 char *line;
841 int ret;
237e0016 842
2e82e3c3 843 if (pop_retrieve_first (server, msgno, &line))
b1ce62a8 844 {
9b956af2
KH
845 char *error = concat ("Error from POP server: ", pop_error, "");
846 strncpy (Errmsg, error, sizeof (Errmsg));
2e82e3c3 847 Errmsg[sizeof (Errmsg)-1] = '\0';
9b956af2 848 free(error);
2e82e3c3 849 return (NOTOK);
237e0016
RS
850 }
851
d89d0243 852 while ((ret = pop_retrieve_next (server, &line)) >= 0)
b1ce62a8 853 {
2e82e3c3
RS
854 if (! line)
855 break;
856
d89d0243 857 if (mbx_write (line, ret, arg) != OK)
b1ce62a8 858 {
2e82e3c3
RS
859 strcpy (Errmsg, strerror (errno));
860 pop_close (server);
861 return (NOTOK);
237e0016
RS
862 }
863 }
237e0016 864
2e82e3c3 865 if (ret)
b1ce62a8 866 {
9b956af2
KH
867 char *error = concat ("Error from POP server: ", pop_error, "");
868 strncpy (Errmsg, error, sizeof (Errmsg));
2e82e3c3 869 Errmsg[sizeof (Errmsg)-1] = '\0';
9b956af2 870 free(error);
2e82e3c3 871 return (NOTOK);
237e0016
RS
872 }
873
2e82e3c3 874 return (OK);
237e0016
RS
875}
876
2e82e3c3
RS
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] == ' '))
237e0016 883
2e82e3c3 884int
d89d0243 885mbx_write (line, len, mbf)
b1ce62a8 886 char *line;
d89d0243 887 int len;
b1ce62a8 888 FILE *mbf;
237e0016 889{
d04f5031 890#ifdef MOVEMAIL_QUOTE_POP_FROM_LINES
2e82e3c3
RS
891 if (IS_FROM_LINE (line))
892 {
893 if (fputc ('>', mbf) == EOF)
894 return (NOTOK);
895 }
d04f5031
PE
896#endif
897 if (line[0] == '\037')
898 {
899 if (fputs ("^_", mbf) == EOF)
900 return (NOTOK);
901 line++;
902 len--;
903 }
d89d0243 904 if (fwrite (line, 1, len, mbf) != len)
2e82e3c3
RS
905 return (NOTOK);
906 if (fputc (0x0a, mbf) == EOF)
907 return (NOTOK);
908 return (OK);
237e0016
RS
909}
910
2e82e3c3 911int
b1ce62a8
RS
912mbx_delimit_begin (mbf)
913 FILE *mbf;
237e0016 914{
2e82e3c3
RS
915 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF)
916 return (NOTOK);
917 return (OK);
237e0016
RS
918}
919
b1ce62a8
RS
920mbx_delimit_end (mbf)
921 FILE *mbf;
237e0016 922{
2e82e3c3
RS
923 if (putc ('\037', mbf) == EOF)
924 return (NOTOK);
925 return (OK);
237e0016
RS
926}
927
928#endif /* MAIL_USE_POP */
e5f7ea68
RM
929\f
930#ifndef HAVE_STRERROR
931char *
932strerror (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 */