comparison lib-src/movemail.c @ 70:131b0175ea99 r20-0b30

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