122445Sdist /* 222445Sdist * Copyright (c) 1980 Regents of the University of California. 3*33499Sbostic * All rights reserved. 4*33499Sbostic * 5*33499Sbostic * Redistribution and use in source and binary forms are permitted 6*33499Sbostic * provided that this notice is preserved and that due credit is given 7*33499Sbostic * to the University of California at Berkeley. The name of the University 8*33499Sbostic * may not be used to endorse or promote products derived from this 9*33499Sbostic * software without specific prior written permission. This software 10*33499Sbostic * is provided ``as is'' without express or implied warranty. 1122445Sdist */ 1222445Sdist 13*33499Sbostic #ifdef notdef 14*33499Sbostic static char sccsid[] = "@(#)cmd2.c 5.5 (Berkeley) 02/18/88"; 15*33499Sbostic #endif /* notdef */ 161224Skas 171224Skas #include "rcv.h" 181224Skas #include <sys/stat.h> 1931142Sedward #include <sys/wait.h> 201224Skas 211224Skas /* 221224Skas * Mail -- a mail program 231224Skas * 241224Skas * More user commands. 251224Skas */ 261224Skas 271224Skas /* 281224Skas * If any arguments were given, go to the next applicable argument 291224Skas * following dot, otherwise, go to the next applicable message. 301224Skas * If given as first command with no arguments, print first message. 311224Skas */ 321224Skas 331224Skas next(msgvec) 341224Skas int *msgvec; 351224Skas { 361224Skas register struct message *mp; 371224Skas register int *ip, *ip2; 381224Skas int list[2], mdot; 391224Skas 401224Skas if (*msgvec != NULL) { 411224Skas 421224Skas /* 431224Skas * If some messages were supplied, find the 441224Skas * first applicable one following dot using 451224Skas * wrap around. 461224Skas */ 471224Skas 481224Skas mdot = dot - &message[0] + 1; 491470Skas 501470Skas /* 511470Skas * Find the first message in the supplied 521470Skas * message list which follows dot. 531470Skas */ 541470Skas 551224Skas for (ip = msgvec; *ip != NULL; ip++) 561224Skas if (*ip > mdot) 571224Skas break; 581224Skas if (*ip == NULL) 591224Skas ip = msgvec; 601224Skas ip2 = ip; 611224Skas do { 621224Skas mp = &message[*ip2 - 1]; 631224Skas if ((mp->m_flag & MDELETED) == 0) { 641224Skas dot = mp; 651224Skas goto hitit; 661224Skas } 671470Skas if (*ip2 != NULL) 681470Skas ip2++; 691470Skas if (*ip2 == NULL) 701470Skas ip2 = msgvec; 711224Skas } while (ip2 != ip); 721224Skas printf("No messages applicable\n"); 731224Skas return(1); 741224Skas } 751224Skas 761224Skas /* 771224Skas * If this is the first command, select message 1. 781224Skas * Note that this must exist for us to get here at all. 791224Skas */ 801224Skas 811481Skas if (!sawcom) 821224Skas goto hitit; 831224Skas 841224Skas /* 851224Skas * Just find the next good message after dot, no 861224Skas * wraparound. 871224Skas */ 881224Skas 891224Skas for (mp = dot+1; mp < &message[msgCount]; mp++) 901224Skas if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 911224Skas break; 921224Skas if (mp >= &message[msgCount]) { 931224Skas printf("At EOF\n"); 941224Skas return(0); 951224Skas } 961224Skas dot = mp; 971224Skas hitit: 981224Skas /* 991224Skas * Print dot. 1001224Skas */ 1011224Skas 1021224Skas list[0] = dot - &message[0] + 1; 1031224Skas list[1] = NULL; 1041224Skas return(type(list)); 1051224Skas } 1061224Skas 1071224Skas /* 1085776Skurt * Save a message in a file. Mark the message as saved 1095776Skurt * so we can discard when the user quits. 1101224Skas */ 1111224Skas save(str) 1121224Skas char str[]; 1131224Skas { 1145776Skurt 1155776Skurt return(save1(str, 1)); 1165776Skurt } 1175776Skurt 1185776Skurt /* 1195776Skurt * Copy a message to a file without affected its saved-ness 1205776Skurt */ 1215776Skurt copycmd(str) 1225776Skurt char str[]; 1235776Skurt { 1245776Skurt 1255776Skurt return(save1(str, 0)); 1265776Skurt } 1275776Skurt 1285776Skurt /* 1295776Skurt * Save/copy the indicated messages at the end of the passed file name. 1305776Skurt * If mark is true, mark the message "saved." 1315776Skurt */ 1325776Skurt save1(str, mark) 1335776Skurt char str[]; 1345776Skurt { 1351224Skas register int *ip, mesg; 1361224Skas register struct message *mp; 1375776Skurt char *file, *disp, *cmd; 1388747Scarl int f, *msgvec, lc, t; 1398747Scarl long cc; 1401224Skas FILE *obuf; 1411224Skas struct stat statb; 1421224Skas 1435776Skurt cmd = mark ? "save" : "copy"; 1441224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 1451224Skas if ((file = snarf(str, &f)) == NOSTR) 1461224Skas return(1); 1471224Skas if (!f) { 1481224Skas *msgvec = first(0, MMNORM); 1491224Skas if (*msgvec == NULL) { 1505776Skurt printf("No messages to %s.\n", cmd); 1511224Skas return(1); 1521224Skas } 1531224Skas msgvec[1] = NULL; 1541224Skas } 1551224Skas if (f && getmsglist(str, msgvec, 0) < 0) 1561224Skas return(1); 1571224Skas if ((file = expand(file)) == NOSTR) 1581224Skas return(1); 1591224Skas printf("\"%s\" ", file); 16016859Sralph fflush(stdout); 1611224Skas if (stat(file, &statb) >= 0) 1621224Skas disp = "[Appended]"; 1631224Skas else 1641224Skas disp = "[New file]"; 1651224Skas if ((obuf = fopen(file, "a")) == NULL) { 1661224Skas perror(NOSTR); 1671224Skas return(1); 1681224Skas } 1698747Scarl cc = 0L; 1708747Scarl lc = 0; 1711224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 1721224Skas mesg = *ip; 1731224Skas touch(mesg); 1741224Skas mp = &message[mesg-1]; 1757573Skurt if ((t = send(mp, obuf, 0)) < 0) { 1761224Skas perror(file); 1771224Skas fclose(obuf); 1781224Skas return(1); 1791224Skas } 1801224Skas lc += t; 1818747Scarl cc += mp->m_size; 1825776Skurt if (mark) 1835776Skurt mp->m_flag |= MSAVED; 1841224Skas } 1851224Skas fflush(obuf); 1861224Skas if (ferror(obuf)) 1871224Skas perror(file); 1881224Skas fclose(obuf); 1898747Scarl printf("%s %d/%ld\n", disp, lc, cc); 1901224Skas return(0); 1911224Skas } 1921224Skas 1931224Skas /* 1941224Skas * Write the indicated messages at the end of the passed 1951224Skas * file name, minus header and trailing blank line. 1961224Skas */ 1971224Skas 1981224Skas swrite(str) 1991224Skas char str[]; 2001224Skas { 2011224Skas register int *ip, mesg; 2021224Skas register struct message *mp; 2031224Skas register char *file, *disp; 2041224Skas char linebuf[BUFSIZ]; 2051224Skas int f, *msgvec, lc, cc, t; 2061224Skas FILE *obuf, *mesf; 2071224Skas struct stat statb; 2081224Skas 2091224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 2101224Skas if ((file = snarf(str, &f)) == NOSTR) 2111224Skas return(1); 2121224Skas if ((file = expand(file)) == NOSTR) 2131224Skas return(1); 2141224Skas if (!f) { 2151224Skas *msgvec = first(0, MMNORM); 2161224Skas if (*msgvec == NULL) { 2171224Skas printf("No messages to write.\n"); 2181224Skas return(1); 2191224Skas } 2201224Skas msgvec[1] = NULL; 2211224Skas } 2221224Skas if (f && getmsglist(str, msgvec, 0) < 0) 2231224Skas return(1); 2241224Skas printf("\"%s\" ", file); 22516859Sralph fflush(stdout); 2261224Skas if (stat(file, &statb) >= 0) 2271224Skas disp = "[Appended]"; 2281224Skas else 2291224Skas disp = "[New file]"; 2301224Skas if ((obuf = fopen(file, "a")) == NULL) { 2311224Skas perror(NOSTR); 2321224Skas return(1); 2331224Skas } 2341224Skas cc = lc = 0; 2351224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 2361224Skas mesg = *ip; 2371224Skas touch(mesg); 2381224Skas mp = &message[mesg-1]; 2391224Skas mesf = setinput(mp); 24024681Sserge t = mp->m_lines - 1; 2411224Skas while (t-- > 0) { 24224681Sserge readline(mesf, linebuf); 24324681Sserge if (blankline(linebuf)) 24424681Sserge break; 24524681Sserge } 24624681Sserge while (t-- > 0) { 2471224Skas fgets(linebuf, BUFSIZ, mesf); 2481224Skas fputs(linebuf, obuf); 2491224Skas cc += strlen(linebuf); 2501224Skas } 2511224Skas lc += mp->m_lines - 2; 2521224Skas mp->m_flag |= MSAVED; 2531224Skas } 2541224Skas fflush(obuf); 2551224Skas if (ferror(obuf)) 2561224Skas perror(file); 2571224Skas fclose(obuf); 2581224Skas printf("%s %d/%d\n", disp, lc, cc); 2591224Skas return(0); 2601224Skas } 2611224Skas 2621224Skas /* 2631224Skas * Snarf the file from the end of the command line and 2641224Skas * return a pointer to it. If there is no file attached, 2651224Skas * just return NOSTR. Put a null in front of the file 2661224Skas * name so that the message list processing won't see it, 2671224Skas * unless the file name is the only thing on the line, in 2681224Skas * which case, return 0 in the reference flag variable. 2691224Skas */ 2701224Skas 2711224Skas char * 2721224Skas snarf(linebuf, flag) 2731224Skas char linebuf[]; 2741224Skas int *flag; 2751224Skas { 2761224Skas register char *cp; 2771224Skas 2781224Skas *flag = 1; 2791224Skas cp = strlen(linebuf) + linebuf - 1; 2801224Skas 2811224Skas /* 2821224Skas * Strip away trailing blanks. 2831224Skas */ 2841224Skas 28531142Sedward while (cp > linebuf && isspace(*cp)) 2861224Skas cp--; 2871224Skas *++cp = 0; 2881224Skas 2891224Skas /* 2901224Skas * Now search for the beginning of the file name. 2911224Skas */ 2921224Skas 29331142Sedward while (cp > linebuf && !isspace(*cp)) 2941224Skas cp--; 2951224Skas if (*cp == '\0') { 2961224Skas printf("No file specified.\n"); 2971224Skas return(NOSTR); 2981224Skas } 29931142Sedward if (isspace(*cp)) 3001224Skas *cp++ = 0; 3011224Skas else 3021224Skas *flag = 0; 3031224Skas return(cp); 3041224Skas } 3051224Skas 3061224Skas /* 3071224Skas * Delete messages. 3081224Skas */ 3091224Skas 3101224Skas delete(msgvec) 3111224Skas int msgvec[]; 3121224Skas { 3131224Skas return(delm(msgvec)); 3141224Skas } 3151224Skas 3161224Skas /* 3171224Skas * Delete messages, then type the new dot. 3181224Skas */ 3191224Skas 3201224Skas deltype(msgvec) 3211224Skas int msgvec[]; 3221224Skas { 3231224Skas int list[2]; 3244493Skurt int lastdot; 3251224Skas 3264493Skurt lastdot = dot - &message[0] + 1; 3271224Skas if (delm(msgvec) >= 0) { 3281224Skas list[0] = dot - &message[0]; 3291224Skas list[0]++; 3304493Skurt if (list[0] > lastdot) { 3314493Skurt touch(list[0]); 3324493Skurt list[1] = NULL; 3334493Skurt return(type(list)); 3344493Skurt } 3354493Skurt printf("At EOF\n"); 3364493Skurt return(0); 3371224Skas } 3381224Skas else { 3391224Skas printf("No more messages\n"); 3401224Skas return(0); 3411224Skas } 3421224Skas } 3431224Skas 3441224Skas /* 3451224Skas * Delete the indicated messages. 3461224Skas * Set dot to some nice place afterwards. 3471224Skas * Internal interface. 3481224Skas */ 3491224Skas 3501224Skas delm(msgvec) 3511224Skas int *msgvec; 3521224Skas { 3531224Skas register struct message *mp; 3541224Skas register *ip, mesg; 3551224Skas int last; 3561224Skas 3571224Skas last = NULL; 3581224Skas for (ip = msgvec; *ip != NULL; ip++) { 3591224Skas mesg = *ip; 3601224Skas touch(mesg); 3611224Skas mp = &message[mesg-1]; 3623319Skas mp->m_flag |= MDELETED|MTOUCH; 3633319Skas mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 3641224Skas last = mesg; 3651224Skas } 3661224Skas if (last != NULL) { 3671224Skas dot = &message[last-1]; 3681224Skas last = first(0, MDELETED); 3691224Skas if (last != NULL) { 3701224Skas dot = &message[last-1]; 3711224Skas return(0); 3721224Skas } 3731224Skas else { 3741224Skas dot = &message[0]; 3751224Skas return(-1); 3761224Skas } 3771224Skas } 3781224Skas 3791224Skas /* 3801224Skas * Following can't happen -- it keeps lint happy 3811224Skas */ 3821224Skas 3831224Skas return(-1); 3841224Skas } 3851224Skas 3861224Skas /* 3871224Skas * Undelete the indicated messages. 3881224Skas */ 3891224Skas 3901224Skas undelete(msgvec) 3911224Skas int *msgvec; 3921224Skas { 3931224Skas register struct message *mp; 3941224Skas register *ip, mesg; 3951224Skas 3961224Skas for (ip = msgvec; ip-msgvec < msgCount; ip++) { 3971224Skas mesg = *ip; 3981224Skas if (mesg == 0) 3991224Skas return; 4001224Skas touch(mesg); 4011224Skas mp = &message[mesg-1]; 4021224Skas dot = mp; 4031224Skas mp->m_flag &= ~MDELETED; 4041224Skas } 4051224Skas } 4061224Skas 4071224Skas /* 4081224Skas * Interactively dump core on "core" 4091224Skas */ 4101224Skas 4111224Skas core() 4121224Skas { 4131224Skas register int pid; 41431142Sedward union wait status; 4151224Skas 4161224Skas if ((pid = vfork()) == -1) { 4171224Skas perror("fork"); 4181224Skas return(1); 4191224Skas } 4201224Skas if (pid == 0) { 4211224Skas abort(); 4221224Skas _exit(1); 4231224Skas } 4241224Skas printf("Okie dokie"); 4251224Skas fflush(stdout); 4261224Skas while (wait(&status) != pid) 4271224Skas ; 42831142Sedward if (status.w_coredump) 4291224Skas printf(" -- Core dumped\n"); 4301224Skas else 4311224Skas printf("\n"); 43231142Sedward return 0; 4331224Skas } 4344340Skurt 4354340Skurt /* 4364340Skurt * Clobber as many bytes of stack as the user requests. 4374340Skurt */ 4384340Skurt clobber(argv) 4394340Skurt char **argv; 4404340Skurt { 4414340Skurt register int times; 4424340Skurt 4434340Skurt if (argv[0] == 0) 4444340Skurt times = 1; 4454340Skurt else 4464340Skurt times = (atoi(argv[0]) + 511) / 512; 4477561Skurt clob1(times); 4484340Skurt } 4494340Skurt 4504340Skurt /* 4514340Skurt * Clobber the stack. 4524340Skurt */ 4537561Skurt clob1(n) 4544340Skurt { 4554340Skurt char buf[512]; 4564340Skurt register char *cp; 4574340Skurt 4584340Skurt if (n <= 0) 4594340Skurt return; 4604340Skurt for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 4614340Skurt ; 4627561Skurt clob1(n - 1); 4634340Skurt } 4647573Skurt 4657573Skurt /* 46618662Sserge * Add the given header fields to the retained list. 46718662Sserge * If no arguments, print the current list of retained fields. 46818662Sserge */ 46918662Sserge retfield(list) 47018662Sserge char *list[]; 47118662Sserge { 47218662Sserge char field[BUFSIZ]; 47318662Sserge register int h; 47418662Sserge register struct ignore *igp; 47518662Sserge char **ap; 47618662Sserge 47718662Sserge if (argcount(list) == 0) 47818662Sserge return(retshow()); 47918662Sserge for (ap = list; *ap != 0; ap++) { 48018662Sserge istrcpy(field, *ap); 48118662Sserge 48218662Sserge if (member(field, retain)) 48318662Sserge continue; 48418662Sserge 48518662Sserge h = hash(field); 48618662Sserge igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 48731142Sedward igp->i_field = calloc((unsigned) strlen(field) + 1, 48831142Sedward sizeof (char)); 48918662Sserge strcpy(igp->i_field, field); 49018662Sserge igp->i_link = retain[h]; 49118662Sserge retain[h] = igp; 49218662Sserge nretained++; 49318662Sserge } 49418662Sserge return(0); 49518662Sserge } 49618662Sserge 49718662Sserge /* 49818662Sserge * Print out all currently retained fields. 49918662Sserge */ 50018662Sserge retshow() 50118662Sserge { 50218662Sserge register int h, count; 50318662Sserge struct ignore *igp; 50418662Sserge char **ap, **ring; 50518662Sserge int igcomp(); 50618662Sserge 50718662Sserge count = 0; 50818662Sserge for (h = 0; h < HSHSIZE; h++) 50918662Sserge for (igp = retain[h]; igp != 0; igp = igp->i_link) 51018662Sserge count++; 51118662Sserge if (count == 0) { 51218662Sserge printf("No fields currently being retained.\n"); 51318662Sserge return(0); 51418662Sserge } 51518662Sserge ring = (char **) salloc((count + 1) * sizeof (char *)); 51618662Sserge ap = ring; 51718662Sserge for (h = 0; h < HSHSIZE; h++) 51818662Sserge for (igp = retain[h]; igp != 0; igp = igp->i_link) 51918662Sserge *ap++ = igp->i_field; 52018662Sserge *ap = 0; 52131142Sedward qsort((char *) ring, count, sizeof (char *), igcomp); 52218662Sserge for (ap = ring; *ap != 0; ap++) 52318662Sserge printf("%s\n", *ap); 52418662Sserge return(0); 52518662Sserge } 52618662Sserge 52718662Sserge /* 5287573Skurt * Add the given header fields to the ignored list. 5297573Skurt * If no arguments, print the current list of ignored fields. 5307573Skurt */ 5317573Skurt igfield(list) 5327573Skurt char *list[]; 5337573Skurt { 5347573Skurt char field[BUFSIZ]; 5357573Skurt register int h; 5367573Skurt register struct ignore *igp; 5377573Skurt char **ap; 5387573Skurt 5397573Skurt if (argcount(list) == 0) 5407573Skurt return(igshow()); 5417573Skurt for (ap = list; *ap != 0; ap++) { 5427582Skurt if (isign(*ap)) 5437582Skurt continue; 5447573Skurt istrcpy(field, *ap); 5457573Skurt h = hash(field); 5467573Skurt igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 54731142Sedward igp->i_field = calloc((unsigned) strlen(field) + 1, 54831142Sedward sizeof (char)); 5497573Skurt strcpy(igp->i_field, field); 5507573Skurt igp->i_link = ignore[h]; 5517573Skurt ignore[h] = igp; 5527573Skurt } 5537573Skurt return(0); 5547573Skurt } 5557573Skurt 5567573Skurt /* 5577573Skurt * Print out all currently ignored fields. 5587573Skurt */ 5597573Skurt igshow() 5607573Skurt { 5617582Skurt register int h, count; 5627573Skurt struct ignore *igp; 5637582Skurt char **ap, **ring; 5647582Skurt int igcomp(); 5657573Skurt 5667582Skurt count = 0; 5677573Skurt for (h = 0; h < HSHSIZE; h++) 5687582Skurt for (igp = ignore[h]; igp != 0; igp = igp->i_link) 5697582Skurt count++; 5707582Skurt if (count == 0) { 5717573Skurt printf("No fields currently being ignored.\n"); 5727582Skurt return(0); 5737582Skurt } 5747584Skurt ring = (char **) salloc((count + 1) * sizeof (char *)); 5757582Skurt ap = ring; 5767582Skurt for (h = 0; h < HSHSIZE; h++) 5777582Skurt for (igp = ignore[h]; igp != 0; igp = igp->i_link) 5787582Skurt *ap++ = igp->i_field; 5797582Skurt *ap = 0; 58031142Sedward qsort((char *) ring, count, sizeof (char *), igcomp); 5817582Skurt for (ap = ring; *ap != 0; ap++) 5827582Skurt printf("%s\n", *ap); 5837573Skurt return(0); 5847573Skurt } 5857582Skurt 5867582Skurt /* 5877582Skurt * Compare two names for sorting ignored field list. 5887582Skurt */ 5897582Skurt igcomp(l, r) 5907582Skurt char **l, **r; 5917582Skurt { 5927582Skurt 5937582Skurt return(strcmp(*l, *r)); 5947582Skurt } 595