Mercurial > hg > xemacs-beta
annotate lib-src/movemail.c @ 5908:6174848f3e6c
Use parse_integer() in read_atom(); support bases with ratios like integers
src/ChangeLog addition:
2015-05-08 Aidan Kehoe <kehoea@parhasard.net>
* data.c (init_errors_once_early):
Move the Qunsupported_type here from numbers.c, so it's available
when the majority of our types are not supported.
* general-slots.h: Add it here, too.
* number.c: Remove the definition of Qunsupported_type from here.
* lread.c (read_atom):
Check if the first character could reflect a rational, if so, call
parse_integer(), don't check the syntax of the other
characters. This allows us to accept the non-ASCII digit
characters too.
If that worked partially, but not completely, and the next char is
a slash, try to parse as a ratio.
If that fails, try isfloat_string(), but only if the first
character could plausibly be part of a float.
Otherwise, treat as a symbol.
* lread.c (read_rational):
Rename from read_integer. Handle ratios with the same radix
specification as was used for integers.
* lread.c (read1):
Rename read_integer in this function. Support the Common Lisp
#NNNrMMM syntax for parsing a number MMM of arbitrary radix NNN.
man/ChangeLog addition:
2015-05-08 Aidan Kehoe <kehoea@parhasard.net>
* lispref/numbers.texi (Numbers):
Describe the newly-supported arbitrary-base syntax for rationals
(integers and ratios). Describe that ratios can take the same base
specification as integers, something also new.
tests/ChangeLog addition:
2015-05-08 Aidan Kehoe <kehoea@parhasard.net>
* automated/lisp-reader-tests.el:
Check the arbitrary-base integer reader syntax support, just
added. Check the reader base support for ratios, just added.
Check the non-ASCII-digit support in the reader, just added.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Sat, 09 May 2015 00:40:57 +0100 |
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 */ |