NetBSD/usr.bin/mail/cmd4.c

388 lines
7.8 KiB
C

/* $NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Anon Ymous.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95";
#else
__RCSID("$NetBSD: cmd4.c,v 1.6 2009/04/11 14:22:32 christos Exp $");
#endif
#endif /* not lint */
#include "rcv.h"
#include <util.h>
#include "extern.h"
/*
* Mail -- a mail program
*
* Still more user commands.
* XXX - should this be renamed smopts.c?
*/
#if 0 /* XXX - debugging stuff - to be removed */
void showname(struct name *);
void
showname(struct name *np)
{
for (/*EMPTY*/; np; np = np->n_flink)
(void)printf("np: %p np->n_type: %d np->n_name: '%s' (%p)\n",
np, np->n_type, np->n_name, np->n_name);
}
__unused
static void
showsmopts(struct smopts_s *sp)
{
(void)printf("%s (%p)\n", sp->s_name, sp);
showname(sp->s_smopts);
}
#endif /* XXX - debugging stuff - to be removed */
static int
hashcase(const char *key)
{
char *lckey;
lckey = salloc(strlen(key) + 1);
istrcpy(lckey, key);
return hash(lckey);
}
static struct smopts_s *
findsmopts_core(const char *name)
{
struct smopts_s *sh;
for (sh = smoptstbl[hashcase(name)]; sh; sh = sh->s_link)
if (strcasecmp(sh->s_name, name) == 0)
return sh;
return NULL;
}
/*
* The exported smopts lookup routine.
*/
PUBLIC struct smopts_s *
findsmopts(const char *name, int top_only)
{
const char *cp;
struct smopts_s *sh;
if ((sh = findsmopts_core(name)) != NULL)
return sh;
if (top_only)
return NULL;
for (cp = strchr(name, '@'); cp; cp = strchr(cp + 1, '.'))
if ((sh = findsmopts_core(cp)) != NULL)
return sh;
return findsmopts_core(".");
}
static void
printsmopts(const char *name)
{
struct smopts_s *sp;
if ((sp = findsmopts(name, 1)) == NULL) {
(void)printf("%s:\n", name);
return;
}
(void)printf("%s:\t%s\n", sp->s_name, detract(sp->s_smopts, GSMOPTS));
}
static void
printsmoptstbl(void)
{
struct smopts_s *sp;
const char **argv;
const char **ap;
int h;
int cnt;
cnt = 1;
for (h = 0; h < (int)__arraycount(smoptstbl); h++)
for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link)
cnt++;
argv = salloc(cnt * sizeof(*argv));
ap = argv;
for (h = 0; h < (int)__arraycount(smoptstbl); h++)
for (sp = smoptstbl[h]; sp && sp->s_name != NULL; sp = sp->s_link)
*ap++ = sp->s_name;
*ap = NULL;
sort(argv);
for (ap = argv; *ap != NULL; ap++)
printsmopts(*ap);
}
static struct name *
name_expand(char *sname, int ntype)
{
struct grouphead *gh;
struct name *np;
if ((gh = findgroup(sname)) != NULL) {
np = gexpand(NULL, gh, 0, ntype);
}
else {
np = csalloc(1, sizeof(*np));
np->n_name = sname;
np->n_type = ntype;
}
return np;
}
static struct name *
ncalloc(char *str, int ntype)
{
struct name *np;
np = ecalloc(1, sizeof(*np));
np->n_type = ntype;
np->n_name = vcopy(str);
return np;
}
static void
smopts_core(const char *sname, char **argv)
{
struct smopts_s *sp;
struct name *np;
struct name *t;
int h;
char **ap;
if ((sp = findsmopts(sname, 1)) != NULL) {
char *cp;
cp = detract(sp->s_smopts, GSMOPTS);
(void)printf("%s already defined as: %s\n", sname, cp);
return;
}
h = hashcase(sname);
sp = ecalloc(1, sizeof(*sp));
sp->s_name = vcopy(sname);
if (smoptstbl[h])
sp->s_link = smoptstbl[h];
smoptstbl[h] = sp;
np = NULL;
for (ap = argv + 1; *ap != NULL; ap++) {
t = ncalloc(*ap, GSMOPTS);
if (sp->s_smopts == NULL)
sp->s_smopts = t;
else
np->n_flink = t;
t->n_blink = np;
np = t;
}
}
/*
* Takes a list of entries, expands them, and adds the results to the
* smopts table.
*/
PUBLIC int
smoptscmd(void *v)
{
struct name *np;
char **argv;
argv = v;
if (*argv == NULL) {
printsmoptstbl();
return 0;
}
np = name_expand(argv[0], GTO);
if (argv[1] == NULL) {
for (/*EMPTY*/; np; np = np->n_flink)
printsmopts(np->n_name);
return 0;
}
for (/*EMPTY*/; np; np = np->n_flink)
smopts_core(np->n_name, argv);
return 0;
}
static void
free_name(struct name *np)
{
struct name *next_np;
for (/*EMPTY*/; np; np = next_np) {
next_np = np->n_flink;
free(next_np);
}
}
static void
delsmopts(char *name)
{
struct smopts_s *sp;
struct smopts_s **last_link;
last_link = &smoptstbl[hashcase(name)];
for (sp = *last_link; sp; sp = sp->s_link) {
if (strcasecmp(sp->s_name, name) == 0) {
*last_link = sp->s_link;
free_name(sp->s_smopts);
free(sp);
}
}
}
/*
* Takes a list of entries and removes them from the smoptstbl.
*/
PUBLIC int
unsmoptscmd(void *v)
{
struct name *np;
char **ap;
for (ap = v; *ap != NULL; ap++)
for (np = name_expand(*ap, GTO); np; np = np->n_flink)
delsmopts(np->n_name);
return 0;
}
static struct name *
alloc_Header(char *str)
{
struct name *np;
/*
* Don't use salloc() routines here as these strings must persist.
*/
np = ecalloc(1, sizeof(*np));
np->n_name = estrdup(str);
np->n_type = GMISC;
return np;
}
static int
free_Header(char *str)
{
struct name *np;
struct name *next_np;
size_t len;
len = strlen(str);
for (np = extra_headers; np != NULL; np = next_np) {
next_np = np->n_flink;
if (strncasecmp(np->n_name, str, len) == 0) {
if (np == extra_headers) {
extra_headers = np->n_flink;
if (extra_headers)
extra_headers->n_blink = NULL;
}
else {
struct name *bp;
struct name *fp;
bp = np->n_blink;
fp = np->n_flink;
if (bp)
bp->n_flink = fp;
if (fp)
fp->n_blink = bp;
}
if (np->n_name)
free(np->n_name);
free(np);
}
}
return 0;
}
/*
* Takes a string and includes it in the header.
*/
PUBLIC int
Header(void *v)
{
struct name *np;
char *str;
char *p;
str = v;
if (str == NULL)
return 0;
(void)strip_WSP(str); /* strip trailing whitespace */
if (str[0] == '\0') { /* Show the extra headers */
for (np = extra_headers; np != NULL; np = np->n_flink)
(void)printf("%s\n", np->n_name);
return 0;
}
/*
* Check for a valid header line: find the end of its name.
*/
for (p = str; *p != '\0' && *p != ':' && !is_WSP(*p); p++)
continue;
if (p[0] == ':' && p[1] == '\0') /* free headers of this type */
return free_Header(str);
/*
* Check for a valid header name.
*/
if (*p != ':' || !is_WSP(p[1])) {
(void)printf("invalid header string: `%s'\n", str);
return 0;
}
np = alloc_Header(str);
if (extra_headers == NULL)
extra_headers = np;
else {
struct name *tp;
for (tp = extra_headers; tp->n_flink; tp = tp->n_flink)
continue;
tp->n_flink = np;
np->n_blink = tp;
}
return 0;
}