comparison lib-src/movemail.c @ 48:56c54cf7c5b6 r19-16b90

Import from CVS: tag r19-16b90
author cvs
date Mon, 13 Aug 2007 08:56:04 +0200
parents 376386a54a3c
children 05472e90ae02
comparison
equal deleted inserted replaced
47:11c6df210d7f 48:56c54cf7c5b6
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 #include <stdlib.h>
66 #include <string.h>
67 #ifdef MAIL_USE_POP
68 #include "pop.h"
69 #endif
67 70
68 #ifdef MSDOS 71 #ifdef MSDOS
69 #undef access 72 #undef access
70 #endif /* MSDOS */ 73 #endif /* MSDOS */
71 74
75 #ifndef DIRECTORY_SEP
76 #define DIRECTORY_SEP '/'
77 #endif
78 #ifndef IS_DIRECTORY_SEP
79 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
80 #endif
81
82 #ifdef WINDOWSNT
83 #undef access
84 #undef unlink
85 #define fork() 0
86 #define sys_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 #define DISABLE_DIRECT_ACCESS
93 #endif /* WINDOWSNT */
94
72 #ifdef USG 95 #ifdef USG
73 #include <fcntl.h> 96 #include <fcntl.h>
74 #include <unistd.h> 97 #include <unistd.h>
75 #if defined (sun)
76 #include <stdlib.h>
77 #endif /* sun */
78 #ifndef F_OK 98 #ifndef F_OK
79 #define F_OK 0 99 #define F_OK 0
80 #define X_OK 1 100 #define X_OK 1
81 #define W_OK 2 101 #define W_OK 2
82 #define R_OK 4 102 #define R_OK 4
85 105
86 #ifdef HAVE_UNISTD_H 106 #ifdef HAVE_UNISTD_H
87 #include <unistd.h> 107 #include <unistd.h>
88 #endif 108 #endif
89 109
90 #ifdef XENIX 110 #if defined (XENIX) || defined (WINDOWSNT)
91 #include <sys/locking.h> 111 #include <sys/locking.h>
92 #endif 112 #endif
93 113
94 #ifdef MAIL_USE_LOCKF 114 #ifdef MAIL_USE_LOCKF
95 #define MAIL_USE_SYSTEM_LOCK 115 #define MAIL_USE_SYSTEM_LOCK
107 #undef open 127 #undef open
108 #undef read 128 #undef read
109 #undef write 129 #undef write
110 #undef close 130 #undef close
111 131
112 static char *concat (CONST char *s1, CONST char *s2, CONST char *s3);
113 static void *xmalloc (unsigned int size);
114 #ifndef errno 132 #ifndef errno
115 extern int errno; 133 extern int errno;
116 #endif 134 #endif
117 135 char *strerror ();
118 static void error (CONST char *s1, CONST char *s2, CONST char *s3); 136
119 static void fatal (CONST char *s1, CONST char *s2); 137 void fatal (char *, char*);
120 static void pfatal_with_name (CONST char *name); 138 void error ();
121 static void pfatal_and_delete (CONST char *name); 139 void pfatal_with_name ();
122 140 void pfatal_and_delete ();
123 #ifndef HAVE_STRERROR 141 char *concat ();
124 char *strerror (int); 142 long *xmalloc ();
125 #endif 143 int popmail ();
144 int pop_retr ();
145 int mbx_write ();
146 int mbx_delimit_begin ();
147 int mbx_delimit_end ();
126 148
127 /* Nonzero means this is name of a lock file to delete on fatal error. */ 149 /* Nonzero means this is name of a lock file to delete on fatal error. */
128 char *delete_lockname; 150 char *delete_lockname;
129 151
130 void 152 int
131 main (argc, argv) 153 main (argc, argv)
132 int argc; 154 int argc;
133 char **argv; 155 char **argv;
134 { 156 {
135 char *inname, *outname; 157 char *inname, *outname;
147 #endif /* not MAIL_USE_SYSTEM_LOCK */ 169 #endif /* not MAIL_USE_SYSTEM_LOCK */
148 170
149 delete_lockname = 0; 171 delete_lockname = 0;
150 172
151 if (argc < 3) 173 if (argc < 3)
152 fatal ("two arguments required", ""); 174 {
175 fprintf (stderr, "Usage: movemail inbox destfile [POP-password]\n");
176 exit(1);
177 }
153 178
154 inname = argv[1]; 179 inname = argv[1];
155 outname = argv[2]; 180 outname = argv[2];
156 181
157 #ifdef MAIL_USE_MMDF 182 #ifdef MAIL_USE_MMDF
158 mmdf_init (argv[0]); 183 mmdf_init (argv[0]);
159 #endif 184 #endif
185
186 if (*outname == 0)
187 fatal ("Destination file name is empty", 0);
160 188
161 /* Check access to output file. */ 189 /* Check access to output file. */
162 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) 190 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
163 pfatal_with_name (outname); 191 pfatal_with_name (outname);
164 192
165 /* Also check that outname's directory is writeable to the real uid. */ 193 /* Also check that outname's directory is writable to the real uid. */
166 { 194 {
167 char *buf = (char *) xmalloc (strlen (outname) + 1); 195 char *buf = (char *) xmalloc (strlen (outname) + 1);
168 char *p; 196 char *p;
169 strcpy (buf, outname); 197 strcpy (buf, outname);
170 p = buf + strlen (buf); 198 p = buf + strlen (buf);
171 while (p > buf && p[-1] != '/') 199 while (p > buf && !IS_DIRECTORY_SEP (p[-1]))
172 *--p = 0; 200 *--p = 0;
173 if (p == buf) 201 if (p == buf)
174 *p++ = '.'; 202 *p++ = '.';
175 if (access (buf, W_OK) != 0) 203 if (access (buf, W_OK) != 0)
176 pfatal_with_name (buf); 204 pfatal_with_name (buf);
177 free (buf); 205 free (buf);
178 } 206 }
179 207
180 #ifdef MAIL_USE_POP 208 #ifdef MAIL_USE_POP
181 if (!memcmp (inname, "po:", 3)) 209 if (!strncmp (inname, "po:", 3))
182 { 210 {
183 int status; char *user; 211 int status;
184 212
185 for (user = &inname[strlen (inname) - 1]; user >= inname; user--) 213 status = popmail (inname + 3, outname, argc > 3 ? argv[3] : NULL);
186 if (*user == ':')
187 break;
188
189 status = popmail (user, outname);
190 exit (status); 214 exit (status);
191 } 215 }
192 216
193 setuid (getuid ()); 217 setuid (getuid ());
194 #endif /* MAIL_USE_POP */ 218 #endif /* MAIL_USE_POP */
219
220 #ifndef DISABLE_DIRECT_ACCESS
195 221
196 /* Check access to input file. */ 222 /* Check access to input file. */
197 if (access (inname, R_OK | W_OK) != 0) 223 if (access (inname, R_OK | W_OK) != 0)
198 pfatal_with_name (inname); 224 pfatal_with_name (inname);
199 225
200 #ifndef MAIL_USE_MMDF 226 #ifndef MAIL_USE_MMDF
201 #ifndef MAIL_USE_SYSTEM_LOCK 227 #ifndef MAIL_USE_SYSTEM_LOCK
202 /* Use a lock file named /usr/spool/mail/$USER.lock: 228 /* Use a lock file named after our first argument with .lock appended:
203 If it exists, the mail file is locked. */ 229 If it exists, the mail file is locked. */
204 /* Note: this locking mechanism is *required* by the mailer 230 /* Note: this locking mechanism is *required* by the mailer
205 (on systems which use it) to prevent loss of mail. 231 (on systems which use it) to prevent loss of mail.
206 232
207 On systems that use a lock file, extracting the mail without locking 233 On systems that use a lock file, extracting the mail without locking
208 WILL occasionally cause loss of mail due to timing errors! 234 WILL occasionally cause loss of mail due to timing errors!
209 235
210 So, if creation of the lock file fails 236 So, if creation of the lock file fails
211 due to access permission on /usr/spool/mail, 237 due to access permission on the mail spool directory,
212 you simply MUST change the permission 238 you simply MUST change the permission
213 and/or make movemail a setgid program 239 and/or make movemail a setgid program
214 so it can create lock files properly. 240 so it can create lock files properly.
215 241
216 You might also wish to verify that your system is one 242 You might also wish to verify that your system is one
224 250
225 lockname = concat (inname, ".lock", ""); 251 lockname = concat (inname, ".lock", "");
226 tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); 252 tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1);
227 strcpy (tempname, inname); 253 strcpy (tempname, inname);
228 p = tempname + strlen (tempname); 254 p = tempname + strlen (tempname);
229 while (p != tempname && p[-1] != '/') 255 while (p != tempname && !IS_DIRECTORY_SEP (p[-1]))
230 p--; 256 p--;
231 *p = 0; 257 *p = 0;
232 strcpy (p, "EXXXXXX"); 258 strcpy (p, "EXXXXXX");
233 mktemp (tempname); 259 mktemp (tempname);
234 unlink (tempname); 260 unlink (tempname);
237 { 263 {
238 /* Create the lock file, but not under the lock file name. */ 264 /* Create the lock file, but not under the lock file name. */
239 /* Give up if cannot do that. */ 265 /* Give up if cannot do that. */
240 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); 266 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666);
241 if (desc < 0) 267 if (desc < 0)
242 pfatal_with_name ("lock file--see source file lib-src/movemail.c"); 268 {
269 char *message = (char *) xmalloc (strlen (tempname) + 50);
270 sprintf (message, "%s--see source file lib-src/movemail.c",
271 tempname);
272 pfatal_with_name (message);
273 }
243 close (desc); 274 close (desc);
244 275
245 tem = link (tempname, lockname); 276 tem = link (tempname, lockname);
246 unlink (tempname); 277 unlink (tempname);
247 if (tem >= 0) 278 if (tem >= 0)
248 break; 279 break;
249 sleep (1); 280 sleep (1);
250 281
251 /* If lock file is a minute old, unlock it. */ 282 /* If lock file is five minutes old, unlock it.
283 Five minutes should be good enough to cope with crashes
284 and wedgitude, and long enough to avoid being fooled
285 by time differences between machines. */
252 if (stat (lockname, &st) >= 0) 286 if (stat (lockname, &st) >= 0)
253 { 287 {
254 now = time (0); 288 now = time (0);
255 if (st.st_ctime < now - 60) 289 if (st.st_ctime < now - 300)
256 unlink (lockname); 290 unlink (lockname);
257 } 291 }
258 } 292 }
259 293
260 delete_lockname = lockname; 294 delete_lockname = lockname;
261 #endif /* not MAIL_USE_SYSTEM_LOCK */ 295 #endif /* not MAIL_USE_SYSTEM_LOCK */
293 if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname); 327 if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname);
294 #else /* not MAIL_USE_LOCKF */ 328 #else /* not MAIL_USE_LOCKF */
295 #ifdef XENIX 329 #ifdef XENIX
296 if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); 330 if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname);
297 #else 331 #else
332 #ifdef WINDOWSNT
333 if (locking (indesc, LK_RLCK, -1L) < 0) pfatal_with_name (inname);
334 #else
298 if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); 335 if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname);
336 #endif
299 #endif 337 #endif
300 #endif /* not MAIL_USE_LOCKF */ 338 #endif /* not MAIL_USE_LOCKF */
301 #endif /* MAIL_USE_SYSTEM_LOCK */ 339 #endif /* MAIL_USE_SYSTEM_LOCK */
302 340
303 { 341 {
326 /* Check to make sure no errors before we zap the inbox. */ 364 /* Check to make sure no errors before we zap the inbox. */
327 if (close (outdesc) != 0) 365 if (close (outdesc) != 0)
328 pfatal_and_delete (outname); 366 pfatal_and_delete (outname);
329 367
330 #ifdef MAIL_USE_SYSTEM_LOCK 368 #ifdef MAIL_USE_SYSTEM_LOCK
331 #if defined (STRIDE) || defined (XENIX) 369 #if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT)
332 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ 370 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */
333 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); 371 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
334 #else 372 #else
335 ftruncate (indesc, 0L); 373 ftruncate (indesc, 0L);
336 #endif /* STRIDE or XENIX */ 374 #endif /* STRIDE or XENIX */
363 exit (WRETCODE (status)); 401 exit (WRETCODE (status));
364 402
365 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK) 403 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
366 unlink (lockname); 404 unlink (lockname);
367 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */ 405 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */
368 exit (0); 406
407 #endif /* ! DISABLE_DIRECT_ACCESS */
408
409 return 0;
369 } 410 }
370 411
371 /* Print error message and exit. */ 412 /* Print error message and exit. */
372 413
373 static void 414 void
374 fatal (s1, s2) 415 fatal (s1, s2)
375 CONST char *s1, *s2; 416 char *s1, *s2;
376 { 417 {
377 if (delete_lockname) 418 if (delete_lockname)
378 error (s1, s2, "");
379 unlink (delete_lockname); 419 unlink (delete_lockname);
420 error (s1, s2);
380 exit (1); 421 exit (1);
381 } 422 }
382 423
383 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ 424 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
384 425
385 static void 426 void
386 error (s1, s2, s3) 427 error (s1, s2, s3)
387 CONST char *s1, *s2, *s3; 428 char *s1, *s2, *s3;
388 { 429 {
389 printf ("movemail: "); 430 fprintf (stderr, "movemail: ");
390 printf (s1, s2, s3); 431 fprintf (stderr, s1, s2, s3);
391 printf ("\n"); 432 fprintf (stderr, "\n");
392 } 433 }
393 434
394 static void 435 void
395 pfatal_with_name (name) 436 pfatal_with_name (name)
396 CONST char *name; 437 char *name;
397 { 438 {
398 char *s; 439 char *s = concat ("", strerror (errno), " for %s");
399
400 s = concat ("", strerror (errno), " for %s");
401 fatal (s, name); 440 fatal (s, name);
402 } 441 }
403 442
404 static void 443 void
405 pfatal_and_delete (name) 444 pfatal_and_delete (name)
406 CONST char *name; 445 char *name;
407 { 446 {
408 char *s; 447 char *s = concat ("", strerror (errno), " for %s");
409
410 s = concat ("", strerror (errno), " for %s");
411 unlink (name); 448 unlink (name);
412 fatal (s, name); 449 fatal (s, name);
413 } 450 }
414 451
415 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ 452 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
416 453
417 static char * 454 char *
418 concat (s1, s2, s3) 455 concat (s1, s2, s3)
419 CONST char *s1, *s2, *s3; 456 char *s1, *s2, *s3;
420 { 457 {
421 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); 458 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
422 char *result = (char *) xmalloc (len1 + len2 + len3 + 1); 459 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
423 460
424 strcpy (result, s1); 461 strcpy (result, s1);
429 return result; 466 return result;
430 } 467 }
431 468
432 /* Like malloc but get fatal error if memory is exhausted. */ 469 /* Like malloc but get fatal error if memory is exhausted. */
433 470
434 static void * 471 long *
435 xmalloc (size) 472 xmalloc (size)
436 unsigned int size; 473 unsigned size;
437 { 474 {
438 void *result = (void *) malloc (size); 475 long *result = (long *) malloc (size);
439 if (!result) 476 if (!result)
440 fatal ("virtual memory exhausted", (char *) 0); 477 fatal ("virtual memory exhausted", 0);
441 return result; 478 return result;
442 } 479 }
443 480
444 /* This is the guts of the interface to the Post Office Protocol. */ 481 /* This is the guts of the interface to the Post Office Protocol. */
445 482
446 #ifdef MAIL_USE_POP 483 #ifdef MAIL_USE_POP
447 484
485 #ifndef WINDOWSNT
448 #include <sys/socket.h> 486 #include <sys/socket.h>
449 #include <netinet/in.h> 487 #include <netinet/in.h>
450 #include <netdb.h> 488 #include <netdb.h>
489 #else
490 #undef _WINSOCKAPI_
491 #include <winsock.h>
492 #endif
451 #include <stdio.h> 493 #include <stdio.h>
452 #include <pwd.h> 494 #include <pwd.h>
453 495
454 #ifdef USG 496 #ifdef USG
455 #include <fcntl.h> 497 #include <fcntl.h>
465 #define DONE 1 507 #define DONE 1
466 508
467 char *progname; 509 char *progname;
468 FILE *sfi; 510 FILE *sfi;
469 FILE *sfo; 511 FILE *sfo;
512 char ibuffer[BUFSIZ];
513 char obuffer[BUFSIZ];
470 char Errmsg[80]; 514 char Errmsg[80];
471 515
472 static int debug = 0; 516 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; 517 char *user;
481 char *outfile; 518 char *outfile;
482 { 519 char *password;
483 char *host; 520 {
484 int nmsgs, nbytes; 521 int nmsgs, nbytes;
485 char response[128];
486 register int i; 522 register int i;
487 int mbfi; 523 int mbfi;
488 FILE *mbf; 524 FILE *mbf;
489 struct passwd *pw = (struct passwd *) getpwuid (getuid ()); 525 char *getenv ();
490 if (pw == NULL) 526 int mbx_write ();
491 fatal ("cannot determine user name"); 527 popserver server;
492 528 extern char *strerror ();
493 host = getenv ("MAILHOST"); 529
494 if (host == NULL) 530 server = pop_open (0, user, password, POP_NO_GETPASS);
495 { 531 if (! server)
496 fatal ("no MAILHOST defined"); 532 {
497 } 533 error (pop_error);
498 534 return (1);
499 if (pop_init (host) == NOTOK) 535 }
500 { 536
501 fatal (Errmsg); 537 if (pop_stat (server, &nmsgs, &nbytes))
502 } 538 {
503 539 error (pop_error);
504 if (getline (response, sizeof response, sfi) != OK) 540 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 } 541 }
521 542
522 if (!nmsgs) 543 if (!nmsgs)
523 { 544 {
524 pop_command ("QUIT"); 545 pop_close (server);
525 return 0; 546 return (0);
526 } 547 }
527 548
528 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); 549 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
529 if (mbfi < 0) 550 if (mbfi < 0)
530 { 551 {
531 pop_command ("QUIT"); 552 pop_close (server);
532 pfatal_and_delete (outfile); 553 error ("Error in open: %s, %s", strerror (errno), outfile);
533 } 554 return (1);
555 }
534 fchown (mbfi, getuid (), -1); 556 fchown (mbfi, getuid (), -1);
535 557
536 if ((mbf = fdopen (mbfi, "w")) == NULL) 558 if ((mbf = fdopen (mbfi, "wb")) == NULL)
537 { 559 {
538 pop_command ("QUIT"); 560 pop_close (server);
539 pfatal_and_delete (outfile); 561 error ("Error in fdopen: %s", strerror (errno));
540 } 562 close (mbfi);
541 563 unlink (outfile);
542 for (i = 1; i <= nmsgs; i++) 564 return (1);
565 }
566
567 for (i = 1; i <= nmsgs; i++)
543 { 568 {
544 mbx_delimit_begin (mbf); 569 mbx_delimit_begin (mbf);
545 if (pop_retr (i, mbx_write, mbf) != OK) 570 if (pop_retr (server, i, mbx_write, mbf) != OK)
546 { 571 {
547 pop_command ("QUIT"); 572 error (Errmsg);
548 close (mbfi); 573 close (mbfi);
549 unlink (outfile); 574 return (1);
550 fatal (Errmsg); 575 }
551 }
552 mbx_delimit_end (mbf); 576 mbx_delimit_end (mbf);
553 fflush (mbf); 577 fflush (mbf);
554 } 578 if (ferror (mbf))
555 579 {
580 error ("Error in fflush: %s", strerror (errno));
581 pop_close (server);
582 close (mbfi);
583 return (1);
584 }
585 }
586
587 /* On AFS, a call to write only modifies the file in the local
588 * workstation's AFS cache. The changes are not written to the server
589 * until a call to fsync or close is made. Users with AFS home
590 * directories have lost mail when over quota because these checks were
591 * not made in previous versions of movemail. */
592
593 #ifdef BSD
556 if (fsync (mbfi) < 0) 594 if (fsync (mbfi) < 0)
557 { 595 {
558 pop_command ("QUIT"); 596 error ("Error in fsync: %s", strerror (errno));
559 pfatal_and_delete (outfile); 597 return (1);
560 } 598 }
599 #endif
561 600
562 if (close (mbfi) == -1) 601 if (close (mbfi) == -1)
563 { 602 {
564 pop_command ("QUIT"); 603 error ("Error in close: %s", strerror (errno));
565 pfatal_and_delete (outfile); 604 return (1);
566 } 605 }
567 606
568 for (i = 1; i <= nmsgs; i++) 607 for (i = 1; i <= nmsgs; i++)
569 { 608 {
570 if (pop_command ("DELE %d", i) == NOTOK) 609 if (pop_delete (server, i))
571 { 610 {
572 /* Better to ignore this failure. */ 611 error (pop_error);
573 } 612 pop_close (server);
574 } 613 return (1);
575 614 }
576 pop_command ("QUIT"); 615 }
616
617 if (pop_quit (server))
618 {
619 error (pop_error);
620 return (1);
621 }
622
577 return (0); 623 return (0);
578 } 624 }
579 625
626 pop_retr (server, msgno, action, arg)
627 popserver server;
628 int (*action)();
629 {
630 extern char *strerror ();
631 char *line;
632 int ret;
633
634 if (pop_retrieve_first (server, msgno, &line))
635 {
636 strncpy (Errmsg, pop_error, sizeof (Errmsg));
637 Errmsg[sizeof (Errmsg)-1] = '\0';
638 return (NOTOK);
639 }
640
641 while (! (ret = pop_retrieve_next (server, &line)))
642 {
643 if (! line)
644 break;
645
646 if ((*action)(line, arg) != OK)
647 {
648 strcpy (Errmsg, strerror (errno));
649 pop_close (server);
650 return (NOTOK);
651 }
652 }
653
654 if (ret)
655 {
656 strncpy (Errmsg, pop_error, sizeof (Errmsg));
657 Errmsg[sizeof (Errmsg)-1] = '\0';
658 return (NOTOK);
659 }
660
661 return (OK);
662 }
663
664 /* Do this as a macro instead of using strcmp to save on execution time. */
665 #define IS_FROM_LINE(a) ((a[0] == 'F') \
666 && (a[1] == 'r') \
667 && (a[2] == 'o') \
668 && (a[3] == 'm') \
669 && (a[4] == ' '))
670
580 int 671 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) 672 mbx_write (line, mbf)
791 char *line; 673 char *line;
792 FILE *mbf; 674 FILE *mbf;
793 { 675 {
794 fputs (line, mbf); 676 if (IS_FROM_LINE (line))
795 fputc (0x0a, mbf); 677 {
796 } 678 if (fputc ('>', mbf) == EOF)
797 679 return (NOTOK);
680 }
681 if (fputs (line, mbf) == EOF)
682 return (NOTOK);
683 if (fputc (0x0a, mbf) == EOF)
684 return (NOTOK);
685 return (OK);
686 }
687
688 int
798 mbx_delimit_begin (mbf) 689 mbx_delimit_begin (mbf)
799 FILE *mbf; 690 FILE *mbf;
800 { 691 {
801 fputs ("\f\n0, unseen,,\n", mbf); 692 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF)
693 return (NOTOK);
694 return (OK);
802 } 695 }
803 696
804 mbx_delimit_end (mbf) 697 mbx_delimit_end (mbf)
805 FILE *mbf; 698 FILE *mbf;
806 { 699 {
807 putc ('\037', mbf); 700 if (putc ('\037', mbf) == EOF)
701 return (NOTOK);
702 return (OK);
808 } 703 }
809 704
810 #endif /* MAIL_USE_POP */ 705 #endif /* MAIL_USE_POP */
811 706
812 #ifndef HAVE_STRERROR 707 #ifndef HAVE_STRERROR