* Copyright (c) 1980 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
static char sccsid
[] = "@(#)names.c 5.11 (Berkeley) %G%";
* Allocate a single element of a name list,
* initialize its name field to the passed
register struct name
*np
;
np
= (struct name
*) salloc(sizeof *np
);
np
->n_name
= savestr(str
);
* Find the tail of a list and return it.
register struct name
*np
;
while (np
->n_flink
!= NIL
)
* Extract a list of names from a line,
* and make a list of names from it.
* Return the list or NIL if none found.
register struct name
*top
, *np
, *t
;
if (line
== NOSTR
|| *line
== '\0')
while ((cp
= yankword(cp
, nbuf
)) != NOSTR
) {
* Turn a list of names into a string of the same names.
register struct name
*np
;
fprintf(stderr
, "detract asked to insert commas\n");
for (p
= np
; p
!= NIL
; p
= p
->n_flink
) {
if (ntype
&& (p
->n_type
& GMASK
) != ntype
)
s
+= strlen(p
->n_name
) + 1;
for (p
= np
; p
!= NIL
; p
= p
->n_flink
) {
if (ntype
&& (p
->n_type
& GMASK
) != ntype
)
cp
= copy(p
->n_name
, cp
);
if (comma
&& p
->n_flink
!= NIL
)
if (comma
&& *--cp
== ',')
* Grab a single word (liberal word)
* Throw away things between ()'s, and take anything between <>.
register int nesting
= 0;
} else if (*cp
== ' ' || *cp
== '\t' || *cp
== ',')
for (cp2
= wbuf
; *cp
&& (*cp2
++ = *cp
++) != '>';)
for (cp2
= wbuf
; *cp
&& !any(*cp
, " \t,("); *cp2
++ = *cp
++)
* For each recipient in the passed name list with a /
* in the name, append the message to the end of the named file
* and remove him from the recipient list.
* Recipients whose name begins with | are piped through the given
register struct name
*np
, *top
;
register struct name
*t
, *x
;
char *date
, *fname
, *shell
, *ctime();
if (!isfileaddr(np
->n_name
) && np
->n_name
[0] != '|') {
ispipe
= np
->n_name
[0] == '|';
fname
= expand(np
->n_name
);
* See if we have copied the complete message out yet.
if ((fout
= fopen(tempEdit
, "a")) == NULL
) {
image
= open(tempEdit
, 2);
fprintf(fout
, "From %s %s", myname
, date
);
puthead(hp
, fout
, GTO
|GSUBJECT
|GCC
|GNL
);
while ((c
= getc(fo
)) != EOF
)
* Now either copy "image" to the desired file
* or give it as the standard input to the desired
* program as appropriate.
if ((shell
= value("SHELL")) == NOSTR
)
sigmask(SIGHUP
)|sigmask(SIGINT
)|
image
, -1, "-c", fname
, NOSTR
) < 0) {
if ((fout
= fopen(fname
, "a")) == NULL
) {
fin
= Fdopen(image
, "r");
fprintf(stderr
, "Can't reopen image\n");
while ((c
= getc(fin
)) != EOF
)
senderr
++, perror(fname
);
* In days of old we removed the entry from the
* the list; now for sake of header expansion
* we leave it in and mark it as deleted.
* Determine if the passed address is a local "send to file" address.
* If any of the network metacharacters precedes any slashes, it can't
* be a filename. We cheat with .'s to allow path names like ./...
for (cp
= name
; *cp
; cp
++) {
if (*cp
== '!' || *cp
== '%' || *cp
== '@')
* Map all of the aliased users in the invoker's mailrc
* file and insert them into the list.
* Changed after all these months of service to recursively
* expand names (2/14/80).
register struct name
*new, *np
, *cp
;
metoo
= (value("metoo") != NOSTR
);
if (np
->n_name
[0] == '\\') {
gh
= findgroup(np
->n_name
);
new = gexpand(new, gh
, metoo
, np
->n_type
);
* Recursively expand a group name. We limit the expansion to some
* fixed level to keep things from going haywire.
* Direct recursion is not expanded for convenience.
gexpand(nlist
, gh
, metoo
, ntype
)
printf("Expanding alias to depth larger than %d\n", MAXEXP
);
for (gp
= gh
->g_list
; gp
!= NOGE
; gp
= gp
->ge_link
) {
if (strcmp(cp
, gh
->g_name
) == 0)
if ((ngh
= findgroup(cp
)) != NOGRP
) {
nlist
= gexpand(nlist
, ngh
, metoo
, ntype
);
* At this point should allow to expand
* to self if only person in group
if (gp
== gh
->g_list
&& gp
->ge_link
== NOGE
)
if (!metoo
&& strcmp(cp
, myname
) == 0)
* Concatenate the two passed name lists, return the result.
register struct name
*tail
;
* Unpack the name list onto a vector of strings.
* Return an error if the name list won't fit.
register char **ap
, **top
;
int t
, extra
, metoo
, verbose
;
panic("No names to unpack");
* Compute the number of extra arguments we will need.
* We need at least two extra -- one for "mail" and one for
* the terminating 0 pointer. Additional spots may be needed
* to pass along -f to the host mailer.
metoo
= value("metoo") != NOSTR
;
verbose
= value("verbose") != NOSTR
;
top
= (char **) salloc((t
+ extra
) * sizeof *top
);
* Remove all of the duplicates from the passed name list by
* insertion sorting them, then checking for dups.
* Return the head of the new list.
register struct name
*np
, *t
, *new;
while (nstrcmp(t
->n_name
, np
->n_name
) < 0) {
* If we ran out of t's, put the new entry after
* the current value of t.
if (nstrcmp(t
->n_name
, np
->n_name
) < 0) {
* Otherwise, put the new entry in front of the
* current t. If at the front of the list,
* the new guy becomes the new head of the list.
* The normal case -- we are inserting into the
* Now the list headed up by new is sorted.
* Go through it and remove duplicates.
while (t
->n_flink
!=NIL
&&
icequal(np
->n_name
,t
->n_flink
->n_name
))
if (t
== np
|| t
== NIL
) {
* Now t points to the last entry with the same name
* as np. Make np point beyond t.
np
->n_flink
= t
->n_flink
;
t
->n_flink
->n_blink
= np
;
* Version of strcmp which ignores case differences.
} while (c1
&& c1
== c2
);
* Put another node onto a list of names and return
struct name
*list
, *node
;
* Determine the number of elements in
* a name list and return it.
register struct name
*np
;
for (c
= 0; np
!= NIL
; c
++, np
= np
->n_flink
)
* Delete the given name from a namelist, using the passed
* function to compare the names.
delname(np
, name
, cmpfun
)
register struct name
*np
;
for (p
= np
; p
!= NIL
; p
= p
->n_flink
)
if ((* cmpfun
)(p
->n_name
, name
)) {
p
->n_flink
->n_blink
= NIL
;
p
->n_blink
->n_flink
= NIL
;
p
->n_blink
->n_flink
= p
->n_flink
;
p
->n_flink
->n_blink
= p
->n_blink
;
* Pretty print a name list
* Uncomment it if you need it.
register struct name *np;
fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);