Blame view

mh/mh_whom.c 5.37 KB
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2
   Copyright (C) 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
3 4 5

   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
6
   the Free Software Foundation; either version 3, or (at your option)
7 8 9 10 11 12 13 14 15
   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, write to the Free Software
16 17
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301 USA */
18 19 20 21 22 23 24 25

#include <mh.h>

struct recipient {
  char *addr;
  int isbcc;
};

26 27
static mu_list_t local_rcp;   /* Local recipients */
static mu_list_t network_rcp; /* Network recipients */
28 29

static void
30
addrcp (mu_list_t *list, char *addr, int isbcc)
31 32 33 34 35
{
  int rc;
  struct recipient *p = xmalloc (sizeof (*p));
  p->addr = addr;
  p->isbcc = isbcc;
36
  if (!*list && (rc = mu_list_create (list)))
37
    {
38
      mu_error (_("Cannot create list: %s"), mu_strerror (rc));
39 40
      exit (1);
    }
41
  mu_list_append (*list, p);
42 43 44 45 46
}

static int
ismydomain (char *p)
{
47
  const char *domain;
48 49 50 51 52 53
  if (!p)
    return 1;
  mu_get_user_email_domain (&domain);
  return strcasecmp (domain, p + 1) == 0;
}

54
int
55
mh_alias_expand (const char *str, mu_address_t *paddr, int *incl)
56
{
57
  int argc;
58
  char **argv;
59
  int i;
60
  char *buf;
61
  mu_address_t exaddr = NULL;
62 63 64

  if (incl)
    *incl = 0;
65
  mu_argcv_get (str, ",", NULL, &argc, &argv);
66 67 68 69
  for (i = 0; i < argc;)
    {
      if (i + 1 == argc)
	{
70
	  if (mh_alias_get_address (argv[i], &exaddr, incl) == 0)
71 72 73 74 75 76 77 78 79 80 81
	    {
	      free (argv[i]);
	      memcpy (&argv[i], &argv[i+1],
		      (argc - i + 1) * sizeof (argv[0]));
	      argc--;
	    }
	  else
	    i++;
	}
      else if (argv[i + 1][0] == ',')
	{
82
	  if (mh_alias_get_address (argv[i], &exaddr, incl) == 0)
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
	    {
	      free (argv[i]);
	      free (argv[i+1]);
	      memcpy (&argv[i], &argv[i+2],
		      (argc - i) * sizeof (argv[0]));
	      argc -= 2;
	    }
	  else
	    i += 2;
	}
      else
	{
	  for (; i < argc; i++)
	    if (argv[i][0] == ',')
	      {
		i++;
		break;
	      }
	}
    }

  if (argc)
    {
      int status;
107
      mu_argcv_string (argc, argv, &buf);
108
      if ((status = mu_address_create (paddr, buf)))
109
	mu_error (_("Bad address `%s': %s"), buf, mu_strerror (status));
110 111 112
      free (buf);
    }

113
  mu_argcv_free (argc, argv);
114
  
115 116
  mu_address_union (paddr, exaddr);
  mu_address_destroy (&exaddr);
117 118 119 120 121
  return 0;
}


static void
122
scan_addrs (const char *str, int isbcc)
123
{
124
  mu_address_t addr = NULL;
125 126 127 128 129 130 131 132 133
  size_t i, count;
  char *buf;
  int rc;

  if (!str)
    return;

  mh_alias_expand (str, &addr, NULL);
    
134
  if (addr == NULL || mu_address_get_count (addr, &count))
135
    return;
136
    
137 138
  for (i = 1; i <= count; i++)
    {
139 140
      char *p;

141
      rc = mu_address_aget_email (addr, i, &buf);
142 143
      if (rc)
	{
144
	  mu_error ("mu_address_aget_email: %s", mu_strerror (rc));
145 146
	  continue;
	}
147

148
      p = strchr (buf, '@');
149
     
150 151 152 153 154
      if (ismydomain (p))
	addrcp (&local_rcp, buf, isbcc);
      else
	addrcp (&network_rcp, buf, isbcc);
    }
155
  mu_address_destroy (&addr);
156 157 158 159 160 161 162 163 164 165 166 167
}

static int
_destroy_recipient (void *item, void *unused_data)
{
  struct recipient *p = item;
  free (p->addr);
  free (p);
  return 0;
}

static void
168
destroy_addrs (mu_list_t *list)
169 170 171
{
  if (!*list)
    return;
172 173
  mu_list_do (*list, _destroy_recipient, NULL);
  mu_list_destroy (list);
174 175 176 177 178 179 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 214 215 216 217 218
}

/* Print an email in more readable form: localpart + "at" + domain */
static void
print_readable (char *email, int islocal)
{
  printf ("  ");
  for (; *email && *email != '@'; email++)
    putchar (*email);

  if (!*email || islocal)
    return;

  printf (_(" at %s"), email+1);
}

static int
_print_recipient (void *item, void *data)
{
  struct recipient *p = item;
  size_t *count = data;
  
  print_readable (p->addr, 0);
  if (p->isbcc)
    printf ("[BCC]");
  printf ("\n");
  (*count)++;
  return 0;
}

static int
_print_local_recipient (void *item, void *data)
{
  struct recipient *p = item;
  size_t *count = data;
  
  print_readable (p->addr, 1);
  if (p->isbcc)
    printf ("[BCC]");
  printf ("\n");
  (*count)++;
  return 0;
}
		  
int
219
mh_whom (const char *filename, int check)
220 221 222 223
{
  int rc = 0;
  mh_context_t *ctx;

224
  mh_read_aliases ();
225
  ctx = mh_context_create (filename, 1);
226
  if ((rc = mh_context_read (ctx)))
227
    {
228 229 230 231 232
      if (rc == ENOENT)
	mu_error ("%s: %s", filename, mu_strerror (rc));
      else
	mu_error ("%s: %s (%s)", filename, _("Malformed message"),
		  mu_strerror (rc));
233 234 235 236 237 238 239 240 241 242 243 244 245
      rc = -1;
    }
  else
    {
      size_t count = 0;
      
      scan_addrs (mh_context_get_value (ctx, MU_HEADER_TO, NULL), 0);
      scan_addrs (mh_context_get_value (ctx, MU_HEADER_CC, NULL), 0);
      scan_addrs (mh_context_get_value (ctx, MU_HEADER_BCC, NULL), 1);

      if (local_rcp)
	{
	  printf ("  %s\n", _("-- Local Recipients --"));
246
	  mu_list_do (local_rcp, _print_local_recipient, &count);
247 248 249 250 251
	}

      if (network_rcp)
	{
	  printf ("  %s\n", _("-- Network Recipients --"));
252
	  mu_list_do (network_rcp, _print_recipient, &count);
253 254 255 256
	}

      if (count == 0)
	{
257
	  mu_error(_("No recipients"));
258 259 260 261 262 263 264 265
	  rc = -1;
	}
    }
  free (ctx);
  destroy_addrs (&network_rcp);
  destroy_addrs (&local_rcp);
  return rc;
}