1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 1999-2021 Free Software Foundation, Inc.
3 
4    GNU Mailutils is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    GNU Mailutils is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include "mail.h"
18 
19 static mu_assoc_t aliases;
20 
21 static void
alias_free(void * data)22 alias_free (void *data)
23 {
24   mu_list_t al = data;
25   util_slist_destroy (&al);
26 }
27 
28 static void
alias_print_group(const char * name,mu_list_t al)29 alias_print_group (const char *name, mu_list_t al)
30 {
31   mu_printf ("%s    ", name);
32   util_slist_print (al, 0);
33   mu_printf ("\n");
34 }
35 
36 static mu_list_t
alias_lookup(const char * name)37 alias_lookup (const char *name)
38 {
39   return mu_assoc_get (aliases, name);
40 }
41 
42 static void
alias_print(char * name)43 alias_print (char *name)
44 {
45   if (!name)
46     {
47       mu_iterator_t itr;
48 
49       if (!aliases)
50 	return;
51 
52       mu_assoc_get_iterator (aliases, &itr);
53       for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
54 	   mu_iterator_next (itr))
55 	{
56 	  const char *name;
57 	  mu_list_t al;
58 	  if (mu_iterator_current_kv (itr, (const void **)&name, (void**)&al))
59 	    continue;
60 	  alias_print_group (name, al);
61 	}
62     }
63   else
64     {
65       mu_list_t al;
66 
67       al = alias_lookup (name);
68       if (!al)
69 	{
70 	  mu_error (_("\"%s\": not a group"), name);
71 	  return;
72 	}
73       alias_print_group (name, al);
74     }
75 }
76 
77 static int
alias_create(const char * name,mu_list_t * al)78 alias_create (const char *name, mu_list_t *al)
79 {
80   int rc;
81   mu_list_t l;
82 
83   if (!aliases)
84     {
85       mu_assoc_create (&aliases, 0);
86       mu_assoc_set_destroy_item (aliases, alias_free);
87     }
88   if (mu_assoc_lookup_ref (aliases, name, al))
89     {
90       rc = mu_list_create (&l);
91       if (rc)
92 	return rc;
93       mu_assoc_install (aliases, name, l);
94       *al = l;
95       return 0;
96     }
97   return 1;
98 }
99 
100 void
alias_destroy(const char * name)101 alias_destroy (const char *name)
102 {
103   mu_assoc_remove (aliases, name);
104 }
105 
106 
107 static void
recursive_alias_expand(const char * name,mu_list_t exlist,mu_list_t origlist)108 recursive_alias_expand (const char *name, mu_list_t exlist, mu_list_t origlist)
109 {
110   mu_list_t al;
111   mu_iterator_t itr;
112 
113   if ((al = alias_lookup (name)) == NULL)
114     {
115       if (mu_list_locate (exlist, (void*)name, NULL) == MU_ERR_NOENT)
116 	mu_list_append (exlist, (void*)name);
117       return;
118     }
119 
120   mu_list_get_iterator (al, &itr);
121   for (mu_iterator_first (itr);
122        !mu_iterator_is_done (itr);
123        mu_iterator_next (itr))
124     {
125       char *word;
126 
127       mu_iterator_current (itr, (void **)&word);
128       if (mu_list_locate (origlist, word, NULL) == MU_ERR_NOENT)
129 	{
130 	  mu_list_push (origlist, word);
131 	  recursive_alias_expand (word, exlist, origlist);
132 	  mu_list_pop (origlist, NULL);
133 	}
134     }
135   mu_iterator_destroy (&itr);
136 }
137 
138 static int
string_comp(const void * item,const void * value)139 string_comp (const void *item, const void *value)
140 {
141   return strcmp (item, value);
142 }
143 
144 char *
alias_expand(const char * name)145 alias_expand (const char *name)
146 {
147   mu_list_t al;
148   mu_list_t list;
149 
150   if (mailvar_is_true (mailvar_name_recursivealiases))
151     {
152       char *s;
153       mu_list_t origlist;
154 
155       int status = mu_list_create (&list);
156       if (status)
157 	{
158 	  mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, status);
159 	  return NULL;
160 	}
161       status = mu_list_create (&origlist);
162       if (status)
163 	{
164 	  mu_list_destroy (&origlist);
165 	  mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, status);
166 	  return NULL;
167 	}
168       mu_list_set_comparator (list, string_comp);
169       mu_list_set_comparator (origlist, string_comp);
170       recursive_alias_expand (name, list, origlist);
171       s = util_slist_to_string (list, ",");
172       mu_list_destroy (&origlist);
173       mu_list_destroy (&list);
174       return s;
175     }
176 
177   if ((al = alias_lookup (name)) == NULL)
178     return NULL;
179   return util_slist_to_string (al, ",");
180 }
181 
182 
183 struct alias_iterator
184 {
185   mu_iterator_t itr;
186   const char *prefix;
187   int prefixlen;
188   int pos;
189 };
190 
191 const char *
alias_iterate_next(alias_iterator_t atr)192 alias_iterate_next (alias_iterator_t atr)
193 {
194   while (!mu_iterator_is_done (atr->itr))
195     {
196       const char *name;
197       mu_list_t al;
198 
199       if (mu_iterator_current_kv (atr->itr, (const void **)&name, (void**)&al))
200 	continue;
201       mu_iterator_next (atr->itr);
202       if (strlen (name) >= atr->prefixlen
203 	  && strncmp (name, atr->prefix, atr->prefixlen) == 0)
204 	return name;
205     }
206   return NULL;
207 }
208 
209 const char *
alias_iterate_first(const char * prefix,alias_iterator_t * pc)210 alias_iterate_first (const char *prefix, alias_iterator_t *pc)
211 {
212   mu_iterator_t itr;
213   alias_iterator_t atr;
214 
215   if (!aliases)
216     {
217       *pc = NULL;
218       return NULL;
219     }
220 
221   if (mu_assoc_get_iterator (aliases, &itr))
222     return NULL;
223   mu_iterator_first (itr);
224   atr = mu_alloc (sizeof *atr);
225   atr->prefix = prefix;
226   atr->prefixlen = strlen (prefix);
227   atr->pos = 0;
228   atr->itr = itr;
229   *pc = atr;
230 
231   return alias_iterate_next (atr);
232 }
233 
234 void
alias_iterate_end(alias_iterator_t * pc)235 alias_iterate_end (alias_iterator_t *pc)
236 {
237   mu_iterator_destroy (&(*pc)->itr);
238   free (*pc);
239   *pc = NULL;
240 }
241 
242 
243 
244 /*
245  * a[lias] [alias [address...]]
246  * g[roup] [alias [address...]]
247  */
248 
249 int
mail_alias(int argc,char ** argv)250 mail_alias (int argc, char **argv)
251 {
252   if (argc == 1)
253     alias_print (NULL);
254   else if (argc == 2)
255     alias_print (argv[1]);
256   else
257     {
258       mu_list_t al;
259 
260       if (alias_create (argv[1], &al))
261 	return 1;
262 
263       argc--;
264       argv++;
265       while (--argc)
266 	util_slist_add (&al, *++argv);
267     }
268   return 0;
269 }
270 
271 
272