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