Blame view

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

   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
7
   the Free Software Foundation; either version 3, or (at your option)
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
16
   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
17 18 19 20 21 22 23 24

#include <mh.h>

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

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

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

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

53
/* FIXME: incl is not used */
54
int
55
mh_alias_expand (const char *str, mu_address_t *paddr, int *incl)
56
{
57 58 59 60
  size_t i, count;
  mu_address_t addr;
  int status;
  
Sergey Poznyakoff authored
61 62 63 64 65 66
  if (!str || !*str)
    {
      *paddr = NULL;
      return 0;
    }

67 68
  if (incl)
    *incl = 0;
69 70
  status = mu_address_create_hint (&addr, str, NULL, 0);
  if (status)
71
    {
72 73 74 75 76 77 78 79 80 81 82
      mu_error (_("Bad address `%s': %s"), str, mu_strerror (status));
      return 1;
    }

  mu_address_get_count (addr, &count);
  for (i = 1; i <= count; i++)
    {
      mu_address_t subaddr = NULL;
      const char *key;

      if (mu_address_sget_domain (addr, i, &key) == 0 && key == NULL)
83
	{
84 85 86
	  if (mu_address_sget_local_part (addr, i, &key) == 0
	      && mh_alias_get_address (key, paddr, incl) == 0)
	    continue;
87
	}
88 89 90

      status = mu_address_get_nth (addr, i, &subaddr);
      if (status)
91
	{
92 93 94
	  mu_error (_("%s: cannot get address #%lu: %s"),
		    str, (unsigned long) i, mu_strerror (status));
	  continue;
95 96
	}

97 98
      mu_address_union (paddr, subaddr);
      mu_address_destroy (&subaddr);
99
    }
100 101 102 103 104
  return 0;
}


static void
105
scan_addrs (const char *str, int isbcc)
106
{
107
  mu_address_t addr = NULL;
108 109 110 111 112 113 114 115 116
  size_t i, count;
  char *buf;
  int rc;

  if (!str)
    return;

  mh_alias_expand (str, &addr, NULL);
    
117
  if (addr == NULL || mu_address_get_count (addr, &count))
118
    return;
119
    
120 121
  for (i = 1; i <= count; i++)
    {
122 123
      char *p;

124
      rc = mu_address_aget_email (addr, i, &buf);
125 126
      if (rc)
	{
127
	  mu_error ("mu_address_aget_email: %s", mu_strerror (rc));
128 129
	  continue;
	}
130

131
      p = strchr (buf, '@');
132
     
133 134 135 136 137
      if (ismydomain (p))
	addrcp (&local_rcp, buf, isbcc);
      else
	addrcp (&network_rcp, buf, isbcc);
    }
138
  mu_address_destroy (&addr);
139 140 141 142 143 144 145 146 147 148 149 150
}

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

static void
151
destroy_addrs (mu_list_t *list)
152 153 154
{
  if (!*list)
    return;
155 156
  mu_list_do (*list, _destroy_recipient, NULL);
  mu_list_destroy (list);
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 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
}

/* 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;
}
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

static mu_header_t
read_header (mu_stream_t stream)
{
  int rc;
  mu_stream_t flt;
  mu_off_t size;
  size_t total;
  char *blurb;
  mu_header_t hdr;
  
  rc = mu_stream_size (stream, &size);
  if (rc)
    {
      mu_error (_("cannot get stream size: %s"), mu_strerror (rc));
      exit (1);
    }
  
  rc = mu_filter_create (&flt, stream, "HEADER",
			 MU_FILTER_DECODE, MU_STREAM_READ);
  if (rc)
    {
      mu_error (_("cannot open filter stream: %s"), mu_strerror (rc));
      exit (1);
    }

  blurb = xmalloc (size + 1);

  total = 0;
  while (1)
    {
      size_t n;
      
      rc = mu_stream_read (flt, blurb + total, size - total, &n);
      if (rc)
	break;
      if (n == 0)
	break;
      total += n;
    }

  mu_stream_destroy (&flt);
  if (rc)
    {
      free (blurb);
      mu_error (_("read error: %s"), mu_strerror (rc));
      exit (1);
    }

  rc = mu_header_create (&hdr, blurb, total);
  free (blurb);
  if (rc)
    {
      mu_diag_funcall (MU_DIAG_ERROR, "mu_header_create", NULL, rc);
      exit (1);
    }
  return hdr;
}

259
int
260
mh_whom (const char *filename, int check)
261 262 263
{
  int rc = 0;

264
  if (access (filename, R_OK))
265
    {
266
      mu_error ("%s: %s", filename, mu_strerror (errno));
267 268 269 270 271
      rc = -1;
    }
  else
    {
      size_t count = 0;
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
      mu_header_t hdr;
      mu_stream_t str;
      int rc;
      const char *val;

      rc = mu_file_stream_create (&str, filename, MU_STREAM_READ);
      if (rc)
	{
	  mu_diag_funcall (MU_DIAG_ERROR, "mu_file_stream_create",
			   filename, rc);
	  exit (1);
	}
      hdr = read_header (str);
      mu_stream_unref (str);

287
      mh_read_aliases ();
288 289 290 291 292 293 294

      if (mu_header_sget_value (hdr, MU_HEADER_TO, &val) == 0)
	scan_addrs (val, 0);
      if (mu_header_sget_value (hdr, MU_HEADER_CC, &val) == 0)
	scan_addrs (val, 0);
      if (mu_header_sget_value (hdr, MU_HEADER_BCC, &val) == 0)
	scan_addrs (val, 1);
295 296 297 298

      if (local_rcp)
	{
	  printf ("  %s\n", _("-- Local Recipients --"));
299
	  mu_list_do (local_rcp, _print_local_recipient, &count);
300 301 302 303 304
	}

      if (network_rcp)
	{
	  printf ("  %s\n", _("-- Network Recipients --"));
305
	  mu_list_do (network_rcp, _print_recipient, &count);
306 307 308 309
	}

      if (count == 0)
	{
310
	  mu_error(_("no recipients"));
311 312
	  rc = -1;
	}
313
      mu_header_destroy (&hdr);
314 315 316 317 318
    }
  destroy_addrs (&network_rcp);
  destroy_addrs (&local_rcp);
  return rc;
}