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