1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char *sccsid = "@(#)cmd2.c 5.3 (Berkeley) 09/10/85"; 9 #endif not lint 10 11 #include "rcv.h" 12 #include <sys/stat.h> 13 14 /* 15 * Mail -- a mail program 16 * 17 * More user commands. 18 */ 19 20 /* 21 * If any arguments were given, go to the next applicable argument 22 * following dot, otherwise, go to the next applicable message. 23 * If given as first command with no arguments, print first message. 24 */ 25 26 next(msgvec) 27 int *msgvec; 28 { 29 register struct message *mp; 30 register int *ip, *ip2; 31 int list[2], mdot; 32 33 if (*msgvec != NULL) { 34 35 /* 36 * If some messages were supplied, find the 37 * first applicable one following dot using 38 * wrap around. 39 */ 40 41 mdot = dot - &message[0] + 1; 42 43 /* 44 * Find the first message in the supplied 45 * message list which follows dot. 46 */ 47 48 for (ip = msgvec; *ip != NULL; ip++) 49 if (*ip > mdot) 50 break; 51 if (*ip == NULL) 52 ip = msgvec; 53 ip2 = ip; 54 do { 55 mp = &message[*ip2 - 1]; 56 if ((mp->m_flag & MDELETED) == 0) { 57 dot = mp; 58 goto hitit; 59 } 60 if (*ip2 != NULL) 61 ip2++; 62 if (*ip2 == NULL) 63 ip2 = msgvec; 64 } while (ip2 != ip); 65 printf("No messages applicable\n"); 66 return(1); 67 } 68 69 /* 70 * If this is the first command, select message 1. 71 * Note that this must exist for us to get here at all. 72 */ 73 74 if (!sawcom) 75 goto hitit; 76 77 /* 78 * Just find the next good message after dot, no 79 * wraparound. 80 */ 81 82 for (mp = dot+1; mp < &message[msgCount]; mp++) 83 if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 84 break; 85 if (mp >= &message[msgCount]) { 86 printf("At EOF\n"); 87 return(0); 88 } 89 dot = mp; 90 hitit: 91 /* 92 * Print dot. 93 */ 94 95 list[0] = dot - &message[0] + 1; 96 list[1] = NULL; 97 return(type(list)); 98 } 99 100 /* 101 * Save a message in a file. Mark the message as saved 102 * so we can discard when the user quits. 103 */ 104 save(str) 105 char str[]; 106 { 107 108 return(save1(str, 1)); 109 } 110 111 /* 112 * Copy a message to a file without affected its saved-ness 113 */ 114 copycmd(str) 115 char str[]; 116 { 117 118 return(save1(str, 0)); 119 } 120 121 /* 122 * Save/copy the indicated messages at the end of the passed file name. 123 * If mark is true, mark the message "saved." 124 */ 125 save1(str, mark) 126 char str[]; 127 { 128 register int *ip, mesg; 129 register struct message *mp; 130 char *file, *disp, *cmd; 131 int f, *msgvec, lc, t; 132 long cc; 133 FILE *obuf; 134 struct stat statb; 135 136 cmd = mark ? "save" : "copy"; 137 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 138 if ((file = snarf(str, &f)) == NOSTR) 139 return(1); 140 if (!f) { 141 *msgvec = first(0, MMNORM); 142 if (*msgvec == NULL) { 143 printf("No messages to %s.\n", cmd); 144 return(1); 145 } 146 msgvec[1] = NULL; 147 } 148 if (f && getmsglist(str, msgvec, 0) < 0) 149 return(1); 150 if ((file = expand(file)) == NOSTR) 151 return(1); 152 printf("\"%s\" ", file); 153 fflush(stdout); 154 if (stat(file, &statb) >= 0) 155 disp = "[Appended]"; 156 else 157 disp = "[New file]"; 158 if ((obuf = fopen(file, "a")) == NULL) { 159 perror(NOSTR); 160 return(1); 161 } 162 cc = 0L; 163 lc = 0; 164 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 165 mesg = *ip; 166 touch(mesg); 167 mp = &message[mesg-1]; 168 if ((t = send(mp, obuf, 0)) < 0) { 169 perror(file); 170 fclose(obuf); 171 return(1); 172 } 173 lc += t; 174 cc += mp->m_size; 175 if (mark) 176 mp->m_flag |= MSAVED; 177 } 178 fflush(obuf); 179 if (ferror(obuf)) 180 perror(file); 181 fclose(obuf); 182 printf("%s %d/%ld\n", disp, lc, cc); 183 return(0); 184 } 185 186 /* 187 * Write the indicated messages at the end of the passed 188 * file name, minus header and trailing blank line. 189 */ 190 191 swrite(str) 192 char str[]; 193 { 194 register int *ip, mesg; 195 register struct message *mp; 196 register char *file, *disp; 197 char linebuf[BUFSIZ]; 198 int f, *msgvec, lc, cc, t; 199 FILE *obuf, *mesf; 200 struct stat statb; 201 202 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 203 if ((file = snarf(str, &f)) == NOSTR) 204 return(1); 205 if ((file = expand(file)) == NOSTR) 206 return(1); 207 if (!f) { 208 *msgvec = first(0, MMNORM); 209 if (*msgvec == NULL) { 210 printf("No messages to write.\n"); 211 return(1); 212 } 213 msgvec[1] = NULL; 214 } 215 if (f && getmsglist(str, msgvec, 0) < 0) 216 return(1); 217 printf("\"%s\" ", file); 218 fflush(stdout); 219 if (stat(file, &statb) >= 0) 220 disp = "[Appended]"; 221 else 222 disp = "[New file]"; 223 if ((obuf = fopen(file, "a")) == NULL) { 224 perror(NOSTR); 225 return(1); 226 } 227 cc = lc = 0; 228 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 229 mesg = *ip; 230 touch(mesg); 231 mp = &message[mesg-1]; 232 mesf = setinput(mp); 233 t = mp->m_lines - 1; 234 while (t-- > 0) { 235 readline(mesf, linebuf); 236 if (blankline(linebuf)) 237 break; 238 } 239 while (t-- > 0) { 240 fgets(linebuf, BUFSIZ, mesf); 241 fputs(linebuf, obuf); 242 cc += strlen(linebuf); 243 } 244 lc += mp->m_lines - 2; 245 mp->m_flag |= MSAVED; 246 } 247 fflush(obuf); 248 if (ferror(obuf)) 249 perror(file); 250 fclose(obuf); 251 printf("%s %d/%d\n", disp, lc, cc); 252 return(0); 253 } 254 255 /* 256 * Snarf the file from the end of the command line and 257 * return a pointer to it. If there is no file attached, 258 * just return NOSTR. Put a null in front of the file 259 * name so that the message list processing won't see it, 260 * unless the file name is the only thing on the line, in 261 * which case, return 0 in the reference flag variable. 262 */ 263 264 char * 265 snarf(linebuf, flag) 266 char linebuf[]; 267 int *flag; 268 { 269 register char *cp; 270 271 *flag = 1; 272 cp = strlen(linebuf) + linebuf - 1; 273 274 /* 275 * Strip away trailing blanks. 276 */ 277 278 while (*cp == ' ' && cp > linebuf) 279 cp--; 280 *++cp = 0; 281 282 /* 283 * Now search for the beginning of the file name. 284 */ 285 286 while (cp > linebuf && !any(*cp, "\t ")) 287 cp--; 288 if (*cp == '\0') { 289 printf("No file specified.\n"); 290 return(NOSTR); 291 } 292 if (any(*cp, " \t")) 293 *cp++ = 0; 294 else 295 *flag = 0; 296 return(cp); 297 } 298 299 /* 300 * Delete messages. 301 */ 302 303 delete(msgvec) 304 int msgvec[]; 305 { 306 return(delm(msgvec)); 307 } 308 309 /* 310 * Delete messages, then type the new dot. 311 */ 312 313 deltype(msgvec) 314 int msgvec[]; 315 { 316 int list[2]; 317 int lastdot; 318 319 lastdot = dot - &message[0] + 1; 320 if (delm(msgvec) >= 0) { 321 list[0] = dot - &message[0]; 322 list[0]++; 323 if (list[0] > lastdot) { 324 touch(list[0]); 325 list[1] = NULL; 326 return(type(list)); 327 } 328 printf("At EOF\n"); 329 return(0); 330 } 331 else { 332 printf("No more messages\n"); 333 return(0); 334 } 335 } 336 337 /* 338 * Delete the indicated messages. 339 * Set dot to some nice place afterwards. 340 * Internal interface. 341 */ 342 343 delm(msgvec) 344 int *msgvec; 345 { 346 register struct message *mp; 347 register *ip, mesg; 348 int last; 349 350 last = NULL; 351 for (ip = msgvec; *ip != NULL; ip++) { 352 mesg = *ip; 353 touch(mesg); 354 mp = &message[mesg-1]; 355 mp->m_flag |= MDELETED|MTOUCH; 356 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 357 last = mesg; 358 } 359 if (last != NULL) { 360 dot = &message[last-1]; 361 last = first(0, MDELETED); 362 if (last != NULL) { 363 dot = &message[last-1]; 364 return(0); 365 } 366 else { 367 dot = &message[0]; 368 return(-1); 369 } 370 } 371 372 /* 373 * Following can't happen -- it keeps lint happy 374 */ 375 376 return(-1); 377 } 378 379 /* 380 * Undelete the indicated messages. 381 */ 382 383 undelete(msgvec) 384 int *msgvec; 385 { 386 register struct message *mp; 387 register *ip, mesg; 388 389 for (ip = msgvec; ip-msgvec < msgCount; ip++) { 390 mesg = *ip; 391 if (mesg == 0) 392 return; 393 touch(mesg); 394 mp = &message[mesg-1]; 395 dot = mp; 396 mp->m_flag &= ~MDELETED; 397 } 398 } 399 400 /* 401 * Interactively dump core on "core" 402 */ 403 404 core() 405 { 406 register int pid; 407 int status; 408 409 if ((pid = vfork()) == -1) { 410 perror("fork"); 411 return(1); 412 } 413 if (pid == 0) { 414 sigchild(); 415 abort(); 416 _exit(1); 417 } 418 printf("Okie dokie"); 419 fflush(stdout); 420 while (wait(&status) != pid) 421 ; 422 if (status & 0200) 423 printf(" -- Core dumped\n"); 424 else 425 printf("\n"); 426 } 427 428 /* 429 * Clobber as many bytes of stack as the user requests. 430 */ 431 clobber(argv) 432 char **argv; 433 { 434 register int times; 435 436 if (argv[0] == 0) 437 times = 1; 438 else 439 times = (atoi(argv[0]) + 511) / 512; 440 clob1(times); 441 } 442 443 /* 444 * Clobber the stack. 445 */ 446 clob1(n) 447 { 448 char buf[512]; 449 register char *cp; 450 451 if (n <= 0) 452 return; 453 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 454 ; 455 clob1(n - 1); 456 } 457 458 /* 459 * Add the given header fields to the retained list. 460 * If no arguments, print the current list of retained fields. 461 */ 462 retfield(list) 463 char *list[]; 464 { 465 char field[BUFSIZ]; 466 register int h; 467 register struct ignore *igp; 468 char **ap; 469 470 if (argcount(list) == 0) 471 return(retshow()); 472 for (ap = list; *ap != 0; ap++) { 473 istrcpy(field, *ap); 474 475 if (member(field, retain)) 476 continue; 477 478 h = hash(field); 479 igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 480 igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 481 strcpy(igp->i_field, field); 482 igp->i_link = retain[h]; 483 retain[h] = igp; 484 nretained++; 485 } 486 return(0); 487 } 488 489 /* 490 * Print out all currently retained fields. 491 */ 492 retshow() 493 { 494 register int h, count; 495 struct ignore *igp; 496 char **ap, **ring; 497 int igcomp(); 498 499 count = 0; 500 for (h = 0; h < HSHSIZE; h++) 501 for (igp = retain[h]; igp != 0; igp = igp->i_link) 502 count++; 503 if (count == 0) { 504 printf("No fields currently being retained.\n"); 505 return(0); 506 } 507 ring = (char **) salloc((count + 1) * sizeof (char *)); 508 ap = ring; 509 for (h = 0; h < HSHSIZE; h++) 510 for (igp = retain[h]; igp != 0; igp = igp->i_link) 511 *ap++ = igp->i_field; 512 *ap = 0; 513 qsort(ring, count, sizeof (char *), igcomp); 514 for (ap = ring; *ap != 0; ap++) 515 printf("%s\n", *ap); 516 return(0); 517 } 518 519 /* 520 * Add the given header fields to the ignored list. 521 * If no arguments, print the current list of ignored fields. 522 */ 523 igfield(list) 524 char *list[]; 525 { 526 char field[BUFSIZ]; 527 register int h; 528 register struct ignore *igp; 529 char **ap; 530 531 if (argcount(list) == 0) 532 return(igshow()); 533 for (ap = list; *ap != 0; ap++) { 534 if (isign(*ap)) 535 continue; 536 istrcpy(field, *ap); 537 h = hash(field); 538 igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 539 igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 540 strcpy(igp->i_field, field); 541 igp->i_link = ignore[h]; 542 ignore[h] = igp; 543 } 544 return(0); 545 } 546 547 /* 548 * Print out all currently ignored fields. 549 */ 550 igshow() 551 { 552 register int h, count; 553 struct ignore *igp; 554 char **ap, **ring; 555 int igcomp(); 556 557 count = 0; 558 for (h = 0; h < HSHSIZE; h++) 559 for (igp = ignore[h]; igp != 0; igp = igp->i_link) 560 count++; 561 if (count == 0) { 562 printf("No fields currently being ignored.\n"); 563 return(0); 564 } 565 ring = (char **) salloc((count + 1) * sizeof (char *)); 566 ap = ring; 567 for (h = 0; h < HSHSIZE; h++) 568 for (igp = ignore[h]; igp != 0; igp = igp->i_link) 569 *ap++ = igp->i_field; 570 *ap = 0; 571 qsort(ring, count, sizeof (char *), igcomp); 572 for (ap = ring; *ap != 0; ap++) 573 printf("%s\n", *ap); 574 return(0); 575 } 576 577 /* 578 * Compare two names for sorting ignored field list. 579 */ 580 igcomp(l, r) 581 char **l, **r; 582 { 583 584 return(strcmp(*l, *r)); 585 } 586