1 /* $OpenBSD: cmd2.c,v 1.2 1996/06/11 12:53:33 deraadt Exp $ */ 2 /* $NetBSD: cmd2.c,v 1.5 1996/06/08 19:48:13 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93"; 40 #else 41 static char rcsid[] = "$OpenBSD: cmd2.c,v 1.2 1996/06/11 12:53:33 deraadt Exp $"; 42 #endif 43 #endif /* not lint */ 44 45 #include "rcv.h" 46 #include <sys/wait.h> 47 #include "extern.h" 48 49 /* 50 * Mail -- a mail program 51 * 52 * More user commands. 53 */ 54 static int igcomp __P((const void *, const void *)); 55 56 /* 57 * If any arguments were given, go to the next applicable argument 58 * following dot, otherwise, go to the next applicable message. 59 * If given as first command with no arguments, print first message. 60 */ 61 int 62 next(v) 63 void *v; 64 { 65 int *msgvec = v; 66 register struct message *mp; 67 register int *ip, *ip2; 68 int list[2], mdot; 69 70 if (*msgvec != NULL) { 71 72 /* 73 * If some messages were supplied, find the 74 * first applicable one following dot using 75 * wrap around. 76 */ 77 78 mdot = dot - &message[0] + 1; 79 80 /* 81 * Find the first message in the supplied 82 * message list which follows dot. 83 */ 84 85 for (ip = msgvec; *ip != NULL; ip++) 86 if (*ip > mdot) 87 break; 88 if (*ip == NULL) 89 ip = msgvec; 90 ip2 = ip; 91 do { 92 mp = &message[*ip2 - 1]; 93 if ((mp->m_flag & MDELETED) == 0) { 94 dot = mp; 95 goto hitit; 96 } 97 if (*ip2 != NULL) 98 ip2++; 99 if (*ip2 == NULL) 100 ip2 = msgvec; 101 } while (ip2 != ip); 102 printf("No messages applicable\n"); 103 return(1); 104 } 105 106 /* 107 * If this is the first command, select message 1. 108 * Note that this must exist for us to get here at all. 109 */ 110 111 if (!sawcom) 112 goto hitit; 113 114 /* 115 * Just find the next good message after dot, no 116 * wraparound. 117 */ 118 119 for (mp = dot+1; mp < &message[msgCount]; mp++) 120 if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 121 break; 122 if (mp >= &message[msgCount]) { 123 printf("At EOF\n"); 124 return(0); 125 } 126 dot = mp; 127 hitit: 128 /* 129 * Print dot. 130 */ 131 132 list[0] = dot - &message[0] + 1; 133 list[1] = NULL; 134 return(type(list)); 135 } 136 137 /* 138 * Save a message in a file. Mark the message as saved 139 * so we can discard when the user quits. 140 */ 141 int 142 save(v) 143 void *v; 144 { 145 char *str = v; 146 147 return save1(str, 1, "save", saveignore); 148 } 149 150 /* 151 * Copy a message to a file without affected its saved-ness 152 */ 153 int 154 copycmd(v) 155 void *v; 156 { 157 char *str = v; 158 159 return save1(str, 0, "copy", saveignore); 160 } 161 162 /* 163 * Save/copy the indicated messages at the end of the passed file name. 164 * If mark is true, mark the message "saved." 165 */ 166 int 167 save1(str, mark, cmd, ignore) 168 char str[]; 169 int mark; 170 char *cmd; 171 struct ignoretab *ignore; 172 { 173 register int *ip; 174 register struct message *mp; 175 char *file, *disp; 176 int f, *msgvec; 177 FILE *obuf; 178 179 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 180 if ((file = snarf(str, &f)) == NOSTR) 181 return(1); 182 if (!f) { 183 *msgvec = first(0, MMNORM); 184 if (*msgvec == NULL) { 185 printf("No messages to %s.\n", cmd); 186 return(1); 187 } 188 msgvec[1] = NULL; 189 } 190 if (f && getmsglist(str, msgvec, 0) < 0) 191 return(1); 192 if ((file = expand(file)) == NOSTR) 193 return(1); 194 printf("\"%s\" ", file); 195 fflush(stdout); 196 if (access(file, 0) >= 0) 197 disp = "[Appended]"; 198 else 199 disp = "[New file]"; 200 if ((obuf = Fopen(file, "a")) == NULL) { 201 perror(NOSTR); 202 return(1); 203 } 204 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 205 mp = &message[*ip - 1]; 206 touch(mp); 207 if (send(mp, obuf, ignore, NOSTR) < 0) { 208 perror(file); 209 Fclose(obuf); 210 return(1); 211 } 212 if (mark) 213 mp->m_flag |= MSAVED; 214 } 215 fflush(obuf); 216 if (ferror(obuf)) 217 perror(file); 218 Fclose(obuf); 219 printf("%s\n", disp); 220 return(0); 221 } 222 223 /* 224 * Write the indicated messages at the end of the passed 225 * file name, minus header and trailing blank line. 226 */ 227 int 228 swrite(v) 229 void *v; 230 { 231 char *str = v; 232 233 return save1(str, 1, "write", ignoreall); 234 } 235 236 /* 237 * Snarf the file from the end of the command line and 238 * return a pointer to it. If there is no file attached, 239 * just return NOSTR. Put a null in front of the file 240 * name so that the message list processing won't see it, 241 * unless the file name is the only thing on the line, in 242 * which case, return 0 in the reference flag variable. 243 */ 244 245 char * 246 snarf(linebuf, flag) 247 char linebuf[]; 248 int *flag; 249 { 250 register char *cp; 251 252 *flag = 1; 253 cp = strlen(linebuf) + linebuf - 1; 254 255 /* 256 * Strip away trailing blanks. 257 */ 258 259 while (cp > linebuf && isspace(*cp)) 260 cp--; 261 *++cp = 0; 262 263 /* 264 * Now search for the beginning of the file name. 265 */ 266 267 while (cp > linebuf && !isspace(*cp)) 268 cp--; 269 if (*cp == '\0') { 270 printf("No file specified.\n"); 271 return(NOSTR); 272 } 273 if (isspace(*cp)) 274 *cp++ = 0; 275 else 276 *flag = 0; 277 return(cp); 278 } 279 280 /* 281 * Delete messages. 282 */ 283 int 284 delete(v) 285 void *v; 286 { 287 int *msgvec = v; 288 delm(msgvec); 289 return 0; 290 } 291 292 /* 293 * Delete messages, then type the new dot. 294 */ 295 int 296 deltype(v) 297 void *v; 298 { 299 int *msgvec = v; 300 int list[2]; 301 int lastdot; 302 303 lastdot = dot - &message[0] + 1; 304 if (delm(msgvec) >= 0) { 305 list[0] = dot - &message[0] + 1; 306 if (list[0] > lastdot) { 307 touch(dot); 308 list[1] = NULL; 309 return(type(list)); 310 } 311 printf("At EOF\n"); 312 } else 313 printf("No more messages\n"); 314 return(0); 315 } 316 317 /* 318 * Delete the indicated messages. 319 * Set dot to some nice place afterwards. 320 * Internal interface. 321 */ 322 int 323 delm(msgvec) 324 int *msgvec; 325 { 326 register struct message *mp; 327 register *ip; 328 int last; 329 330 last = NULL; 331 for (ip = msgvec; *ip != NULL; ip++) { 332 mp = &message[*ip - 1]; 333 touch(mp); 334 mp->m_flag |= MDELETED|MTOUCH; 335 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 336 last = *ip; 337 } 338 if (last != NULL) { 339 dot = &message[last-1]; 340 last = first(0, MDELETED); 341 if (last != NULL) { 342 dot = &message[last-1]; 343 return(0); 344 } 345 else { 346 dot = &message[0]; 347 return(-1); 348 } 349 } 350 351 /* 352 * Following can't happen -- it keeps lint happy 353 */ 354 355 return(-1); 356 } 357 358 /* 359 * Undelete the indicated messages. 360 */ 361 int 362 undeletecmd(v) 363 void *v; 364 { 365 int *msgvec = v; 366 register struct message *mp; 367 register *ip; 368 369 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 370 mp = &message[*ip - 1]; 371 touch(mp); 372 dot = mp; 373 mp->m_flag &= ~MDELETED; 374 } 375 return 0; 376 } 377 378 /* 379 * Interactively dump core on "core" 380 */ 381 int 382 core(v) 383 void *v; 384 { 385 int pid; 386 extern union wait wait_status; 387 388 switch (pid = vfork()) { 389 case -1: 390 perror("fork"); 391 return(1); 392 case 0: 393 abort(); 394 _exit(1); 395 } 396 printf("Okie dokie"); 397 fflush(stdout); 398 wait_child(pid); 399 if (wait_status.w_coredump) 400 printf(" -- Core dumped.\n"); 401 else 402 printf(" -- Can't dump core.\n"); 403 return 0; 404 } 405 406 /* 407 * Clobber as many bytes of stack as the user requests. 408 */ 409 int 410 clobber(v) 411 void *v; 412 { 413 char **argv = v; 414 register int times; 415 416 if (argv[0] == 0) 417 times = 1; 418 else 419 times = (atoi(argv[0]) + 511) / 512; 420 clob1(times); 421 return 0; 422 } 423 424 /* 425 * Clobber the stack. 426 */ 427 void 428 clob1(n) 429 int n; 430 { 431 char buf[512]; 432 register char *cp; 433 434 if (n <= 0) 435 return; 436 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 437 ; 438 clob1(n - 1); 439 } 440 441 /* 442 * Add the given header fields to the retained list. 443 * If no arguments, print the current list of retained fields. 444 */ 445 int 446 retfield(v) 447 void *v; 448 { 449 char **list = v; 450 451 return ignore1(list, ignore + 1, "retained"); 452 } 453 454 /* 455 * Add the given header fields to the ignored list. 456 * If no arguments, print the current list of ignored fields. 457 */ 458 int 459 igfield(v) 460 void *v; 461 { 462 char **list = v; 463 464 return ignore1(list, ignore, "ignored"); 465 } 466 467 int 468 saveretfield(v) 469 void *v; 470 { 471 char **list = v; 472 473 return ignore1(list, saveignore + 1, "retained"); 474 } 475 476 int 477 saveigfield(v) 478 void *v; 479 { 480 char **list = v; 481 482 return ignore1(list, saveignore, "ignored"); 483 } 484 485 int 486 ignore1(list, tab, which) 487 char *list[]; 488 struct ignoretab *tab; 489 char *which; 490 { 491 char field[BUFSIZ]; 492 register int h; 493 register struct ignore *igp; 494 char **ap; 495 496 if (*list == NOSTR) 497 return igshow(tab, which); 498 for (ap = list; *ap != 0; ap++) { 499 istrcpy(field, *ap); 500 if (member(field, tab)) 501 continue; 502 h = hash(field); 503 igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 504 igp->i_field = calloc((unsigned) strlen(field) + 1, 505 sizeof (char)); 506 strcpy(igp->i_field, field); 507 igp->i_link = tab->i_head[h]; 508 tab->i_head[h] = igp; 509 tab->i_count++; 510 } 511 return 0; 512 } 513 514 /* 515 * Print out all currently retained fields. 516 */ 517 int 518 igshow(tab, which) 519 struct ignoretab *tab; 520 char *which; 521 { 522 register int h; 523 struct ignore *igp; 524 char **ap, **ring; 525 526 if (tab->i_count == 0) { 527 printf("No fields currently being %s.\n", which); 528 return 0; 529 } 530 ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); 531 ap = ring; 532 for (h = 0; h < HSHSIZE; h++) 533 for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) 534 *ap++ = igp->i_field; 535 *ap = 0; 536 qsort(ring, tab->i_count, sizeof (char *), igcomp); 537 for (ap = ring; *ap != 0; ap++) 538 printf("%s\n", *ap); 539 return 0; 540 } 541 542 /* 543 * Compare two names for sorting ignored field list. 544 */ 545 static int 546 igcomp(l, r) 547 const void *l, *r; 548 { 549 return (strcmp(*(char **)l, *(char **)r)); 550 } 551