Mercurial > hg > xemacs-beta
annotate lib-src/movemail.c @ 5765:e88d026f3917
Include uname and configure arguments in stdout.
| author | Stephen J. Turnbull <stephen@xemacs.org> |
|---|---|
| date | Sun, 15 Sep 2013 23:50:20 +0900 |
| 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 */ |
