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.2 (Berkeley) 06/21/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 - 2; 234 readline(mesf, linebuf); 235 while (t-- > 0) { 236 fgets(linebuf, BUFSIZ, mesf); 237 fputs(linebuf, obuf); 238 cc += strlen(linebuf); 239 } 240 lc += mp->m_lines - 2; 241 mp->m_flag |= MSAVED; 242 } 243 fflush(obuf); 244 if (ferror(obuf)) 245 perror(file); 246 fclose(obuf); 247 printf("%s %d/%d\n", disp, lc, cc); 248 return(0); 249 } 250 251 /* 252 * Snarf the file from the end of the command line and 253 * return a pointer to it. If there is no file attached, 254 * just return NOSTR. Put a null in front of the file 255 * name so that the message list processing won't see it, 256 * unless the file name is the only thing on the line, in 257 * which case, return 0 in the reference flag variable. 258 */ 259 260 char * 261 snarf(linebuf, flag) 262 char linebuf[]; 263 int *flag; 264 { 265 register char *cp; 266 267 *flag = 1; 268 cp = strlen(linebuf) + linebuf - 1; 269 270 /* 271 * Strip away trailing blanks. 272 */ 273 274 while (*cp == ' ' && cp > linebuf) 275 cp--; 276 *++cp = 0; 277 278 /* 279 * Now search for the beginning of the file name. 280 */ 281 282 while (cp > linebuf && !any(*cp, "\t ")) 283 cp--; 284 if (*cp == '\0') { 285 printf("No file specified.\n"); 286 return(NOSTR); 287 } 288 if (any(*cp, " \t")) 289 *cp++ = 0; 290 else 291 *flag = 0; 292 return(cp); 293 } 294 295 /* 296 * Delete messages. 297 */ 298 299 delete(msgvec) 300 int msgvec[]; 301 { 302 return(delm(msgvec)); 303 } 304 305 /* 306 * Delete messages, then type the new dot. 307 */ 308 309 deltype(msgvec) 310 int msgvec[]; 311 { 312 int list[2]; 313 int lastdot; 314 315 lastdot = dot - &message[0] + 1; 316 if (delm(msgvec) >= 0) { 317 list[0] = dot - &message[0]; 318 list[0]++; 319 if (list[0] > lastdot) { 320 touch(list[0]); 321 list[1] = NULL; 322 return(type(list)); 323 } 324 printf("At EOF\n"); 325 return(0); 326 } 327 else { 328 printf("No more messages\n"); 329 return(0); 330 } 331 } 332 333 /* 334 * Delete the indicated messages. 335 * Set dot to some nice place afterwards. 336 * Internal interface. 337 */ 338 339 delm(msgvec) 340 int *msgvec; 341 { 342 register struct message *mp; 343 register *ip, mesg; 344 int last; 345 346 last = NULL; 347 for (ip = msgvec; *ip != NULL; ip++) { 348 mesg = *ip; 349 touch(mesg); 350 mp = &message[mesg-1]; 351 mp->m_flag |= MDELETED|MTOUCH; 352 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 353 last = mesg; 354 } 355 if (last != NULL) { 356 dot = &message[last-1]; 357 last = first(0, MDELETED); 358 if (last != NULL) { 359 dot = &message[last-1]; 360 return(0); 361 } 362 else { 363 dot = &message[0]; 364 return(-1); 365 } 366 } 367 368 /* 369 * Following can't happen -- it keeps lint happy 370 */ 371 372 return(-1); 373 } 374 375 /* 376 * Undelete the indicated messages. 377 */ 378 379 undelete(msgvec) 380 int *msgvec; 381 { 382 register struct message *mp; 383 register *ip, mesg; 384 385 for (ip = msgvec; ip-msgvec < msgCount; ip++) { 386 mesg = *ip; 387 if (mesg == 0) 388 return; 389 touch(mesg); 390 mp = &message[mesg-1]; 391 dot = mp; 392 mp->m_flag &= ~MDELETED; 393 } 394 } 395 396 /* 397 * Interactively dump core on "core" 398 */ 399 400 core() 401 { 402 register int pid; 403 int status; 404 405 if ((pid = vfork()) == -1) { 406 perror("fork"); 407 return(1); 408 } 409 if (pid == 0) { 410 sigchild(); 411 abort(); 412 _exit(1); 413 } 414 printf("Okie dokie"); 415 fflush(stdout); 416 while (wait(&status) != pid) 417 ; 418 if (status & 0200) 419 printf(" -- Core dumped\n"); 420 else 421 printf("\n"); 422 } 423 424 /* 425 * Clobber as many bytes of stack as the user requests. 426 */ 427 clobber(argv) 428 char **argv; 429 { 430 register int times; 431 432 if (argv[0] == 0) 433 times = 1; 434 else 435 times = (atoi(argv[0]) + 511) / 512; 436 clob1(times); 437 } 438 439 /* 440 * Clobber the stack. 441 */ 442 clob1(n) 443 { 444 char buf[512]; 445 register char *cp; 446 447 if (n <= 0) 448 return; 449 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 450 ; 451 clob1(n - 1); 452 } 453 454 /* 455 * Add the given header fields to the retained list. 456 * If no arguments, print the current list of retained fields. 457 */ 458 retfield(list) 459 char *list[]; 460 { 461 char field[BUFSIZ]; 462 register int h; 463 register struct ignore *igp; 464 char **ap; 465 466 if (argcount(list) == 0) 467 return(retshow()); 468 for (ap = list; *ap != 0; ap++) { 469 istrcpy(field, *ap); 470 471 if (member(field, retain)) 472 continue; 473 474 h = hash(field); 475 igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 476 igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 477 strcpy(igp->i_field, field); 478 igp->i_link = retain[h]; 479 retain[h] = igp; 480 nretained++; 481 } 482 return(0); 483 } 484 485 /* 486 * Print out all currently retained fields. 487 */ 488 retshow() 489 { 490 register int h, count; 491 struct ignore *igp; 492 char **ap, **ring; 493 int igcomp(); 494 495 count = 0; 496 for (h = 0; h < HSHSIZE; h++) 497 for (igp = retain[h]; igp != 0; igp = igp->i_link) 498 count++; 499 if (count == 0) { 500 printf("No fields currently being retained.\n"); 501 return(0); 502 } 503 ring = (char **) salloc((count + 1) * sizeof (char *)); 504 ap = ring; 505 for (h = 0; h < HSHSIZE; h++) 506 for (igp = retain[h]; igp != 0; igp = igp->i_link) 507 *ap++ = igp->i_field; 508 *ap = 0; 509 qsort(ring, count, sizeof (char *), igcomp); 510 for (ap = ring; *ap != 0; ap++) 511 printf("%s\n", *ap); 512 return(0); 513 } 514 515 /* 516 * Add the given header fields to the ignored list. 517 * If no arguments, print the current list of ignored fields. 518 */ 519 igfield(list) 520 char *list[]; 521 { 522 char field[BUFSIZ]; 523 register int h; 524 register struct ignore *igp; 525 char **ap; 526 527 if (argcount(list) == 0) 528 return(igshow()); 529 for (ap = list; *ap != 0; ap++) { 530 if (isign(*ap)) 531 continue; 532 istrcpy(field, *ap); 533 h = hash(field); 534 igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 535 igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 536 strcpy(igp->i_field, field); 537 igp->i_link = ignore[h]; 538 ignore[h] = igp; 539 } 540 return(0); 541 } 542 543 /* 544 * Print out all currently ignored fields. 545 */ 546 igshow() 547 { 548 register int h, count; 549 struct ignore *igp; 550 char **ap, **ring; 551 int igcomp(); 552 553 count = 0; 554 for (h = 0; h < HSHSIZE; h++) 555 for (igp = ignore[h]; igp != 0; igp = igp->i_link) 556 count++; 557 if (count == 0) { 558 printf("No fields currently being ignored.\n"); 559 return(0); 560 } 561 ring = (char **) salloc((count + 1) * sizeof (char *)); 562 ap = ring; 563 for (h = 0; h < HSHSIZE; h++) 564 for (igp = ignore[h]; igp != 0; igp = igp->i_link) 565 *ap++ = igp->i_field; 566 *ap = 0; 567 qsort(ring, count, sizeof (char *), igcomp); 568 for (ap = ring; *ap != 0; ap++) 569 printf("%s\n", *ap); 570 return(0); 571 } 572 573 /* 574 * Compare two names for sorting ignored field list. 575 */ 576 igcomp(l, r) 577 char **l, **r; 578 { 579 580 return(strcmp(*l, *r)); 581 } 582