2 * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
4 * This program 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 2 of the License, or
7 * (at your option) any later version.
9 * This program 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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "mutt_regex.h"
25 #include "mutt_curses.h"
26 #include "mutt_idna.h"
31 ADDRESS *mutt_lookup_alias (const char *s)
35 for (; t; t = t->next)
36 if (!mutt_strcasecmp (s, t->name))
38 return (NULL); /* no such alias */
41 static ADDRESS *mutt_expand_aliases_r (ADDRESS *a, LIST **expn)
43 ADDRESS *head = NULL, *last = NULL, *t, *w;
50 if (!a->group && !a->personal && a->mailbox && strchr (a->mailbox, '@') == NULL)
52 t = mutt_lookup_alias (a->mailbox);
57 for (u = *expn; u; u = u->next)
59 if (mutt_strcmp (a->mailbox, u->data) == 0) /* alias already found */
61 dprint (1, (debugfile, "mutt_expand_aliases_r(): loop in alias found for '%s'\n", a->mailbox));
69 u = safe_malloc (sizeof (LIST));
70 u->data = safe_strdup (a->mailbox);
73 w = rfc822_cpy_adr (t);
74 w = mutt_expand_aliases_r (w, expn);
79 while (last && last->next)
85 rfc822_free_address (&t);
90 struct passwd *pw = getpwnam (a->mailbox);
96 mutt_gecos_name (namebuf, sizeof (namebuf), pw);
97 mutt_str_replace (&a->personal, namebuf);
117 if (option (OPTUSEDOMAIN) && (fqdn = mutt_fqdn(1)))
119 /* now qualify all local addresses */
120 rfc822_qualify (head, fqdn);
126 ADDRESS *mutt_expand_aliases (ADDRESS *a)
129 LIST *expn = NULL; /* previously expanded aliases to avoid loops */
131 t = mutt_expand_aliases_r (a, &expn);
132 mutt_free_list (&expn);
133 return (mutt_remove_duplicates (t));
136 void mutt_expand_aliases_env (ENVELOPE *env)
138 env->from = mutt_expand_aliases (env->from);
139 env->to = mutt_expand_aliases (env->to);
140 env->cc = mutt_expand_aliases (env->cc);
141 env->bcc = mutt_expand_aliases (env->bcc);
142 env->reply_to = mutt_expand_aliases (env->reply_to);
143 env->mail_followup_to = mutt_expand_aliases (env->mail_followup_to);
148 * if someone has an address like
149 * From: Michael `/bin/rm -f ~` Elkins <me@mutt.org>
150 * and the user creates an alias for this, Mutt could wind up executing
151 * the backtics because it writes aliases like
152 * alias me Michael `/bin/rm -f ~` Elkins <me@mutt.org>
153 * To avoid this problem, use a backslash (\) to quote any backtics. We also
154 * need to quote backslashes as well, since you could defeat the above by
156 * From: Michael \`/bin/rm -f ~\` Elkins <me@mutt.org>
157 * since that would get aliased as
158 * alias me Michael \\`/bin/rm -f ~\\` Elkins <me@mutt.org>
159 * which still gets evaluated because the double backslash is not a quote.
161 * Additionally, we need to quote ' and " characters - otherwise, mutt will
162 * interpret them on the wrong parsing step.
164 * $ wants to be quoted since it may indicate the start of an environment
168 static void write_safe_address (FILE *fp, char *s)
172 if (*s == '\\' || *s == '`' || *s == '\'' || *s == '"'
180 ADDRESS *mutt_get_address (ENVELOPE *env, char **pfxp)
185 if (mutt_addr_is_user (env->from))
187 if (env->to && !mutt_is_mail_list (env->to))
198 else if (env->reply_to && !mutt_is_mail_list (env->reply_to))
209 if (pfxp) *pfxp = pfx;
214 void mutt_create_alias (ENVELOPE *cur, ADDRESS *iadr)
217 char buf[LONG_STRING], tmp[LONG_STRING], prompt[SHORT_STRING], *pc;
219 char fixed[LONG_STRING];
225 adr = mutt_get_address (cur, NULL);
232 if (adr && adr->mailbox)
234 strfcpy (tmp, adr->mailbox, sizeof (tmp));
235 if ((pc = strchr (tmp, '@')))
241 /* Don't suggest a bad alias name in the event of a strange local part. */
242 mutt_check_alias_name (tmp, buf, sizeof (buf));
245 /* add a new alias */
246 if (mutt_get_field (_("Alias as: "), buf, sizeof (buf), 0) != 0 || !buf[0])
249 /* check to see if the user already has an alias defined */
250 if (mutt_lookup_alias (buf))
252 mutt_error _("You already have an alias defined with that name!");
256 if (mutt_check_alias_name (buf, fixed, sizeof (fixed)))
258 switch (mutt_yesorno (_("Warning: This alias name may not work. Fix it?"), M_YES))
261 strfcpy (buf, fixed, sizeof (buf));
268 new = safe_calloc (1, sizeof (ALIAS));
270 new->name = safe_strdup (buf);
272 mutt_addrlist_to_local (adr);
275 strfcpy (buf, adr->mailbox, sizeof (buf));
279 mutt_addrlist_to_idna (adr, NULL);
283 if (mutt_get_field (_("Address: "), buf, sizeof (buf), 0) != 0 || !buf[0])
285 mutt_free_alias (&new);
289 if((new->addr = rfc822_parse_adrlist (new->addr, buf)) == NULL)
291 if (mutt_addrlist_to_idna (new->addr, &err))
293 mutt_error (_("Error: '%s' is a bad IDN."), err);
298 while(new->addr == NULL);
300 if (adr && adr->personal && !mutt_is_mail_list (adr))
301 strfcpy (buf, adr->personal, sizeof (buf));
305 if (mutt_get_field (_("Personal name: "), buf, sizeof (buf), 0) != 0)
307 mutt_free_alias (&new);
310 new->addr->personal = safe_strdup (buf);
313 rfc822_write_address (buf, sizeof (buf), new->addr, 1);
314 snprintf (prompt, sizeof (prompt), _("[%s = %s] Accept?"), new->name, buf);
315 if (mutt_yesorno (prompt, M_YES) != M_YES)
317 mutt_free_alias (&new);
330 strfcpy (buf, NONULL (AliasFile), sizeof (buf));
331 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf), M_FILE) != 0)
333 mutt_expand_path (buf, sizeof (buf));
334 if ((rc = fopen (buf, "a+")))
336 /* terminate existing file with \n if necessary */
337 if (fseek (rc, 0, SEEK_END))
341 if (fseek (rc, -1, SEEK_CUR) < 0)
343 if (fread(buf, 1, 1, rc) < 0)
345 mutt_perror (_("Error reading alias file"));
348 if (fseek (rc, 0, SEEK_END) < 0)
354 if (mutt_check_alias_name (new->name, NULL, 0))
355 mutt_quote_filename (buf, sizeof (buf), new->name);
357 strfcpy (buf, new->name, sizeof (buf));
358 fprintf (rc, "alias %s ", buf);
360 rfc822_write_address (buf, sizeof (buf), new->addr, 0);
361 write_safe_address (rc, buf);
364 mutt_message _("Alias added.");
372 mutt_perror (_("Error seeking in alias file"));
378 * Sanity-check an alias name: Only characters which are non-special to both
379 * the RFC 822 and the mutt configuration parser are permitted.
382 int mutt_check_alias_name (const char *s, char *dest, size_t destlen)
387 int rv = 0, bad = 0, dry = !dest || !destlen;
389 memset (&mb, 0, sizeof (mbstate_t));
393 for (; s && *s && (dry || destlen) &&
394 (l = mbrtowc (&wc, s, MB_CUR_MAX, &mb)) != 0;
395 s += l, destlen -= l)
397 bad = l == (size_t)(-1) || l == (size_t)(-2); /* conversion error */
398 bad = bad || (!dry && l > destlen); /* too few room for mb char */
400 bad = bad || (strchr ("-_+=.", *s) == NULL && !iswalnum (wc));
402 bad = bad || !iswalnum (wc);
422 * This routine looks to see if the user has an alias defined for the given
425 ADDRESS *alias_reverse_lookup (ADDRESS *a)
430 if (!a || !a->mailbox)
433 for (; t; t = t->next)
435 /* cycle through all addresses if this is a group alias */
436 for (ap = t->addr; ap; ap = ap->next)
438 if (!ap->group && ap->mailbox &&
439 ascii_strcasecmp (ap->mailbox, a->mailbox) == 0)
446 /* alias_complete() -- alias completion routine
448 * given a partial alias, this routine attempts to fill in the alias
449 * from the alias list as much as possible. if given empty search string
450 * or found nothing, present all aliases
452 int mutt_alias_complete (char *s, size_t buflen)
455 ALIAS *a_list = NULL, *a_cur = NULL;
456 char bestname[HUGE_STRING];
459 #define min(a,b) ((a<b)?a:b)
461 if (s[0] != 0) /* avoid empty string as strstr argument */
463 memset (bestname, 0, sizeof (bestname));
467 if (a->name && strstr (a->name, s) == a->name)
469 if (!bestname[0]) /* init */
470 strfcpy (bestname, a->name,
471 min (mutt_strlen (a->name) + 1, sizeof (bestname)));
474 for (i = 0 ; a->name[i] && a->name[i] == bestname[i] ; i++)
482 if (bestname[0] != 0)
484 if (mutt_strcmp (bestname, s) != 0)
486 /* we are adding something to the completion */
487 strfcpy (s, bestname, mutt_strlen (bestname) + 1);
491 /* build alias list and show it */
496 if (a->name && (strstr (a->name, s) == a->name))
498 if (!a_list) /* init */
499 a_cur = a_list = (ALIAS *) safe_malloc (sizeof (ALIAS));
502 a_cur->next = (ALIAS *) safe_malloc (sizeof (ALIAS));
505 memcpy (a_cur, a, sizeof (ALIAS));
514 mutt_alias_menu (bestname, sizeof(bestname), a_list ? a_list : Aliases);
515 if (bestname[0] != 0)
516 strfcpy (s, bestname, buflen);
518 /* free the alias list */
522 a_list = a_list->next;
526 /* remove any aliases marked for deletion */
528 for (a_cur = Aliases; a_cur;)
533 a_list->next = a_cur->next;
535 Aliases = a_cur->next;
538 mutt_free_alias (&a_cur);
555 static int string_is_address(const char *str, const char *u, const char *d)
557 char buf[LONG_STRING];
559 snprintf(buf, sizeof(buf), "%s@%s", NONULL(u), NONULL(d));
560 if (ascii_strcasecmp(str, buf) == 0)
566 /* returns TRUE if the given address belongs to the user. */
567 int mutt_addr_is_user (ADDRESS *addr)
569 /* NULL address is assumed to be the user. */
572 dprint (5, (debugfile, "mutt_addr_is_user: yes, NULL address\n"));
577 dprint (5, (debugfile, "mutt_addr_is_user: no, no mailbox\n"));
581 if (ascii_strcasecmp (addr->mailbox, Username) == 0)
583 dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s\n", addr->mailbox, Username));
586 if (string_is_address(addr->mailbox, Username, Hostname))
588 dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, Hostname));
591 if (string_is_address(addr->mailbox, Username, mutt_fqdn(0)))
593 dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, mutt_fqdn (0)));
596 if (string_is_address(addr->mailbox, Username, mutt_fqdn(1)))
598 dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, mutt_fqdn (1)));
602 if (From && !ascii_strcasecmp (From->mailbox, addr->mailbox))
604 dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s\n", addr->mailbox, From->mailbox));
608 if (mutt_match_rx_list (addr->mailbox, Alternates))
610 dprint (5, (debugfile, "mutt_addr_is_user: yes, %s matched by alternates.\n", addr->mailbox));
611 if (mutt_match_rx_list (addr->mailbox, UnAlternates))
612 dprint (5, (debugfile, "mutt_addr_is_user: but, %s matched by unalternates.\n", addr->mailbox));
617 dprint (5, (debugfile, "mutt_addr_is_user: no, all failed.\n"));