1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * 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[] = "from: @(#)cmd2.c 5.14 (Berkeley) 6/25/90";*/ 36 static char rcsid[] = "$Id: cmd2.c,v 1.2 1993/08/01 18:13:13 mycroft Exp $"; 37 #endif /* not lint */ 38 39 #include "rcv.h" 40 #include <sys/wait.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 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 != NULL) { 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 != NULL; ip++) 77 if (*ip > mdot) 78 break; 79 if (*ip == NULL) 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 != NULL) 89 ip2++; 90 if (*ip2 == NULL) 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] = NULL; 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 save(str) 133 char str[]; 134 { 135 136 return save1(str, 1, "save", saveignore); 137 } 138 139 /* 140 * Copy a message to a file without affected its saved-ness 141 */ 142 copycmd(str) 143 char str[]; 144 { 145 146 return save1(str, 0, "copy", saveignore); 147 } 148 149 /* 150 * Save/copy the indicated messages at the end of the passed file name. 151 * If mark is true, mark the message "saved." 152 */ 153 save1(str, mark, cmd, ignore) 154 char str[]; 155 char *cmd; 156 struct ignoretab *ignore; 157 { 158 register int *ip; 159 register struct message *mp; 160 char *file, *disp; 161 int f, *msgvec; 162 FILE *obuf; 163 164 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 165 if ((file = snarf(str, &f)) == NOSTR) 166 return(1); 167 if (!f) { 168 *msgvec = first(0, MMNORM); 169 if (*msgvec == NULL) { 170 printf("No messages to %s.\n", cmd); 171 return(1); 172 } 173 msgvec[1] = NULL; 174 } 175 if (f && getmsglist(str, msgvec, 0) < 0) 176 return(1); 177 if ((file = expand(file)) == NOSTR) 178 return(1); 179 printf("\"%s\" ", file); 180 fflush(stdout); 181 if (access(file, 0) >= 0) 182 disp = "[Appended]"; 183 else 184 disp = "[New file]"; 185 if ((obuf = Fopen(file, "a")) == NULL) { 186 perror(NOSTR); 187 return(1); 188 } 189 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 190 mp = &message[*ip - 1]; 191 touch(mp); 192 if (send(mp, obuf, ignore, NOSTR) < 0) { 193 perror(file); 194 Fclose(obuf); 195 return(1); 196 } 197 if (mark) 198 mp->m_flag |= MSAVED; 199 } 200 fflush(obuf); 201 if (ferror(obuf)) 202 perror(file); 203 Fclose(obuf); 204 printf("%s\n", disp); 205 return(0); 206 } 207 208 /* 209 * Write the indicated messages at the end of the passed 210 * file name, minus header and trailing blank line. 211 */ 212 213 swrite(str) 214 char str[]; 215 { 216 217 return save1(str, 1, "write", ignoreall); 218 } 219 220 /* 221 * Snarf the file from the end of the command line and 222 * return a pointer to it. If there is no file attached, 223 * just return NOSTR. Put a null in front of the file 224 * name so that the message list processing won't see it, 225 * unless the file name is the only thing on the line, in 226 * which case, return 0 in the reference flag variable. 227 */ 228 229 char * 230 snarf(linebuf, flag) 231 char linebuf[]; 232 int *flag; 233 { 234 register char *cp; 235 236 *flag = 1; 237 cp = strlen(linebuf) + linebuf - 1; 238 239 /* 240 * Strip away trailing blanks. 241 */ 242 243 while (cp > linebuf && isspace(*cp)) 244 cp--; 245 *++cp = 0; 246 247 /* 248 * Now search for the beginning of the file name. 249 */ 250 251 while (cp > linebuf && !isspace(*cp)) 252 cp--; 253 if (*cp == '\0') { 254 printf("No file specified.\n"); 255 return(NOSTR); 256 } 257 if (isspace(*cp)) 258 *cp++ = 0; 259 else 260 *flag = 0; 261 return(cp); 262 } 263 264 /* 265 * Delete messages. 266 */ 267 268 delete(msgvec) 269 int msgvec[]; 270 { 271 delm(msgvec); 272 return 0; 273 } 274 275 /* 276 * Delete messages, then type the new dot. 277 */ 278 279 deltype(msgvec) 280 int msgvec[]; 281 { 282 int list[2]; 283 int lastdot; 284 285 lastdot = dot - &message[0] + 1; 286 if (delm(msgvec) >= 0) { 287 list[0] = dot - &message[0] + 1; 288 if (list[0] > lastdot) { 289 touch(dot); 290 list[1] = NULL; 291 return(type(list)); 292 } 293 printf("At EOF\n"); 294 } else 295 printf("No more messages\n"); 296 return(0); 297 } 298 299 /* 300 * Delete the indicated messages. 301 * Set dot to some nice place afterwards. 302 * Internal interface. 303 */ 304 305 delm(msgvec) 306 int *msgvec; 307 { 308 register struct message *mp; 309 register *ip; 310 int last; 311 312 last = NULL; 313 for (ip = msgvec; *ip != NULL; ip++) { 314 mp = &message[*ip - 1]; 315 touch(mp); 316 mp->m_flag |= MDELETED|MTOUCH; 317 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 318 last = *ip; 319 } 320 if (last != NULL) { 321 dot = &message[last-1]; 322 last = first(0, MDELETED); 323 if (last != NULL) { 324 dot = &message[last-1]; 325 return(0); 326 } 327 else { 328 dot = &message[0]; 329 return(-1); 330 } 331 } 332 333 /* 334 * Following can't happen -- it keeps lint happy 335 */ 336 337 return(-1); 338 } 339 340 /* 341 * Undelete the indicated messages. 342 */ 343 344 undelete(msgvec) 345 int *msgvec; 346 { 347 register struct message *mp; 348 register *ip; 349 350 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 351 mp = &message[*ip - 1]; 352 touch(mp); 353 dot = mp; 354 mp->m_flag &= ~MDELETED; 355 } 356 return 0; 357 } 358 359 /* 360 * Interactively dump core on "core" 361 */ 362 363 core() 364 { 365 int pid; 366 extern union wait wait_status; 367 368 switch (pid = vfork()) { 369 case -1: 370 perror("fork"); 371 return(1); 372 case 0: 373 abort(); 374 _exit(1); 375 } 376 printf("Okie dokie"); 377 fflush(stdout); 378 wait_child(pid); 379 if (wait_status.w_coredump) 380 printf(" -- Core dumped.\n"); 381 else 382 printf(" -- Can't dump core.\n"); 383 return 0; 384 } 385 386 /* 387 * Clobber as many bytes of stack as the user requests. 388 */ 389 clobber(argv) 390 char **argv; 391 { 392 register int times; 393 394 if (argv[0] == 0) 395 times = 1; 396 else 397 times = (atoi(argv[0]) + 511) / 512; 398 clob1(times); 399 return 0; 400 } 401 402 /* 403 * Clobber the stack. 404 */ 405 clob1(n) 406 { 407 char buf[512]; 408 register char *cp; 409 410 if (n <= 0) 411 return; 412 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 413 ; 414 clob1(n - 1); 415 } 416 417 /* 418 * Add the given header fields to the retained list. 419 * If no arguments, print the current list of retained fields. 420 */ 421 retfield(list) 422 char *list[]; 423 { 424 425 return ignore1(list, ignore + 1, "retained"); 426 } 427 428 /* 429 * Add the given header fields to the ignored list. 430 * If no arguments, print the current list of ignored fields. 431 */ 432 igfield(list) 433 char *list[]; 434 { 435 436 return ignore1(list, ignore, "ignored"); 437 } 438 439 saveretfield(list) 440 char *list[]; 441 { 442 443 return ignore1(list, saveignore + 1, "retained"); 444 } 445 446 saveigfield(list) 447 char *list[]; 448 { 449 450 return ignore1(list, saveignore, "ignored"); 451 } 452 453 ignore1(list, tab, which) 454 char *list[]; 455 struct ignoretab *tab; 456 char *which; 457 { 458 char field[BUFSIZ]; 459 register int h; 460 register struct ignore *igp; 461 char **ap; 462 463 if (*list == NOSTR) 464 return igshow(tab, which); 465 for (ap = list; *ap != 0; ap++) { 466 istrcpy(field, *ap); 467 if (member(field, tab)) 468 continue; 469 h = hash(field); 470 igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 471 igp->i_field = calloc((unsigned) strlen(field) + 1, 472 sizeof (char)); 473 strcpy(igp->i_field, field); 474 igp->i_link = tab->i_head[h]; 475 tab->i_head[h] = igp; 476 tab->i_count++; 477 } 478 return 0; 479 } 480 481 /* 482 * Print out all currently retained fields. 483 */ 484 igshow(tab, which) 485 struct ignoretab *tab; 486 char *which; 487 { 488 register int h; 489 struct ignore *igp; 490 char **ap, **ring; 491 int igcomp(); 492 493 if (tab->i_count == 0) { 494 printf("No fields currently being %s.\n", which); 495 return 0; 496 } 497 ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); 498 ap = ring; 499 for (h = 0; h < HSHSIZE; h++) 500 for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) 501 *ap++ = igp->i_field; 502 *ap = 0; 503 qsort((char *) ring, tab->i_count, sizeof (char *), igcomp); 504 for (ap = ring; *ap != 0; ap++) 505 printf("%s\n", *ap); 506 return 0; 507 } 508 509 /* 510 * Compare two names for sorting ignored field list. 511 */ 512 igcomp(l, r) 513 char **l, **r; 514 { 515 516 return strcmp(*l, *r); 517 } 518