alias.c 15.2 KB
Newer Older
Thomas Roessler's avatar
Thomas Roessler committed
1
/*
2
 * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
Thomas Roessler's avatar
Thomas Roessler committed
3 4 5 6 7 8 9 10 11 12 13 14 15
 * 
 *     This program 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 2 of the License, or
 *     (at your option) any later version.
 * 
 *     This program 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 this program; if not, write to the Free Software
16
 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Thomas Roessler's avatar
Thomas Roessler committed
17 18
 */ 

19 20 21 22
#if HAVE_CONFIG_H
# include "config.h"
#endif

Thomas Roessler's avatar
Thomas Roessler committed
23 24
#include "mutt.h"
#include "mutt_regex.h"
Thomas Roessler's avatar
Thomas Roessler committed
25
#include "mutt_curses.h"
26
#include "mutt_idna.h"
Thomas Roessler's avatar
Thomas Roessler committed
27 28

#include <string.h>
29
#include <ctype.h>
Thomas Roessler's avatar
Thomas Roessler committed
30

31
ADDRESS *mutt_lookup_alias (const char *s)
Thomas Roessler's avatar
Thomas Roessler committed
32 33 34 35
{
  ALIAS *t = Aliases;

  for (; t; t = t->next)
36
    if (!mutt_strcasecmp (s, t->name))
Thomas Roessler's avatar
Thomas Roessler committed
37 38 39 40 41 42 43 44 45
      return (t->addr);
  return (NULL);   /* no such alias */
}

static ADDRESS *mutt_expand_aliases_r (ADDRESS *a, LIST **expn)
{
  ADDRESS *head = NULL, *last = NULL, *t, *w;
  LIST *u;
  char i;
Thomas Roessler's avatar
Thomas Roessler committed
46 47
  const char *fqdn;
  
Thomas Roessler's avatar
Thomas Roessler committed
48 49 50 51
  while (a)
  {
    if (!a->group && !a->personal && a->mailbox && strchr (a->mailbox, '@') == NULL)
    {
52
      t = mutt_lookup_alias (a->mailbox);
Thomas Roessler's avatar
Thomas Roessler committed
53 54 55 56 57 58

      if (t)
      {	
        i = 0;
        for (u = *expn; u; u = u->next)
	{
59
	  if (mutt_strcmp (a->mailbox, u->data) == 0) /* alias already found */
Thomas Roessler's avatar
Thomas Roessler committed
60 61 62 63 64 65 66 67 68 69 70 71 72
	  {
	    dprint (1, (debugfile, "mutt_expand_aliases_r(): loop in alias found for '%s'\n", a->mailbox));
	    i = 1;
	    break;
	  }
	}

        if (!i)
	{
          u = safe_malloc (sizeof (LIST));
          u->data = safe_strdup (a->mailbox);
          u->next = *expn;
          *expn = u;
73
	  w = rfc822_cpy_adr (t, 0);
Thomas Roessler's avatar
Thomas Roessler committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	  w = mutt_expand_aliases_r (w, expn);
	  if (head)
	    last->next = w;
	  else
	    head = last = w;
	  while (last && last->next)
	    last = last->next;
        }
	t = a;
	a = a->next;
	t->next = NULL;
	rfc822_free_address (&t);
	continue;
      }
      else
      {
	struct passwd *pw = getpwnam (a->mailbox);

	if (pw)
	{
94 95 96 97 98
	  char namebuf[STRING];
	  
	  mutt_gecos_name (namebuf, sizeof (namebuf), pw);
	  mutt_str_replace (&a->personal, namebuf);
	  
Thomas Roessler's avatar
Thomas Roessler committed
99
#ifdef EXACT_ADDRESS
Thomas Roessler's avatar
Thomas Roessler committed
100
	  FREE (&a->val);
Thomas Roessler's avatar
Thomas Roessler committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
#endif
	}
      }
    }

    if (head)
    {
      last->next = a;
      last = last->next;
    }
    else
      head = last = a;
    a = a->next;
    last->next = NULL;
  }

Thomas Roessler's avatar
Thomas Roessler committed
117
  if (option (OPTUSEDOMAIN) && (fqdn = mutt_fqdn(1)))
Thomas Roessler's avatar
Thomas Roessler committed
118 119
  {
    /* now qualify all local addresses */
Thomas Roessler's avatar
Thomas Roessler committed
120
    rfc822_qualify (head, fqdn);
Thomas Roessler's avatar
Thomas Roessler committed
121 122 123 124 125 126 127 128 129 130 131 132
  }

  return (head);
}

ADDRESS *mutt_expand_aliases (ADDRESS *a)
{
  ADDRESS *t;
  LIST *expn = NULL; /* previously expanded aliases to avoid loops */

  t = mutt_expand_aliases_r (a, &expn);
  mutt_free_list (&expn);
133
  return (mutt_remove_duplicates (t));
Thomas Roessler's avatar
Thomas Roessler committed
134 135
}

Thomas Roessler's avatar
Thomas Roessler committed
136 137 138 139 140 141 142 143 144 145 146
void mutt_expand_aliases_env (ENVELOPE *env)
{
  env->from = mutt_expand_aliases (env->from);
  env->to = mutt_expand_aliases (env->to);
  env->cc = mutt_expand_aliases (env->cc);
  env->bcc = mutt_expand_aliases (env->bcc);
  env->reply_to = mutt_expand_aliases (env->reply_to);
  env->mail_followup_to = mutt_expand_aliases (env->mail_followup_to);
}


147 148
/* 
 * if someone has an address like
149
 *	From: Michael `/bin/rm -f ~` Elkins <me@mutt.org>
Thomas Roessler's avatar
Thomas Roessler committed
150
 * and the user creates an alias for this, Mutt could wind up executing
151
 * the backticks 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 backticks.  We also
Thomas Roessler's avatar
Thomas Roessler committed
154 155
 * need to quote backslashes as well, since you could defeat the above by
 * doing
156
 *	From: Michael \`/bin/rm -f ~\` Elkins <me@mutt.org>
Thomas Roessler's avatar
Thomas Roessler committed
157
 * since that would get aliased as
158
 *	alias me Michael \\`/bin/rm -f ~\\` Elkins <me@mutt.org>
Thomas Roessler's avatar
Thomas Roessler committed
159
 * which still gets evaluated because the double backslash is not a quote.
160 161 162 163 164 165
 * 
 * Additionally, we need to quote ' and " characters - otherwise, mutt will
 * interpret them on the wrong parsing step.
 * 
 * $ wants to be quoted since it may indicate the start of an environment
 * variable.
Thomas Roessler's avatar
Thomas Roessler committed
166
 */
167

Thomas Roessler's avatar
Thomas Roessler committed
168 169 170 171
static void write_safe_address (FILE *fp, char *s)
{
  while (*s)
  {
172 173
    if (*s == '\\' || *s == '`' || *s == '\'' || *s == '"'
	|| *s == '$')
Thomas Roessler's avatar
Thomas Roessler committed
174 175 176 177 178 179
      fputc ('\\', fp);
    fputc (*s, fp);
    s++;
  }
}

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
ADDRESS *mutt_get_address (ENVELOPE *env, char **pfxp)
{
  ADDRESS *adr;
  char *pfx = NULL;

  if (mutt_addr_is_user (env->from))
  {
    if (env->to && !mutt_is_mail_list (env->to))
    {
      pfx = "To";
      adr = env->to;
    }
    else
    {
      pfx = "Cc";
      adr = env->cc;
    }
  }
  else if (env->reply_to && !mutt_is_mail_list (env->reply_to))
  {
    pfx = "Reply-To";
    adr = env->reply_to;
  }
  else
  {
    adr = env->from;
    pfx = "From";
  }

  if (pfxp) *pfxp = pfx;

  return adr;
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227
static void recode_buf (char *buf, size_t buflen)
{
  char *s;

  if (!ConfigCharset || !*ConfigCharset || !Charset)
    return;
  s = safe_strdup (buf);
  if (!s)
    return;
  if (mutt_convert_string (&s, Charset, ConfigCharset, 0) == 0)
    strfcpy (buf, s, buflen);
  FREE(&s);
}

Thomas Roessler's avatar
Thomas Roessler committed
228 229 230
void mutt_create_alias (ENVELOPE *cur, ADDRESS *iadr)
{
  ALIAS *new, *t;
231
  char buf[LONG_STRING], tmp[LONG_STRING], prompt[SHORT_STRING], *pc;
232
  char *err = NULL;
233
  char fixed[LONG_STRING];
Thomas Roessler's avatar
Thomas Roessler committed
234 235 236 237 238
  FILE *rc;
  ADDRESS *adr = NULL;

  if (cur)
  {
239
    adr = mutt_get_address (cur, NULL);
Thomas Roessler's avatar
Thomas Roessler committed
240 241 242 243 244 245 246 247
  }
  else if (iadr)
  {
    adr = iadr;
  }

  if (adr && adr->mailbox)
  {
248 249
    strfcpy (tmp, adr->mailbox, sizeof (tmp));
    if ((pc = strchr (tmp, '@')))
Thomas Roessler's avatar
Thomas Roessler committed
250 251 252
      *pc = 0;
  }
  else
253
    tmp[0] = '\0';
254 255

  /* Don't suggest a bad alias name in the event of a strange local part. */
256
  mutt_check_alias_name (tmp, buf, sizeof (buf));
Thomas Roessler's avatar
Thomas Roessler committed
257
  
258
retry_name:
259
  /* L10N: prompt to add a new alias */
260
  if (mutt_get_field (_("Alias as: "), buf, sizeof (buf), 0) != 0 || !buf[0])
Thomas Roessler's avatar
Thomas Roessler committed
261 262 263
    return;

  /* check to see if the user already has an alias defined */
264
  if (mutt_lookup_alias (buf))
Thomas Roessler's avatar
Thomas Roessler committed
265
  {
266
    mutt_error _("You already have an alias defined with that name!");
Thomas Roessler's avatar
Thomas Roessler committed
267 268
    return;
  }
269
  
270
  if (mutt_check_alias_name (buf, fixed, sizeof (fixed)))
271
  {
272
    switch (mutt_yesorno (_("Warning: This alias name may not work.  Fix it?"), MUTT_YES))
273
    {
274
      case MUTT_YES:
275 276 277 278 279 280 281
      	strfcpy (buf, fixed, sizeof (buf));
	goto retry_name;
      case -1: 
	return;
    }
  }
  
282 283
  new       = safe_calloc (1, sizeof (ALIAS));
  new->self = new;
Thomas Roessler's avatar
Thomas Roessler committed
284 285
  new->name = safe_strdup (buf);

Thomas Roessler's avatar
Thomas Roessler committed
286 287
  mutt_addrlist_to_local (adr);
  
Thomas Roessler's avatar
Thomas Roessler committed
288 289 290 291 292
  if (adr)
    strfcpy (buf, adr->mailbox, sizeof (buf));
  else
    buf[0] = 0;

293
  mutt_addrlist_to_intl (adr, NULL);
Thomas Roessler's avatar
Thomas Roessler committed
294
  
Thomas Roessler's avatar
Thomas Roessler committed
295
  do
Thomas Roessler's avatar
Thomas Roessler committed
296
  {
297
    if (mutt_get_field (_("Address: "), buf, sizeof (buf), 0) != 0 || !buf[0])
Thomas Roessler's avatar
Thomas Roessler committed
298 299 300 301 302 303 304
    {
      mutt_free_alias (&new);
      return;
    }
    
    if((new->addr = rfc822_parse_adrlist (new->addr, buf)) == NULL)
      BEEP ();
305
    if (mutt_addrlist_to_intl (new->addr, &err))
306 307
    {
      mutt_error (_("Error: '%s' is a bad IDN."), err);
308
      FREE (&err);
309 310 311
      mutt_sleep (2);
      continue;
    }
Thomas Roessler's avatar
Thomas Roessler committed
312
  }
Thomas Roessler's avatar
Thomas Roessler committed
313 314
  while(new->addr == NULL);
  
Thomas Roessler's avatar
Thomas Roessler committed
315 316 317 318 319
  if (adr && adr->personal && !mutt_is_mail_list (adr))
    strfcpy (buf, adr->personal, sizeof (buf));
  else
    buf[0] = 0;

320
  if (mutt_get_field (_("Personal name: "), buf, sizeof (buf), 0) != 0)
Thomas Roessler's avatar
Thomas Roessler committed
321 322 323 324 325 326 327
  {
    mutt_free_alias (&new);
    return;
  }
  new->addr->personal = safe_strdup (buf);

  buf[0] = 0;
328
  rfc822_write_address (buf, sizeof (buf), new->addr, 1);
329
  snprintf (prompt, sizeof (prompt), _("[%s = %s] Accept?"), new->name, buf);
330
  if (mutt_yesorno (prompt, MUTT_YES) != MUTT_YES)
Thomas Roessler's avatar
Thomas Roessler committed
331 332 333 334 335
  {
    mutt_free_alias (&new);
    return;
  }

Rocco Rutte's avatar
Rocco Rutte committed
336
  mutt_alias_add_reverse (new);
Thomas Roessler's avatar
Thomas Roessler committed
337
  
Thomas Roessler's avatar
Thomas Roessler committed
338 339 340 341 342 343 344 345 346 347
  if ((t = Aliases))
  {
    while (t->next)
      t = t->next;
    t->next = new;
  }
  else
    Aliases = new;

  strfcpy (buf, NONULL (AliasFile), sizeof (buf));
348
  if (mutt_get_field (_("Save to file: "), buf, sizeof (buf), MUTT_FILE) != 0)
Thomas Roessler's avatar
Thomas Roessler committed
349 350
    return;
  mutt_expand_path (buf, sizeof (buf));
351
  if ((rc = fopen (buf, "a+")))
Thomas Roessler's avatar
Thomas Roessler committed
352
  {
353 354 355 356 357 358 359
    /* terminate existing file with \n if necessary */
    if (fseek (rc, 0, SEEK_END))
      goto fseek_err;
    if (ftell(rc) > 0)
    {
      if (fseek (rc, -1, SEEK_CUR) < 0)
	goto fseek_err;
Erik Hovland's avatar
Erik Hovland committed
360
      if (fread(buf, 1, 1, rc) != 1)
361 362
      {
	mutt_perror (_("Error reading alias file"));
363
	safe_fclose (&rc);
364 365 366 367 368 369 370 371
	return;
      }
      if (fseek (rc, 0, SEEK_END) < 0)
	goto fseek_err;
      if (buf[0] != '\n')
	fputc ('\n', rc);
    }

372
    if (mutt_check_alias_name (new->name, NULL, 0))
373 374 375
      mutt_quote_filename (buf, sizeof (buf), new->name);
    else
      strfcpy (buf, new->name, sizeof (buf));
376
    recode_buf (buf, sizeof (buf));
377
    fprintf (rc, "alias %s ", buf);
Thomas Roessler's avatar
Thomas Roessler committed
378
    buf[0] = 0;
379
    rfc822_write_address (buf, sizeof (buf), new->addr, 0);
380
    recode_buf (buf, sizeof (buf));
Thomas Roessler's avatar
Thomas Roessler committed
381 382
    write_safe_address (rc, buf);
    fputc ('\n', rc);
383
    safe_fclose (&rc);
384
    mutt_message _("Alias added.");
Thomas Roessler's avatar
Thomas Roessler committed
385 386 387
  }
  else
    mutt_perror (buf);
388 389 390 391 392

  return;
  
  fseek_err:
  mutt_perror (_("Error seeking in alias file"));
393
  safe_fclose (&rc);
394
  return;
Thomas Roessler's avatar
Thomas Roessler committed
395 396
}

397 398 399 400 401
/* 
 * Sanity-check an alias name:  Only characters which are non-special to both
 * the RFC 822 and the mutt configuration parser are permitted.
 */

402
int mutt_check_alias_name (const char *s, char *dest, size_t destlen)
403
{
404 405 406 407 408 409 410 411 412 413 414 415
  wchar_t wc;
  mbstate_t mb;
  size_t l;
  int rv = 0, bad = 0, dry = !dest || !destlen;

  memset (&mb, 0, sizeof (mbstate_t));

  if (!dry)
    destlen--;
  for (; s && *s && (dry || destlen) &&
       (l = mbrtowc (&wc, s, MB_CUR_MAX, &mb)) != 0;
       s += l, destlen -= l)
416
  {
417 418 419 420 421 422 423
    bad = l == (size_t)(-1) || l == (size_t)(-2); /* conversion error */
    bad = bad || (!dry && l > destlen);		/* too few room for mb char */
    if (l == 1)
      bad = bad || (strchr ("-_+=.", *s) == NULL && !iswalnum (wc));
    else
      bad = bad || !iswalnum (wc);
    if (bad)
424
    {
425
      if (dry)
426
	return -1;
427 428
      if (l == (size_t)(-1))
        memset (&mb, 0, sizeof (mbstate_t));
429 430 431 432 433 434 435
      *dest++ = '_';
      rv = -1;
    }
    else if (!dry)
    {
      memcpy (dest, s, l);
      dest += l;
436 437
    }
  }
438 439
  if (!dry)
    *dest = 0;
440 441 442
  return rv;
}

Thomas Roessler's avatar
Thomas Roessler committed
443 444 445 446 447 448 449
/*
 * This routine looks to see if the user has an alias defined for the given
 * address.
 */
ADDRESS *alias_reverse_lookup (ADDRESS *a)
{
  if (!a || !a->mailbox)
Thomas Roessler's avatar
Thomas Roessler committed
450 451 452 453
      return NULL;
  
  return hash_find (ReverseAlias, a->mailbox);
}
Thomas Roessler's avatar
Thomas Roessler committed
454

Rocco Rutte's avatar
Rocco Rutte committed
455
void mutt_alias_add_reverse (ALIAS *t)
Thomas Roessler's avatar
Thomas Roessler committed
456 457 458 459
{
  ADDRESS *ap;
  if (!t)
    return;
460 461 462 463 464 465

  /* Note that the address mailbox should be converted to intl form
   * before using as a key in the hash.  This is currently done
   * by all callers, but added here mostly as documentation.. */
  mutt_addrlist_to_intl (t->addr, NULL);

Thomas Roessler's avatar
Thomas Roessler committed
466
  for (ap = t->addr; ap; ap = ap->next)
Thomas Roessler's avatar
Thomas Roessler committed
467
  {
Thomas Roessler's avatar
Thomas Roessler committed
468
    if (!ap->group && ap->mailbox)
469
      hash_insert (ReverseAlias, ap->mailbox, ap);
Thomas Roessler's avatar
Thomas Roessler committed
470 471 472
  }
}

Rocco Rutte's avatar
Rocco Rutte committed
473
void mutt_alias_delete_reverse (ALIAS *t)
Thomas Roessler's avatar
Thomas Roessler committed
474 475 476 477
{
  ADDRESS *ap;
  if (!t)
    return;
478 479 480 481 482

  /* If the alias addresses were converted to local form, they won't
   * match the hash entries. */
  mutt_addrlist_to_intl (t->addr, NULL);

Thomas Roessler's avatar
Thomas Roessler committed
483 484 485 486
  for (ap = t->addr; ap; ap = ap->next)
  {
    if (!ap->group && ap->mailbox)
      hash_delete (ReverseAlias, ap->mailbox, ap, NULL);
Thomas Roessler's avatar
Thomas Roessler committed
487 488 489 490 491 492
  }
}

/* alias_complete() -- alias completion routine
 *
 * given a partial alias, this routine attempts to fill in the alias
493 494
 * from the alias list as much as possible. if given empty search string
 * or found nothing, present all aliases
Thomas Roessler's avatar
Thomas Roessler committed
495 496 497 498 499
 */
int mutt_alias_complete (char *s, size_t buflen)
{
  ALIAS *a = Aliases;
  ALIAS *a_list = NULL, *a_cur = NULL;
500
  char bestname[HUGE_STRING];
Thomas Roessler's avatar
Thomas Roessler committed
501 502
  int i;

503
#ifndef min
Thomas Roessler's avatar
Thomas Roessler committed
504
#define min(a,b)        ((a<b)?a:b)
505
#endif
Thomas Roessler's avatar
Thomas Roessler committed
506

507
  if (s[0] != 0) /* avoid empty string as strstr argument */
Thomas Roessler's avatar
Thomas Roessler committed
508
  {
509 510 511
    memset (bestname, 0, sizeof (bestname));

    while (a)
Thomas Roessler's avatar
Thomas Roessler committed
512
    {
513
      if (a->name && strstr (a->name, s) == a->name)
Thomas Roessler's avatar
Thomas Roessler committed
514
      {
515 516 517 518 519 520 521 522 523
	if (!bestname[0]) /* init */
	  strfcpy (bestname, a->name,
		   min (mutt_strlen (a->name) + 1, sizeof (bestname)));
	else
	{
	  for (i = 0 ; a->name[i] && a->name[i] == bestname[i] ; i++)
	    ;
	  bestname[i] = 0;
	}
Thomas Roessler's avatar
Thomas Roessler committed
524
      }
525
      a = a->next;
Thomas Roessler's avatar
Thomas Roessler committed
526 527
    }

528
    if (bestname[0] != 0)
Thomas Roessler's avatar
Thomas Roessler committed
529
    {
530 531 532 533 534 535 536
      if (mutt_strcmp (bestname, s) != 0)
      {
	/* we are adding something to the completion */
	strfcpy (s, bestname, mutt_strlen (bestname) + 1);
	return 1;
      }

Thomas Roessler's avatar
Thomas Roessler committed
537
      /* build alias list and show it */
538

Thomas Roessler's avatar
Thomas Roessler committed
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
      a = Aliases;
      while (a)
      {
	if (a->name && (strstr (a->name, s) == a->name))
	{
	  if (!a_list)  /* init */
	    a_cur = a_list = (ALIAS *) safe_malloc (sizeof (ALIAS));
	  else
	  {
	    a_cur->next = (ALIAS *) safe_malloc (sizeof (ALIAS));
	    a_cur = a_cur->next;
	  }
	  memcpy (a_cur, a, sizeof (ALIAS));
	  a_cur->next = NULL;
	}
	a = a->next;
      }
556 557
    }
  }
Thomas Roessler's avatar
Thomas Roessler committed
558

559 560 561 562
  bestname[0] = 0;
  mutt_alias_menu (bestname, sizeof(bestname), a_list ? a_list : Aliases);
  if (bestname[0] != 0)
    strfcpy (s, bestname, buflen);
Thomas Roessler's avatar
Thomas Roessler committed
563

564 565 566 567 568
  /* free the alias list */
  while (a_list)
  {
    a_cur = a_list;
    a_list = a_list->next;
569
    FREE (&a_cur);
Thomas Roessler's avatar
Thomas Roessler committed
570 571
  }

572 573
  /* remove any aliases marked for deletion */
  a_list = NULL;
574
  for (a_cur = Aliases; a_cur;)
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
  {
    if (a_cur->del)
    {
      if (a_list)
	a_list->next = a_cur->next;
      else
	Aliases = a_cur->next;
      
      a_cur->next = NULL;
      mutt_free_alias (&a_cur);
      
      if (a_list)
	a_cur = a_list;
      else
	a_cur = Aliases;
    }
    else
592
    {
593
      a_list = a_cur;
594 595
      a_cur  = a_cur->next;
    }
596 597
  }
  
598
  return 0;
Thomas Roessler's avatar
Thomas Roessler committed
599 600
}

Thomas Roessler's avatar
Thomas Roessler committed
601
static int string_is_address(const char *str, const char *u, const char *d)
Thomas Roessler's avatar
Thomas Roessler committed
602 603
{
  char buf[LONG_STRING];
Thomas Roessler's avatar
Thomas Roessler committed
604 605
  
  snprintf(buf, sizeof(buf), "%s@%s", NONULL(u), NONULL(d));
606
  if (ascii_strcasecmp(str, buf) == 0)
Thomas Roessler's avatar
Thomas Roessler committed
607 608 609 610
    return 1;
  
  return 0;
}
Thomas Roessler's avatar
Thomas Roessler committed
611

Thomas Roessler's avatar
Thomas Roessler committed
612 613 614
/* returns TRUE if the given address belongs to the user. */
int mutt_addr_is_user (ADDRESS *addr)
{
615 616
  const char *fqdn;

Thomas Roessler's avatar
Thomas Roessler committed
617 618
  /* NULL address is assumed to be the user. */
  if (!addr)
619
  {
620
    dprint (5, (debugfile, "mutt_addr_is_user: yes, NULL address\n"));
Thomas Roessler's avatar
Thomas Roessler committed
621
    return 1;
622
  }
Thomas Roessler's avatar
Thomas Roessler committed
623
  if (!addr->mailbox)
624
  {
625
    dprint (5, (debugfile, "mutt_addr_is_user: no, no mailbox\n"));
Thomas Roessler's avatar
Thomas Roessler committed
626
    return 0;
627
  }
Thomas Roessler's avatar
Thomas Roessler committed
628

629
  if (ascii_strcasecmp (addr->mailbox, Username) == 0)
630
  {
631
    dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s\n", addr->mailbox, Username));
Thomas Roessler's avatar
Thomas Roessler committed
632
    return 1;
633
  }
634
  if (string_is_address(addr->mailbox, Username, Hostname))
635
  {
636
    dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, Hostname));
Thomas Roessler's avatar
Thomas Roessler committed
637
    return 1;
638
  }
639 640
  fqdn = mutt_fqdn (0);
  if (string_is_address(addr->mailbox, Username, fqdn))
641
  {
642
    dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, NONULL(fqdn)));
Thomas Roessler's avatar
Thomas Roessler committed
643
    return 1;
644
  }
645 646
  fqdn = mutt_fqdn (1);
  if (string_is_address(addr->mailbox, Username, fqdn))
647
  {
648
    dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s @ %s \n", addr->mailbox, Username, NONULL(fqdn)));
649
    return 1;
650
  }
651

652
  if (From && !ascii_strcasecmp (From->mailbox, addr->mailbox))
653
  {
654
    dprint (5, (debugfile, "mutt_addr_is_user: yes, %s = %s\n", addr->mailbox, From->mailbox));
Thomas Roessler's avatar
Thomas Roessler committed
655
    return 1;
656
  }
Thomas Roessler's avatar
Thomas Roessler committed
657

658 659
  if (mutt_match_rx_list (addr->mailbox, Alternates))
  {
660
    dprint (5, (debugfile, "mutt_addr_is_user: yes, %s matched by alternates.\n", addr->mailbox));
661
    if (mutt_match_rx_list (addr->mailbox, UnAlternates))
662
      dprint (5, (debugfile, "mutt_addr_is_user: but, %s matched by unalternates.\n", addr->mailbox));
663 664
    else
      return 1;
665
  }
Thomas Roessler's avatar
Thomas Roessler committed
666
  
667
  dprint (5, (debugfile, "mutt_addr_is_user: no, all failed.\n"));
Thomas Roessler's avatar
Thomas Roessler committed
668 669
  return 0;
}