Mercurial > hg > xemacs-beta
annotate lib-src/movemail.c @ 5781:0853e1ec8529
Use alloca_{rawbytes,ibytes} in #'copy-file, #'insert-file-contents-internal
src/ChangeLog addition:
2014-01-20 Aidan Kehoe <kehoea@parhasard.net>
* fileio.c (Fcopy_file, Finsert_file_contents_internal):
Use alloca_{rawbytes,ibytes} here instead of the implicit alloca
on the stack; doesn't change where the buffers are allocated for
these two functions, but does mean that decisions about alloca
vs. malloc based on buffer size are made in the same place
(ultimately, the ALLOCA() macro).
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Mon, 20 Jan 2014 17:53:07 +0000 |
parents | 308d34e9f07d |
children | 574f0cded429 |
rev | line source |
---|---|
428 | 1 /* movemail foo bar -- move file foo to file bar, |
438 | 2 locking file foo. |
428 | 3 Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. |
4 | |
438 | 5 This file is part of XEmacs. |
428 | 6 |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2584
diff
changeset
|
7 XEmacs is free software: you can redistribute it and/or modify it |
438 | 8 under the terms of the GNU General Public License as published by the |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2584
diff
changeset
|
9 Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2584
diff
changeset
|
10 option) any later version. |
428 | 11 |
438 | 12 XEmacs is distributed in the hope that it will be useful, but WITHOUT |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
428 | 16 |
17 You should have received a copy of the GNU General Public License | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2584
diff
changeset
|
18 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. |
438 | 19 Please mail bugs and suggestions to the XEmacs maintainer. |
20 */ | |
428 | 21 |
438 | 22 /* Important notice: |
23 * | |
24 * You *must* coordinate the locking method used by movemail with that | |
25 * used by your mail delivery agent, as well as that of the other mail | |
26 * user agents on your system. movemail allows you to do this at run | |
27 * time via the -m flag. Moreover, it uses a default determined by | |
28 * the MAIL_LOCK_DOT, MAIL_LOCK_LOCKF, MAIL_LOCK_FLOCK, | |
29 * MAIL_LOCK_LOCKING, and MAIL_LOCK_MMDF preprocessor settings. | |
30 */ | |
428 | 31 |
438 | 32 /* |
33 * Mike Sperber <sperber@informatik.uni-tuebingen.de> reorganized | |
34 * everything that has to with locking in December 1999. | |
35 */ | |
428 | 36 |
37 /* | |
38 * Modified January, 1986 by Michael R. Gretzinger (Project Athena) | |
39 * | |
40 * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP | |
41 * movemail will accept input filename arguments of the form | |
42 * "po:username". This will cause movemail to open a connection to | |
43 * a pop server running on $MAILHOST (environment variable). Movemail | |
44 * must be setuid to root in order to work with POP. | |
45 * | |
46 * New module: popmail.c | |
47 * Modified routines: | |
48 * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ()) | |
49 * after POP code. | |
50 * New routines in movemail.c: | |
51 * get_errmsg - return pointer to system error message | |
52 * | |
53 * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies) | |
54 * | |
55 * Move all of the POP code into a separate file, "pop.c". | |
56 * Use strerror instead of get_errmsg. | |
57 * | |
58 */ | |
59 | |
60 #define NO_SHORTNAMES /* Tell config not to load remap.h */ | |
438 | 61 #include <config.h> |
428 | 62 #include <sys/types.h> |
63 #include <sys/stat.h> | |
64 #include <stdio.h> | |
65 #include <errno.h> | |
66 #include "../src/sysfile.h" | |
67 #include "../src/syswait.h" | |
442 | 68 #ifndef WIN32_NATIVE |
428 | 69 #include "../src/systime.h" |
70 #endif | |
71 #include <stdlib.h> | |
72 #include <string.h> | |
73 #include "getopt.h" | |
74 #ifdef MAIL_USE_POP | |
75 #include "pop.h" | |
76 #include "../src/regex.h" | |
77 #endif | |
78 | |
79 extern char *optarg; | |
80 extern int optind, opterr; | |
81 | |
82 #ifndef HAVE_STRERROR | |
83 char * strerror (int errnum); | |
84 #endif /* HAVE_STRERROR */ | |
85 | |
86 #ifndef DIRECTORY_SEP | |
87 #define DIRECTORY_SEP '/' | |
88 #endif | |
89 #ifndef IS_DIRECTORY_SEP | |
90 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) | |
91 #endif | |
92 | |
442 | 93 #ifdef WIN32_NATIVE |
428 | 94 #undef access |
95 #undef unlink | |
96 #define fork() 0 | |
97 #define sys_wait(var) (*(var) = 0) | |
98 /* Unfortunately, Samba doesn't seem to properly lock Unix files even | |
99 though the locking call succeeds (and indeed blocks local access from | |
100 other NT programs). If you have direct file access using an NFS | |
101 client or something other than Samba, the locking call might work | |
102 properly - make sure it does before you enable this! */ | |
103 #define DISABLE_DIRECT_ACCESS | |
104 #include <io.h> | |
442 | 105 #endif /* WIN32_NATIVE */ |
428 | 106 |
438 | 107 #if defined (HAVE_UNISTD_H) |
428 | 108 #include <unistd.h> |
109 #endif /* unistd.h */ | |
110 #ifndef F_OK | |
111 #define F_OK 0 | |
112 #define X_OK 1 | |
113 #define W_OK 2 | |
114 #define R_OK 4 | |
115 #endif /* No F_OK */ | |
116 | |
438 | 117 #if defined (HAVE_FCNTL_H) |
428 | 118 #include <fcntl.h> |
119 #endif /* fcntl.h */ | |
120 | |
438 | 121 #ifdef HAVE_LOCKING |
428 | 122 #include <sys/locking.h> |
123 #endif | |
124 | |
438 | 125 #ifdef HAVE_MMDF |
428 | 126 extern int lk_open (), lk_close (); |
127 #endif | |
128 | |
129 /* Cancel substitutions made by config.h for Emacs. */ | |
130 #undef open | |
131 #undef read | |
132 #undef write | |
133 #undef close | |
134 | |
135 static void fatal (char *, char*); | |
136 static void error (char *, char *, char *); | |
438 | 137 static void usage(int); |
428 | 138 static void pfatal_with_name (char *); |
139 static void pfatal_and_delete (char *); | |
140 static char *concat (char *, char *, char *); | |
647 | 141 static long *xmalloc (int); |
428 | 142 #ifdef MAIL_USE_POP |
143 static int popmail (char *, char *, char *); | |
144 static int pop_retr (popserver server, int msgno, | |
440 | 145 int (*action)(char *, FILE *), FILE *arg); |
428 | 146 static int mbx_write (char *, FILE *); |
147 static int mbx_delimit_begin (FILE *); | |
148 static int mbx_delimit_end (FILE *); | |
149 static struct re_pattern_buffer* compile_regex (char* regexp_pattern); | |
150 static int pop_search_top (popserver server, int msgno, int lines, | |
151 struct re_pattern_buffer* regexp); | |
152 #endif | |
153 | |
154 int verbose=0; | |
155 #ifdef MAIL_USE_POP | |
156 int reverse=0; | |
157 int keep_messages=0; | |
158 struct re_pattern_buffer* regexp_pattern=0; | |
159 int match_lines=10; | |
160 #endif | |
161 | |
162 #define VERBOSE(x) if (verbose) { printf x; fflush(stdout); } | |
163 | |
164 struct option longopts[] = | |
165 { | |
166 { "inbox", required_argument, NULL, 'i' }, | |
167 { "outfile", required_argument, NULL, 'o' }, | |
168 #ifdef MAIL_USE_POP | |
169 { "password", required_argument, NULL, 'p' }, | |
170 { "reverse-pop-order", no_argument, NULL, 'x' }, | |
171 { "keep-messages", no_argument, NULL, 'k' }, | |
172 { "regex", required_argument, NULL, 'r' }, | |
173 { "match-lines", required_argument, NULL, 'l' }, | |
174 #endif | |
438 | 175 { "lock-method", required_argument, NULL, 'm' }, |
176 { "help", no_argument, NULL, 'h' }, | |
428 | 177 { "verbose", no_argument, NULL, 'v' }, |
178 { 0 } | |
179 }; | |
180 | |
438 | 181 #define DOTLOCKING 0 |
182 #define FLOCKING 1 | |
183 #define LOCKFING 2 | |
184 #define MMDF 3 | |
185 #define LOCKING 4 | |
186 | |
187 #if defined(MAIL_LOCK_FLOCK) && defined(HAVE_FLOCK) | |
188 #define DEFAULT_LOCKING FLOCKING | |
189 #elif defined(MAIL_LOCK_LOCKF) && defined(HAVE_LOCKF) | |
190 #define DEFAULT_LOCKING LOCKFING | |
191 #elif defined(MAIL_LOCK_MMDF) && defined(HAVE_MMDF) | |
192 #define DEFAULT_LOCKING MMDF | |
193 #elif defined(MAIL_LOCK_LOCKING) && defined(HAVE_LOCKING) | |
194 #define DEFAULT_LOCKING LOCKING | |
195 #else | |
196 #define DEFAULT_LOCKING DOTLOCKING | |
197 #endif | |
198 | |
442 | 199 #ifndef DISABLE_DIRECT_ACCESS |
438 | 200 static void lock_dot(char *); |
442 | 201 #endif |
438 | 202 static void unlock_dot(char *); |
203 static int parse_lock_method(char *); | |
204 static char *unparse_lock_method(int); | |
205 | |
428 | 206 int |
207 main (int argc, char *argv[]) | |
208 { | |
209 char *inname=0, *outname=0, *poppass=0; | |
210 #ifndef DISABLE_DIRECT_ACCESS | |
211 int indesc, outdesc; | |
212 int nread; | |
213 int status; | |
214 #endif | |
215 | |
438 | 216 int lock_method = DEFAULT_LOCKING; |
217 | |
218 char *maybe_lock_env; | |
428 | 219 |
438 | 220 maybe_lock_env = getenv("EMACSLOCKMETHOD"); |
221 if (maybe_lock_env) | |
222 { | |
223 printf("maybe-lock_env: %s\n", maybe_lock_env); | |
224 lock_method = parse_lock_method(maybe_lock_env); | |
225 } | |
428 | 226 |
438 | 227 for (;;) |
428 | 228 { |
229 #ifdef MAIL_USE_POP | |
438 | 230 char* optstring = "i:o:m:p:l:r:xvhk"; |
428 | 231 #else |
438 | 232 char* optstring = "i:o:m:vh"; |
428 | 233 #endif |
234 int opt = getopt_long (argc, argv, optstring, longopts, 0); | |
235 | |
236 if (opt == EOF) | |
237 break; | |
238 | |
239 switch (opt) | |
240 { | |
241 case 0: | |
242 break; | |
243 case 1: /* one of the standard arguments seen */ | |
244 if (!inname) | |
245 inname = optarg; | |
246 else if (!outname) | |
247 outname = optarg; | |
248 else | |
249 poppass = optarg; | |
250 break; | |
251 | |
252 case 'i': /* infile */ | |
253 inname = optarg; | |
254 break; | |
255 | |
256 case 'o': /* outfile */ | |
257 outname = optarg; | |
258 break; | |
259 #ifdef MAIL_USE_POP | |
260 case 'p': /* pop password */ | |
261 poppass = optarg; | |
262 break; | |
263 case 'k': keep_messages=1; break; | |
264 case 'x': reverse = 1; break; | |
265 case 'l': /* lines to match */ | |
266 match_lines = atoi (optarg); | |
267 break; | |
268 | |
269 case 'r': /* regular expression */ | |
270 regexp_pattern = compile_regex (optarg); | |
271 break; | |
272 #endif | |
438 | 273 |
274 case 'm': | |
275 lock_method = parse_lock_method(optarg); | |
276 break; | |
277 case 'h': | |
278 usage(lock_method); | |
279 exit(0); | |
280 case 'v': | |
281 verbose = 1; | |
282 break; | |
428 | 283 } |
284 } | |
285 | |
286 while (optind < argc) | |
287 { | |
288 if (!inname) | |
289 inname = argv[optind]; | |
290 else if (!outname) | |
291 outname = argv[optind]; | |
292 else | |
293 poppass = argv[optind]; | |
294 optind++; | |
295 } | |
296 | |
297 if (!inname || !outname) | |
298 { | |
438 | 299 usage(lock_method); |
428 | 300 exit(1); |
301 } | |
302 | |
438 | 303 #ifdef HAVE_MMDF |
304 if (lock_method == MMDF) | |
305 mmdf_init (argv[0]); | |
428 | 306 #endif |
307 | |
308 if (*outname == 0) | |
309 fatal ("Destination file name is empty", 0); | |
310 | |
438 | 311 VERBOSE(("checking access to output file\n")); |
428 | 312 /* Check access to output file. */ |
313 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) | |
314 pfatal_with_name (outname); | |
315 | |
316 /* Also check that outname's directory is writable to the real uid. */ | |
317 { | |
318 char *buf = (char *) xmalloc (strlen (outname) + 1); | |
319 char *cp; | |
320 strcpy (buf, outname); | |
321 cp = buf + strlen (buf); | |
322 while (cp > buf && !IS_DIRECTORY_SEP (cp[-1])) | |
323 *--cp = 0; | |
324 if (cp == buf) | |
325 *cp++ = '.'; | |
326 if (access (buf, W_OK) != 0) | |
327 pfatal_with_name (buf); | |
328 free (buf); | |
329 } | |
330 | |
331 #ifdef MAIL_USE_POP | |
332 if (!strncmp (inname, "po:", 3)) | |
333 { | |
334 int retcode = popmail (inname + 3, outname, poppass); | |
335 exit (retcode); | |
336 } | |
337 | |
442 | 338 #ifndef WIN32_NATIVE |
428 | 339 setuid (getuid ()); |
340 #endif | |
341 #endif /* MAIL_USE_POP */ | |
342 | |
343 #ifndef DISABLE_DIRECT_ACCESS | |
344 | |
345 /* Check access to input file. */ | |
346 if (access (inname, R_OK | W_OK) != 0) | |
347 pfatal_with_name (inname); | |
348 | |
438 | 349 |
350 if (fork () == 0) | |
351 { | |
352 setuid (getuid ()); | |
353 | |
354 VERBOSE(("opening input file\n")); | |
355 | |
356 switch (lock_method) | |
357 { | |
358 case DOTLOCKING: | |
359 indesc = open (inname, O_RDONLY); | |
360 break; | |
361 #ifdef HAVE_LOCKF | |
362 case LOCKFING: | |
363 indesc = open (inname, O_RDWR); | |
364 break; | |
365 #endif | |
366 #ifdef HAVE_FLOCK | |
367 case FLOCKING: | |
368 indesc = open (inname, O_RDWR); | |
369 break; | |
370 #endif | |
371 #ifdef HAVE_LOCKING | |
372 case LOCKING: | |
373 indesc = open (inname, O_RDWR); | |
374 break; | |
375 #endif | |
376 #ifdef HAVE_MMDF | |
377 case MMDF: | |
378 indesc = lk_open (inname, O_RDONLY, 0, 0, 10); | |
379 break; | |
380 #endif | |
381 default: abort(); | |
382 } | |
383 | |
384 if (indesc < 0) | |
385 pfatal_with_name (inname); | |
386 | |
387 #ifdef HAVE_UMASK | |
388 /* In case movemail is setuid to root, make sure the user can | |
389 read the output file. */ | |
390 umask (umask (0) & 0333); | |
391 #endif | |
392 | |
393 outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
394 if (outdesc < 0) | |
395 pfatal_with_name (outname); | |
396 | |
397 VERBOSE(("locking input file\n")); | |
428 | 398 |
438 | 399 switch (lock_method) |
400 { | |
401 #ifdef HAVE_LOCKF | |
402 case LOCKFING: | |
403 if (lockf (indesc, F_LOCK, 0) < 0) | |
404 pfatal_with_name (inname); | |
405 break; | |
406 #endif | |
407 #ifdef HAVE_FLOCK | |
408 case FLOCKING: | |
409 if (flock (indesc, LOCK_EX) < 0) | |
410 pfatal_with_name (inname); | |
411 break; | |
412 #endif | |
413 #ifdef HAVE_LOCKING | |
414 case LOCKING: | |
415 if (locking (indesc, LK_RLCK, -1L) < 0) | |
416 pfatal_with_name (inname); | |
417 break; | |
418 #endif | |
419 case DOTLOCKING: | |
420 lock_dot(inname); | |
421 break; | |
422 } | |
423 | |
424 VERBOSE(("copying input file to output file\n")); | |
425 | |
426 { | |
427 char buf[1024]; | |
428 | |
429 while (1) | |
430 { | |
431 nread = read (indesc, buf, sizeof buf); | |
432 if (nread != write (outdesc, buf, nread)) | |
433 { | |
434 int saved_errno = errno; | |
435 unlink (outname); | |
436 errno = saved_errno; | |
437 pfatal_with_name (outname); | |
438 } | |
647 | 439 if (nread < (int) sizeof (buf)) |
438 | 440 break; |
441 } | |
442 } | |
443 | |
444 #ifdef HAVE_FSYNC | |
445 if (fsync (outdesc) < 0) | |
446 pfatal_and_delete (outname); | |
447 #endif | |
448 | |
449 /* Check to make sure no errors before we zap the inbox. */ | |
450 if (close (outdesc) != 0) | |
451 pfatal_and_delete (outname); | |
452 | |
453 VERBOSE(("deleting or truncating input file\n")); | |
428 | 454 |
438 | 455 switch (lock_method) |
456 { | |
457 case LOCKFING: | |
458 case FLOCKING: | |
459 case LOCKING: | |
460 #ifdef HAVE_FTRUNCATE | |
461 ftruncate (indesc, 0L); | |
462 #else | |
463 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); | |
464 #endif | |
465 close (indesc); | |
466 break; | |
467 #ifdef HAVE_MMDF | |
468 case MMDF: | |
469 lk_close (indesc, 0, 0, 0); | |
470 break; | |
471 #endif | |
472 case DOTLOCKING: | |
473 creat (inname, 0600); | |
474 break; | |
475 } | |
476 | |
477 exit (0); | |
478 } | |
428 | 479 |
438 | 480 wait (&status); |
481 if (!WIFEXITED (status)) | |
482 exit (1); | |
483 else if (WEXITSTATUS (status) != 0) | |
484 exit (WEXITSTATUS (status)); | |
485 | |
486 if (lock_method == DOTLOCKING) | |
487 unlock_dot(inname); | |
488 | |
489 #endif /* not DISABLE_DIRECT_ACCESS */ | |
490 | |
491 return 0; | |
492 } | |
493 | |
494 static void | |
495 usage(int lock_method) | |
496 { | |
497 printf ("Usage: movemail [-rvxkh] [-l lines ] [-m method ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); | |
498 printf("where method is one of: dot"); | |
499 #ifdef HAVE_LOCKF | |
500 printf(", lockf"); | |
501 #endif | |
502 #ifdef HAVE_FLOCK | |
503 printf(", flock"); | |
504 #endif | |
505 #ifdef HAVE_MMDF | |
506 printf(", mmdf"); | |
507 #endif | |
508 #ifdef HAVE_LOCKING | |
509 printf(", locking"); | |
510 #endif | |
511 printf("\nDefault is: %s\n", unparse_lock_method(lock_method)); | |
512 | |
513 } | |
428 | 514 |
438 | 515 static char * |
516 unparse_lock_method(int lock_method) | |
517 { | |
518 switch (lock_method) | |
519 { | |
520 case DOTLOCKING: return "dot"; | |
521 case FLOCKING: return "flock"; | |
522 case LOCKFING: return "lockf"; | |
523 case LOCKING: return "locking"; | |
524 case MMDF: return "mmdf"; | |
525 default: abort();return 0; | |
526 } | |
527 } | |
428 | 528 |
438 | 529 static int |
530 parse_lock_method(char *method_name) | |
531 { | |
532 if (!strcmp("dot", method_name) || !strcmp("file", method_name)) | |
533 return DOTLOCKING; | |
534 #ifdef HAVE_LOCKF | |
535 else if (!strcmp("lockf", method_name)) | |
536 return LOCKFING; | |
537 #endif | |
538 #ifdef HAVE_FLOCK | |
539 else if (!strcmp("flock", method_name)) | |
540 return FLOCKING; | |
541 #endif | |
542 #ifdef HAVE_MMDF | |
543 else if (!strcmp("mmdf", method_name)) | |
544 return MMDF; | |
545 #endif | |
546 #ifdef HAVE_LOCKING | |
547 else if (!strcmp("locking", method_name)) | |
548 return LOCKING; | |
549 #endif | |
550 else | |
551 fatal("invalid lock method: %s", method_name); | |
552 return 0; /* unreached */ | |
553 } | |
554 | |
555 static char * | |
556 dot_filename(char *filename) | |
557 { | |
558 return concat (filename, ".lock", ""); | |
559 } | |
560 | |
561 static char *dotlock_filename = NULL; | |
562 | |
442 | 563 #ifndef DISABLE_DIRECT_ACCESS |
438 | 564 static void |
565 lock_dot(char *filename) | |
566 { | |
567 struct stat st; | |
568 long now; | |
569 int tem; | |
570 char *lockname, *p; | |
571 char *tempname; | |
572 int desc; | |
573 | |
574 dotlock_filename = (char *) xmalloc(strlen(filename) + 1); | |
575 | |
576 /* Use a lock file named after our first argument with .lock appended: | |
577 If it exists, the mail file is locked. */ | |
578 | |
579 lockname = dot_filename(filename); | |
580 tempname = (char *) xmalloc (strlen (filename) + strlen ("EXXXXXX") + 1); | |
581 strcpy (tempname, filename); | |
428 | 582 p = tempname + strlen (tempname); |
583 while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) | |
584 p--; | |
585 *p = 0; | |
586 strcpy (p, "EXXXXXX"); | |
567 | 587 #ifndef HAVE_MKSTEMP |
428 | 588 mktemp (tempname); |
589 unlink (tempname); | |
567 | 590 #endif |
428 | 591 |
438 | 592 for (;;) |
428 | 593 { |
594 /* Create the lock file, but not under the lock file name. */ | |
595 /* Give up if cannot do that. */ | |
567 | 596 #ifdef HAVE_MKSTEMP |
597 desc = mkstemp (tempname); | |
598 #else | |
428 | 599 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); |
567 | 600 #endif |
428 | 601 if (desc < 0) |
602 { | |
603 char *message = (char *) xmalloc (strlen (tempname) + 50); | |
604 sprintf (message, "%s--see source file lib-src/movemail.c", | |
605 tempname); | |
606 pfatal_with_name (message); | |
607 } | |
608 close (desc); | |
609 | |
610 tem = link (tempname, lockname); | |
611 unlink (tempname); | |
612 if (tem >= 0) | |
613 break; | |
614 sleep (1); | |
615 | |
616 /* If lock file is five minutes old, unlock it. | |
617 Five minutes should be good enough to cope with crashes | |
618 and wedgitude, and long enough to avoid being fooled | |
619 by time differences between machines. */ | |
620 if (stat (lockname, &st) >= 0) | |
621 { | |
622 now = time (0); | |
623 if (st.st_ctime < now - 300) | |
624 unlink (lockname); | |
625 } | |
626 } | |
438 | 627 strcpy(dotlock_filename, filename); |
628 } | |
442 | 629 #endif /* not DISABLE_DIRECT_ACCESS */ |
428 | 630 |
438 | 631 static void |
632 unlock_dot(char *filename) | |
633 { | |
634 unlink(dot_filename(filename)); | |
635 } | |
428 | 636 |
438 | 637 static void |
638 maybe_unlock_dot(void) | |
639 { | |
640 if (dotlock_filename) | |
641 unlock_dot(dotlock_filename); | |
642 } | |
428 | 643 |
644 /* Print error message and exit. */ | |
645 | |
646 static void | |
647 fatal (char *s1, char *s2) | |
648 { | |
438 | 649 maybe_unlock_dot(); |
428 | 650 error (s1, s2, NULL); |
651 exit (1); | |
652 } | |
653 | |
654 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ | |
655 | |
656 static void | |
657 error (char *s1, char *s2, char *s3) | |
658 { | |
659 fprintf (stderr, "movemail: "); | |
660 fprintf (stderr, s1, s2, s3); | |
661 fprintf (stderr, "\n"); | |
662 } | |
663 | |
664 static void | |
665 pfatal_with_name (char *name) | |
666 { | |
667 char *s = concat ("", strerror (errno), " for %s"); | |
668 fatal (s, name); | |
669 } | |
670 | |
671 static void | |
672 pfatal_and_delete (char *name) | |
673 { | |
674 char *s = concat ("", strerror (errno), " for %s"); | |
675 unlink (name); | |
676 fatal (s, name); | |
677 } | |
678 | |
679 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ | |
680 | |
681 static char * | |
682 concat (char *s1, char *s2, char *s3) | |
683 { | |
684 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); | |
685 char *result = (char *) xmalloc (len1 + len2 + len3 + 1); | |
686 | |
687 strcpy (result, s1); | |
688 strcpy (result + len1, s2); | |
689 strcpy (result + len1 + len2, s3); | |
690 *(result + len1 + len2 + len3) = 0; | |
691 | |
692 return result; | |
693 } | |
694 | |
695 /* Like malloc but get fatal error if memory is exhausted. */ | |
696 | |
697 static long * | |
647 | 698 xmalloc (int size) |
428 | 699 { |
700 long *result = (long *) malloc (size); | |
701 if (!result) | |
702 fatal ("virtual memory exhausted", 0); | |
703 return result; | |
704 } | |
438 | 705 |
428 | 706 /* This is the guts of the interface to the Post Office Protocol. */ |
707 | |
708 #ifdef MAIL_USE_POP | |
709 | |
442 | 710 #ifndef WIN32_NATIVE |
428 | 711 #include <sys/socket.h> |
712 #include <netinet/in.h> | |
713 #include <netdb.h> | |
714 #else | |
715 #undef _WINSOCKAPI_ | |
716 #include <winsock.h> | |
717 #endif | |
718 #include <stdio.h> | |
442 | 719 #include "../src/syspwd.h" |
428 | 720 |
721 #define POP_ERROR (-1) | |
722 #define POP_RETRIEVED (0) | |
723 #define POP_DONE (1) | |
724 | |
725 char *progname; | |
726 FILE *sfi; | |
727 FILE *sfo; | |
728 char ibuffer[BUFSIZ]; | |
729 char obuffer[BUFSIZ]; | |
730 char Errmsg[80]; | |
731 | |
732 static int | |
733 popmail (char *user, char *outfile, char *password) | |
734 { | |
735 int nmsgs, nbytes; | |
736 register int i, idx; | |
737 int mbfi; | |
738 short* retrieved_list; | |
739 FILE *mbf; | |
740 popserver server; | |
741 | |
438 | 742 VERBOSE(("opening server\n")); |
428 | 743 server = pop_open (0, user, password, POP_NO_GETPASS); |
744 if (! server) | |
745 { | |
2584 | 746 error ("%s", pop_error, NULL); |
428 | 747 return (1); |
748 } | |
749 | |
438 | 750 VERBOSE(("stat'ing messages\n")); |
428 | 751 if (pop_stat (server, &nmsgs, &nbytes)) |
752 { | |
2584 | 753 error ("%s", pop_error, NULL); |
428 | 754 return (1); |
755 } | |
756 | |
757 if (!nmsgs) | |
758 { | |
759 VERBOSE(("closing server\n")); | |
760 pop_close (server); | |
761 return (0); | |
762 } | |
763 | |
764 /* build a retrieved table */ | |
765 retrieved_list = (short*) xmalloc (sizeof (short) * (nmsgs+1)); | |
766 memset (retrieved_list, 0, sizeof (short) * (nmsgs+1)); | |
767 | |
768 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
769 if (mbfi < 0) | |
770 { | |
771 pop_close (server); | |
772 error ("Error in open: %s, %s", strerror (errno), outfile); | |
773 return (1); | |
774 } | |
442 | 775 #if !defined(CYGWIN) && !defined(WIN32_NATIVE) |
440 | 776 fchown (mbfi, getuid (), (gid_t) -1); |
428 | 777 #endif |
778 | |
779 if ((mbf = fdopen (mbfi, "wb")) == NULL) | |
780 { | |
781 pop_close (server); | |
782 error ("Error in fdopen: %s", strerror (errno), NULL); | |
783 close (mbfi); | |
784 unlink (outfile); | |
785 return (1); | |
786 } | |
787 | |
788 for (idx = 0; idx < nmsgs; idx++) | |
789 { | |
790 i = reverse ? nmsgs - idx : idx + 1; | |
438 | 791 VERBOSE(("checking message %d \n", i)); |
428 | 792 |
793 if (!regexp_pattern | |
794 || | |
795 pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) | |
796 { | |
438 | 797 VERBOSE(("retrieving message %d \n", i)); |
428 | 798 mbx_delimit_begin (mbf); |
799 if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) | |
800 { | |
2584 | 801 error ("%s", Errmsg, NULL); |
428 | 802 close (mbfi); |
803 return (1); | |
804 } | |
805 | |
806 retrieved_list[i]=1; | |
807 | |
808 mbx_delimit_end (mbf); | |
809 fflush (mbf); | |
810 if (ferror (mbf)) | |
811 { | |
812 error ("Error in fflush: %s", strerror (errno), NULL); | |
813 pop_close (server); | |
814 close (mbfi); | |
815 return (1); | |
816 } | |
817 } | |
818 } | |
819 | |
820 /* On AFS, a call to write only modifies the file in the local | |
821 * workstation's AFS cache. The changes are not written to the server | |
822 * until a call to fsync or close is made. Users with AFS home | |
823 * directories have lost mail when over quota because these checks were | |
824 * not made in previous versions of movemail. */ | |
825 | |
438 | 826 #ifdef HAVE_FSYNC |
428 | 827 if (fsync (mbfi) < 0) |
828 { | |
829 error ("Error in fsync: %s", strerror (errno), NULL); | |
830 return (1); | |
831 } | |
832 #endif | |
833 | |
834 if (close (mbfi) == -1) | |
835 { | |
836 error ("Error in close: %s", strerror (errno), NULL); | |
837 return (1); | |
838 } | |
839 | |
840 if (!keep_messages) | |
841 { | |
842 for (i = 1; i <= nmsgs; i++) | |
843 { | |
844 if (retrieved_list[i] == 1) | |
845 { | |
438 | 846 VERBOSE(("deleting message %d \n", i)); |
428 | 847 if (pop_delete (server, i)) |
848 { | |
2584 | 849 error ("%s", pop_error, NULL); |
428 | 850 pop_close (server); |
851 return (1); | |
852 } | |
853 } | |
854 } | |
855 } | |
856 | |
857 VERBOSE(("closing server \n")); | |
858 if (pop_quit (server)) | |
859 { | |
2584 | 860 error ("%s", pop_error, NULL); |
428 | 861 return (1); |
862 } | |
863 | |
864 return (0); | |
865 } | |
866 | |
867 static int | |
440 | 868 pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), FILE *arg) |
428 | 869 { |
870 char *line; | |
871 int ret; | |
872 | |
873 if (pop_retrieve_first (server, msgno, &line)) | |
874 { | |
875 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
876 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
877 return (POP_ERROR); | |
878 } | |
879 | |
880 while (! (ret = pop_retrieve_next (server, &line))) | |
881 { | |
882 if (! line) | |
883 break; | |
884 | |
885 if ((*action)(line, arg) != POP_RETRIEVED) | |
886 { | |
887 strcpy (Errmsg, strerror (errno)); | |
888 pop_close (server); | |
889 return (POP_ERROR); | |
890 } | |
891 } | |
892 | |
893 if (ret) | |
894 { | |
895 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
896 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
897 return (POP_ERROR); | |
898 } | |
899 | |
900 return (POP_RETRIEVED); | |
901 } | |
902 | |
903 /* search the top lines of each message looking for a match */ | |
904 static int | |
905 pop_search_top (popserver server, int msgno, int lines, struct re_pattern_buffer* regexp) | |
906 { | |
907 char *line; | |
908 int ret; | |
909 int match = POP_DONE; | |
910 | |
911 if (pop_top_first (server, msgno, lines, &line)) | |
912 { | |
913 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
914 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
915 return (POP_ERROR); | |
916 } | |
917 | |
918 while (! (ret = pop_top_next (server, &line))) | |
919 { | |
920 if (! line) | |
921 break; | |
922 | |
923 /* VERBOSE (("checking %s\n", line));*/ | |
924 if (match != POP_RETRIEVED) | |
925 { | |
926 if ((ret = re_match (regexp, line, strlen (line), 0, 0)) == -2 ) | |
927 { | |
928 strcpy (Errmsg, "error in regular expression"); | |
929 pop_close (server); | |
930 return (POP_ERROR); | |
931 } | |
932 else if (ret >=0) | |
933 { | |
934 match = POP_RETRIEVED; | |
935 } | |
936 } | |
937 } | |
938 | |
939 if (ret) | |
940 { | |
941 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
942 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
943 return (POP_ERROR); | |
944 } | |
945 | |
946 return match; | |
947 } | |
948 | |
949 /* Do this as a macro instead of using strcmp to save on execution time. */ | |
950 #define IS_FROM_LINE(a) ((a[0] == 'F') \ | |
951 && (a[1] == 'r') \ | |
952 && (a[2] == 'o') \ | |
953 && (a[3] == 'm') \ | |
954 && (a[4] == ' ')) | |
955 | |
956 static int | |
957 mbx_write (char *line, FILE *mbf) | |
958 { | |
959 if (IS_FROM_LINE (line)) | |
960 { | |
961 if (fputc ('>', mbf) == EOF) | |
962 return (POP_ERROR); | |
963 } | |
964 if (fputs (line, mbf) == EOF) | |
965 return (POP_ERROR); | |
966 if (fputc (0x0a, mbf) == EOF) | |
967 return (POP_ERROR); | |
968 return (POP_RETRIEVED); | |
969 } | |
970 | |
971 static int | |
972 mbx_delimit_begin (FILE *mbf) | |
973 { | |
974 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF) | |
975 return (POP_ERROR); | |
976 return (POP_RETRIEVED); | |
977 } | |
978 | |
979 static int | |
980 mbx_delimit_end (FILE *mbf) | |
981 { | |
982 if (putc ('\037', mbf) == EOF) | |
983 return (POP_ERROR); | |
984 return (POP_RETRIEVED); | |
985 } | |
986 | |
987 /* Turn a name, which is an ed-style (but Emacs syntax) regular | |
988 expression, into a real regular expression by compiling it. */ | |
989 static struct re_pattern_buffer* | |
990 compile_regex (char* pattern) | |
991 { | |
992 char *err; | |
993 struct re_pattern_buffer *patbuf=0; | |
994 | |
995 patbuf = (struct re_pattern_buffer*) xmalloc (sizeof (struct re_pattern_buffer)); | |
996 patbuf->translate = NULL; | |
997 patbuf->fastmap = NULL; | |
998 patbuf->buffer = NULL; | |
999 patbuf->allocated = 0; | |
1000 | |
1001 err = (char*) re_compile_pattern (pattern, strlen (pattern), patbuf); | |
1002 if (err != NULL) | |
1003 { | |
1004 error ("%s while compiling pattern", err, NULL); | |
1005 return 0; | |
1006 } | |
1007 | |
1008 return patbuf; | |
1009 } | |
1010 | |
1011 | |
1012 | |
1013 #endif /* MAIL_USE_POP */ | |
438 | 1014 |
428 | 1015 #ifndef HAVE_STRERROR |
1016 char * | |
1017 strerror (int errnum) | |
1018 { | |
1019 extern char *sys_errlist[]; | |
1020 extern int sys_nerr; | |
1021 | |
1022 if (errnum >= 0 && errnum < sys_nerr) | |
1023 return sys_errlist[errnum]; | |
1024 return (char *) "Unknown error"; | |
1025 } | |
1026 | |
1027 #endif /* ! HAVE_STRERROR */ |