Annotation of 43BSDReno/contrib/emacs-18.55/etc/movemail.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.