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