%{
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003-2021 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see . */
#include
#include
#include
#include
#include
#include
struct mh_alias
{
char *name;
mu_list_t rcpt_list;
int inclusive;
};
static mu_list_t alias_list;
static mu_list_t
list_create_or_die (void)
{
int status;
mu_list_t list;
status = mu_list_create (&list);
if (status)
{
mu_error (_("can't create list: %s"), mu_strerror (status));
exit (1);
}
return list;
}
static char *
ali_list_to_string (mu_list_t *plist)
{
size_t n;
char *string;
mu_list_count (*plist, &n);
if (n == 1)
{
mu_list_get (*plist, 0, (void **)&string);
}
else
{
char *p;
size_t length = 0;
mu_iterator_t itr;
mu_list_get_iterator (*plist, &itr);
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next(itr))
{
char *s;
mu_iterator_current (itr, (void**) &s);
length += strlen (s) + 1;
}
string = mu_alloc (length + 1);
p = string;
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next(itr))
{
char *s;
mu_iterator_current (itr, (void**) &s);
strcpy (p, s);
p += strlen (s);
*p++ = ' ';
}
*--p = 0;
mu_iterator_destroy (&itr);
}
mu_list_destroy (plist);
return string;
}
static void
ali_append (struct mh_alias *ali)
{
if (ali)
{
if (!alias_list)
alias_list = list_create_or_die ();
mu_list_append (alias_list, ali);
}
}
static mu_list_t unix_group_to_list (char *name);
static mu_list_t unix_gid_to_list (char *name);
static mu_list_t unix_passwd_to_list (void);
int yyerror (char *s);
int yylex (void);
%}
%union {
char *string;
mu_list_t list;
struct mh_alias *alias;
}
%token EOL
%token STRING
%type address_list address_group string_list
%type address
%type alias
%locations
%%
input : alias_list
;
alias_list : alias
{
ali_append ($1);
}
| alias_list EOL alias
{
ali_append ($3);
}
;
alias : /* empty */
{
$$ = NULL;
}
| STRING ':' { ali_verbatim (1); } address_group
{
ali_verbatim (0);
$$ = mu_alloc (sizeof (*$$));
$$->name = $1;
$$->rcpt_list = $4;
$$->inclusive = 0;
}
| STRING ';' { ali_verbatim (1); } address_group
{
ali_verbatim (0);
$$ = mu_alloc (sizeof (*$$));
$$->name = $1;
$$->rcpt_list = $4;
$$->inclusive = 1;
}
;
address_group: address_list
| '=' STRING
{
$$ = unix_group_to_list ($2);
free ($2);
}
| '+' STRING
{
$$ = unix_gid_to_list ($2);
free ($2);
}
| '*'
{
$$ = unix_passwd_to_list ();
}
;
address_list : address
{
$$ = list_create_or_die ();
mu_list_append ($$, $1);
}
| address_list ',' address
{
mu_list_append ($1, $3);
$$ = $1;
}
;
address : string_list
{
$$ = ali_list_to_string (&$1);
}
;
string_list : STRING
{
mu_list_create(&$$);
mu_list_append($$, $1);
}
| string_list STRING
{
mu_list_append($1, $2);
$$ = $1;
}
;
%%
static mu_list_t
ali_list_dup (mu_list_t src)
{
mu_list_t dst;
mu_iterator_t itr;
if (mu_list_create (&dst))
return NULL;
if (mu_list_get_iterator (src, &itr))
{
mu_list_destroy (&dst);
return NULL;
}
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
void *data;
mu_iterator_current (itr, (void **)&data);
mu_list_append (dst, data);
}
mu_iterator_destroy (&itr);
return dst;
}
static int
ali_member (mu_list_t list, const char *name)
{
mu_iterator_t itr;
int found = 0;
if (mu_list_get_iterator (list, &itr))
return 0;
for (mu_iterator_first (itr); !found && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
char *item;
mu_address_t tmp;
mu_iterator_current (itr, (void **)&item);
if (strcmp (item, name) == 0)
found = 1;
else if (mu_address_create (&tmp, item) == 0)
{
found = mu_address_contains_email (tmp, name);
mu_address_destroy (&tmp);
}
}
mu_iterator_destroy (&itr);
return found;
}
int
aliascmp (const char *pattern, const char *name)
{
int len = strlen (pattern);
if (len > 1 && pattern[len - 1] == '*')
return strncmp (pattern, name, len - 2);
return strcmp (pattern, name);
}
static int mh_alias_get_internal (const char *name, mu_iterator_t start,
mu_list_t *return_list, int *inclusive);
int
alias_expand_list (mu_list_t name_list, mu_iterator_t orig_itr, int *inclusive)
{
mu_iterator_t itr;
if (mu_list_get_iterator (name_list, &itr))
return 1;
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
char *name;
mu_list_t exlist;
mu_iterator_current (itr, (void **)&name);
if (mh_alias_get_internal (name, orig_itr, &exlist, inclusive) == 0)
{
/* Insert exlist after name */
mu_iterator_ctl (itr, mu_itrctl_insert_list, exlist);
mu_list_destroy (&exlist);
/* Remove name */
mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
}
}
mu_iterator_destroy (&itr);
return 0;
}
/* Look up the named alias. If found, return the list of recipient
names associated with it */
static int
mh_alias_get_internal (const char *name,
mu_iterator_t start, mu_list_t *return_list,
int *inclusive)
{
mu_iterator_t itr;
int rc = 1;
if (!start)
{
if (mu_list_get_iterator (alias_list, &itr))
return 1;
mu_iterator_first (itr);
}
else
{
mu_iterator_dup (&itr, start);
mu_iterator_next (itr);
}
for (; !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
struct mh_alias *alias;
mu_iterator_current (itr, (void **)&alias);
if (aliascmp (alias->name, name) == 0)
{
if (inclusive)
*inclusive |= alias->inclusive;
*return_list = ali_list_dup (alias->rcpt_list);
alias_expand_list (*return_list, itr, inclusive);
rc = 0;
break;
}
}
mu_iterator_destroy (&itr);
return rc;
}
int
mh_alias_get (const char *name, mu_list_t *return_list)
{
return mh_alias_get_internal (name, NULL, return_list, NULL);
}
int
mh_alias_get_address (const char *name, mu_address_t *paddr, int *incl)
{
mu_iterator_t itr;
mu_list_t list;
if (incl)
*incl = 0;
if (mh_alias_get_internal (name, NULL, &list, incl))
return 1;
if (mu_list_is_empty (list))
{
mu_list_destroy (&list);
return 1;
}
if (mu_list_get_iterator (list, &itr) == 0)
{
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
char *item;
mu_address_t a;
char *ptr = NULL;
mu_iterator_current (itr, (void **)&item);
if (mu_address_create (&a, item))
{
mu_error (_("Error expanding aliases -- invalid address `%s'"),
item);
}
else
{
if (incl && *incl)
mu_address_set_personal (a, 1, name);
mu_address_union (paddr, a);
mu_address_destroy (&a);
}
if (ptr)
free (ptr);
}
mu_iterator_destroy (&itr);
}
mu_list_destroy (&list);
return 0;
}
/* Look up the given user name in the aliases. Return the list of
alias names this user is member of */
int
mh_alias_get_alias (const char *uname, mu_list_t *return_list)
{
mu_iterator_t itr;
int rc = 1;
if (mu_list_get_iterator (alias_list, &itr))
return 1;
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
struct mh_alias *alias;
mu_iterator_current (itr, (void **)&alias);
if (ali_member (alias->rcpt_list, uname))
{
if (*return_list == NULL && mu_list_create (return_list))
break;
mu_list_append (*return_list, alias->name);
rc = 0;
}
}
mu_iterator_destroy (&itr);
return rc;
}
void
mh_alias_enumerate (mh_alias_enumerator_t fun, void *data)
{
mu_iterator_t itr;
int rc = 0;
if (mu_list_get_iterator (alias_list, &itr))
return ;
for (mu_iterator_first (itr);
rc == 0 && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
struct mh_alias *alias;
mu_list_t tmp;
mu_iterator_current (itr, (void **)&alias);
tmp = ali_list_dup (alias->rcpt_list);
alias_expand_list (tmp, itr, NULL);
rc = fun (alias->name, tmp, data);
mu_list_destroy (&tmp);
}
mu_iterator_destroy (&itr);
}
static mu_list_t
unix_group_to_list (char *name)
{
struct group *grp = getgrnam (name);
mu_list_t lst = list_create_or_die ();
if (grp)
{
char **p;
for (p = grp->gr_mem; *p; p++)
mu_list_append (lst, mu_strdup (*p));
}
return lst;
}
static mu_list_t
unix_gid_to_list (char *name)
{
struct group *grp = getgrnam (name);
mu_list_t lst = list_create_or_die ();
if (grp)
{
struct passwd *pw;
setpwent();
while ((pw = getpwent ()))
{
if (pw->pw_gid == grp->gr_gid)
mu_list_append (lst, mu_strdup (pw->pw_name));
}
endpwent();
}
return lst;
}
static mu_list_t
unix_passwd_to_list ()
{
mu_list_t lst = list_create_or_die ();
struct passwd *pw;
setpwent();
while ((pw = getpwent ()))
{
if (pw->pw_uid > 200)
mu_list_append (lst, mu_strdup (pw->pw_name));
}
endpwent();
return lst;
}
int
mh_read_aliases (void)
{
const char *p;
if (alias_list)
return 0;
p = mh_global_profile_get ("Aliasfile", NULL);
if (p)
{
struct mu_wordsplit ws;
if (mu_wordsplit (p, &ws, MU_WRDSF_DEFFLAGS))
{
mu_error (_("cannot split line `%s': %s"), p,
mu_wordsplit_strerror (&ws));
}
else
{
size_t i;
for (i = 0; i < ws.ws_wordc; i++)
mh_alias_read (ws.ws_wordv[i], 1);
mu_wordsplit_free (&ws);
}
}
mh_alias_read (DEFAULT_ALIAS_FILE, 0);
return 0;
}