|
|
1.1 ! root 1: /* movemail foo bar -- move file foo to file bar, ! 2: locking file foo the way /bin/mail respects. ! 3: Copyright (C) 1986 Free Software Foundation, Inc. ! 4: ! 5: This file is part of GNU Emacs. ! 6: ! 7: GNU Emacs is distributed in the hope that it will be useful, ! 8: but without any warranty. No author or distributor ! 9: accepts responsibility to anyone for the consequences of using it ! 10: or for whether it serves any particular purpose or works at all, ! 11: unless he says so in writing. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: document "GNU Emacs copying permission notice". An exact copy ! 16: of the document is supposed to have been given to you along with ! 17: GNU Emacs so that you can know how you may redistribute it all. ! 18: It should be in a file named COPYING. Among other things, the ! 19: copyright notice and this notice must be preserved on all copies. */ ! 20: ! 21: /* ! 22: * Modified January, 1986 by Michael R. Gretzinger (Project Athena) ! 23: * ! 24: * Added POP (Post Office Protocol) service. When compiled -DPOP ! 25: * movemail will accept input filename arguments of the form ! 26: * "po:username". This will cause movemail to open a connection to ! 27: * a pop server running on $MAILHOST (environment variable). Movemail ! 28: * must be setuid to root in order to work with POP. ! 29: * ! 30: * New module: popmail.c ! 31: * Modified routines: ! 32: * main - added code within #ifdef MAIL_USE_POP; added setuid(getuid()) ! 33: * after POP code. ! 34: * New routines in movemail.c: ! 35: * get_errmsg - return pointer to system error message ! 36: * ! 37: */ ! 38: ! 39: #include <sys/types.h> ! 40: #include <sys/stat.h> ! 41: #include <sys/file.h> ! 42: #include <errno.h> ! 43: #define NO_SHORTNAMES /* Tell config not to load remap.h */ ! 44: #include "../src/config.h" ! 45: ! 46: #ifdef USG ! 47: #include <fcntl.h> ! 48: #include <unistd.h> ! 49: #ifndef F_OK ! 50: #define F_OK 0 ! 51: #define X_OK 1 ! 52: #define W_OK 2 ! 53: #define R_OK 4 ! 54: #endif ! 55: #endif /* USG */ ! 56: ! 57: #ifdef XENIX ! 58: #include <sys/locking.h> ! 59: #endif ! 60: ! 61: /* Cancel substitutions made by config.h for Emacs. */ ! 62: #undef open ! 63: #undef read ! 64: #undef write ! 65: #undef close ! 66: ! 67: char *concat (); ! 68: extern int errno; ! 69: ! 70: /* Nonzero means this is name of a lock file to delete on fatal error. */ ! 71: char *delete_lockname; ! 72: ! 73: main (argc, argv) ! 74: int argc; ! 75: char **argv; ! 76: { ! 77: char *inname, *outname; ! 78: int indesc, outdesc; ! 79: char buf[1024]; ! 80: int nread; ! 81: ! 82: #ifndef MAIL_USE_FLOCK ! 83: struct stat st; ! 84: long now; ! 85: int tem; ! 86: char *lockname, *p; ! 87: char tempname[40]; ! 88: int desc; ! 89: #endif /* not MAIL_USE_FLOCK */ ! 90: ! 91: delete_lockname = 0; ! 92: ! 93: if (argc < 3) ! 94: fatal ("two arguments required"); ! 95: ! 96: inname = argv[1]; ! 97: outname = argv[2]; ! 98: ! 99: /* Check access to input and output file. */ ! 100: if (access (inname, R_OK | W_OK) != 0) ! 101: pfatal_with_name (inname); ! 102: if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) ! 103: pfatal_with_name (outname); ! 104: ! 105: /* Also check that outname's directory is writeable to the real uid. */ ! 106: { ! 107: char *buf = (char *) malloc (strlen (outname) + 1); ! 108: char *p, q; ! 109: strcpy (buf, outname); ! 110: p = buf + strlen (buf); ! 111: while (p > buf && p[-1] != '/') ! 112: *--p = 0; ! 113: if (p == buf) ! 114: *p++ = '.'; ! 115: if (access (buf, W_OK) != 0) ! 116: pfatal_with_name (buf); ! 117: free (buf); ! 118: } ! 119: ! 120: #ifdef MAIL_USE_POP ! 121: if (!bcmp (inname, "po:", 3)) ! 122: { ! 123: int status; char *user; ! 124: ! 125: user = (char *) rindex (inname, ':') + 1; ! 126: status = popmail (user, outname); ! 127: exit (status); ! 128: } ! 129: ! 130: setuid (getuid()); ! 131: #endif /* MAIL_USE_POP */ ! 132: ! 133: #ifndef MAIL_USE_FLOCK ! 134: /* Use a lock file named /usr/spool/mail/$USER.lock: ! 135: If it exists, the mail file is locked. */ ! 136: lockname = concat (inname, ".lock", ""); ! 137: strcpy (tempname, inname); ! 138: p = tempname + strlen (tempname); ! 139: while (p != tempname && p[-1] != '/') ! 140: p--; ! 141: *p = 0; ! 142: strcpy (p, "EXXXXXX"); ! 143: mktemp (tempname); ! 144: (void) unlink (tempname); ! 145: ! 146: while (1) ! 147: { ! 148: /* Create the lock file, but not under the lock file name. */ ! 149: /* Give up if cannot do that. */ ! 150: desc = open (tempname, O_WRONLY | O_CREAT, 0666); ! 151: if (desc < 0) ! 152: pfatal_with_name (concat ("temporary file \"", tempname, "\"")); ! 153: close (desc); ! 154: ! 155: tem = link (tempname, lockname); ! 156: (void) unlink (tempname); ! 157: if (tem >= 0) ! 158: break; ! 159: sleep (1); ! 160: ! 161: /* If lock file is a minute old, unlock it. */ ! 162: if (stat (lockname, &st) >= 0) ! 163: { ! 164: now = time (0); ! 165: if (st.st_ctime < now - 60) ! 166: (void) unlink (lockname); ! 167: } ! 168: } ! 169: ! 170: delete_lockname = lockname; ! 171: #endif /* not MAIL_USE_FLOCK */ ! 172: ! 173: #ifdef MAIL_USE_FLOCK ! 174: indesc = open (inname, O_RDWR); ! 175: #else /* if not MAIL_USE_FLOCK */ ! 176: indesc = open (inname, O_RDONLY); ! 177: #endif /* not MAIL_USE_FLOCK */ ! 178: if (indesc < 0) ! 179: pfatal_with_name (inname); ! 180: ! 181: #if defined(BSD) || defined(XENIX) ! 182: /* In case movemail is setuid to root, make sure the user can ! 183: read the output file. */ ! 184: /* This is desirable for all systems ! 185: but I don't want to assume all have the umask system call */ ! 186: umask (umask (0) & 0333); ! 187: #endif /* BSD or Xenix */ ! 188: outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); ! 189: if (outdesc < 0) ! 190: pfatal_with_name (outname); ! 191: #ifdef MAIL_USE_FLOCK ! 192: #ifdef XENIX ! 193: if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); ! 194: #else ! 195: flock (indesc, LOCK_EX); ! 196: #endif ! 197: #endif /* MAIL_USE_FLOCK */ ! 198: ! 199: while (1) ! 200: { ! 201: nread = read (indesc, buf, sizeof buf); ! 202: if (nread != write (outdesc, buf, nread)) ! 203: { ! 204: int saved_errno = errno; ! 205: (void) unlink (outname); ! 206: errno = saved_errno; ! 207: pfatal_with_name (outname); ! 208: } ! 209: if (nread < sizeof buf) ! 210: break; ! 211: } ! 212: ! 213: #ifdef BSD ! 214: fsync (outdesc); ! 215: #endif ! 216: ! 217: /* Check to make sure no errors before we zap the inbox. */ ! 218: if (close (outdesc) != 0) ! 219: { ! 220: int saved_errno = errno; ! 221: (void) unlink (outname); ! 222: errno = saved_errno; ! 223: pfatal_with_name (outname); ! 224: } ! 225: ! 226: #ifdef MAIL_USE_FLOCK ! 227: #if defined(STRIDE) || defined(XENIX) ! 228: /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ ! 229: (void) close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); ! 230: #else ! 231: (void) ftruncate (indesc, 0L); ! 232: #endif /* STRIDE or XENIX */ ! 233: #endif /* MAIL_USE_FLOCK */ ! 234: close (indesc); ! 235: ! 236: #ifndef MAIL_USE_FLOCK ! 237: /* Delete the input file; if we can't, at least get rid of its contents. */ ! 238: if (unlink (inname) < 0) ! 239: if (errno != ENOENT) ! 240: creat (inname, 0666); ! 241: (void) unlink (lockname); ! 242: #endif /* not MAIL_USE_FLOCK */ ! 243: exit (0); ! 244: } ! 245: ! 246: /* Print error message and exit. */ ! 247: ! 248: fatal (s1, s2) ! 249: char *s1, *s2; ! 250: { ! 251: if (delete_lockname) ! 252: unlink (delete_lockname); ! 253: error (s1, s2); ! 254: exit (1); ! 255: } ! 256: ! 257: /* Print error message. `s1' is printf control string, `s2' is arg for it. */ ! 258: ! 259: error (s1, s2) ! 260: char *s1, *s2; ! 261: { ! 262: printf ("movemail: "); ! 263: printf (s1, s2); ! 264: printf ("\n"); ! 265: } ! 266: ! 267: pfatal_with_name (name) ! 268: char *name; ! 269: { ! 270: extern int errno, sys_nerr; ! 271: extern char *sys_errlist[]; ! 272: char *s; ! 273: ! 274: if (errno < sys_nerr) ! 275: s = concat ("", sys_errlist[errno], " for %s"); ! 276: else ! 277: s = "cannot open %s"; ! 278: fatal (s, name); ! 279: } ! 280: ! 281: /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ ! 282: ! 283: char * ! 284: concat (s1, s2, s3) ! 285: char *s1, *s2, *s3; ! 286: { ! 287: int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); ! 288: char *result = (char *) xmalloc (len1 + len2 + len3 + 1); ! 289: ! 290: strcpy (result, s1); ! 291: strcpy (result + len1, s2); ! 292: strcpy (result + len1 + len2, s3); ! 293: *(result + len1 + len2 + len3) = 0; ! 294: ! 295: return result; ! 296: } ! 297: ! 298: /* Like malloc but get fatal error if memory is exhausted. */ ! 299: ! 300: int ! 301: xmalloc (size) ! 302: int size; ! 303: { ! 304: int result = malloc (size); ! 305: if (!result) ! 306: fatal ("virtual memory exhausted", 0); ! 307: return result; ! 308: } ! 309: ! 310: /* This is the guts of the interface to the Post Office Protocol. */ ! 311: ! 312: #ifdef MAIL_USE_POP ! 313: ! 314: #include <sys/socket.h> ! 315: #include <netinet/in.h> ! 316: #include <netdb.h> ! 317: #include <stdio.h> ! 318: ! 319: #ifdef USG ! 320: #include <fcntl.h> ! 321: /* Cancel substitutions made by config.h for Emacs. */ ! 322: #undef open ! 323: #undef read ! 324: #undef write ! 325: #undef close ! 326: #endif /* USG */ ! 327: ! 328: #define NOTOK (-1) ! 329: #define OK 0 ! 330: #define DONE 1 ! 331: ! 332: char *progname; ! 333: FILE *sfi; ! 334: FILE *sfo; ! 335: char Errmsg[80]; ! 336: ! 337: static int debug = 0; ! 338: ! 339: popmail(user, outfile) ! 340: char *user; ! 341: char *outfile; ! 342: { ! 343: char *host; ! 344: int nmsgs, nbytes; ! 345: char response[128]; ! 346: register int i; ! 347: int mbfi; ! 348: FILE *mbf; ! 349: char *getenv(); ! 350: int mbx_write(); ! 351: char *get_errmsg(); ! 352: ! 353: host = getenv("MAILHOST"); ! 354: if (host == NULL) { ! 355: fatal("no MAILHOST defined"); ! 356: } ! 357: ! 358: if (pop_init(host) == NOTOK) { ! 359: error(Errmsg); ! 360: return(1); ! 361: } ! 362: ! 363: if (getline(response, sizeof response, sfi) != OK) { ! 364: error(response); ! 365: return(1); ! 366: } ! 367: ! 368: if (pop_command("USER %s", user) == NOTOK || ! 369: pop_command("RPOP %s", user) == NOTOK) { ! 370: error(Errmsg); ! 371: pop_command("QUIT"); ! 372: return(1); ! 373: } ! 374: ! 375: if (pop_stat(&nmsgs, &nbytes) == NOTOK) { ! 376: error(Errmsg); ! 377: pop_command("QUIT"); ! 378: return(1); ! 379: } ! 380: ! 381: if (!nmsgs) ! 382: { ! 383: pop_command("QUIT"); ! 384: return(0); ! 385: } ! 386: ! 387: mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); ! 388: if (mbfi < 0) ! 389: { ! 390: pop_command("QUIT"); ! 391: error("Error in open: %s, %s", get_errmsg(), outfile); ! 392: return(1); ! 393: } ! 394: fchown(mbfi, getuid(), -1); ! 395: ! 396: if ((mbf = fdopen(mbfi, "w")) == NULL) ! 397: { ! 398: pop_command("QUIT"); ! 399: error("Error in fdopen: %s", get_errmsg()); ! 400: close(mbfi); ! 401: unlink(outfile); ! 402: return(1); ! 403: } ! 404: ! 405: for (i = 1; i <= nmsgs; i++) { ! 406: mbx_delimit_begin(mbf); ! 407: if (pop_retr(i, mbx_write, mbf) != OK) { ! 408: error(Errmsg); ! 409: pop_command("QUIT"); ! 410: close(mbfi); ! 411: return(1); ! 412: } ! 413: mbx_delimit_end(mbf); ! 414: fflush(mbf); ! 415: } ! 416: ! 417: for (i = 1; i <= nmsgs; i++) { ! 418: if (pop_command("DELE %d", i) == NOTOK) { ! 419: error(Errmsg); ! 420: pop_command("QUIT"); ! 421: close(mbfi); ! 422: return(1); ! 423: } ! 424: } ! 425: ! 426: pop_command("QUIT"); ! 427: close(mbfi); ! 428: return(0); ! 429: } ! 430: ! 431: pop_init(host) ! 432: char *host; ! 433: { ! 434: register struct hostent *hp; ! 435: register struct servent *sp; ! 436: int lport = IPPORT_RESERVED - 1; ! 437: struct sockaddr_in sin; ! 438: register int s; ! 439: char *get_errmsg(); ! 440: ! 441: hp = gethostbyname(host); ! 442: if (hp == NULL) { ! 443: sprintf(Errmsg, "MAILHOST unknown: %s", host); ! 444: return(NOTOK); ! 445: } ! 446: ! 447: sp = getservbyname("pop", "tcp"); ! 448: if (sp == 0) { ! 449: strcpy(Errmsg, "tcp/pop: unknown service"); ! 450: return(NOTOK); ! 451: } ! 452: ! 453: sin.sin_family = hp->h_addrtype; ! 454: bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); ! 455: sin.sin_port = sp->s_port; ! 456: s = rresvport(&lport); ! 457: if (s < 0) { ! 458: sprintf(Errmsg, "error creating socket: %s", get_errmsg()); ! 459: return(NOTOK); ! 460: } ! 461: ! 462: if (connect(s, (char *)&sin, sizeof sin) < 0) { ! 463: sprintf(Errmsg, "error during connect: %s", get_errmsg()); ! 464: close(s); ! 465: return(NOTOK); ! 466: } ! 467: ! 468: sfi = fdopen(s, "r"); ! 469: sfo = fdopen(s, "w"); ! 470: if (sfi == NULL || sfo == NULL) { ! 471: sprintf(Errmsg, "error in fdopen: %s", get_errmsg()); ! 472: close(s); ! 473: return(NOTOK); ! 474: } ! 475: ! 476: return(OK); ! 477: } ! 478: ! 479: pop_command(fmt, a, b, c, d) ! 480: char *fmt; ! 481: { ! 482: char buf[128]; ! 483: char errmsg[64]; ! 484: ! 485: sprintf(buf, fmt, a, b, c, d); ! 486: ! 487: if (debug) fprintf(stderr, "---> %s\n", buf); ! 488: if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK); ! 489: ! 490: if (getline(buf, sizeof buf, sfi) != OK) { ! 491: strcpy(Errmsg, buf); ! 492: return(NOTOK); ! 493: } ! 494: ! 495: if (debug) fprintf(stderr, "<--- %s\n", buf); ! 496: if (*buf != '+') { ! 497: strcpy(Errmsg, buf); ! 498: return(NOTOK); ! 499: } else { ! 500: return(OK); ! 501: } ! 502: } ! 503: ! 504: ! 505: pop_stat(nmsgs, nbytes) ! 506: int *nmsgs, *nbytes; ! 507: { ! 508: char buf[128]; ! 509: ! 510: if (debug) fprintf(stderr, "---> STAT\n"); ! 511: if (putline("STAT", Errmsg, sfo) == NOTOK) return(NOTOK); ! 512: ! 513: if (getline(buf, sizeof buf, sfi) != OK) { ! 514: strcpy(Errmsg, buf); ! 515: return(NOTOK); ! 516: } ! 517: ! 518: if (debug) fprintf(stderr, "<--- %s\n", buf); ! 519: if (*buf != '+') { ! 520: strcpy(Errmsg, buf); ! 521: return(NOTOK); ! 522: } else { ! 523: sscanf(buf, "+OK %d %d", nmsgs, nbytes); ! 524: return(OK); ! 525: } ! 526: } ! 527: ! 528: pop_retr(msgno, action, arg) ! 529: int (*action)(); ! 530: { ! 531: char buf[128]; ! 532: ! 533: sprintf(buf, "RETR %d", msgno); ! 534: if (debug) fprintf(stderr, "%s\n", buf); ! 535: if (putline(buf, Errmsg, sfo) == NOTOK) return(NOTOK); ! 536: ! 537: if (getline(buf, sizeof buf, sfi) != OK) { ! 538: strcpy(Errmsg, buf); ! 539: return(NOTOK); ! 540: } ! 541: ! 542: while (1) { ! 543: switch (multiline(buf, sizeof buf, sfi)) { ! 544: case OK: ! 545: (*action)(buf, arg); ! 546: break; ! 547: case DONE: ! 548: return (OK); ! 549: case NOTOK: ! 550: strcpy(Errmsg, buf); ! 551: return (NOTOK); ! 552: } ! 553: } ! 554: } ! 555: ! 556: getline(buf, n, f) ! 557: char *buf; ! 558: register int n; ! 559: FILE *f; ! 560: { ! 561: register char *p; ! 562: int c; ! 563: ! 564: p = buf; ! 565: while (--n > 0 && (c = fgetc(f)) != EOF) ! 566: if ((*p++ = c) == '\n') break; ! 567: ! 568: if (ferror(f)) { ! 569: strcpy(buf, "error on connection"); ! 570: return (NOTOK); ! 571: } ! 572: ! 573: if (c == EOF && p == buf) { ! 574: strcpy(buf, "connection closed by foreign host"); ! 575: return (DONE); ! 576: } ! 577: ! 578: *p = NULL; ! 579: if (*--p == '\n') *p = NULL; ! 580: if (*--p == '\r') *p = NULL; ! 581: return(OK); ! 582: } ! 583: ! 584: multiline(buf, n, f) ! 585: char *buf; ! 586: register int n; ! 587: FILE *f; ! 588: { ! 589: if (getline(buf, n, f) != OK) return (NOTOK); ! 590: if (*buf == '.') { ! 591: if (*(buf+1) == NULL) { ! 592: return (DONE); ! 593: } else { ! 594: strcpy(buf, buf+1); ! 595: } ! 596: } ! 597: return(OK); ! 598: } ! 599: ! 600: char * ! 601: get_errmsg() ! 602: { ! 603: extern int errno, sys_nerr; ! 604: extern char *sys_errlist[]; ! 605: char *s; ! 606: ! 607: if (errno < sys_nerr) ! 608: s = sys_errlist[errno]; ! 609: else ! 610: s = "unknown error"; ! 611: return(s); ! 612: } ! 613: ! 614: putline(buf, err, f) ! 615: char *buf; ! 616: char *err; ! 617: FILE *f; ! 618: { ! 619: fprintf(f, "%s\r\n", buf); ! 620: fflush(f); ! 621: if (ferror(f)) { ! 622: strcpy(err, "lost connection"); ! 623: return(NOTOK); ! 624: } ! 625: return(OK); ! 626: } ! 627: ! 628: mbx_write(line, mbf) ! 629: char *line; ! 630: FILE *mbf; ! 631: { ! 632: fputs(line, mbf); ! 633: fputc(0x0a, mbf); ! 634: } ! 635: ! 636: mbx_delimit_begin(mbf) ! 637: FILE *mbf; ! 638: { ! 639: fputs("\f\n0,unseen,,\n", mbf); ! 640: } ! 641: ! 642: mbx_delimit_end(mbf) ! 643: FILE *mbf; ! 644: { ! 645: putc('\037', mbf); ! 646: } ! 647: ! 648: #endif /* MAIL_USE_POP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.