~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to dovecot-sieve/src/libsieve/message.c

  • Committer: Bazaar Package Importer
  • Author(s): CHuck Short, Chuck Short
  • Date: 2009-11-06 00:47:29 UTC
  • mfrom: (4.1.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091106004729-i39n7v9e7d4h51f6
Tags: 1:1.2.6-1ubuntu1
* Merge from debian testing, remaining changes:
  Add new binary pkg dovecot-postfix that integrates postfix and dovecot
  automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restrictions
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
   + debian/dovecot-postfix.dirs: create backup directory for postfix's configuration
   + restart postfix and dovecot.
   + debian/dovecot-postfix.postrm:
     - remove all dovecot related configuration from postfix.
     - restart postfix and dovecot.
   + debian/dovecot-common.init:
     - check if /etc/dovecot/dovecot-postfix.conf exists and use it
       as the configuration file if so.
   + debian/patches/warning-ubuntu-postfix.dpatch
     - add warning about dovecot-postfix.conf in dovecot default 
       configuration file
   + debian/patches/dovecot-postfix.conf.diff:
     - Ubuntu server custom changes to the default dovecot configuration for
       better interfation with postfix
     - enable sieve plugin
   + debian/patches/dovecot-postfix.conf.diff:
     + Ubuntu server custom changes to the default dovecot configuration for
       better integration with postfix:
       - enable imap, pop3, imaps, pop3s and managesieve by default.
       - enable dovecot LDA (deliver).
       - enable SASL auth socket in postfix private directory.
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules:
       + install profile
     - debian/control:
       + Suggest ufw
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). LP: #254721
   + debian/control:
     - Update Vcs-* headers.
   + debian/rules:
     - Create emtpy stamp.h.in files in dovecot-sieve/ and dovecot-managesieve/
       if they're not there since empty files are not included in the diff.gz 
       file.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
   + Dropped:
     - debian/patches/security-CVE-2009-3235: Applied upstream.
     - debian/patches/fix-pop3-assertion.dpatch: Applied upstream.
     - dovecot-sieve and dovecot-managesieve: Use the debian patches instead.

  [Chuck Short]
  - Updated dovecot-sieve to 0.1.13.
  - Updated dovecot-managesieve to 0.11.9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* message.c -- message parsing functions
2
 
 * Larry Greenfield
3
 
 * $Id$
4
 
 */
5
 
/***********************************************************
6
 
        Copyright 1999 by Carnegie Mellon University
7
 
 
8
 
                      All Rights Reserved
9
 
 
10
 
Permission to use, copy, modify, and distribute this software and its
11
 
documentation for any purpose and without fee is hereby granted,
12
 
provided that the above copyright notice appear in all copies and that
13
 
both that copyright notice and this permission notice appear in
14
 
supporting documentation, and that the name of Carnegie Mellon
15
 
University not be used in advertising or publicity pertaining to
16
 
distribution of the software without specific, written prior
17
 
permission.
18
 
 
19
 
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
20
 
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 
FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
22
 
ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23
 
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24
 
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
25
 
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
 
******************************************************************/
27
 
 
28
 
#ifdef HAVE_CONFIG_H
29
 
#include <config.h>
30
 
#endif
31
 
 
32
 
#include <stdlib.h>
33
 
#include <unistd.h>
34
 
#include <sys/mman.h>
35
 
#include <sys/stat.h>
36
 
#include <sys/types.h>
37
 
#include <sys/stat.h>
38
 
#include <fcntl.h>
39
 
#include <string.h>
40
 
 
41
 
#include "lib.h"
42
 
#include "md5.h"
43
 
#include "sieve_interface.h"
44
 
#include "interp.h"
45
 
#include "message.h"
46
 
#include "parseaddr.h"
47
 
#include "xmalloc.h"
48
 
 
49
 
/* reject message m with message msg
50
 
 *
51
 
 * incompatible with: fileinto, redirect
52
 
 */
53
 
int do_reject(action_list_t *a, const char *msg)
54
 
{
55
 
    action_list_t *b = NULL;
56
 
 
57
 
    /* see if this conflicts with any previous actions taken on this message */
58
 
    while (a != NULL) {
59
 
        b = a;
60
 
        if (a->a == ACTION_FILEINTO ||
61
 
            a->a == ACTION_KEEP ||
62
 
            a->a == ACTION_REDIRECT ||
63
 
            a->a == ACTION_REJECT ||
64
 
            a->a == ACTION_VACATION ||
65
 
            a->a == ACTION_SETFLAG ||
66
 
            a->a == ACTION_ADDFLAG ||
67
 
            a->a == ACTION_REMOVEFLAG ||
68
 
            a->a == ACTION_MARK ||
69
 
            a->a == ACTION_UNMARK
70
 
            )
71
 
            return SIEVE_RUN_ERROR;
72
 
        a = a->next;
73
 
    }
74
 
 
75
 
    /* add to the action list */
76
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
77
 
    if (a == NULL)
78
 
        return SIEVE_NOMEM;
79
 
    a->a = ACTION_REJECT;
80
 
    a->cancel_keep = 1;
81
 
    a->u.rej.msg = msg;
82
 
    b->next = a;
83
 
    a->next =  NULL;
84
 
    return 0;
85
 
}
86
 
 
87
 
/* fileinto message m into mailbox 
88
 
 *
89
 
 * incompatible with: reject
90
 
 */
91
 
int do_fileinto(action_list_t *a, const char *mbox, int cancel_keep,
92
 
                sieve_imapflags_t *imapflags)
93
 
{
94
 
    action_list_t *b = NULL;
95
 
 
96
 
    /* see if this conflicts with any previous actions taken on this message */
97
 
    while (a != NULL) {
98
 
        b = a;
99
 
        if (a->a == ACTION_REJECT)
100
 
            return SIEVE_RUN_ERROR;
101
 
        a = a->next;
102
 
    }
103
 
 
104
 
    /* add to the action list */
105
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
106
 
    if (a == NULL)
107
 
        return SIEVE_NOMEM;
108
 
    a->a = ACTION_FILEINTO;
109
 
    a->cancel_keep = cancel_keep;
110
 
    a->u.fil.mailbox = mbox;
111
 
    a->u.fil.imapflags = imapflags;
112
 
    b->next = a;
113
 
    a->next = NULL;
114
 
    return 0;
115
 
}
116
 
 
117
 
/* redirect message m to to addr
118
 
 *
119
 
 * incompatible with: reject
120
 
 */
121
 
int do_redirect(action_list_t *a, const char *addr, int cancel_keep)
122
 
{
123
 
    action_list_t *b = NULL;
124
 
 
125
 
    /* xxx we should validate addr */
126
 
 
127
 
    /* see if this conflicts with any previous actions taken on this message */
128
 
    while (a != NULL) {
129
 
        b = a;
130
 
        if (a->a == ACTION_REJECT)
131
 
            return SIEVE_RUN_ERROR;
132
 
        a = a->next;
133
 
    }
134
 
 
135
 
    /* add to the action list */
136
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
137
 
    if (a == NULL)
138
 
        return SIEVE_NOMEM;
139
 
    a->a = ACTION_REDIRECT;
140
 
    a->cancel_keep = cancel_keep;
141
 
    a->u.red.addr = addr;
142
 
    a->next = NULL;
143
 
    b->next = a;
144
 
    return 0;
145
 
}
146
 
 
147
 
/* keep message
148
 
 *
149
 
 * incompatible with: reject
150
 
 */
151
 
int do_keep(action_list_t *a, sieve_imapflags_t *imapflags)
152
 
{
153
 
    action_list_t *b = NULL;
154
 
 
155
 
    /* see if this conflicts with any previous actions taken on this message */
156
 
    while (a != NULL) {
157
 
        b = a;
158
 
        if (a->a == ACTION_REJECT)
159
 
            return SIEVE_RUN_ERROR;
160
 
        if (a->a == ACTION_KEEP) /* don't bother doing it twice */
161
 
            return 0;
162
 
        a = a->next;
163
 
    }
164
 
 
165
 
    /* add to the action list */
166
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
167
 
    if (a == NULL)
168
 
        return SIEVE_NOMEM;
169
 
    a->a = ACTION_KEEP;
170
 
    a->cancel_keep = 1;
171
 
    a->u.keep.imapflags = imapflags;
172
 
    a->next = NULL;
173
 
    b->next = a;
174
 
    return 0;
175
 
}
176
 
 
177
 
/* discard message m
178
 
 *
179
 
 * incompatible with: nothing---it doesn't cancel any actions
180
 
 */
181
 
int do_discard(action_list_t *a)
182
 
{
183
 
    action_list_t *b = NULL;
184
 
 
185
 
    /* see if this conflicts with any previous actions taken on this message */
186
 
    while (a != NULL) {
187
 
        b = a;
188
 
        if (a->a == ACTION_DISCARD) /* don't bother doing twice */
189
 
            return 0;
190
 
        a = a->next;
191
 
    }
192
 
 
193
 
    /* add to the action list */
194
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
195
 
    if (a == NULL)
196
 
        return SIEVE_NOMEM;
197
 
    a->a = ACTION_DISCARD;
198
 
    a->cancel_keep = 1;
199
 
    a->next = NULL;
200
 
    b->next = a;
201
 
    return 0;
202
 
}
203
 
 
204
 
static int makehash(unsigned char hash[],
205
 
                    const char *s1, const char *s2, const char *s3)
206
 
{
207
 
    struct md5_context ctx;
208
 
 
209
 
    md5_init(&ctx);
210
 
    md5_update(&ctx, s1, strlen(s1));
211
 
    md5_update(&ctx, s2, strlen(s2));
212
 
    if (s3) md5_update(&ctx, s3, strlen(s3));
213
 
    md5_final(&ctx, hash);
214
 
 
215
 
    return SIEVE_OK;
216
 
}
217
 
 
218
 
int do_vacation(action_list_t *a, char *addr, char *fromaddr,
219
 
                char *subj, const char *msg, int days,
220
 
                int mime, const char *handle)
221
 
{
222
 
    action_list_t *b = NULL;
223
 
 
224
 
    /* see if this conflicts with any previous actions taken on this message */
225
 
    while (a != NULL) {
226
 
        b = a;
227
 
        if (a->a == ACTION_REJECT ||
228
 
            a->a == ACTION_VACATION) /* vacation can't be used twice */
229
 
            return SIEVE_RUN_ERROR;
230
 
        a = a->next;
231
 
    }
232
 
 
233
 
    /* add to the action list */
234
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
235
 
    if (a == NULL)
236
 
        return SIEVE_NOMEM;
237
 
    a->a = ACTION_VACATION;
238
 
    a->cancel_keep = 0;
239
 
    a->u.vac.send.addr = addr;
240
 
    a->u.vac.send.fromaddr = fromaddr;
241
 
    a->u.vac.send.subj = subj;  /* user specified subject */
242
 
    a->u.vac.send.msg = msg;
243
 
    a->u.vac.send.mime = mime;
244
 
    if (handle)
245
 
        makehash(a->u.vac.autoresp.hash, addr, handle, NULL);
246
 
    else
247
 
        makehash(a->u.vac.autoresp.hash, addr, fromaddr, msg);
248
 
    a->u.vac.autoresp.days = days;
249
 
    a->next = NULL;
250
 
    b->next = a;
251
 
    return 0;
252
 
}
253
 
 
254
 
/* setflag f on message m
255
 
 *
256
 
 * incompatible with: reject
257
 
 */
258
 
int do_setflag(action_list_t *a, const char *flag)
259
 
{
260
 
    action_list_t *b = NULL;
261
 
 
262
 
    /* see if this conflicts with any previous actions taken on this message */
263
 
    while (a != NULL) {
264
 
        b = a;
265
 
        if (a->a == ACTION_REJECT)
266
 
            return SIEVE_RUN_ERROR;
267
 
        a = a->next;
268
 
    }
269
 
 
270
 
    /* add to the action list */
271
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
272
 
    if (a == NULL)
273
 
        return SIEVE_NOMEM;
274
 
    a->a = ACTION_SETFLAG;
275
 
    a->cancel_keep = 0;
276
 
    a->u.fla.flag = flag;
277
 
    b->next = a;
278
 
    a->next = NULL;
279
 
    return 0;
280
 
}
281
 
 
282
 
/* addflag f on message m
283
 
 *
284
 
 * incompatible with: reject
285
 
 */
286
 
int do_addflag(action_list_t *a, const char *flag)
287
 
{
288
 
    action_list_t *b = NULL;
289
 
 
290
 
    /* see if this conflicts with any previous actions taken on this message */
291
 
    while (a != NULL) {
292
 
        b = a;
293
 
        if (a->a == ACTION_REJECT)
294
 
            return SIEVE_RUN_ERROR;
295
 
        a = a->next;
296
 
    }
297
 
 
298
 
    /* add to the action list */
299
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
300
 
    if (a == NULL)
301
 
        return SIEVE_NOMEM;
302
 
    a->a = ACTION_ADDFLAG;
303
 
    a->cancel_keep = 0;
304
 
    a->u.fla.flag = flag;
305
 
    b->next = a;
306
 
    a->next = NULL;
307
 
    return 0;
308
 
}
309
 
 
310
 
/* removeflag f on message m
311
 
 *
312
 
 * incompatible with: reject
313
 
 */
314
 
int do_removeflag(action_list_t *a, const char *flag)
315
 
{
316
 
    action_list_t *b = NULL;
317
 
 
318
 
    /* see if this conflicts with any previous actions taken on this message */
319
 
    while (a != NULL) {
320
 
        b = a;
321
 
        if (a->a == ACTION_REJECT)
322
 
            return SIEVE_RUN_ERROR;
323
 
        a = a->next;
324
 
    }
325
 
 
326
 
    /* add to the action list */
327
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
328
 
    if (a == NULL)
329
 
        return SIEVE_NOMEM;
330
 
    a->a = ACTION_REMOVEFLAG;
331
 
    a->cancel_keep = 0;
332
 
    a->u.fla.flag = flag;
333
 
    b->next = a;
334
 
    a->next = NULL;
335
 
    return 0;
336
 
}
337
 
 
338
 
 
339
 
/* mark message m
340
 
 *
341
 
 * incompatible with: reject
342
 
 */
343
 
int do_mark(action_list_t *a)
344
 
{
345
 
    action_list_t *b = NULL;
346
 
 
347
 
    /* see if this conflicts with any previous actions taken on this message */
348
 
    while (a != NULL) {
349
 
        b = a;
350
 
        if (a->a == ACTION_REJECT)
351
 
            return SIEVE_RUN_ERROR;
352
 
        a = a->next;
353
 
    }
354
 
 
355
 
    /* add to the action list */
356
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
357
 
    if (a == NULL)
358
 
        return SIEVE_NOMEM;
359
 
    a->a = ACTION_MARK;
360
 
    a->cancel_keep = 0;
361
 
    b->next = a;
362
 
    a->next = NULL;
363
 
    return 0;
364
 
}
365
 
 
366
 
 
367
 
/* unmark message m
368
 
 *
369
 
 * incompatible with: reject
370
 
 */
371
 
int do_unmark(action_list_t *a)
372
 
{
373
 
 
374
 
    action_list_t *b = NULL;
375
 
    /* see if this conflicts with any previous actions taken on this message */
376
 
    while (a != NULL) {
377
 
        b = a;
378
 
        if (a->a == ACTION_REJECT)
379
 
            return SIEVE_RUN_ERROR;
380
 
        a = a->next;
381
 
    }
382
 
 
383
 
    /* add to the action list */
384
 
    a = (action_list_t *) xmalloc(sizeof(action_list_t));
385
 
    if (a == NULL)
386
 
        return SIEVE_NOMEM;
387
 
    a->a = ACTION_UNMARK;
388
 
    a->cancel_keep = 0;
389
 
    b->next = a;
390
 
    a->next = NULL;
391
 
    return 0;
392
 
}
393
 
 
394
 
/* notify
395
 
 *
396
 
 * incompatible with: none
397
 
 */
398
 
int do_notify(notify_list_t *a, const char *id,
399
 
              const char *method, const char **options,
400
 
              const char *priority, const char *message)
401
 
{
402
 
    notify_list_t *b = NULL;
403
 
 
404
 
    /* find the end of the notify list */
405
 
    while (a != NULL) {
406
 
        b = a;
407
 
        a = a->next;
408
 
    }
409
 
 
410
 
    /* add to the notify list */
411
 
    a = (notify_list_t *) xmalloc(sizeof(notify_list_t));
412
 
    if (a == NULL)
413
 
        return SIEVE_NOMEM;
414
 
 
415
 
    b->next = a;
416
 
    a->isactive = 1;
417
 
    a->id = id;
418
 
    a->method = method;
419
 
    a->options = options;
420
 
    a->priority = priority;
421
 
    a->message = message;
422
 
    a->next = NULL;
423
 
    return 0;
424
 
}
425
 
 
426
 
/* denotify
427
 
 *
428
 
 * incomaptible with: none
429
 
 */
430
 
int do_denotify(notify_list_t *n, comparator_t *comp, const void *pat,
431
 
                void *comprock, const char *priority)
432
 
{
433
 
    while (n != NULL) {
434
 
        if (n->isactive && 
435
 
            (!priority || !strcasecmp(n->priority, priority)) &&
436
 
            (!comp || (n->id && comp(n->id, strlen(n->id), pat, comprock)))) {
437
 
            n->isactive = 0;
438
 
        }
439
 
        n = n->next;
440
 
    }
441
 
 
442
 
    return 0;
443
 
}
444
 
 
445
 
 
446
 
 
447
 
/* given a header, extract an address out of it.  if marker points to NULL,
448
 
   extract the first address.  otherwise, it's an index into the header to
449
 
   say where to start extracting */
450
 
struct addr_marker {
451
 
    struct address *where;
452
 
    char *freeme;
453
 
};
454
 
 
455
 
int parse_address(const char *header, void **data, void **marker)
456
 
{
457
 
    struct addr_marker *am = (struct addr_marker *) *marker;
458
 
 
459
 
    parseaddr_list(header, (struct address **) data);
460
 
    am = (void *) xmalloc(sizeof(struct addr_marker));
461
 
    am->where = *data;
462
 
    am->freeme = NULL;
463
 
    *marker = am;
464
 
    return SIEVE_OK;
465
 
}
466
 
 
467
 
char *get_address(address_part_t addrpart,
468
 
                  void **data ATTR_UNUSED,
469
 
                  void **marker,
470
 
                  int canon_domain)
471
 
{
472
 
    char *ret = NULL;
473
 
    struct address *a;
474
 
    struct addr_marker *am = *marker;
475
 
 
476
 
    a = am->where;
477
 
    if (am->freeme) {
478
 
        free(am->freeme);
479
 
        am->freeme = NULL;
480
 
    }
481
 
 
482
 
    if (a == NULL) {
483
 
        ret = NULL;
484
 
    } else {
485
 
        if (canon_domain && a->domain)
486
 
            lcase(a->domain);
487
 
 
488
 
        switch (addrpart) { 
489
 
        case ADDRESS_ALL:
490
 
#define U_DOMAIN "unspecified-domain"
491
 
#define U_USER "unknown-user"
492
 
            if (a->mailbox || a->domain) {
493
 
                char *m = a->mailbox ? a->mailbox : U_USER;
494
 
                char *d = a->domain ? a->domain : U_DOMAIN;
495
 
                am->freeme = (char *) xmalloc(strlen(m) + strlen(d) + 2);
496
 
 
497
 
                sprintf(am->freeme, "%s@%s", m, d);
498
 
                ret = am->freeme;
499
 
            } else {
500
 
                ret = NULL;
501
 
            }
502
 
            break;
503
 
 
504
 
        case ADDRESS_LOCALPART:
505
 
            ret = a->mailbox;
506
 
            break;
507
 
            
508
 
        case ADDRESS_DOMAIN:
509
 
            ret = a->domain;
510
 
            break;
511
 
 
512
 
        case ADDRESS_USER:
513
 
            if (a->mailbox) {
514
 
                char *p = strchr(a->mailbox, '+');
515
 
                int len = p ? p - a->mailbox : (int)strlen(a->mailbox);
516
 
 
517
 
                am->freeme = (char *) xmalloc(len + 1);
518
 
                strncpy(am->freeme, a->mailbox, len);
519
 
                am->freeme[len] = '\0';
520
 
                ret = am->freeme;
521
 
            } else {
522
 
                ret = NULL;
523
 
            }
524
 
            break;
525
 
 
526
 
        case ADDRESS_DETAIL:
527
 
            if (a->mailbox)
528
 
            {       
529
 
                char *p = strchr(a->mailbox, '+');
530
 
                ret = (p ? p + 1 : NULL);
531
 
            }
532
 
            else
533
 
            {
534
 
                ret = NULL;
535
 
            }
536
 
            break;
537
 
        }
538
 
        a = a->next;
539
 
        am->where = a;
540
 
    }
541
 
    *marker = am;
542
 
    return ret;
543
 
}
544
 
 
545
 
int free_address(void **data, void **marker)
546
 
{
547
 
    struct addr_marker *am = (struct addr_marker *) *marker;
548
 
 
549
 
    if (*data)
550
 
        parseaddr_free((struct address *) *data);
551
 
    *data = NULL;
552
 
    if (am->freeme) free(am->freeme);
553
 
    free(am);
554
 
    *marker = NULL;
555
 
    return SIEVE_OK;
556
 
}
557
 
 
558
 
notify_list_t *new_notify_list(void)    
559
 
{
560
 
    notify_list_t *ret = xmalloc(sizeof(notify_list_t));
561
 
 
562
 
    if (ret != NULL) {
563
 
        ret->isactive = 0;
564
 
        ret->id       = NULL;
565
 
        ret->method   = NULL;
566
 
        ret->options  = NULL;
567
 
        ret->priority = NULL;
568
 
        ret->message  = NULL;
569
 
        ret->next     = NULL;
570
 
    }
571
 
    return ret;
572
 
}
573
 
 
574
 
void free_notify_list(notify_list_t *n)
575
 
{
576
 
    while (n) {
577
 
        notify_list_t *b = n->next;
578
 
        free(n->options); /* strings live in bytecode, only free the array */
579
 
        free(n);
580
 
        n = b;
581
 
    }
582
 
}
583
 
 
584
 
action_list_t *new_action_list(void)
585
 
{
586
 
    action_list_t *ret = xmalloc(sizeof(action_list_t));
587
 
 
588
 
    if (ret != NULL) {
589
 
        ret->a = ACTION_NONE;
590
 
        ret->param = NULL;
591
 
        ret->next = NULL;
592
 
        ret->cancel_keep = 0;
593
 
    }
594
 
    return ret;
595
 
}
596
 
 
597
 
void free_action_list(action_list_t *a)
598
 
{
599
 
    while (a) {
600
 
        action_list_t *b = a->next;
601
 
 
602
 
        if(a->a == ACTION_VACATION) {
603
 
            if(a->u.vac.send.subj) free(a->u.vac.send.subj);
604
 
            if(a->u.vac.send.addr) free(a->u.vac.send.addr);
605
 
            if(a->u.vac.send.fromaddr) free(a->u.vac.send.fromaddr);
606
 
        }
607
 
 
608
 
        free(a);
609
 
        a = b;
610
 
    }
611
 
}
612