static char SccsId
[] = "@(#)recipient.c 3.19 %G%";
** SENDTO -- Designate a send list.
** The parameter is a comma-separated list of people to send to.
** This routine arranges to send to all of them.
** list -- the send list.
** copyf -- the copy flag; passed to parse.
** ctladdr -- the address template for the person to
** send to -- effective uid/gid are important.
sendto(list
, copyf
, ctladdr
)
bool more
; /* set if more addresses to send to */
ADDRESS
*al
; /* list of addresses to send to */
printf("sendto: %s\n", list
);
/* find the end of this address */
while (*p
== ' ' || *p
== '\t')
while ((c
= *p
++) != '\0' && c
!= ',' && c
!= '\n')
if ((a
= parse(q
, (ADDRESS
*) NULL
, copyf
)) == NULL
)
/* put it on the local send list */
/* arrange to send to everyone on the local send list */
register ADDRESS
*a
= al
;
** RECIPIENT -- Designate a message recipient
** Saves the named person for future mailing.
** a -- the (preparsed) address header for the recipient.
register struct mailer
*m
;
extern ADDRESS
*getctladdr();
printf("recipient(%s)\n", To
);
/* break aliasing loops */
if (AliasLevel
> MAXRCRSN
)
usrerr("aliasing/forwarding loop broken");
** Do sickly crude mapping for program mailing, etc.
if (a
->q_mailer
== MN_LOCAL
)
if (getctladdr(a
) == NULL
&& Debug
== 0)
usrerr("Cannot mail directly to programs");
** Look up this person in the recipient list. If they
** are there already, return, otherwise continue.
** If the list is empty, just add it.
for (pq
= &m
->m_sendq
; (q
= *pq
) != NULL
; pq
= &q
->q_next
)
if (!ForceMail
&& sameaddr(q
, a
, FALSE
))
printf("(%s in sendq)\n", a
->q_paddr
);
if (Verbose
&& !bitset(QDONTSEND
, a
->q_flags
))
message(Arpa_Info
, "duplicate suppressed");
/* add address on list */
** Alias the name and handle :include: specs.
if (a
->q_mailer
== MN_LOCAL
)
if (strncmp(a
->q_user
, ":include:", 9) == 0)
if (getctladdr(a
) == NULL
&& Debug
== 0)
usrerr("Cannot mail directly to :include:s");
message(Arpa_Info
, "including file %s", &a
->q_user
[9]);
include(&a
->q_user
[9], " sending", a
);
** If the user is local and still being sent, verify that
** the address is good. If it is, try to forward.
** If the address is already good, we have a forwarding
** loop. This can be broken by just sending directly to
** the user (which is probably correct anyway).
if (!bitset(QDONTSEND
, a
->q_flags
) && a
->q_mailer
== MN_LOCAL
)
for (p
= buf
; *p
!= '\0' && !quoted
; p
++)
/* see if this is to a file */
if ((p
= rindex(buf
, '/')) != NULL
)
/* check if writable or creatable */
if (getctladdr(a
) == NULL
&& Debug
== 0)
usrerr("Cannot mail directly to files");
else if ((stat(buf
, &stb
) >= 0) ? (!writable(&stb
)) :
(*p
= '\0', access(buf
, 3) < 0))
giveresponse(EX_CANTCREAT
, TRUE
, m
);
register struct passwd
*pw
;
extern struct passwd
*finduser();
giveresponse(EX_NOUSER
, TRUE
, m
);
if (strcmp(a
->q_user
, pw
->pw_name
) != 0)
a
->q_user
= newstr(pw
->pw_name
);
strcpy(buf
, pw
->pw_name
);
a
->q_home
= newstr(pw
->pw_dir
);
** FINDUSER -- find the password entry for a user.
** This looks a lot like getpwnam, except that it may want to
** do some fancier pattern matching in /etc/passwd.
** name -- the name to match against.
** A pointer to a pw struct.
** NULL if name is unknown or ambiguous.
extern struct passwd
*getpwent();
register struct passwd
*pw
;
while ((pw
= getpwent()) != NULL
)
if (strcmp(pw
->pw_name
, name
) == 0)
buildfname(pw
->pw_gecos
, pw
->pw_name
, buf
);
for (p
= buf
; (p
= index(p
, ' ')) != NULL
; )
if (gotaspace
&& sameword(buf
, name
))
message(Arpa_Info
, "sending to login name %s",
** WRITABLE -- predicate returning if the file is writable.
** This routine must duplicate the algorithm in sys/fio.c.
** Unfortunately, we cannot use the access call since we
** won't necessarily be the real uid when we try to
** actually open the file.
** Notice that ANY file with ANY execute bit is automatically
** not writable. This is also enforced by mailfile.
** s -- pointer to a stat struct for the file.
** TRUE -- if we will be able to write this file.
** FALSE -- if we cannot write this file.
if (bitset(0111, s
->st_mode
))
if (bitset(S_ISUID
, s
->st_mode
))
if (bitset(S_ISGID
, s
->st_mode
))
return ((s
->st_mode
& bits
) != 0);
** INCLUDE -- handle :include: specification.
** fname -- filename to include.
** msg -- message to print in verbose mode.
** ctladdr -- address template to use to fill in these
** addresses -- effective user/group id are
** reads the :include: file and sends to everyone
include(fname
, msg
, ctladdr
)
usrerr("Cannot open %s", fname
);
if (fstat(fileno(fp
), &st
) < 0)
syserr("Cannot fstat %s!", fname
);
ctladdr
->q_uid
= st
.st_uid
;
ctladdr
->q_gid
= st
.st_gid
;
ctladdr
->q_flags
|= QGOODUID
;
/* read the file -- each line is a comma-separated list. */
while (fgets(buf
, sizeof buf
, fp
) != NULL
)
register char *p
= index(buf
, '\n');
message(Arpa_Info
, "%s to %s", msg
, buf
);
** SENDTOARGV -- send to an argument vector.
** argv -- argument vector to send to.
** puts all addresses on the argument vector onto the
while ((p
= *argv
++) != NULL
)
if (argv
[0] != NULL
&& argv
[1] != NULL
&& sameword(argv
[0], "at"))
if (strlen(p
) + strlen(argv
[1]) + 2 > sizeof nbuf
)
usrerr("address overflow");
(void) strcat(nbuf
, "@");
(void) strcat(nbuf
, argv
[1]);
** GETCTLADDR -- get controlling address from an address header.
** If none, get one corresponding to the effective userid.
** a -- the address to find the controller of.
** the controlling address.
while (a
!= NULL
&& !bitset(QGOODUID
, a
->q_flags
))