Mercurial > hg > xemacs-beta
comparison lib-src/movemail.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 84b14dcb0985 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* movemail foo bar -- move file foo to file bar, | |
2 locking file foo the way /bin/mail respects. | |
3 Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. | |
4 | |
5 This file is part of GNU Emacs. | |
6 | |
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 | |
9 the Free Software Foundation; either version 2, or (at your option) | |
10 any later version. | |
11 | |
12 GNU Emacs is distributed in the hope that it will be useful, | |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
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 | |
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 Boston, MA 02111-1307, USA. */ | |
21 | |
22 /* 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 | |
24 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 | |
26 system's own conventions. It is not a choice that is up to you. | |
27 | |
28 So, if your system uses lock files rather than flock, then the only way | |
29 you can get proper operation is to enable movemail to write lockfiles there. | |
30 This means you must either give that directory access modes | |
31 that permit everyone to write lockfiles in it, or you must make movemail | |
32 a setuid or setgid program. */ | |
33 | |
34 /* | |
35 * Modified January, 1986 by Michael R. Gretzinger (Project Athena) | |
36 * | |
37 * Added POP (Post Office Protocol) service. When compiled -DMAIL_USE_POP | |
38 * movemail will accept input filename arguments of the form | |
39 * "po:username". This will cause movemail to open a connection to | |
40 * a pop server running on $MAILHOST (environment variable). Movemail | |
41 * must be setuid to root in order to work with POP. | |
42 * | |
43 * New module: popmail.c | |
44 * Modified routines: | |
45 * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ()) | |
46 * after POP code. | |
47 * New routines in movemail.c: | |
48 * get_errmsg - return pointer to system error message | |
49 * | |
50 * Modified August, 1993 by Jonathan Kamens (OpenVision Technologies) | |
51 * | |
52 * Move all of the POP code into a separate file, "pop.c". | |
53 * Use strerror instead of get_errmsg. | |
54 * | |
55 */ | |
56 | |
57 #define NO_SHORTNAMES /* Tell config not to load remap.h */ | |
58 #define DONT_ENCAPSULATE | |
59 #include <../src/config.h> | |
60 #include <sys/types.h> | |
61 #include <sys/stat.h> | |
62 #include <stdio.h> | |
63 #include <errno.h> | |
64 #include "../src/sysfile.h" | |
65 #include "../src/syswait.h" | |
66 #ifndef WINDOWSNT | |
67 #include "../src/systime.h" | |
68 #endif | |
69 #include <stdlib.h> | |
70 #include <string.h> | |
71 #include "getopt.h" | |
72 #ifdef MAIL_USE_POP | |
73 #include "pop.h" | |
74 #include "../src/regex.h" | |
75 #endif | |
76 | |
77 extern char *optarg; | |
78 extern int optind, opterr; | |
79 | |
80 #ifndef HAVE_STRERROR | |
81 char * strerror (int errnum); | |
82 #endif /* HAVE_STRERROR */ | |
83 | |
84 #ifdef MSDOS | |
85 #undef access | |
86 #endif /* MSDOS */ | |
87 | |
88 #ifndef DIRECTORY_SEP | |
89 #define DIRECTORY_SEP '/' | |
90 #endif | |
91 #ifndef IS_DIRECTORY_SEP | |
92 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) | |
93 #endif | |
94 | |
95 #ifdef WINDOWSNT | |
96 #undef access | |
97 #undef unlink | |
98 #define fork() 0 | |
99 #define sys_wait(var) (*(var) = 0) | |
100 /* Unfortunately, Samba doesn't seem to properly lock Unix files even | |
101 though the locking call succeeds (and indeed blocks local access from | |
102 other NT programs). If you have direct file access using an NFS | |
103 client or something other than Samba, the locking call might work | |
104 properly - make sure it does before you enable this! */ | |
105 #define DISABLE_DIRECT_ACCESS | |
106 #include <io.h> | |
107 #endif /* WINDOWSNT */ | |
108 | |
109 #if defined (HAVE_UNISTD_H) || defined (USG) | |
110 #include <unistd.h> | |
111 #endif /* unistd.h */ | |
112 #ifndef F_OK | |
113 #define F_OK 0 | |
114 #define X_OK 1 | |
115 #define W_OK 2 | |
116 #define R_OK 4 | |
117 #endif /* No F_OK */ | |
118 | |
119 #if defined (HAVE_FCNTL_H) || defined (USG) | |
120 #include <fcntl.h> | |
121 #endif /* fcntl.h */ | |
122 | |
123 #if defined (XENIX) || defined (WINDOWSNT) | |
124 #include <sys/locking.h> | |
125 #endif | |
126 | |
127 #ifdef MAIL_USE_LOCKF | |
128 #define MAIL_USE_SYSTEM_LOCK | |
129 #endif | |
130 | |
131 #ifdef MAIL_USE_FLOCK | |
132 #define MAIL_USE_SYSTEM_LOCK | |
133 #endif | |
134 | |
135 #ifdef MAIL_USE_MMDF | |
136 extern int lk_open (), lk_close (); | |
137 #endif | |
138 | |
139 /* Cancel substitutions made by config.h for Emacs. */ | |
140 #undef open | |
141 #undef read | |
142 #undef write | |
143 #undef close | |
144 | |
145 static void fatal (char *, char*); | |
146 static void error (char *, char *, char *); | |
147 static void pfatal_with_name (char *); | |
148 static void pfatal_and_delete (char *); | |
149 static char *concat (char *, char *, char *); | |
150 static long *xmalloc (unsigned int); | |
151 #ifdef MAIL_USE_POP | |
152 static int popmail (char *, char *, char *); | |
153 static int pop_retr (popserver server, int msgno, | |
154 int (*action)(char *, FILE *), void *arg); | |
155 static int mbx_write (char *, FILE *); | |
156 static int mbx_delimit_begin (FILE *); | |
157 static int mbx_delimit_end (FILE *); | |
158 static struct re_pattern_buffer* compile_regex (char* regexp_pattern); | |
159 static int pop_search_top (popserver server, int msgno, int lines, | |
160 struct re_pattern_buffer* regexp); | |
161 #endif | |
162 | |
163 /* Nonzero means this is name of a lock file to delete on fatal error. */ | |
164 char *delete_lockname; | |
165 | |
166 int verbose=0; | |
167 #ifdef MAIL_USE_POP | |
168 int reverse=0; | |
169 int keep_messages=0; | |
170 struct re_pattern_buffer* regexp_pattern=0; | |
171 int match_lines=10; | |
172 #endif | |
173 | |
174 #define VERBOSE(x) if (verbose) { printf x; fflush(stdout); } | |
175 | |
176 struct option longopts[] = | |
177 { | |
178 { "inbox", required_argument, NULL, 'i' }, | |
179 { "outfile", required_argument, NULL, 'o' }, | |
180 #ifdef MAIL_USE_POP | |
181 { "password", required_argument, NULL, 'p' }, | |
182 { "reverse-pop-order", no_argument, NULL, 'x' }, | |
183 { "keep-messages", no_argument, NULL, 'k' }, | |
184 { "regex", required_argument, NULL, 'r' }, | |
185 { "match-lines", required_argument, NULL, 'l' }, | |
186 #endif | |
187 { "verbose", no_argument, NULL, 'v' }, | |
188 { 0 } | |
189 }; | |
190 | |
191 int | |
192 main (int argc, char *argv[]) | |
193 { | |
194 char *inname=0, *outname=0, *poppass=0; | |
195 #ifndef DISABLE_DIRECT_ACCESS | |
196 int indesc, outdesc; | |
197 int nread; | |
198 int status; | |
199 #endif | |
200 | |
201 #ifndef MAIL_USE_SYSTEM_LOCK | |
202 struct stat st; | |
203 long now; | |
204 int tem; | |
205 char *lockname, *p; | |
206 char *tempname; | |
207 int desc; | |
208 #endif /* not MAIL_USE_SYSTEM_LOCK */ | |
209 | |
210 delete_lockname = 0; | |
211 | |
212 while (1) | |
213 { | |
214 #ifdef MAIL_USE_POP | |
215 char* optstring = "i:o:p:l:r:xvk"; | |
216 #else | |
217 char* optstring = "i:o:v"; | |
218 #endif | |
219 int opt = getopt_long (argc, argv, optstring, longopts, 0); | |
220 | |
221 if (opt == EOF) | |
222 break; | |
223 | |
224 switch (opt) | |
225 { | |
226 case 0: | |
227 break; | |
228 case 1: /* one of the standard arguments seen */ | |
229 if (!inname) | |
230 inname = optarg; | |
231 else if (!outname) | |
232 outname = optarg; | |
233 else | |
234 poppass = optarg; | |
235 break; | |
236 | |
237 case 'i': /* infile */ | |
238 inname = optarg; | |
239 break; | |
240 | |
241 case 'o': /* outfile */ | |
242 outname = optarg; | |
243 break; | |
244 #ifdef MAIL_USE_POP | |
245 case 'p': /* pop password */ | |
246 poppass = optarg; | |
247 break; | |
248 case 'k': keep_messages=1; break; | |
249 case 'x': reverse = 1; break; | |
250 case 'l': /* lines to match */ | |
251 match_lines = atoi (optarg); | |
252 break; | |
253 | |
254 case 'r': /* regular expression */ | |
255 regexp_pattern = compile_regex (optarg); | |
256 break; | |
257 #endif | |
258 case 'v': verbose = 1; break; | |
259 } | |
260 } | |
261 | |
262 while (optind < argc) | |
263 { | |
264 if (!inname) | |
265 inname = argv[optind]; | |
266 else if (!outname) | |
267 outname = argv[optind]; | |
268 else | |
269 poppass = argv[optind]; | |
270 optind++; | |
271 } | |
272 | |
273 if (!inname || !outname) | |
274 { | |
275 fprintf (stderr, "Usage: movemail [-rvxk] [-l lines ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); | |
276 exit(1); | |
277 } | |
278 | |
279 #ifdef MAIL_USE_MMDF | |
280 mmdf_init (argv[0]); | |
281 #endif | |
282 | |
283 if (*outname == 0) | |
284 fatal ("Destination file name is empty", 0); | |
285 | |
286 /* Check access to output file. */ | |
287 if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) | |
288 pfatal_with_name (outname); | |
289 | |
290 /* Also check that outname's directory is writable to the real uid. */ | |
291 { | |
292 char *buf = (char *) xmalloc (strlen (outname) + 1); | |
293 char *cp; | |
294 strcpy (buf, outname); | |
295 cp = buf + strlen (buf); | |
296 while (cp > buf && !IS_DIRECTORY_SEP (cp[-1])) | |
297 *--cp = 0; | |
298 if (cp == buf) | |
299 *cp++ = '.'; | |
300 if (access (buf, W_OK) != 0) | |
301 pfatal_with_name (buf); | |
302 free (buf); | |
303 } | |
304 | |
305 #ifdef MAIL_USE_POP | |
306 if (!strncmp (inname, "po:", 3)) | |
307 { | |
308 int retcode = popmail (inname + 3, outname, poppass); | |
309 exit (retcode); | |
310 } | |
311 | |
312 #ifndef WINDOWSNT | |
313 setuid (getuid ()); | |
314 #endif | |
315 #endif /* MAIL_USE_POP */ | |
316 | |
317 #ifndef DISABLE_DIRECT_ACCESS | |
318 | |
319 /* Check access to input file. */ | |
320 if (access (inname, R_OK | W_OK) != 0) | |
321 pfatal_with_name (inname); | |
322 | |
323 #ifndef MAIL_USE_MMDF | |
324 #ifndef MAIL_USE_SYSTEM_LOCK | |
325 /* Use a lock file named after our first argument with .lock appended: | |
326 If it exists, the mail file is locked. */ | |
327 /* Note: this locking mechanism is *required* by the mailer | |
328 (on systems which use it) to prevent loss of mail. | |
329 | |
330 On systems that use a lock file, extracting the mail without locking | |
331 WILL occasionally cause loss of mail due to timing errors! | |
332 | |
333 So, if creation of the lock file fails | |
334 due to access permission on the mail spool directory, | |
335 you simply MUST change the permission | |
336 and/or make movemail a setgid program | |
337 so it can create lock files properly. | |
338 | |
339 You might also wish to verify that your system is one | |
340 which uses lock files for this purpose. Some systems use other methods. | |
341 | |
342 If your system uses the `flock' system call for mail locking, | |
343 define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file | |
344 and recompile movemail. If the s- file for your system | |
345 should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report | |
346 to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */ | |
347 | |
348 lockname = concat (inname, ".lock", ""); | |
349 tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); | |
350 strcpy (tempname, inname); | |
351 p = tempname + strlen (tempname); | |
352 while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) | |
353 p--; | |
354 *p = 0; | |
355 strcpy (p, "EXXXXXX"); | |
356 mktemp (tempname); | |
357 unlink (tempname); | |
358 | |
359 while (1) | |
360 { | |
361 /* Create the lock file, but not under the lock file name. */ | |
362 /* Give up if cannot do that. */ | |
363 desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
364 if (desc < 0) | |
365 { | |
366 char *message = (char *) xmalloc (strlen (tempname) + 50); | |
367 sprintf (message, "%s--see source file lib-src/movemail.c", | |
368 tempname); | |
369 pfatal_with_name (message); | |
370 } | |
371 close (desc); | |
372 | |
373 tem = link (tempname, lockname); | |
374 unlink (tempname); | |
375 if (tem >= 0) | |
376 break; | |
377 sleep (1); | |
378 | |
379 /* If lock file is five minutes old, unlock it. | |
380 Five minutes should be good enough to cope with crashes | |
381 and wedgitude, and long enough to avoid being fooled | |
382 by time differences between machines. */ | |
383 if (stat (lockname, &st) >= 0) | |
384 { | |
385 now = time (0); | |
386 if (st.st_ctime < now - 300) | |
387 unlink (lockname); | |
388 } | |
389 } | |
390 | |
391 delete_lockname = lockname; | |
392 #endif /* not MAIL_USE_SYSTEM_LOCK */ | |
393 #endif /* not MAIL_USE_MMDF */ | |
394 | |
395 if (fork () == 0) | |
396 { | |
397 setuid (getuid ()); | |
398 | |
399 #ifndef MAIL_USE_MMDF | |
400 #ifdef MAIL_USE_SYSTEM_LOCK | |
401 indesc = open (inname, O_RDWR); | |
402 #else /* if not MAIL_USE_SYSTEM_LOCK */ | |
403 indesc = open (inname, O_RDONLY); | |
404 #endif /* not MAIL_USE_SYSTEM_LOCK */ | |
405 #else /* MAIL_USE_MMDF */ | |
406 indesc = lk_open (inname, O_RDONLY, 0, 0, 10); | |
407 #endif /* MAIL_USE_MMDF */ | |
408 | |
409 if (indesc < 0) | |
410 pfatal_with_name (inname); | |
411 | |
412 #if defined (BSD) || defined (XENIX) | |
413 /* In case movemail is setuid to root, make sure the user can | |
414 read the output file. */ | |
415 /* This is desirable for all systems | |
416 but I don't want to assume all have the umask system call */ | |
417 umask (umask (0) & 0333); | |
418 #endif /* BSD or Xenix */ | |
419 outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
420 if (outdesc < 0) | |
421 pfatal_with_name (outname); | |
422 #ifdef MAIL_USE_SYSTEM_LOCK | |
423 #ifdef MAIL_USE_LOCKF | |
424 if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname); | |
425 #else /* not MAIL_USE_LOCKF */ | |
426 #ifdef XENIX | |
427 if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); | |
428 #else | |
429 #ifdef WINDOWSNT | |
430 if (locking (indesc, LK_RLCK, -1L) < 0) pfatal_with_name (inname); | |
431 #else | |
432 if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); | |
433 #endif | |
434 #endif | |
435 #endif /* not MAIL_USE_LOCKF */ | |
436 #endif /* MAIL_USE_SYSTEM_LOCK */ | |
437 | |
438 { | |
439 char buf[1024]; | |
440 | |
441 while (1) | |
442 { | |
443 nread = read (indesc, buf, sizeof buf); | |
444 if (nread != write (outdesc, buf, nread)) | |
445 { | |
446 int saved_errno = errno; | |
447 unlink (outname); | |
448 errno = saved_errno; | |
449 pfatal_with_name (outname); | |
450 } | |
451 if (nread < sizeof buf) | |
452 break; | |
453 } | |
454 } | |
455 | |
456 #ifdef BSD | |
457 if (fsync (outdesc) < 0) | |
458 pfatal_and_delete (outname); | |
459 #endif | |
460 | |
461 /* Check to make sure no errors before we zap the inbox. */ | |
462 if (close (outdesc) != 0) | |
463 pfatal_and_delete (outname); | |
464 | |
465 #ifdef MAIL_USE_SYSTEM_LOCK | |
466 #if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT) | |
467 /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ | |
468 close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); | |
469 #else | |
470 ftruncate (indesc, 0L); | |
471 #endif /* STRIDE or XENIX */ | |
472 #endif /* MAIL_USE_SYSTEM_LOCK */ | |
473 | |
474 #ifdef MAIL_USE_MMDF | |
475 lk_close (indesc, 0, 0, 0); | |
476 #else | |
477 close (indesc); | |
478 #endif | |
479 | |
480 #ifndef MAIL_USE_SYSTEM_LOCK | |
481 /* Delete the input file; if we can't, at least get rid of its | |
482 contents. */ | |
483 #ifdef MAIL_UNLINK_SPOOL | |
484 /* This is generally bad to do, because it destroys the permissions | |
485 that were set on the file. Better to just empty the file. */ | |
486 if (unlink (inname) < 0 && errno != ENOENT) | |
487 #endif /* MAIL_UNLINK_SPOOL */ | |
488 creat (inname, 0600); | |
489 #endif /* not MAIL_USE_SYSTEM_LOCK */ | |
490 | |
491 exit (0); | |
492 } | |
493 | |
494 wait (&status); | |
495 if (!WIFEXITED (status)) | |
496 exit (1); | |
497 else if (WEXITSTATUS (status) != 0) | |
498 exit (WEXITSTATUS (status)); | |
499 | |
500 #if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK) | |
501 unlink (lockname); | |
502 #endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */ | |
503 | |
504 #endif /* ! DISABLE_DIRECT_ACCESS */ | |
505 | |
506 return 0; | |
507 } | |
508 | |
509 /* Print error message and exit. */ | |
510 | |
511 static void | |
512 fatal (char *s1, char *s2) | |
513 { | |
514 if (delete_lockname) | |
515 unlink (delete_lockname); | |
516 error (s1, s2, NULL); | |
517 exit (1); | |
518 } | |
519 | |
520 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ | |
521 | |
522 static void | |
523 error (char *s1, char *s2, char *s3) | |
524 { | |
525 fprintf (stderr, "movemail: "); | |
526 fprintf (stderr, s1, s2, s3); | |
527 fprintf (stderr, "\n"); | |
528 } | |
529 | |
530 static void | |
531 pfatal_with_name (char *name) | |
532 { | |
533 char *s = concat ("", strerror (errno), " for %s"); | |
534 fatal (s, name); | |
535 } | |
536 | |
537 static void | |
538 pfatal_and_delete (char *name) | |
539 { | |
540 char *s = concat ("", strerror (errno), " for %s"); | |
541 unlink (name); | |
542 fatal (s, name); | |
543 } | |
544 | |
545 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ | |
546 | |
547 static char * | |
548 concat (char *s1, char *s2, char *s3) | |
549 { | |
550 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); | |
551 char *result = (char *) xmalloc (len1 + len2 + len3 + 1); | |
552 | |
553 strcpy (result, s1); | |
554 strcpy (result + len1, s2); | |
555 strcpy (result + len1 + len2, s3); | |
556 *(result + len1 + len2 + len3) = 0; | |
557 | |
558 return result; | |
559 } | |
560 | |
561 /* Like malloc but get fatal error if memory is exhausted. */ | |
562 | |
563 static long * | |
564 xmalloc (unsigned int size) | |
565 { | |
566 long *result = (long *) malloc (size); | |
567 if (!result) | |
568 fatal ("virtual memory exhausted", 0); | |
569 return result; | |
570 } | |
571 | |
572 /* This is the guts of the interface to the Post Office Protocol. */ | |
573 | |
574 #ifdef MAIL_USE_POP | |
575 | |
576 #ifndef WINDOWSNT | |
577 #include <sys/socket.h> | |
578 #include <netinet/in.h> | |
579 #include <netdb.h> | |
580 #else | |
581 #undef _WINSOCKAPI_ | |
582 #include <winsock.h> | |
583 #endif | |
584 #include <stdio.h> | |
585 #include <pwd.h> | |
586 | |
587 #define POP_ERROR (-1) | |
588 #define POP_RETRIEVED (0) | |
589 #define POP_DONE (1) | |
590 | |
591 char *progname; | |
592 FILE *sfi; | |
593 FILE *sfo; | |
594 char ibuffer[BUFSIZ]; | |
595 char obuffer[BUFSIZ]; | |
596 char Errmsg[80]; | |
597 | |
598 static int | |
599 popmail (char *user, char *outfile, char *password) | |
600 { | |
601 int nmsgs, nbytes; | |
602 register int i, idx; | |
603 int mbfi; | |
604 short* retrieved_list; | |
605 FILE *mbf; | |
606 popserver server; | |
607 | |
608 VERBOSE(("opening server\r")); | |
609 server = pop_open (0, user, password, POP_NO_GETPASS); | |
610 if (! server) | |
611 { | |
612 error (pop_error, NULL, NULL); | |
613 return (1); | |
614 } | |
615 | |
616 VERBOSE(("stat'ing messages\r")); | |
617 if (pop_stat (server, &nmsgs, &nbytes)) | |
618 { | |
619 error (pop_error, NULL, NULL); | |
620 return (1); | |
621 } | |
622 | |
623 if (!nmsgs) | |
624 { | |
625 VERBOSE(("closing server\n")); | |
626 pop_close (server); | |
627 return (0); | |
628 } | |
629 | |
630 /* build a retrieved table */ | |
631 retrieved_list = (short*) xmalloc (sizeof (short) * (nmsgs+1)); | |
632 memset (retrieved_list, 0, sizeof (short) * (nmsgs+1)); | |
633 | |
634 mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
635 if (mbfi < 0) | |
636 { | |
637 pop_close (server); | |
638 error ("Error in open: %s, %s", strerror (errno), outfile); | |
639 return (1); | |
640 } | |
641 #if !defined(__CYGWIN32__) && !defined(WINDOWSNT) | |
642 fchown (mbfi, getuid (), -1); | |
643 #endif | |
644 | |
645 if ((mbf = fdopen (mbfi, "wb")) == NULL) | |
646 { | |
647 pop_close (server); | |
648 error ("Error in fdopen: %s", strerror (errno), NULL); | |
649 close (mbfi); | |
650 unlink (outfile); | |
651 return (1); | |
652 } | |
653 | |
654 for (idx = 0; idx < nmsgs; idx++) | |
655 { | |
656 i = reverse ? nmsgs - idx : idx + 1; | |
657 VERBOSE(("checking message %d \r", i)); | |
658 | |
659 if (!regexp_pattern | |
660 || | |
661 pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) | |
662 { | |
663 VERBOSE(("retrieving message %d \r", i)); | |
664 mbx_delimit_begin (mbf); | |
665 if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) | |
666 { | |
667 error (Errmsg, NULL, NULL); | |
668 close (mbfi); | |
669 return (1); | |
670 } | |
671 | |
672 retrieved_list[i]=1; | |
673 | |
674 mbx_delimit_end (mbf); | |
675 fflush (mbf); | |
676 if (ferror (mbf)) | |
677 { | |
678 error ("Error in fflush: %s", strerror (errno), NULL); | |
679 pop_close (server); | |
680 close (mbfi); | |
681 return (1); | |
682 } | |
683 } | |
684 } | |
685 | |
686 /* On AFS, a call to write only modifies the file in the local | |
687 * workstation's AFS cache. The changes are not written to the server | |
688 * until a call to fsync or close is made. Users with AFS home | |
689 * directories have lost mail when over quota because these checks were | |
690 * not made in previous versions of movemail. */ | |
691 | |
692 #ifdef BSD | |
693 if (fsync (mbfi) < 0) | |
694 { | |
695 error ("Error in fsync: %s", strerror (errno), NULL); | |
696 return (1); | |
697 } | |
698 #endif | |
699 | |
700 if (close (mbfi) == -1) | |
701 { | |
702 error ("Error in close: %s", strerror (errno), NULL); | |
703 return (1); | |
704 } | |
705 | |
706 if (!keep_messages) | |
707 { | |
708 for (i = 1; i <= nmsgs; i++) | |
709 { | |
710 if (retrieved_list[i] == 1) | |
711 { | |
712 VERBOSE(("deleting message %d \r", i)); | |
713 if (pop_delete (server, i)) | |
714 { | |
715 error (pop_error, NULL, NULL); | |
716 pop_close (server); | |
717 return (1); | |
718 } | |
719 } | |
720 } | |
721 } | |
722 | |
723 VERBOSE(("closing server \n")); | |
724 if (pop_quit (server)) | |
725 { | |
726 error (pop_error, NULL, NULL); | |
727 return (1); | |
728 } | |
729 | |
730 return (0); | |
731 } | |
732 | |
733 static int | |
734 pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), void *arg) | |
735 { | |
736 char *line; | |
737 int ret; | |
738 | |
739 if (pop_retrieve_first (server, msgno, &line)) | |
740 { | |
741 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
742 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
743 return (POP_ERROR); | |
744 } | |
745 | |
746 while (! (ret = pop_retrieve_next (server, &line))) | |
747 { | |
748 if (! line) | |
749 break; | |
750 | |
751 if ((*action)(line, arg) != POP_RETRIEVED) | |
752 { | |
753 strcpy (Errmsg, strerror (errno)); | |
754 pop_close (server); | |
755 return (POP_ERROR); | |
756 } | |
757 } | |
758 | |
759 if (ret) | |
760 { | |
761 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
762 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
763 return (POP_ERROR); | |
764 } | |
765 | |
766 return (POP_RETRIEVED); | |
767 } | |
768 | |
769 /* search the top lines of each message looking for a match */ | |
770 static int | |
771 pop_search_top (popserver server, int msgno, int lines, struct re_pattern_buffer* regexp) | |
772 { | |
773 char *line; | |
774 int ret; | |
775 int match = POP_DONE; | |
776 | |
777 if (pop_top_first (server, msgno, lines, &line)) | |
778 { | |
779 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
780 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
781 return (POP_ERROR); | |
782 } | |
783 | |
784 while (! (ret = pop_top_next (server, &line))) | |
785 { | |
786 if (! line) | |
787 break; | |
788 | |
789 /* VERBOSE (("checking %s\n", line));*/ | |
790 if (match != POP_RETRIEVED) | |
791 { | |
792 if ((ret = re_match (regexp, line, strlen (line), 0, 0)) == -2 ) | |
793 { | |
794 strcpy (Errmsg, "error in regular expression"); | |
795 pop_close (server); | |
796 return (POP_ERROR); | |
797 } | |
798 else if (ret >=0) | |
799 { | |
800 match = POP_RETRIEVED; | |
801 } | |
802 } | |
803 } | |
804 | |
805 if (ret) | |
806 { | |
807 strncpy (Errmsg, pop_error, sizeof (Errmsg)); | |
808 Errmsg[sizeof (Errmsg)-1] = '\0'; | |
809 return (POP_ERROR); | |
810 } | |
811 | |
812 return match; | |
813 } | |
814 | |
815 /* Do this as a macro instead of using strcmp to save on execution time. */ | |
816 #define IS_FROM_LINE(a) ((a[0] == 'F') \ | |
817 && (a[1] == 'r') \ | |
818 && (a[2] == 'o') \ | |
819 && (a[3] == 'm') \ | |
820 && (a[4] == ' ')) | |
821 | |
822 static int | |
823 mbx_write (char *line, FILE *mbf) | |
824 { | |
825 if (IS_FROM_LINE (line)) | |
826 { | |
827 if (fputc ('>', mbf) == EOF) | |
828 return (POP_ERROR); | |
829 } | |
830 if (fputs (line, mbf) == EOF) | |
831 return (POP_ERROR); | |
832 if (fputc (0x0a, mbf) == EOF) | |
833 return (POP_ERROR); | |
834 return (POP_RETRIEVED); | |
835 } | |
836 | |
837 static int | |
838 mbx_delimit_begin (FILE *mbf) | |
839 { | |
840 if (fputs ("\f\n0, unseen,,\n", mbf) == EOF) | |
841 return (POP_ERROR); | |
842 return (POP_RETRIEVED); | |
843 } | |
844 | |
845 static int | |
846 mbx_delimit_end (FILE *mbf) | |
847 { | |
848 if (putc ('\037', mbf) == EOF) | |
849 return (POP_ERROR); | |
850 return (POP_RETRIEVED); | |
851 } | |
852 | |
853 /* Turn a name, which is an ed-style (but Emacs syntax) regular | |
854 expression, into a real regular expression by compiling it. */ | |
855 static struct re_pattern_buffer* | |
856 compile_regex (char* pattern) | |
857 { | |
858 char *err; | |
859 struct re_pattern_buffer *patbuf=0; | |
860 | |
861 patbuf = (struct re_pattern_buffer*) xmalloc (sizeof (struct re_pattern_buffer)); | |
862 patbuf->translate = NULL; | |
863 patbuf->fastmap = NULL; | |
864 patbuf->buffer = NULL; | |
865 patbuf->allocated = 0; | |
866 | |
867 err = (char*) re_compile_pattern (pattern, strlen (pattern), patbuf); | |
868 if (err != NULL) | |
869 { | |
870 error ("%s while compiling pattern", err, NULL); | |
871 return 0; | |
872 } | |
873 | |
874 return patbuf; | |
875 } | |
876 | |
877 | |
878 | |
879 #endif /* MAIL_USE_POP */ | |
880 | |
881 #ifndef HAVE_STRERROR | |
882 char * | |
883 strerror (int errnum) | |
884 { | |
885 extern char *sys_errlist[]; | |
886 extern int sys_nerr; | |
887 | |
888 if (errnum >= 0 && errnum < sys_nerr) | |
889 return sys_errlist[errnum]; | |
890 return (char *) "Unknown error"; | |
891 } | |
892 | |
893 #endif /* ! HAVE_STRERROR */ |