comparison lib-src/movemail.c @ 118:7d55a9ba150c r20-1b11

Import from CVS: tag r20-1b11
author cvs
date Mon, 13 Aug 2007 09:24:17 +0200
parents 131b0175ea99
children d2f30a177268
comparison
equal deleted inserted replaced
117:578fd4947a72 118:7d55a9ba150c
1 /* movemail foo bar -- move file foo to file bar, 1 /* movemail foo bar -- move file foo to file bar,
2 locking file foo the way /bin/mail respects. 2 locking file foo the way /bin/mail respects.
3 Copyright (C) 1986, 1992, 1993, 1994 Free Software Foundation, Inc. 3 Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
4 4
5 This file is part of GNU Emacs. 5 This file is part of GNU Emacs.
6 6
7 GNU Emacs is free software; you can redistribute it and/or modify 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 8 it under the terms of the GNU General Public License as published by
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details. 15 GNU General Public License for more details.
16 16
17 You should have received a copy of the GNU General Public License 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 18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */ 20 Boston, MA 02111-1307, USA. */
21
22 /* Synched up with: FSF 19.28. */
23 21
24 /* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will 22 /* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will
25 cause loss of mail* if you do it on a system that does not normally 23 cause loss of mail* if you do it on a system that does not normally
26 use flock as its way of interlocking access to inbox files. The 24 use flock as its way of interlocking access to inbox files. The
27 setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the 25 setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the
34 a setuid or setgid program. */ 32 a setuid or setgid program. */
35 33
36 /* 34 /*
37 * Modified January, 1986 by Michael R. Gretzinger (Project Athena) 35 * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
38 * 36 *
39 * Added POP (Post Office Protocol) service. When compiled -DPOP 37 * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP
40 * movemail will accept input filename arguments of the form 38 * movemail will accept input filename arguments of the form
41 * "po:username". This will cause movemail to open a connection to 39 * "po:username". This will cause movemail to open a connection to
42 * a pop server running on $MAILHOST (environment variable). Movemail 40 * a pop server running on $MAILHOST (environment variable). Movemail
43 * must be setuid to root in order to work with POP. 41 * must be setuid to root in order to work with POP.
44 * 42 *
47 * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ()) 45 * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ())
48 * after POP code. 46 * after POP code.
49 * New routines in movemail.c: 47 * New routines in movemail.c:
50 * get_errmsg - return pointer to system error message 48 * get_errmsg - return pointer to system error message
51 * 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 *
52 */ 55 */
53 56
54 #define NO_SHORTNAMES /* Tell config not to load remap.h */ 57 #define NO_SHORTNAMES /* Tell config not to load remap.h */
55 #include <../src/config.h> 58 #include <../src/config.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 #include <time.h> /* for time() */
59 #include <stdio.h> /* for printf() */
60 #include <string.h> /* strcpy() */
61
62 #include <sys/types.h> 59 #include <sys/types.h>
63 #include <sys/stat.h> 60 #include <sys/stat.h>
64 #include <sys/file.h> 61 #include <sys/file.h>
62 #include <stdio.h>
65 #include <errno.h> 63 #include <errno.h>
66 #include <../src/syswait.h> 64 #include <../src/syswait.h>
65 #ifdef MAIL_USE_POP
66 #include "pop.h"
67 #endif
67 68
68 #ifdef MSDOS 69 #ifdef MSDOS
69 #undef access 70 #undef access
70 #endif /* MSDOS */ 71 #endif /* MSDOS */
71 72
73 #ifndef DIRECTORY_SEP
74 #define DIRECTORY_SEP '/'
75 #endif
76 #ifndef IS_DIRECTORY_SEP
77 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
78 #endif
79
80 #ifdef WINDOWSNT
81 #undef access
82 #undef unlink
83 #define fork() 0
84 #define sys_wait(var) (*(var) = 0)
85 /* Unfortunately, Samba doesn't seem to properly lock Unix files even
86 though the locking call succeeds (and indeed blocks local access from
87 other NT programs). If you have direct file access using an NFS
88 client or something other than Samba, the locking call might work
89 properly - make sure it does before you enable this! */
90 #define DISABLE_DIRECT_ACCESS
91 #endif /* WINDOWSNT */
92
72 #ifdef USG 93 #ifdef USG
73 #include <fcntl.h> 94 #include <fcntl.h>
74 #include <unistd.h> 95 #include <unistd.h>
75 #if defined (sun)
76 #include <stdlib.h>
77 #endif /* sun */
78 #ifndef F_OK 96 #ifndef F_OK
79 #define F_OK 0 97 #define F_OK 0
80 #define X_OK 1 98 #define X_OK 1
81 #define W_OK 2 99 #define W_OK 2
82 #define R_OK 4 100 #define R_OK 4
85 103
86 #ifdef HAVE_UNISTD_H 104 #ifdef HAVE_UNISTD_H
87 #include <unistd.h> 105 #include <unistd.h>
88 #endif 106 #endif
89 107
90 #ifdef XENIX 108 #if defined (XENIX) || defined (WINDOWSNT)
91 #include <sys/locking.h> 109 #include <sys/locking.h>
92 #endif 110 #endif
93 111
94 #ifdef MAIL_USE_LOCKF 112 #ifdef MAIL_USE_LOCKF
95 #define MAIL_USE_SYSTEM_LOCK 113 #define MAIL_USE_SYSTEM_LOCK
107 #undef open 125 #undef open
108 #undef read 126 #undef read
109 #undef write 127 #undef write
110 #undef close 128 #undef close
111 129
112 static char *concat (CONST char *s1, CONST char *s2, CONST char *s3);
113 static void *xmalloc (unsigned int size);
114 #ifndef errno 130 #ifndef errno
115 extern int errno; 131 extern int errno;
116 #endif 132 #endif
117 133 char *strerror ();
118 static void error (CONST char *s1, CONST char *s2, CONST char *s3); 134
119 static void fatal (CONST char *s1, CONST char *s2); 135 void fatal ();
120 static void pfatal_with_name (CONST char *name); 136 void error ();
121 static void pfatal_and_delete (CONST char *name); 137 void pfatal_with_name ();
122 138 void pfatal_and_delete ();
123 #ifndef HAVE_STRERROR 139 char *concat ();
124 char *strerror (int); 140 long *xmalloc ();
125 #endif 141 int popmail ();
142 int pop_retr ();
143 int mbx_write ();
144 int mbx_delimit_begin ();
145 int mbx_delimit_end ();
126 146
127 /* Nonzero means this is name of a lock file to delete on fatal error. */ 147 /* Nonzero means this is name of a lock file to delete on fatal error. */
128 char *delete_lockname; 148 char *delete_lockname;
129 149
130 void 150 int
131 main (argc, argv) 151 main (argc, argv)
132 int argc; 152 int argc;
133 char **argv; 153 char **argv;
134 { 154 {
135 char *inname, *outname; 155 char *inname, *outname;
147 #endif /* not MAIL_USE_SYSTEM_LOCK */ 167 #endif /* not MAIL_USE_SYSTEM_LOCK */
148 168
149 delete_lockname = 0; 169 delete_lockname = 0;
150 170
151 if (argc < 3) 171 if (argc < 3)
152 fatal ("two arguments required", ""); 172 {
173 fprintf (stderr, "Usage: movemail inbox destfile [POP-password]\n");
174 exit(1);
175 }
153 176
154 inname = argv[1]; 177 inname = argv[1];
155 outname = argv[2]; 178 outname = argv[2];
156 179
157 #ifdef MAIL_USE_MMDF 180 #ifdef MAIL_USE_MMDF
158 mmdf_init (argv[0]); 181 mmdf_init (argv[0]);
159 #endif 182 #endif
183
184 if (*outname == 0)
185 fatal ("Destination file name is empty", 0);
160 186
161 /* Check access to output file. */ 187 /* Check access to output file. */
162 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) 188 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
163 pfatal_with_name (outname); 189 pfatal_with_name (outname);
164 190
165 /* Also check that outname's directory is writeable to the real uid. */ 191 /* Also check that outname's directory is writable to the real uid. */
166 { 192 {
167 char *buf = (char *) xmalloc (strlen (outname) + 1); 193 char *buf = (char *) xmalloc (strlen (outname) + 1);
168 char *p; 194 char *p;
169 strcpy (buf, outname); 195 strcpy (buf, outname);
170 p = buf + strlen (buf); 196 p = buf + strlen (buf);
171 while (p > buf && p[-1] != '/') 197 while (p > buf && !IS_DIRECTORY_SEP (p[-1]))
172 *--p = 0; 198 *--p = 0;
173 if (p == buf) 199 if (p == buf)
174 *p++ = '.'; 200 *p++ = '.';
175 if (access (buf, W_OK) != 0) 201 if (access (buf, W_OK) != 0)
176 pfatal_with_name (buf); 202 pfatal_with_name (buf);
177 free (buf); 203 free (buf);
178 } 204 }
179 205
180 #ifdef MAIL_USE_POP 206 #ifdef MAIL_USE_POP
181 if (!memcmp (inname, "po:", 3)) 207 if (!strncmp (inname, "po:", 3))
182 { 208 {
183 int status; char *user; 209 int status;
184 210
185 for (user = &inname[strlen (inname) - 1]; user >= inname; user--) 211 status = popmail (inname + 3, outname, argc > 3 ? argv[3] : NULL);
186 if (*user == ':')
187 break;
188
189 status = popmail (user, outname);
190 exit (status); 212 exit (status);
191 } 213 }
192 214
193 setuid (getuid ()); 215 setuid (getuid ());
194 #endif /* MAIL_USE_POP */ 216 #endif /* MAIL_USE_POP */
217
218 #ifndef DISABLE_DIRECT_ACCESS
195 219
196 /* Check access to input file. */ 220 /* Check access to input file. */
197 if (access (inname, R_OK | W_OK) != 0) 221 if (access (inname, R_OK | W_OK) != 0)
198 pfatal_with_name (inname); 222 pfatal_with_name (inname);
199 223
200 #ifndef MAIL_USE_MMDF 224 #ifndef MAIL_USE_MMDF
201 #ifndef MAIL_USE_SYSTEM_LOCK 225 #ifndef MAIL_USE_SYSTEM_LOCK
202 /* Use a lock file named /usr/spool/mail/$USER.lock: 226 /* Use a lock file named after our first argument with .lock appended:
203 If it exists, the mail file is locked. */ 227 If it exists, the mail file is locked. */
204 /* Note: this locking mechanism is *required* by the mailer 228 /* Note: this locking mechanism is *required* by the mailer
205 (on systems which use it) to prevent loss of mail. 229 (on systems which use it) to prevent loss of mail.
206 230
207 On systems that use a lock file, extracting the mail without locking 231 On systems that use a lock file, extracting the mail without locking
208 WILL occasionally cause loss of mail due to timing errors! 232 WILL occasionally cause loss of mail due to timing errors!
209 233
210 So, if creation of the lock file fails 234 So, if creation of the lock file fails
211 due to access permission on /usr/spool/mail, 235 due to access permission on the mail spool directory,
212 you simply MUST change the permission 236 you simply MUST change the permission
213 and/or make movemail a setgid program 237 and/or make movemail a setgid program
214 so it can create lock files properly. 238 so it can create lock files properly.
215 239
216 You might also wish to verify that your system is one 240 You might also wish to verify that your system is one
224 248
225 lockname = concat (inname, ".lock", ""); 249 lockname = concat (inname, ".lock", "");
226 tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); 250 tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1);
227 strcpy (tempname, inname); 251 strcpy (tempname, inname);
228 p = tempname + strlen (tempname); 252 p = tempname + strlen (tempname);
229 while (p != tempname && p[-1] != '/') 253 while (p != tempname && !IS_DIRECTORY_SEP (p[-1]))
230 p--; 254 p--;
231 *p = 0; 255 *p = 0;
232 strcpy (p, "EXXXXXX"); 256 strcpy (p, "EXXXXXX");
233 mktemp (tempname); 257 mktemp (tempname);
234 unlink (tempname); 258 unlink (tempname);
237 { 261 {
238 /* Create the lock file, but not under the lock file name. */ 262 /* Create the lock file, but not under the lock file name. */
239 /* Give up if cannot do that. */ 263 /* Give up if cannot do that. */
240 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); 264 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666);
241 if (desc < 0) 265 if (desc < 0)
242 pfatal_with_name ("lock file--see source file lib-src/movemail.c"); 266 {
267 char *message = (char *) xmalloc (strlen (tempname) + 50);
268 sprintf (message, "%s--see source file lib-src/movemail.c",
269 tempname);
270 pfatal_with_name (message);
271 }
243 close (desc); 272 close (desc);
244 273
245 tem = link (tempname, lockname); 274 tem = link (tempname, lockname);
246 unlink (tempname); 275 unlink (tempname);
247 if (tem >= 0) 276 if (tem >= 0)
248 break; 277 break;
249 sleep (1); 278 sleep (1);
250 279
251 /* If lock file is a minute old, unlock it. */ 280 /* If lock file is five minutes old, unlock it.
281 Five minutes should be good enough to cope with crashes
282 and wedgitude, and long enough to avoid being fooled
283 by time differences between machines. */
252 if (stat (lockname, &st) >= 0) 284 if (stat (lockname, &st) >= 0)
253 { 285 {
254 now = time (0); 286 now = time (0);
255 if (st.st_ctime < now - 60) 287 if (st.st_ctime < now - 300)
256 unlink (lockname); 288 unlink (lockname);
257 } 289 }
258 } 290 }
259 291
260 delete_lockname = lockname; 292 delete_lockname = lockname;
261 #endif /* not MAIL_USE_SYSTEM_LOCK */ 293 #endif /* not MAIL_USE_SYSTEM_LOCK */
293 if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname); 325 if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname);
294 #else /* not MAIL_USE_LOCKF */ 326 #else /* not MAIL_USE_LOCKF */
295 #ifdef XENIX 327 #ifdef XENIX
296 if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); 328 if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname);
297 #else 329 #else
330 #ifdef WINDOWSNT
331 if (locking (indesc, LK_RLCK, -1L) < 0) pfatal_with_name (inname);
332 #else
298 if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); 333 if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname);
334 #endif
299 #endif 335 #endif
300 #endif /* not MAIL_USE_LOCKF */ 336 #endif /* not MAIL_USE_LOCKF */
301 #endif /* MAIL_USE_SYSTEM_LOCK */ 337 #endif /* MAIL_USE_SYSTEM_LOCK */
302 338
303 { 339 {
326 /* Check to make sure no errors before we zap the inbox. */ 362 /* Check to make sure no errors before we zap the inbox. */
327 if (close (outdesc) != 0) 363 if (close (outdesc) != 0)
328 pfatal_and_delete (outname); 364 pfatal_and_delete (outname);
329 365
330 #ifdef MAIL_USE_SYSTEM_LOCK 366 #ifdef MAIL_USE_SYSTEM_LOCK
331 #if defined (STRIDE) || defined (XENIX) 367 #if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT)
332 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ 368 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
333 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); 369 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
334 #else 370 #else
335 ftruncate (indesc, 0L); 371 ftruncate (indesc, 0L);
336 #endif /* STRIDE or XENIX */ 372 #endif /* STRIDE or XENIX */
363 exit (WRETCODE (status)); 399 exit (WRETCODE (status));
364 400
365 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK) 401 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
366 unlink (lockname); 402 unlink (lockname);
367 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */ 403 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
368 exit (0); 404
405 #endif /* ! DISABLE_DIRECT_ACCESS */
406
407 return 0;
369 } 408 }
370 409
371 /* Print error message and exit. */ 410 /* Print error message and exit. */
372 411
373 static void 412 void
374 fatal (s1, s2) 413 fatal (s1, s2)
375 CONST char *s1, *s2; 414 char *s1, *s2;
376 { 415 {
377 if (delete_lockname) 416 if (delete_lockname)
378 error (s1, s2, "");
379 unlink (delete_lockname); 417 unlink (delete_lockname);
418 error (s1, s2);
380 exit (1); 419 exit (1);
381 } 420 }
382 421
383 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ 422 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
384 423
385 static void 424 void
386 error (s1, s2, s3) 425 error (s1, s2, s3)
387 CONST char *s1, *s2, *s3; 426 char *s1, *s2, *s3;
388 { 427 {
389 printf ("movemail: "); 428 fprintf (stderr, "movemail: ");
390 printf (s1, s2, s3); 429 fprintf (stderr, s1, s2, s3);
391 printf ("\n"); 430 fprintf (stderr, "\n");
392 } 431 }
393 432
394 static void 433 void
395 pfatal_with_name (name) 434 pfatal_with_name (name)
396 CONST char *name; 435 char *name;
397 { 436 {
398 char *s; 437 char *s = concat ("", strerror (errno), " for %s");
399
400 s = concat ("", strerror (errno), " for %s");
401 fatal (s, name); 438 fatal (s, name);
402 } 439 }
403 440
404 static void 441 void
405 pfatal_and_delete (name) 442 pfatal_and_delete (name)
406 CONST char *name; 443 char *name;
407 { 444 {
408 char *s; 445 char *s = concat ("", strerror (errno), " for %s");
409
410 s = concat ("", strerror (errno), " for %s");
411 unlink (name); 446 unlink (name);
412 fatal (s, name); 447 fatal (s, name);
413 } 448 }
414 449
415 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ 450 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
416 451
417 static char * 452 char *
418 concat (s1, s2, s3) 453 concat (s1, s2, s3)
419 CONST char *s1, *s2, *s3; 454 char *s1, *s2, *s3;
420 { 455 {
421 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); 456 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
422 char *result = (char *) xmalloc (len1 + len2 + len3 + 1); 457 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
423 458
424 strcpy (result, s1); 459 strcpy (result, s1);
429 return result; 464 return result;
430 } 465 }
431 466
432 /* Like malloc but get fatal error if memory is exhausted. */ 467 /* Like malloc but get fatal error if memory is exhausted. */
433 468
434 static void * 469 long *
435 xmalloc (size) 470 xmalloc (size)
436 unsigned int size; 471 unsigned size;
437 { 472 {
438 void *result = (void *) malloc (size); 473 long *result = (long *) malloc (size);
439 if (!result) 474 if (!result)
440 fatal ("virtual memory exhausted", (char *) 0); 475 fatal ("virtual memory exhausted", 0);
441 return result; 476 return result;
442 } 477 }
443 478
444 /* This is the guts of the interface to the Post Office Protocol. */ 479 /* This is the guts of the interface to the Post Office Protocol. */
445 480
446 #ifdef MAIL_USE_POP 481 #ifdef MAIL_USE_POP
447 482
483 #ifndef WINDOWSNT
448 #include <sys/socket.h> 484 #include <sys/socket.h>
449 #include <netinet/in.h> 485 #include <netinet/in.h>
450 #include <netdb.h> 486 #include <netdb.h>
487 #else
488 #undef _WINSOCKAPI_
489 #include <winsock.h>
490 #endif
451 #include <stdio.h> 491 #include <stdio.h>
452 #include <pwd.h> 492 #include <pwd.h>
453 493
454 #ifdef USG 494 #ifdef USG
455 #include <fcntl.h> 495 #include <fcntl.h>
465 #define DONE 1 505 #define DONE 1
466 506
467 char *progname; 507 char *progname;
468 FILE *sfi; 508 FILE *sfi;
469 FILE *sfo; 509 FILE *sfo;
510 char ibuffer[BUFSIZ];
511 char obuffer[BUFSIZ];
470 char Errmsg[80]; 512 char Errmsg[80];
471 513
472 static int debug = 0; 514 popmail (user, outfile, password)
473
474 char *get_errmsg ();
475 char *getenv ();
476 int mbx_write ();
477
478 int
479 popmail (user, outfile)
480 char *user; 515 char *user;
481 char *outfile; 516 char *outfile;
482 { 517 char *password;
483 char *host; 518 {
484 int nmsgs, nbytes; 519 int nmsgs, nbytes;
485 char response[128];
486 register int i; 520 register int i;
487 int mbfi; 521 int mbfi;
488 FILE *mbf; 522 FILE *mbf;
489 struct passwd *pw = (struct passwd *) getpwuid (getuid ()); 523 char *getenv ();
490 if (pw == NULL) 524 int mbx_write ();
491 fatal ("cannot determine user name"); 525 popserver server;
492 526 extern char *strerror ();
493 host = getenv ("MAILHOST"); 527
494 if (host == NULL) 528 server = pop_open (0, user, password, POP_NO_GETPASS);
495 { 529 if (! server)
496 fatal ("no MAILHOST defined"); 530 {
497 } 531 error (pop_error);
498 532 return (1);
499 if (pop_init (host) == NOTOK) 533 }
500 { 534
501 fatal (Errmsg); 535 if (pop_stat (server, &nmsgs, &nbytes))
502 } 536 {
503 537 error (pop_error);
504 if (getline (response, sizeof response, sfi) != OK) 538 return (1);
505 {
506 fatal (response);
507 }
508
509 if (pop_command ("USER %s", user) == NOTOK
510 || pop_command ("RPOP %s", pw->pw_name) == NOTOK)
511 {
512 pop_command ("QUIT");
513 fatal (Errmsg);
514 }
515
516 if (pop_stat (&nmsgs, &nbytes) == NOTOK)
517 {
518 pop_command ("QUIT");
519 fatal (Errmsg);
520 } 539 }
521 540
522 if (!nmsgs) 541 if (!nmsgs)
523 { 542 {
524 pop_command ("QUIT"); 543 pop_close (server);
525 return 0; 544 return (0);
526 } 545 }
527 546
528 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); 547 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
529 if (mbfi < 0) 548 if (mbfi < 0)
530 { 549 {
531 pop_command ("QUIT"); 550 pop_close (server);
532 pfatal_and_delete (outfile); 551 error ("Error in open: %s, %s", strerror (errno), outfile);
533 } 552 return (1);
553 }
534 fchown (mbfi, getuid (), -1); 554 fchown (mbfi, getuid (), -1);
535 555
536 if ((mbf = fdopen (mbfi, "w")) == NULL) 556 if ((mbf = fdopen (mbfi, "wb")) == NULL)
537 { 557 {
538 pop_command ("QUIT"); 558 pop_close (server);
539 pfatal_and_delete (outfile); 559 error ("Error in fdopen: %s", strerror (errno));
540 } 560 close (mbfi);
541 561 unlink (outfile);
542 for (i = 1; i <= nmsgs; i++) 562 return (1);
563 }
564
565 for (i = 1; i <= nmsgs; i++)
543 { 566 {
544 mbx_delimit_begin (mbf); 567 mbx_delimit_begin (mbf);
545 if (pop_retr (i, mbx_write, mbf) != OK) 568 if (pop_retr (server, i, mbx_write, mbf) != OK)
546 { 569 {
547 pop_command ("QUIT"); 570 error (Errmsg);
548 close (mbfi); 571 close (mbfi);
549 unlink (outfile); 572 return (1);
550 fatal (Errmsg); 573 }
551 }
552 mbx_delimit_end (mbf); 574 mbx_delimit_end (mbf);
553 fflush (mbf); 575 fflush (mbf);
554 } 576 if (ferror (mbf))
555 577 {
578 error ("Error in fflush: %s", strerror (errno));
579 pop_close (server);
580 close (mbfi);
581 return (1);
582 }
583 }
584
585 /* On AFS, a call to write only modifies the file in the local
586 * workstation's AFS cache. The changes are not written to the server
587 * until a call to fsync or close is made. Users with AFS home
588 * directories have lost mail when over quota because these checks were
589 * not made in previous versions of movemail. */
590
591 #ifdef BSD
556 if (fsync (mbfi) < 0) 592 if (fsync (mbfi) < 0)
557 { 593 {
558 pop_command ("QUIT"); 594 error ("Error in fsync: %s", strerror (errno));
559 pfatal_and_delete (outfile); 595 return (1);
560 } 596 }
597 #endif
561 598
562 if (close (mbfi) == -1) 599 if (close (mbfi) == -1)
563 { 600 {
564 pop_command ("QUIT"); 601 error ("Error in close: %s", strerror (errno));
565 pfatal_and_delete (outfile); 602 return (1);
566 } 603 }
567 604
568 for (i = 1; i <= nmsgs; i++) 605 for (i = 1; i <= nmsgs; i++)
569 { 606 {
570 if (pop_command ("DELE %d", i) == NOTOK) 607 if (pop_delete (server, i))
571 { 608 {
572 /* Better to ignore this failure. */ 609 error (pop_error);
573 } 610 pop_close (server);
574 } 611 return (1);
575 612 }
576 pop_command ("QUIT"); 613 }
614
615 if (pop_quit (server))
616 {
617 error (pop_error);
618 return (1);
619 }
620
577 return (0); 621 return (0);
578 } 622 }
579 623
624 pop_retr (server, msgno, action, arg)
625 popserver server;
626 int (*action)();
627 {
628 extern char *strerror ();
629 char *line;
630 int ret;
631
632 if (pop_retrieve_first (server, msgno, &line))
633 {
634 strncpy (Errmsg, pop_error, sizeof (Errmsg));
635 Errmsg[sizeof (Errmsg)-1] = '\0';
636 return (NOTOK);
637 }
638
639 while (! (ret = pop_retrieve_next (server, &line)))
640 {
641 if (! line)
642 break;
643
644 if ((*action)(line, arg) != OK)
645 {
646 strcpy (Errmsg, strerror (errno));
647 pop_close (server);
648 return (NOTOK);
649 }
650 }
651
652 if (ret)
653 {
654 strncpy (Errmsg, pop_error, sizeof (Errmsg));
655 Errmsg[sizeof (Errmsg)-1] = '\0';
656 return (NOTOK);
657 }
658
659 return (OK);
660 }
661
662 /* Do this as a macro instead of using strcmp to save on execution time. */
663 #define IS_FROM_LINE(a) ((a[0] == 'F') \
664 && (a[1] == 'r') \
665 && (a[2] == 'o') \
666 && (a[3] == 'm') \
667 && (a[4] == ' '))
668
580 int 669 int
581 pop_init (host)
582 char *host;
583 {
584 register struct hostent *hp;
585 register struct servent *sp;
586 int lport = IPPORT_RESERVED - 1;
587 struct sockaddr_in sin;
588 register int s;
589
590 hp = gethostbyname (host);
591 if (hp == NULL)
592 {
593 sprintf (Errmsg, "MAILHOST unknown: %s", host);
594 return NOTOK;
595 }
596
597 sp = getservbyname ("pop", "tcp");
598 if (sp == 0)
599 {
600 strcpy (Errmsg, "tcp/pop: unknown service");
601 return NOTOK;
602 }
603
604 sin.sin_family = hp->h_addrtype;
605 memcpy ((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
606 sin.sin_port = sp->s_port;
607 s = rresvport (&lport);
608 if (s < 0)
609 {
610 sprintf (Errmsg, "error creating socket: %s", get_errmsg ());
611 return NOTOK;
612 }
613
614 if (connect (s, (char *)&sin, sizeof sin) < 0)
615 {
616 sprintf (Errmsg, "error during connect: %s", get_errmsg ());
617 close (s);
618 return NOTOK;
619 }
620
621 sfi = fdopen (s, "r");
622 sfo = fdopen (s, "w");
623 if (sfi == NULL || sfo == NULL)
624 {
625 sprintf (Errmsg, "error in fdopen: %s", get_errmsg ());
626 close (s);
627 return NOTOK;
628 }
629
630 return OK;
631 }
632
633 int
634 pop_command (fmt, a, b, c, d)
635 char *fmt;
636 {
637 char buf[128];
638 char errmsg[64];
639
640 sprintf (buf, fmt, a, b, c, d);
641
642 if (debug) fprintf (stderr, "---> %s\n", buf);
643 if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK;
644
645 if (getline (buf, sizeof buf, sfi) != OK)
646 {
647 strcpy (Errmsg, buf);
648 return NOTOK;
649 }
650
651 if (debug) fprintf (stderr, "<--- %s\n", buf);
652 if (*buf != '+')
653 {
654 strcpy (Errmsg, buf);
655 return NOTOK;
656 }
657 else
658 {
659 return OK;
660 }
661 }
662
663
664 pop_stat (nmsgs, nbytes)
665 int *nmsgs, *nbytes;
666 {
667 char buf[128];
668
669 if (debug) fprintf (stderr, "---> STAT\n");
670 if (putline ("STAT", Errmsg, sfo) == NOTOK)
671 return NOTOK;
672
673 if (getline (buf, sizeof buf, sfi) != OK)
674 {
675 strcpy (Errmsg, buf);
676 return NOTOK;
677 }
678
679 if (debug) fprintf (stderr, "<--- %s\n", buf);
680 if (*buf != '+')
681 {
682 strcpy (Errmsg, buf);
683 return NOTOK;
684 }
685 else
686 {
687 sscanf (buf, "+OK %d %d", nmsgs, nbytes);
688 return OK;
689 }
690 }
691
692 pop_retr (msgno, action, arg)
693 int (*action)();
694 {
695 char buf[128];
696
697 sprintf (buf, "RETR %d", msgno);
698 if (debug) fprintf (stderr, "%s\n", buf);
699 if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK;
700
701 if (getline (buf, sizeof buf, sfi) != OK)
702 {
703 strcpy (Errmsg, buf);
704 return NOTOK;
705 }
706
707 while (1)
708 {
709 switch (multiline (buf, sizeof buf, sfi))
710 {
711 case OK:
712 (*action)(buf, arg);
713 break;
714 case DONE:
715 return OK;
716 case NOTOK:
717 strcpy (Errmsg, buf);
718 return NOTOK;
719 }
720 }
721 }
722
723 getline (buf, n, f)
724 char *buf;
725 register int n;
726 FILE *f;
727 {
728 register char *p;
729 int c;
730
731 p = buf;
732 while (--n > 0 && (c = fgetc (f)) != EOF)
733 if ((*p++ = c) == '\n') break;
734
735 if (ferror (f))
736 {
737 strcpy (buf, "error on connection");
738 return NOTOK;
739 }
740
741 if (c == EOF && p == buf)
742 {
743 strcpy (buf, "connection closed by foreign host");
744 return DONE;
745 }
746
747 *p = NULL;
748 if (*--p == '\n') *p = NULL;
749 if (*--p == '\r') *p = NULL;
750 return OK;
751 }
752
753 multiline (buf, n, f)
754 char *buf;
755 register int n;
756 FILE *f;
757 {
758 if (getline (buf, n, f) != OK) return NOTOK;
759 if (*buf == '.')
760 {
761 if (*(buf+1) == NULL)
762 return DONE;
763 else
764 strcpy (buf, buf+1);
765 }
766 return OK;
767 }
768
769 char *
770 get_errmsg ()
771 {
772 return strerror (errno);
773 }
774
775 putline (buf, err, f)
776 char *buf;
777 char *err;
778 FILE *f;
779 {
780 fprintf (f, "%s\r\n", buf);
781 fflush (f);
782 if (ferror (f))
783 {
784 strcpy (err, "lost connection");
785 return NOTOK;
786 }
787 return OK;
788 }
789
790 mbx_write (line, mbf) 670 mbx_write (line, mbf)
791 char *line; 671 char *line;
792 FILE *mbf; 672 FILE *mbf;
793 { 673 {
794 fputs (line, mbf); 674 if (IS_FROM_LINE (line))
795 fputc (0x0a, mbf); 675 {
796 } 676 if (fputc ('>', mbf) == EOF)
797 677 return (NOTOK);
678 }
679 if (fputs (line, mbf) == EOF)
680 return (NOTOK);
681 if (fputc (0x0a, mbf) == EOF)
682 return (NOTOK);
683 return (OK);
684 }
685
686 int
798 mbx_delimit_begin (mbf) 687 mbx_delimit_begin (mbf)
799 FILE *mbf; 688 FILE *mbf;
800 { 689 {
801 fputs ("\f\n0, unseen,,\n", mbf); 690 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF)
691 return (NOTOK);
692 return (OK);
802 } 693 }
803 694
804 mbx_delimit_end (mbf) 695 mbx_delimit_end (mbf)
805 FILE *mbf; 696 FILE *mbf;
806 { 697 {
807 putc ('\037', mbf); 698 if (putc ('\037', mbf) == EOF)
699 return (NOTOK);
700 return (OK);
808 } 701 }
809 702
810 #endif /* MAIL_USE_POP */ 703 #endif /* MAIL_USE_POP */
811 704
812 #ifndef HAVE_STRERROR 705 #ifndef HAVE_STRERROR