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