Blame view

libmu_sieve/tests.c 10.8 KB
Wojciech Polak authored
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2 3
   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
   2009, 2010 Free Software Foundation, Inc.
4

5 6 7
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
8
   version 3 of the License, or (at your option) any later version.
9

10
   This library is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
14

15
   You should have received a copy of the GNU Lesser General
16 17
   Public License along with this library.  If not, see
   <http://www.gnu.org/licenses/>. */
18 19 20 21 22 23 24 25

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif  

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>  
Wojciech Polak authored
26
#include <sieve-priv.h>
27

28
typedef int (*address_aget_t) (mu_address_t addr, size_t no, char **buf);
29

30
static int
31 32
_get_address_part (void *item, void *data)
{
33
  mu_sieve_runtime_tag_t *t = item;
34
  address_aget_t ret = NULL;
35 36
  
  if (strcmp (t->tag, "all") == 0)
37
    ret =  mu_address_aget_email;
38
  else if (strcmp (t->tag, "domain") == 0)
39
    ret =  mu_address_aget_domain;
40
  else if (strcmp (t->tag, "localpart") == 0)
41
    ret = mu_address_aget_local_part;
42 43 44 45 46 47
  if (ret)
    {	  
      *(address_aget_t*)data = ret;
      return 1; /* break the loop */
    }  
  return 0; /* continue */
48 49 50
}

address_aget_t
51
sieve_get_address_part (mu_list_t tags)
52
{
53 54
  address_aget_t ret = mu_address_aget_email;
  mu_list_do (tags, _get_address_part, &ret);
55 56 57 58 59 60 61
  return ret;
}

/* Structure shared between address and envelope tests */
struct address_closure
{
  address_aget_t aget;     /* appropriate address_aget_ function */
62
  void *data;              /* Either mu_header_t or mu_envelope_t */
63
  mu_address_t addr;       /* Obtained address */
64 65
};  

66
static int
67
do_count (mu_list_t args, mu_list_t tags, size_t count, int retval)
68
{
69
  mu_sieve_value_t *arg;
70
  
71
  if (mu_sieve_tag_lookup (tags, "count", &arg))
72 73 74
    {
      size_t limit;
      char *str;
75 76
      mu_sieve_value_t *val;
      mu_sieve_relcmpn_t stest;
77
      
78 79
      val = mu_sieve_value_get (args, 1);
      mu_list_get (val->v.list, 0, (void **) &str);
80 81
      limit = strtoul (str, &str, 10);

82
      mu_sieve_str_to_relcmp (arg->v.string, NULL, &stest);
83 84 85 86 87
      return stest (count, limit);
    }
  return retval;
}

88 89 90 91 92 93 94 95 96
int
retrieve_address (void *item, void *data, int idx, char **pval)
{
  struct address_closure *ap = data;
  char *val;
  int rc;
      
  if (!ap->addr)
    {
97
      if (mu_header_aget_value ((mu_header_t)ap->data, (char*)item, &val))
98
	return 1;
99
      rc = mu_address_create (&ap->addr, val);
100 101 102 103 104 105 106
      free (val);
      if (rc)
	return rc;
    }

  rc = ap->aget (ap->addr, idx+1, pval);
  if (rc)
107
    mu_address_destroy (&ap->addr);
108 109 110
  return rc;
}

111
int
112
sieve_test_address (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
113
{
114
  mu_sieve_value_t *h, *v;
115
  mu_header_t header = NULL;
116 117
  mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach, tags);
  mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach, tags);
118 119
  struct address_closure clos;
  int rc;
120
  size_t count;
121 122
  
  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
123
    mu_sieve_debug (mach, "ADDRESS");
124

125
  h = mu_sieve_value_get (args, 0);
126 127
  if (!h)
    {
128 129
      mu_sieve_arg_error (mach, 1);
      mu_sieve_abort (mach);
130
    }
131
  v = mu_sieve_value_get (args, 1);
132 133
  if (!v)
    {
134 135
      mu_sieve_arg_error (mach, 2);
      mu_sieve_abort (mach);
136 137
    }

138
  mu_message_get_header (mu_sieve_get_message (mach), &header);
139 140 141
  clos.data = header;
  clos.aget = sieve_get_address_part (tags);
  clos.addr = NULL;
142 143
  rc = mu_sieve_vlist_compare (h, v, comp, test, retrieve_address, &clos, &count);
  mu_address_destroy (&clos.addr);
144
  
145
  return do_count (args, tags, count, rc);
146 147
}

148
struct header_closure {
149
  mu_header_t header;
150 151 152
  int index;
};

153
int
154
retrieve_header (void *item, void *data, int idx, char **pval)
155
{
156 157 158 159
  struct header_closure *hc = data;
  char buf[512];
  size_t n;
  
160
  if (idx == 0)
161 162
    hc->index = 1;

163
  while (!mu_header_get_field_name (hc->header, hc->index, buf, sizeof(buf), &n))
164 165
    {
      int i = hc->index++;
166
      if (mu_c_strcasecmp (buf, (char*)item) == 0)
167
	{
168
	  if (mu_header_aget_field_value_unfold (hc->header, i, pval))
169 170 171 172 173
	    return 1;
	  return 0;
	}
    }

174
  return 1;
175 176 177
}

int
178
sieve_test_header (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
179
{
180 181 182
  mu_sieve_value_t *h, *v;
  mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach, tags);
  mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach, tags);
183
  size_t count, mcount = 0;
184
  struct header_closure clos;
185 186
  
  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
187
    mu_sieve_debug (mach, "HEADER");
188

189
  h = mu_sieve_value_get (args, 0);
190 191
  if (!h)
    {
192 193
      mu_sieve_arg_error (mach, 1);
      mu_sieve_abort (mach);
194
    }
195
  v = mu_sieve_value_get (args, 1);
196 197
  if (!v)
    {
198 199
      mu_sieve_arg_error (mach, 2);
      mu_sieve_abort (mach);
200 201
    }

202
  if (mu_sieve_tag_lookup (tags, "mime", NULL))
203 204 205
    {
      int ismime = 0;

206
      mu_message_is_multipart (mach->msg, &ismime);
207 208 209 210
      if (ismime)
	{
	  size_t i, nparts = 0;
	  
211
	  mu_message_get_num_parts (mach->msg, &nparts);
212 213
	  for (i = 1; i <= nparts; i++)
	    {
214
	      mu_message_t message = NULL;
215

216
	      if (mu_message_get_part (mach->msg, i, &message) == 0)
217
		{
218
		  mu_message_get_header (message, &clos.header);
219
		  if (mu_sieve_vlist_compare (h, v, comp, test,
220
					   retrieve_header, &clos, &mcount))
221 222 223 224 225
		    return 1;
		}
	    }
	}
    }
226
  mu_message_get_header (mach->msg, &clos.header);
227
  if (mu_sieve_vlist_compare (h, v, comp, test, retrieve_header, &clos, &count))
228 229
    return 1;

230
  return do_count (args, tags, count + mcount, 0);
231 232 233
}

int
234 235 236 237 238 239 240
retrieve_envelope (void *item, void *data, int idx, char **pval)
{
  struct address_closure *ap = data;
  int rc;
      
  if (!ap->addr)
    {
241
      const char *buf;
242
      
243
      if (mu_c_strcasecmp ((char*)item, "from") != 0)
244 245
	return 1;

246
      if (mu_envelope_sget_sender ((mu_envelope_t)ap->data, &buf))
247 248
	return 1;

249
      rc = mu_address_create (&ap->addr, buf);
250 251 252 253 254 255
      if (rc)
	return rc;
    }

  rc = ap->aget (ap->addr, idx+1, pval);
  if (rc)
256
    mu_address_destroy (&ap->addr);
257 258 259 260
  return rc;
}

int
261
sieve_test_envelope (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
262
{
263 264 265
  mu_sieve_value_t *h, *v;
  mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach, tags);
  mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach, tags);
266 267
  struct address_closure clos;
  int rc;
268
  size_t count;
269 270
  
  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
271
    mu_sieve_debug (mach, "ENVELOPE");
272

273
  h = mu_sieve_value_get (args, 0);
274 275
  if (!h)
    {
276 277
      mu_sieve_arg_error (mach, 1);
      mu_sieve_abort (mach);
278
    }
279
  v = mu_sieve_value_get (args, 1);
280 281
  if (!v)
    {
282 283
      mu_sieve_arg_error (mach, 2);
      mu_sieve_abort (mach);
284 285
    }

286 287
  mu_message_get_envelope (mu_sieve_get_message (mach), 
                           (mu_envelope_t*)&clos.data);
288 289
  clos.aget = sieve_get_address_part (tags);
  clos.addr = NULL;
290
  rc = mu_sieve_vlist_compare (h, v, comp, test, retrieve_envelope, &clos,
291
			    &count);
292
  mu_address_destroy (&clos.addr);
293
  return do_count (args, tags, count, rc);
294 295 296
}

int
297
sieve_test_size (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
298
{
299
  int rc = 1;
300
  mu_sieve_runtime_tag_t *tag = NULL;
301 302
  size_t size;
  
303
  mu_sieve_value_t *val = mu_sieve_value_get (args, 0);
304 305
  if (!val)
    {
306 307
      mu_sieve_arg_error (mach, 1);
      mu_sieve_abort (mach);
308 309
    }

310
  mu_message_size (mu_sieve_get_message (mach), &size);
311
  mu_list_get (tags, 0, (void **)&tag);
312 313
  if (!tag)
    rc = size == val->v.number;
314
  else if (strcmp (tag->tag, "over") == 0)
315
    rc = size > val->v.number;
316
  else if (strcmp (tag->tag, "under") == 0)
317 318 319
    rc = size < val->v.number;

  return rc;
320 321 322
}

int
323
sieve_test_true (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
324
{
325
  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
326
    mu_sieve_debug (mach, "TRUE");
327
  return 1;
328 329 330
}

int
331
sieve_test_false (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
332
{
333
  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
334
    mu_sieve_debug (mach, "FALSE");
335
  return 0;
336 337 338
}

int
339
_test_exists (void *item, void *data)
340
{
341
  mu_header_t hdr = data;
342 343
  size_t n;

344
  return mu_header_get_value (hdr, (char*)item, NULL, 0, &n);
345 346 347
}
  
int
348
sieve_test_exists (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
349
{
350
  mu_header_t header = NULL;
351
  mu_sieve_value_t *val;   
352 353

  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
354
    mu_sieve_debug (mach, "EXISTS");
355

356
  mu_message_get_header (mu_sieve_get_message (mach), &header);
357
  val = mu_sieve_value_get (args, 0);
358 359
  if (!val)
    {
360 361
      mu_sieve_arg_error (mach, 1);
      mu_sieve_abort (mach);
362 363
    }

364
  return mu_sieve_vlist_do (val, _test_exists, header) == 0;
365 366
}

367
static mu_sieve_tag_def_t address_part_tags[] = {
368 369 370 371 372 373
  { "localpart", SVT_VOID },
  { "domain", SVT_VOID },
  { "all", SVT_VOID },
  { NULL }
};

374
static mu_sieve_tag_def_t match_part_tags[] = {
375 376 377 378
  { "is", SVT_VOID },
  { "contains", SVT_VOID },
  { "matches", SVT_VOID },
  { "regex", SVT_VOID },
379 380
  { "count", SVT_STRING },
  { "value", SVT_STRING },
381 382 383
  { "comparator", SVT_STRING },
  { NULL }
};
384

385
static mu_sieve_tag_def_t size_tags[] = {
386 387 388 389 390
  { "over", SVT_VOID },
  { "under", SVT_VOID },
  { NULL }
};

391
static mu_sieve_tag_def_t mime_tags[] = {
392 393 394 395
  { "mime", SVT_VOID },
  { NULL }
};

396 397
#define ADDRESS_PART_GROUP \
  { address_part_tags, NULL }
398

399
#define MATCH_PART_GROUP \
Sergey Poznyakoff authored
400
  { match_part_tags, mu_sieve_match_part_checker }
401

402
#define SIZE_GROUP { size_tags, NULL }
403 404 405 406

#define MIME_GROUP \
  { mime_tags, NULL }

407
mu_sieve_tag_group_t address_tag_groups[] = {
408 409
  ADDRESS_PART_GROUP,
  MATCH_PART_GROUP,
410 411 412
  { NULL }
};

413
mu_sieve_data_type address_req_args[] = {
414 415 416 417 418
  SVT_STRING_LIST,
  SVT_STRING_LIST,
  SVT_VOID
};

419
mu_sieve_tag_group_t size_tag_groups[] = {
420
  SIZE_GROUP,
421 422 423
  { NULL }
};

424
mu_sieve_data_type size_req_args[] = {
425 426 427 428
  SVT_NUMBER,
  SVT_VOID
};

429
mu_sieve_tag_group_t envelope_tag_groups[] = {
430 431
  ADDRESS_PART_GROUP,
  MATCH_PART_GROUP,
432 433 434
  { NULL }
};

435
mu_sieve_data_type exists_req_args[] = {
436 437 438 439
  SVT_STRING_LIST,
  SVT_VOID
};

440
mu_sieve_tag_group_t header_tag_groups[] = {
441
  MATCH_PART_GROUP,
442
  MIME_GROUP,
443
  { NULL }
444 445 446
};

void
447
mu_sv_register_standard_tests (mu_sieve_machine_t mach)
448
{
449 450 451
  mu_sieve_register_test (mach, "false", sieve_test_false, NULL, NULL, 1);
  mu_sieve_register_test (mach, "true", sieve_test_true, NULL, NULL, 1);
  mu_sieve_register_test (mach, "address", sieve_test_address,
452
		       address_req_args, address_tag_groups, 1);
453
  mu_sieve_register_test (mach, "size", sieve_test_size,
454
		       size_req_args, size_tag_groups, 1);
455
  mu_sieve_register_test (mach, "envelope", sieve_test_envelope,
456
		       address_req_args, envelope_tag_groups, 1);
457
  mu_sieve_register_test (mach, "exists", sieve_test_exists,
458
		       exists_req_args, NULL, 1);
459
  mu_sieve_register_test (mach, "header", sieve_test_header,
460
		       address_req_args, header_tag_groups, 1);
461
}