Home | History | Annotate | Line # | Download | only in mail
cmd2.c revision 1.11
      1 /*	$NetBSD: cmd2.c,v 1.11 2001/02/05 02:07:52 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1980, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 #if 0
     39 static char sccsid[] = "@(#)cmd2.c	8.1 (Berkeley) 6/6/93";
     40 #else
     41 __RCSID("$NetBSD: cmd2.c,v 1.11 2001/02/05 02:07:52 christos Exp $");
     42 #endif
     43 #endif /* not lint */
     44 
     45 #include "rcv.h"
     46 #include "extern.h"
     47 
     48 /*
     49  * Mail -- a mail program
     50  *
     51  * More user commands.
     52  */
     53 extern int wait_status;
     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 	struct message *mp;
     67 	int *ip, *ip2;
     68 	int list[2], mdot;
     69 
     70 	if (*msgvec != 0) {
     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 != 0; ip++)
     86 			if (*ip > mdot)
     87 				break;
     88 		if (*ip == 0)
     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 != 0)
     98 				ip2++;
     99 			if (*ip2 == 0)
    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] = 0;
    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 	int *ip;
    174 	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 == 0) {
    185 			printf("No messages to %s.\n", cmd);
    186 			return(1);
    187 		}
    188 		msgvec[1] = 0;
    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 (sendmessage(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 	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((unsigned char)*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((unsigned char)*cp))
    268 		cp--;
    269 	if (*cp == '\0') {
    270 		printf("No file specified.\n");
    271 		return(NOSTR);
    272 	}
    273 	if (isspace((unsigned char)*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] = 0;
    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 	struct message *mp;
    327 	int *ip;
    328 	int last;
    329 
    330 	last = 0;
    331 	for (ip = msgvec; *ip != 0; 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 != 0) {
    339 		dot = &message[last-1];
    340 		last = first(0, MDELETED);
    341 		if (last != 0) {
    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 	struct message *mp;
    367 	int *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 
    387 	switch (pid = vfork()) {
    388 	case -1:
    389 		perror("fork");
    390 		return(1);
    391 	case 0:
    392 		abort();
    393 		_exit(1);
    394 	}
    395 	printf("Okie dokie");
    396 	fflush(stdout);
    397 	wait_child(pid);
    398 	if (WCOREDUMP(wait_status))
    399 		printf(" -- Core dumped.\n");
    400 	else
    401 		printf(" -- Can't dump core.\n");
    402 	return 0;
    403 }
    404 
    405 /*
    406  * Clobber as many bytes of stack as the user requests.
    407  */
    408 int
    409 clobber(v)
    410 	void *v;
    411 {
    412 	char **argv = v;
    413 	int times;
    414 
    415 	if (argv[0] == 0)
    416 		times = 1;
    417 	else
    418 		times = (atoi(argv[0]) + 511) / 512;
    419 	clob1(times);
    420 	return 0;
    421 }
    422 
    423 /*
    424  * Clobber the stack.
    425  */
    426 void
    427 clob1(n)
    428 	int n;
    429 {
    430 	char buf[512];
    431 	char *cp;
    432 
    433 	if (n <= 0)
    434 		return;
    435 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
    436 		;
    437 	clob1(n - 1);
    438 }
    439 
    440 /*
    441  * Add the given header fields to the retained list.
    442  * If no arguments, print the current list of retained fields.
    443  */
    444 int
    445 retfield(v)
    446 	void *v;
    447 {
    448 	char **list = v;
    449 
    450 	return ignore1(list, ignore + 1, "retained");
    451 }
    452 
    453 /*
    454  * Add the given header fields to the ignored list.
    455  * If no arguments, print the current list of ignored fields.
    456  */
    457 int
    458 igfield(v)
    459 	void *v;
    460 {
    461 	char **list = v;
    462 
    463 	return ignore1(list, ignore, "ignored");
    464 }
    465 
    466 int
    467 saveretfield(v)
    468 	void *v;
    469 {
    470 	char **list = v;
    471 
    472 	return ignore1(list, saveignore + 1, "retained");
    473 }
    474 
    475 int
    476 saveigfield(v)
    477 	void *v;
    478 {
    479 	char **list = v;
    480 
    481 	return ignore1(list, saveignore, "ignored");
    482 }
    483 
    484 int
    485 ignore1(list, tab, which)
    486 	char *list[];
    487 	struct ignoretab *tab;
    488 	char *which;
    489 {
    490 	char field[LINESIZE];
    491 	int h;
    492 	struct ignore *igp;
    493 	char **ap;
    494 
    495 	if (*list == NOSTR)
    496 		return igshow(tab, which);
    497 	for (ap = list; *ap != 0; ap++) {
    498 		istrcpy(field, *ap);
    499 		if (member(field, tab))
    500 			continue;
    501 		h = hash(field);
    502 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
    503 		igp->i_field = calloc((unsigned) strlen(field) + 1,
    504 			sizeof (char));
    505 		strcpy(igp->i_field, field);
    506 		igp->i_link = tab->i_head[h];
    507 		tab->i_head[h] = igp;
    508 		tab->i_count++;
    509 	}
    510 	return 0;
    511 }
    512 
    513 /*
    514  * Print out all currently retained fields.
    515  */
    516 int
    517 igshow(tab, which)
    518 	struct ignoretab *tab;
    519 	char *which;
    520 {
    521 	int h;
    522 	struct ignore *igp;
    523 	char **ap, **ring;
    524 
    525 	if (tab->i_count == 0) {
    526 		printf("No fields currently being %s.\n", which);
    527 		return 0;
    528 	}
    529 	ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
    530 	ap = ring;
    531 	for (h = 0; h < HSHSIZE; h++)
    532 		for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
    533 			*ap++ = igp->i_field;
    534 	*ap = 0;
    535 	qsort(ring, tab->i_count, sizeof (char *), igcomp);
    536 	for (ap = ring; *ap != 0; ap++)
    537 		printf("%s\n", *ap);
    538 	return 0;
    539 }
    540 
    541 /*
    542  * Compare two names for sorting ignored field list.
    543  */
    544 static int
    545 igcomp(l, r)
    546 	const void *l, *r;
    547 {
    548 	return (strcmp(*(char **)l, *(char **)r));
    549 }
    550