114524Ssam #ifndef lint 2*18662Sserge static char *sccsid = "@(#)cmd2.c 2.13 (Berkeley) 04/18/85"; 314524Ssam #endif 41224Skas 51224Skas #include "rcv.h" 61224Skas #include <sys/stat.h> 71224Skas 81224Skas /* 91224Skas * Mail -- a mail program 101224Skas * 111224Skas * More user commands. 121224Skas */ 131224Skas 141224Skas /* 151224Skas * If any arguments were given, go to the next applicable argument 161224Skas * following dot, otherwise, go to the next applicable message. 171224Skas * If given as first command with no arguments, print first message. 181224Skas */ 191224Skas 201224Skas next(msgvec) 211224Skas int *msgvec; 221224Skas { 231224Skas register struct message *mp; 241224Skas register int *ip, *ip2; 251224Skas int list[2], mdot; 261224Skas 271224Skas if (*msgvec != NULL) { 281224Skas 291224Skas /* 301224Skas * If some messages were supplied, find the 311224Skas * first applicable one following dot using 321224Skas * wrap around. 331224Skas */ 341224Skas 351224Skas mdot = dot - &message[0] + 1; 361470Skas 371470Skas /* 381470Skas * Find the first message in the supplied 391470Skas * message list which follows dot. 401470Skas */ 411470Skas 421224Skas for (ip = msgvec; *ip != NULL; ip++) 431224Skas if (*ip > mdot) 441224Skas break; 451224Skas if (*ip == NULL) 461224Skas ip = msgvec; 471224Skas ip2 = ip; 481224Skas do { 491224Skas mp = &message[*ip2 - 1]; 501224Skas if ((mp->m_flag & MDELETED) == 0) { 511224Skas dot = mp; 521224Skas goto hitit; 531224Skas } 541470Skas if (*ip2 != NULL) 551470Skas ip2++; 561470Skas if (*ip2 == NULL) 571470Skas ip2 = msgvec; 581224Skas } while (ip2 != ip); 591224Skas printf("No messages applicable\n"); 601224Skas return(1); 611224Skas } 621224Skas 631224Skas /* 641224Skas * If this is the first command, select message 1. 651224Skas * Note that this must exist for us to get here at all. 661224Skas */ 671224Skas 681481Skas if (!sawcom) 691224Skas goto hitit; 701224Skas 711224Skas /* 721224Skas * Just find the next good message after dot, no 731224Skas * wraparound. 741224Skas */ 751224Skas 761224Skas for (mp = dot+1; mp < &message[msgCount]; mp++) 771224Skas if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 781224Skas break; 791224Skas if (mp >= &message[msgCount]) { 801224Skas printf("At EOF\n"); 811224Skas return(0); 821224Skas } 831224Skas dot = mp; 841224Skas hitit: 851224Skas /* 861224Skas * Print dot. 871224Skas */ 881224Skas 891224Skas list[0] = dot - &message[0] + 1; 901224Skas list[1] = NULL; 911224Skas return(type(list)); 921224Skas } 931224Skas 941224Skas /* 955776Skurt * Save a message in a file. Mark the message as saved 965776Skurt * so we can discard when the user quits. 971224Skas */ 981224Skas save(str) 991224Skas char str[]; 1001224Skas { 1015776Skurt 1025776Skurt return(save1(str, 1)); 1035776Skurt } 1045776Skurt 1055776Skurt /* 1065776Skurt * Copy a message to a file without affected its saved-ness 1075776Skurt */ 1085776Skurt copycmd(str) 1095776Skurt char str[]; 1105776Skurt { 1115776Skurt 1125776Skurt return(save1(str, 0)); 1135776Skurt } 1145776Skurt 1155776Skurt /* 1165776Skurt * Save/copy the indicated messages at the end of the passed file name. 1175776Skurt * If mark is true, mark the message "saved." 1185776Skurt */ 1195776Skurt save1(str, mark) 1205776Skurt char str[]; 1215776Skurt { 1221224Skas register int *ip, mesg; 1231224Skas register struct message *mp; 1245776Skurt char *file, *disp, *cmd; 1258747Scarl int f, *msgvec, lc, t; 1268747Scarl long cc; 1271224Skas FILE *obuf; 1281224Skas struct stat statb; 1291224Skas 1305776Skurt cmd = mark ? "save" : "copy"; 1311224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 1321224Skas if ((file = snarf(str, &f)) == NOSTR) 1331224Skas return(1); 1341224Skas if (!f) { 1351224Skas *msgvec = first(0, MMNORM); 1361224Skas if (*msgvec == NULL) { 1375776Skurt printf("No messages to %s.\n", cmd); 1381224Skas return(1); 1391224Skas } 1401224Skas msgvec[1] = NULL; 1411224Skas } 1421224Skas if (f && getmsglist(str, msgvec, 0) < 0) 1431224Skas return(1); 1441224Skas if ((file = expand(file)) == NOSTR) 1451224Skas return(1); 1461224Skas printf("\"%s\" ", file); 14716859Sralph fflush(stdout); 1481224Skas if (stat(file, &statb) >= 0) 1491224Skas disp = "[Appended]"; 1501224Skas else 1511224Skas disp = "[New file]"; 1521224Skas if ((obuf = fopen(file, "a")) == NULL) { 1531224Skas perror(NOSTR); 1541224Skas return(1); 1551224Skas } 1568747Scarl cc = 0L; 1578747Scarl lc = 0; 1581224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 1591224Skas mesg = *ip; 1601224Skas touch(mesg); 1611224Skas mp = &message[mesg-1]; 1627573Skurt if ((t = send(mp, obuf, 0)) < 0) { 1631224Skas perror(file); 1641224Skas fclose(obuf); 1651224Skas return(1); 1661224Skas } 1671224Skas lc += t; 1688747Scarl cc += mp->m_size; 1695776Skurt if (mark) 1705776Skurt mp->m_flag |= MSAVED; 1711224Skas } 1721224Skas fflush(obuf); 1731224Skas if (ferror(obuf)) 1741224Skas perror(file); 1751224Skas fclose(obuf); 1768747Scarl printf("%s %d/%ld\n", disp, lc, cc); 1771224Skas return(0); 1781224Skas } 1791224Skas 1801224Skas /* 1811224Skas * Write the indicated messages at the end of the passed 1821224Skas * file name, minus header and trailing blank line. 1831224Skas */ 1841224Skas 1851224Skas swrite(str) 1861224Skas char str[]; 1871224Skas { 1881224Skas register int *ip, mesg; 1891224Skas register struct message *mp; 1901224Skas register char *file, *disp; 1911224Skas char linebuf[BUFSIZ]; 1921224Skas int f, *msgvec, lc, cc, t; 1931224Skas FILE *obuf, *mesf; 1941224Skas struct stat statb; 1951224Skas 1961224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 1971224Skas if ((file = snarf(str, &f)) == NOSTR) 1981224Skas return(1); 1991224Skas if ((file = expand(file)) == NOSTR) 2001224Skas return(1); 2011224Skas if (!f) { 2021224Skas *msgvec = first(0, MMNORM); 2031224Skas if (*msgvec == NULL) { 2041224Skas printf("No messages to write.\n"); 2051224Skas return(1); 2061224Skas } 2071224Skas msgvec[1] = NULL; 2081224Skas } 2091224Skas if (f && getmsglist(str, msgvec, 0) < 0) 2101224Skas return(1); 2111224Skas printf("\"%s\" ", file); 21216859Sralph fflush(stdout); 2131224Skas if (stat(file, &statb) >= 0) 2141224Skas disp = "[Appended]"; 2151224Skas else 2161224Skas disp = "[New file]"; 2171224Skas if ((obuf = fopen(file, "a")) == NULL) { 2181224Skas perror(NOSTR); 2191224Skas return(1); 2201224Skas } 2211224Skas cc = lc = 0; 2221224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 2231224Skas mesg = *ip; 2241224Skas touch(mesg); 2251224Skas mp = &message[mesg-1]; 2261224Skas mesf = setinput(mp); 2271224Skas t = mp->m_lines - 2; 2281224Skas readline(mesf, linebuf); 2291224Skas while (t-- > 0) { 2301224Skas fgets(linebuf, BUFSIZ, mesf); 2311224Skas fputs(linebuf, obuf); 2321224Skas cc += strlen(linebuf); 2331224Skas } 2341224Skas lc += mp->m_lines - 2; 2351224Skas mp->m_flag |= MSAVED; 2361224Skas } 2371224Skas fflush(obuf); 2381224Skas if (ferror(obuf)) 2391224Skas perror(file); 2401224Skas fclose(obuf); 2411224Skas printf("%s %d/%d\n", disp, lc, cc); 2421224Skas return(0); 2431224Skas } 2441224Skas 2451224Skas /* 2461224Skas * Snarf the file from the end of the command line and 2471224Skas * return a pointer to it. If there is no file attached, 2481224Skas * just return NOSTR. Put a null in front of the file 2491224Skas * name so that the message list processing won't see it, 2501224Skas * unless the file name is the only thing on the line, in 2511224Skas * which case, return 0 in the reference flag variable. 2521224Skas */ 2531224Skas 2541224Skas char * 2551224Skas snarf(linebuf, flag) 2561224Skas char linebuf[]; 2571224Skas int *flag; 2581224Skas { 2591224Skas register char *cp; 2601224Skas 2611224Skas *flag = 1; 2621224Skas cp = strlen(linebuf) + linebuf - 1; 2631224Skas 2641224Skas /* 2651224Skas * Strip away trailing blanks. 2661224Skas */ 2671224Skas 2681224Skas while (*cp == ' ' && cp > linebuf) 2691224Skas cp--; 2701224Skas *++cp = 0; 2711224Skas 2721224Skas /* 2731224Skas * Now search for the beginning of the file name. 2741224Skas */ 2751224Skas 2761224Skas while (cp > linebuf && !any(*cp, "\t ")) 2771224Skas cp--; 2781224Skas if (*cp == '\0') { 2791224Skas printf("No file specified.\n"); 2801224Skas return(NOSTR); 2811224Skas } 2821224Skas if (any(*cp, " \t")) 2831224Skas *cp++ = 0; 2841224Skas else 2851224Skas *flag = 0; 2861224Skas return(cp); 2871224Skas } 2881224Skas 2891224Skas /* 2901224Skas * Delete messages. 2911224Skas */ 2921224Skas 2931224Skas delete(msgvec) 2941224Skas int msgvec[]; 2951224Skas { 2961224Skas return(delm(msgvec)); 2971224Skas } 2981224Skas 2991224Skas /* 3001224Skas * Delete messages, then type the new dot. 3011224Skas */ 3021224Skas 3031224Skas deltype(msgvec) 3041224Skas int msgvec[]; 3051224Skas { 3061224Skas int list[2]; 3074493Skurt int lastdot; 3081224Skas 3094493Skurt lastdot = dot - &message[0] + 1; 3101224Skas if (delm(msgvec) >= 0) { 3111224Skas list[0] = dot - &message[0]; 3121224Skas list[0]++; 3134493Skurt if (list[0] > lastdot) { 3144493Skurt touch(list[0]); 3154493Skurt list[1] = NULL; 3164493Skurt return(type(list)); 3174493Skurt } 3184493Skurt printf("At EOF\n"); 3194493Skurt return(0); 3201224Skas } 3211224Skas else { 3221224Skas printf("No more messages\n"); 3231224Skas return(0); 3241224Skas } 3251224Skas } 3261224Skas 3271224Skas /* 3281224Skas * Delete the indicated messages. 3291224Skas * Set dot to some nice place afterwards. 3301224Skas * Internal interface. 3311224Skas */ 3321224Skas 3331224Skas delm(msgvec) 3341224Skas int *msgvec; 3351224Skas { 3361224Skas register struct message *mp; 3371224Skas register *ip, mesg; 3381224Skas int last; 3391224Skas 3401224Skas last = NULL; 3411224Skas for (ip = msgvec; *ip != NULL; ip++) { 3421224Skas mesg = *ip; 3431224Skas touch(mesg); 3441224Skas mp = &message[mesg-1]; 3453319Skas mp->m_flag |= MDELETED|MTOUCH; 3463319Skas mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 3471224Skas last = mesg; 3481224Skas } 3491224Skas if (last != NULL) { 3501224Skas dot = &message[last-1]; 3511224Skas last = first(0, MDELETED); 3521224Skas if (last != NULL) { 3531224Skas dot = &message[last-1]; 3541224Skas return(0); 3551224Skas } 3561224Skas else { 3571224Skas dot = &message[0]; 3581224Skas return(-1); 3591224Skas } 3601224Skas } 3611224Skas 3621224Skas /* 3631224Skas * Following can't happen -- it keeps lint happy 3641224Skas */ 3651224Skas 3661224Skas return(-1); 3671224Skas } 3681224Skas 3691224Skas /* 3701224Skas * Undelete the indicated messages. 3711224Skas */ 3721224Skas 3731224Skas undelete(msgvec) 3741224Skas int *msgvec; 3751224Skas { 3761224Skas register struct message *mp; 3771224Skas register *ip, mesg; 3781224Skas 3791224Skas for (ip = msgvec; ip-msgvec < msgCount; ip++) { 3801224Skas mesg = *ip; 3811224Skas if (mesg == 0) 3821224Skas return; 3831224Skas touch(mesg); 3841224Skas mp = &message[mesg-1]; 3851224Skas dot = mp; 3861224Skas mp->m_flag &= ~MDELETED; 3871224Skas } 3881224Skas } 3891224Skas 3901224Skas /* 3911224Skas * Interactively dump core on "core" 3921224Skas */ 3931224Skas 3941224Skas core() 3951224Skas { 3961224Skas register int pid; 3971224Skas int status; 3981224Skas 3991224Skas if ((pid = vfork()) == -1) { 4001224Skas perror("fork"); 4011224Skas return(1); 4021224Skas } 4031224Skas if (pid == 0) { 4047540Skurt sigchild(); 4051224Skas abort(); 4061224Skas _exit(1); 4071224Skas } 4081224Skas printf("Okie dokie"); 4091224Skas fflush(stdout); 4101224Skas while (wait(&status) != pid) 4111224Skas ; 4121224Skas if (status & 0200) 4131224Skas printf(" -- Core dumped\n"); 4141224Skas else 4151224Skas printf("\n"); 4161224Skas } 4174340Skurt 4184340Skurt /* 4194340Skurt * Clobber as many bytes of stack as the user requests. 4204340Skurt */ 4214340Skurt clobber(argv) 4224340Skurt char **argv; 4234340Skurt { 4244340Skurt register int times; 4254340Skurt 4264340Skurt if (argv[0] == 0) 4274340Skurt times = 1; 4284340Skurt else 4294340Skurt times = (atoi(argv[0]) + 511) / 512; 4307561Skurt clob1(times); 4314340Skurt } 4324340Skurt 4334340Skurt /* 4344340Skurt * Clobber the stack. 4354340Skurt */ 4367561Skurt clob1(n) 4374340Skurt { 4384340Skurt char buf[512]; 4394340Skurt register char *cp; 4404340Skurt 4414340Skurt if (n <= 0) 4424340Skurt return; 4434340Skurt for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 4444340Skurt ; 4457561Skurt clob1(n - 1); 4464340Skurt } 4477573Skurt 4487573Skurt /* 449*18662Sserge * Add the given header fields to the retained list. 450*18662Sserge * If no arguments, print the current list of retained fields. 451*18662Sserge */ 452*18662Sserge retfield(list) 453*18662Sserge char *list[]; 454*18662Sserge { 455*18662Sserge char field[BUFSIZ]; 456*18662Sserge register int h; 457*18662Sserge register struct ignore *igp; 458*18662Sserge char **ap; 459*18662Sserge 460*18662Sserge if (argcount(list) == 0) 461*18662Sserge return(retshow()); 462*18662Sserge for (ap = list; *ap != 0; ap++) { 463*18662Sserge istrcpy(field, *ap); 464*18662Sserge 465*18662Sserge if (member(field, retain)) 466*18662Sserge continue; 467*18662Sserge 468*18662Sserge h = hash(field); 469*18662Sserge igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 470*18662Sserge igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 471*18662Sserge strcpy(igp->i_field, field); 472*18662Sserge igp->i_link = retain[h]; 473*18662Sserge retain[h] = igp; 474*18662Sserge nretained++; 475*18662Sserge } 476*18662Sserge return(0); 477*18662Sserge } 478*18662Sserge 479*18662Sserge /* 480*18662Sserge * Print out all currently retained fields. 481*18662Sserge */ 482*18662Sserge retshow() 483*18662Sserge { 484*18662Sserge register int h, count; 485*18662Sserge struct ignore *igp; 486*18662Sserge char **ap, **ring; 487*18662Sserge int igcomp(); 488*18662Sserge 489*18662Sserge count = 0; 490*18662Sserge for (h = 0; h < HSHSIZE; h++) 491*18662Sserge for (igp = retain[h]; igp != 0; igp = igp->i_link) 492*18662Sserge count++; 493*18662Sserge if (count == 0) { 494*18662Sserge printf("No fields currently being retained.\n"); 495*18662Sserge return(0); 496*18662Sserge } 497*18662Sserge ring = (char **) salloc((count + 1) * sizeof (char *)); 498*18662Sserge ap = ring; 499*18662Sserge for (h = 0; h < HSHSIZE; h++) 500*18662Sserge for (igp = retain[h]; igp != 0; igp = igp->i_link) 501*18662Sserge *ap++ = igp->i_field; 502*18662Sserge *ap = 0; 503*18662Sserge qsort(ring, count, sizeof (char *), igcomp); 504*18662Sserge for (ap = ring; *ap != 0; ap++) 505*18662Sserge printf("%s\n", *ap); 506*18662Sserge return(0); 507*18662Sserge } 508*18662Sserge 509*18662Sserge /* 5107573Skurt * Add the given header fields to the ignored list. 5117573Skurt * If no arguments, print the current list of ignored fields. 5127573Skurt */ 5137573Skurt igfield(list) 5147573Skurt char *list[]; 5157573Skurt { 5167573Skurt char field[BUFSIZ]; 5177573Skurt register int h; 5187573Skurt register struct ignore *igp; 5197573Skurt char **ap; 5207573Skurt 5217573Skurt if (argcount(list) == 0) 5227573Skurt return(igshow()); 5237573Skurt for (ap = list; *ap != 0; ap++) { 5247582Skurt if (isign(*ap)) 5257582Skurt continue; 5267573Skurt istrcpy(field, *ap); 5277573Skurt h = hash(field); 5287573Skurt igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 5297573Skurt igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 5307573Skurt strcpy(igp->i_field, field); 5317573Skurt igp->i_link = ignore[h]; 5327573Skurt ignore[h] = igp; 5337573Skurt } 5347573Skurt return(0); 5357573Skurt } 5367573Skurt 5377573Skurt /* 5387573Skurt * Print out all currently ignored fields. 5397573Skurt */ 5407573Skurt igshow() 5417573Skurt { 5427582Skurt register int h, count; 5437573Skurt struct ignore *igp; 5447582Skurt char **ap, **ring; 5457582Skurt int igcomp(); 5467573Skurt 5477582Skurt count = 0; 5487573Skurt for (h = 0; h < HSHSIZE; h++) 5497582Skurt for (igp = ignore[h]; igp != 0; igp = igp->i_link) 5507582Skurt count++; 5517582Skurt if (count == 0) { 5527573Skurt printf("No fields currently being ignored.\n"); 5537582Skurt return(0); 5547582Skurt } 5557584Skurt ring = (char **) salloc((count + 1) * sizeof (char *)); 5567582Skurt ap = ring; 5577582Skurt for (h = 0; h < HSHSIZE; h++) 5587582Skurt for (igp = ignore[h]; igp != 0; igp = igp->i_link) 5597582Skurt *ap++ = igp->i_field; 5607582Skurt *ap = 0; 5617582Skurt qsort(ring, count, sizeof (char *), igcomp); 5627582Skurt for (ap = ring; *ap != 0; ap++) 5637582Skurt printf("%s\n", *ap); 5647573Skurt return(0); 5657573Skurt } 5667582Skurt 5677582Skurt /* 5687582Skurt * Compare two names for sorting ignored field list. 5697582Skurt */ 5707582Skurt igcomp(l, r) 5717582Skurt char **l, **r; 5727582Skurt { 5737582Skurt 5747582Skurt return(strcmp(*l, *r)); 5757582Skurt } 576