~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/exchange/lib/e2k-action.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
 
3
 
/* Copyright (C) 2002-2004 Novell, Inc.
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or
6
 
 * modify it under the terms of version 2 of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation.
8
 
 *
9
 
 * This program is distributed in the hope that it will be useful,
10
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 
 * General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU Lesser General Public
15
 
 * License along with this program; if not, write to the
16
 
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
 
 * Boston, MA 02110-1301, USA.
18
 
 */
19
 
 
20
 
/* e2k-action.c: Exchange server-side rule actions */
21
 
 
22
 
#ifdef HAVE_CONFIG_H
23
 
#include <config.h>
24
 
#endif
25
 
 
26
 
#include <string.h>
27
 
 
28
 
#include "e2k-action.h"
29
 
#include "e2k-propnames.h"
30
 
#include "e2k-restriction.h"
31
 
#include "e2k-rule.h"
32
 
#include "e2k-utils.h"
33
 
#include "mapi.h"
34
 
 
35
 
/* The apparently-constant store entryid prefix for a move or copy action */
36
 
#define E2K_ACTION_XFER_STORE_ENTRYID_PREFIX "\x00\x00\x00\x00\x38\xa1\xbb\x10\x05\xe5\x10\x1a\xa1\xbb\x08\x00\x2b\x2a\x56\xc2\x00\x00\x45\x4d\x53\x4d\x44\x42\x2e\x44\x4c\x4c\x00\x00\x00\x00"
37
 
#define E2K_ACTION_XFER_STORE_ENTRYID_PREFIX_LEN (sizeof (E2K_ACTION_XFER_STORE_ENTRYID_PREFIX) - 1)
38
 
 
39
 
static GByteArray *
40
 
copy_bytearray (GByteArray *ba)
41
 
{
42
 
        GByteArray *copy;
43
 
 
44
 
        copy = g_byte_array_sized_new (ba->len);
45
 
        copy->len = ba->len;
46
 
        memcpy (copy->data, ba->data, copy->len);
47
 
 
48
 
        return copy;
49
 
}
50
 
 
51
 
static E2kAction *
52
 
xfer_action (E2kActionType type, GByteArray *store_entryid,
53
 
             GByteArray *folder_source_key)
54
 
{
55
 
        E2kAction *act;
56
 
 
57
 
        act = g_new0 (E2kAction, 1);
58
 
        act->type = type;
59
 
        act->act.xfer.store_entryid = copy_bytearray (store_entryid);
60
 
        act->act.xfer.folder_source_key = copy_bytearray (folder_source_key);
61
 
 
62
 
        return act;
63
 
}
64
 
 
65
 
/**
66
 
 * e2k_action_move:
67
 
 * @store_entryid: The PR_STORE_ENTRYID of the message store
68
 
 * @folder_source_key: The PR_SOURCE_KEY of a folder in that store
69
 
 *
70
 
 * Creates a rule action to move a message into the indicated folder
71
 
 *
72
 
 * Return value: the new rule action
73
 
 **/
74
 
E2kAction *
75
 
e2k_action_move (GByteArray *store_entryid, GByteArray *folder_source_key)
76
 
{
77
 
        return xfer_action (E2K_ACTION_MOVE, store_entryid, folder_source_key);
78
 
}
79
 
 
80
 
/**
81
 
 * e2k_action_copy:
82
 
 * @store_entryid: The PR_STORE_ENTRYID of the message store
83
 
 * @folder_source_key: The PR_SOURCE_KEY of a folder in that store
84
 
 *
85
 
 * Creates a rule action to copy a message into the indicated folder
86
 
 *
87
 
 * Return value: the new rule action
88
 
 **/
89
 
E2kAction *
90
 
e2k_action_copy (GByteArray *store_entryid, GByteArray *folder_source_key)
91
 
{
92
 
        return xfer_action (E2K_ACTION_COPY, store_entryid, folder_source_key);
93
 
}
94
 
 
95
 
static E2kAction *
96
 
reply_action (E2kActionType type, GByteArray *template_entryid,
97
 
              guint8 template_guid[16])
98
 
{
99
 
        E2kAction *act;
100
 
 
101
 
        act = g_new0 (E2kAction, 1);
102
 
        act->type = type;
103
 
        act->act.reply.entryid = copy_bytearray (template_entryid);
104
 
        memcpy (act->act.reply.reply_template_guid, template_guid, 16);
105
 
 
106
 
        return act;
107
 
}
108
 
 
109
 
/**
110
 
 * e2k_action_reply:
111
 
 * @template_entryid: The entryid of the reply template
112
 
 * @template_guid: The GUID of the reply template
113
 
 *
114
 
 * Creates a rule action to reply to a message using the indicated
115
 
 * template
116
 
 *
117
 
 * Return value: the new rule action
118
 
 **/
119
 
E2kAction *
120
 
e2k_action_reply (GByteArray *template_entryid, guint8 template_guid[16])
121
 
{
122
 
        return reply_action (E2K_ACTION_REPLY, template_entryid, template_guid);
123
 
}
124
 
 
125
 
/**
126
 
 * e2k_action_oof_reply:
127
 
 * @template_entryid: The entryid of the reply template
128
 
 * @template_guid: The GUID of the reply template
129
 
 *
130
 
 * Creates a rule action to send an Out-of-Office reply to a message
131
 
 * using the indicated template
132
 
 *
133
 
 * Return value: the new rule action
134
 
 **/
135
 
E2kAction *
136
 
e2k_action_oof_reply (GByteArray *template_entryid, guint8 template_guid[16])
137
 
{
138
 
        return reply_action (E2K_ACTION_OOF_REPLY, template_entryid, template_guid);
139
 
}
140
 
 
141
 
/**
142
 
 * e2k_action_defer:
143
 
 * @data: data identifying the deferred action
144
 
 *
145
 
 * Creates a rule action to defer processing on a message
146
 
 *
147
 
 * Return value: the new rule action
148
 
 **/
149
 
E2kAction *
150
 
e2k_action_defer (GByteArray *data)
151
 
{
152
 
        E2kAction *act;
153
 
 
154
 
        act = g_new0 (E2kAction, 1);
155
 
        act->type = E2K_ACTION_DEFER;
156
 
        act->act.defer_data = copy_bytearray (data);
157
 
 
158
 
        return act;
159
 
}
160
 
 
161
 
/**
162
 
 * e2k_action_bounce:
163
 
 * @bounce_code: a bounce code
164
 
 *
165
 
 * Creates a rule action to bounce a message
166
 
 *
167
 
 * Return value: the new rule action
168
 
 **/
169
 
E2kAction *
170
 
e2k_action_bounce (E2kActionBounceCode bounce_code)
171
 
{
172
 
        E2kAction *act;
173
 
 
174
 
        act = g_new0 (E2kAction, 1);
175
 
        act->type = E2K_ACTION_BOUNCE;
176
 
        act->act.bounce_code = bounce_code;
177
 
 
178
 
        return act;
179
 
}
180
 
 
181
 
static E2kAction *
182
 
forward_action (E2kActionType type, E2kAddrList *list)
183
 
{
184
 
        E2kAction *act;
185
 
 
186
 
        g_return_val_if_fail (type == E2K_ACTION_FORWARD || type == E2K_ACTION_DELEGATE, NULL);
187
 
        g_return_val_if_fail (list->nentries > 0, NULL);
188
 
 
189
 
        act = g_new0 (E2kAction, 1);
190
 
        act->type = type;
191
 
        act->act.addr_list = list;
192
 
 
193
 
        return act;
194
 
}
195
 
 
196
 
/**
197
 
 * e2k_action_forward:
198
 
 * @list: a list of recipients
199
 
 *
200
 
 * Creates a rule action to forward a message to the indicated list of
201
 
 * recipients
202
 
 *
203
 
 * Return value: the new rule action
204
 
 **/
205
 
E2kAction *
206
 
e2k_action_forward (E2kAddrList *list)
207
 
{
208
 
        return forward_action (E2K_ACTION_FORWARD, list);
209
 
}
210
 
 
211
 
/**
212
 
 * e2k_action_delegate:
213
 
 * @list: a list of recipients
214
 
 *
215
 
 * Creates a rule action to delegate a meeting request to the
216
 
 * indicated list of recipients
217
 
 *
218
 
 * Return value: the new rule action
219
 
 **/
220
 
E2kAction *
221
 
e2k_action_delegate (E2kAddrList *list)
222
 
{
223
 
        return forward_action (E2K_ACTION_DELEGATE, list);
224
 
}
225
 
 
226
 
/**
227
 
 * e2k_action_tag:
228
 
 * @propname: a MAPI property name
229
 
 * @type: the type of @propname
230
 
 * @value: the value for @propname
231
 
 *
232
 
 * Creates a rule action to set the given property to the given value
233
 
 * on a message.
234
 
 *
235
 
 * Return value: the new rule action
236
 
 **/
237
 
E2kAction *
238
 
e2k_action_tag (const gchar *propname, E2kPropType type, gpointer value)
239
 
{
240
 
        E2kAction *act;
241
 
 
242
 
        act = g_new0 (E2kAction, 1);
243
 
        act->type = E2K_ACTION_TAG;
244
 
        e2k_rule_prop_set (&act->act.proptag.prop, propname);
245
 
        act->act.proptag.type = type;
246
 
        act->act.proptag.value = value; /* FIXME: copy? */
247
 
 
248
 
        return act;
249
 
}
250
 
 
251
 
/**
252
 
 * e2k_action_delete:
253
 
 *
254
 
 * Creates a rule action to permanently delete a message (ie, not just
255
 
 * move it to the trash).
256
 
 *
257
 
 * Return value: the new rule action
258
 
 **/
259
 
E2kAction *
260
 
e2k_action_delete (void)
261
 
{
262
 
        E2kAction *act;
263
 
 
264
 
        act = g_new0 (E2kAction, 1);
265
 
        act->type = E2K_ACTION_DELETE;
266
 
 
267
 
        return act;
268
 
}
269
 
 
270
 
/**
271
 
 * e2k_addr_list_new:
272
 
 * @nentries: the number of entries
273
 
 *
274
 
 * Creates an address list for a forward or delegate rule, with
275
 
 * @nentries slots
276
 
 *
277
 
 * Return value: the new address list
278
 
 **/
279
 
E2kAddrList *
280
 
e2k_addr_list_new (gint nentries)
281
 
{
282
 
        E2kAddrList *list;
283
 
 
284
 
        list = g_malloc0 (sizeof (E2kAddrList) +
285
 
                          (nentries - 1) * sizeof (E2kAddrEntry));
286
 
        list->nentries = nentries;
287
 
 
288
 
        return list;
289
 
}
290
 
 
291
 
static void
292
 
addr_entry_set_core (E2kPropValue *pv, GByteArray *entryid,
293
 
                     const gchar *display_name, const gchar *email_type,
294
 
                     const gchar *email_addr)
295
 
{
296
 
        e2k_rule_prop_set (&pv[0].prop, PR_ENTRYID);
297
 
        pv[0].type = E2K_PROP_TYPE_BINARY;
298
 
        pv[0].value = entryid;
299
 
 
300
 
        e2k_rule_prop_set (&pv[1].prop, PR_DISPLAY_NAME);
301
 
        pv[1].type = E2K_PROP_TYPE_STRING;
302
 
        pv[1].value = g_strdup (display_name);
303
 
 
304
 
        e2k_rule_prop_set (&pv[2].prop, PR_OBJECT_TYPE);
305
 
        pv[2].type = E2K_PROP_TYPE_INT;
306
 
        pv[2].value = GINT_TO_POINTER (MAPI_MAILUSER);
307
 
 
308
 
        e2k_rule_prop_set (&pv[3].prop, PR_DISPLAY_TYPE);
309
 
        pv[3].type = E2K_PROP_TYPE_INT;
310
 
        pv[3].value = GINT_TO_POINTER (DT_MAILUSER);
311
 
 
312
 
        e2k_rule_prop_set (&pv[4].prop, PR_TRANSMITTABLE_DISPLAY_NAME);
313
 
        pv[4].type = E2K_PROP_TYPE_STRING;
314
 
        pv[4].value = g_strdup (display_name);
315
 
 
316
 
        e2k_rule_prop_set (&pv[5].prop, PR_EMAIL_ADDRESS);
317
 
        pv[5].type = E2K_PROP_TYPE_STRING;
318
 
        pv[5].value = g_strdup (email_addr);
319
 
 
320
 
        e2k_rule_prop_set (&pv[6].prop, PR_ADDRTYPE);
321
 
        pv[6].type = E2K_PROP_TYPE_STRING;
322
 
        pv[6].value = g_strdup (email_type);
323
 
 
324
 
        e2k_rule_prop_set (&pv[7].prop, PR_SEND_INTERNET_ENCODING);
325
 
        pv[7].type = E2K_PROP_TYPE_INT;
326
 
        pv[7].value = GINT_TO_POINTER (0); /* "Let transport decide" */
327
 
 
328
 
        e2k_rule_prop_set (&pv[8].prop, PR_RECIPIENT_TYPE);
329
 
        pv[8].type = E2K_PROP_TYPE_INT;
330
 
        pv[8].value = GINT_TO_POINTER (MAPI_TO);
331
 
 
332
 
        e2k_rule_prop_set (&pv[9].prop, PR_SEARCH_KEY);
333
 
        pv[9].type = E2K_PROP_TYPE_BINARY;
334
 
        pv[9].value = e2k_search_key_generate (email_type, email_addr);
335
 
}
336
 
 
337
 
/**
338
 
 * e2k_addr_list_set_local:
339
 
 * @list: the address list
340
 
 * @entry_num: the list entry to set
341
 
 * @display_name: the UTF-8 display name of the recipient
342
 
 * @exchange_dn: the Exchange 5.5-style DN of the recipient
343
 
 * @email: the SMTP email address of the recipient
344
 
 *
345
 
 * Sets entry number @entry_num of @list to refer to the indicated
346
 
 * local Exchange user.
347
 
 **/
348
 
void
349
 
e2k_addr_list_set_local (E2kAddrList *list, gint entry_num,
350
 
                         const gchar *display_name,
351
 
                         const gchar *exchange_dn,
352
 
                         const gchar *email)
353
 
{
354
 
        E2kPropValue *pv;
355
 
 
356
 
        list->entry[entry_num].nvalues = 12;
357
 
        list->entry[entry_num].propval = pv = g_new0 (E2kPropValue, 12);
358
 
 
359
 
        addr_entry_set_core (pv, e2k_entryid_generate_local (exchange_dn),
360
 
                             display_name, "EX", exchange_dn);
361
 
 
362
 
        e2k_rule_prop_set (&pv[10].prop, PR_EMS_AB_DISPLAY_NAME_PRINTABLE);
363
 
        pv[10].type = E2K_PROP_TYPE_STRING;
364
 
        pv[10].value = g_strdup ("FIXME");
365
 
 
366
 
        e2k_rule_prop_set (&pv[11].prop, PR_SMTP_ADDRESS);
367
 
        pv[11].type = E2K_PROP_TYPE_STRING;
368
 
        pv[11].value = g_strdup (email);
369
 
}
370
 
 
371
 
/**
372
 
 * e2k_addr_list_set_oneoff:
373
 
 * @list: the address list
374
 
 * @entry_num: the list entry to set
375
 
 * @display_name: the UTF-8 display name of the recipient
376
 
 * @email: the SMTP email address of the recipient
377
 
 *
378
 
 * Sets entry number @entry_num of @list to refer to the indicated
379
 
 * "one-off" SMTP user.
380
 
 **/
381
 
void
382
 
e2k_addr_list_set_oneoff (E2kAddrList *list, gint entry_num,
383
 
                          const gchar *display_name, const gchar *email)
384
 
{
385
 
        E2kPropValue *pv;
386
 
 
387
 
        list->entry[entry_num].nvalues = 12;
388
 
        list->entry[entry_num].propval = pv = g_new0 (E2kPropValue, 12);
389
 
 
390
 
        addr_entry_set_core (pv, e2k_entryid_generate_oneoff (display_name, email, TRUE),
391
 
                             display_name, "SMTP", email);
392
 
 
393
 
        e2k_rule_prop_set (&pv[10].prop, PR_SEND_RICH_INFO);
394
 
        pv[10].type = E2K_PROP_TYPE_BOOL;
395
 
        pv[10].value = GINT_TO_POINTER (FALSE);
396
 
 
397
 
        e2k_rule_prop_set (&pv[11].prop, PR_RECORD_KEY);
398
 
        pv[11].type = E2K_PROP_TYPE_BINARY;
399
 
        pv[11].value = e2k_entryid_generate_oneoff (display_name, email, FALSE);
400
 
}
401
 
 
402
 
/**
403
 
 * e2k_addr_list_free:
404
 
 * @list: the address list
405
 
 *
406
 
 * Frees @list and all its entries.
407
 
 **/
408
 
void
409
 
e2k_addr_list_free (E2kAddrList *list)
410
 
{
411
 
        gint i, j;
412
 
        E2kAddrEntry *entry;
413
 
 
414
 
        for (i = 0; i < list->nentries; i++) {
415
 
                entry = &list->entry[i];
416
 
 
417
 
                for (j = 0; j < entry->nvalues; j++)
418
 
                        e2k_rule_free_propvalue (&entry->propval[j]);
419
 
                g_free (entry->propval);
420
 
        }
421
 
        g_free (list);
422
 
}
423
 
 
424
 
/**
425
 
 * e2k_action_free:
426
 
 * @act: the action
427
 
 *
428
 
 * Frees @act
429
 
 **/
430
 
void
431
 
e2k_action_free (E2kAction *act)
432
 
{
433
 
        switch (act->type) {
434
 
        case E2K_ACTION_MOVE:
435
 
        case E2K_ACTION_COPY:
436
 
                if (act->act.xfer.store_entryid)
437
 
                        g_byte_array_free (act->act.xfer.store_entryid, TRUE);
438
 
                if (act->act.xfer.folder_source_key)
439
 
                        g_byte_array_free (act->act.xfer.folder_source_key, TRUE);
440
 
                break;
441
 
 
442
 
        case E2K_ACTION_REPLY:
443
 
        case E2K_ACTION_OOF_REPLY:
444
 
                if (act->act.reply.entryid)
445
 
                        g_byte_array_free (act->act.reply.entryid, TRUE);
446
 
                break;
447
 
 
448
 
        case E2K_ACTION_DEFER:
449
 
                if (act->act.defer_data)
450
 
                        g_byte_array_free (act->act.defer_data, TRUE);
451
 
                break;
452
 
 
453
 
        case E2K_ACTION_FORWARD:
454
 
        case E2K_ACTION_DELEGATE:
455
 
                if (act->act.addr_list)
456
 
                        e2k_addr_list_free (act->act.addr_list);
457
 
                break;
458
 
 
459
 
        case E2K_ACTION_TAG:
460
 
                e2k_rule_free_propvalue (&act->act.proptag);
461
 
                break;
462
 
 
463
 
        default:
464
 
                /* Nothing to free */
465
 
                break;
466
 
        }
467
 
 
468
 
        g_free (act);
469
 
}
470
 
 
471
 
/**
472
 
 * e2k_actions_free:
473
 
 * @actions: an array of #E2kAction
474
 
 *
475
 
 * Frees @actions and all of its elements
476
 
 **/
477
 
void
478
 
e2k_actions_free (GPtrArray *actions)
479
 
{
480
 
        gint i;
481
 
 
482
 
        for (i = 0; i < actions->len; i++)
483
 
                e2k_action_free (actions->pdata[i]);
484
 
        g_ptr_array_free (actions, TRUE);
485
 
}
486
 
 
487
 
static gboolean
488
 
extract_action (guint8 **data, gint *len, E2kAction **act_ret)
489
 
{
490
 
        gint my_len;
491
 
        guint8 *my_data;
492
 
        guint16 actlen;
493
 
        E2kAction *act;
494
 
 
495
 
        if (!e2k_rule_extract_uint16 (data, len, &actlen))
496
 
                return FALSE;
497
 
 
498
 
        my_data = *data;
499
 
        my_len = actlen;
500
 
 
501
 
        *data += actlen;
502
 
        *len -= actlen;
503
 
 
504
 
        data = &my_data;
505
 
        len = &my_len;
506
 
 
507
 
        if (*len < 1)
508
 
                return FALSE;
509
 
 
510
 
        act = g_new0 (E2kAction, 1);
511
 
        act->type = **data;
512
 
        (*data)++;
513
 
        (*len)--;
514
 
 
515
 
        if (!e2k_rule_extract_uint32 (data, len, &act->flavor))
516
 
                goto lose;
517
 
        if (!e2k_rule_extract_uint32 (data, len, &act->flags))
518
 
                goto lose;
519
 
 
520
 
        switch (act->type) {
521
 
        case E2K_ACTION_MOVE:
522
 
        case E2K_ACTION_COPY:
523
 
                /* FIXME: what is this? */
524
 
                if (*len < 1 || **data != 1)
525
 
                        goto lose;
526
 
                (*len)--;
527
 
                (*data)++;
528
 
 
529
 
                if (!e2k_rule_extract_binary (data, len, &act->act.xfer.store_entryid))
530
 
                        goto lose;
531
 
                /* Remove the constant part */
532
 
                if (act->act.xfer.store_entryid->len <= E2K_ACTION_XFER_STORE_ENTRYID_PREFIX_LEN ||
533
 
                    memcmp (act->act.xfer.store_entryid->data,
534
 
                            E2K_ACTION_XFER_STORE_ENTRYID_PREFIX,
535
 
                            E2K_ACTION_XFER_STORE_ENTRYID_PREFIX_LEN) != 0)
536
 
                        goto lose;
537
 
                act->act.xfer.store_entryid->len -=
538
 
                        E2K_ACTION_XFER_STORE_ENTRYID_PREFIX_LEN;
539
 
                memmove (act->act.xfer.store_entryid->data,
540
 
                         act->act.xfer.store_entryid->data +
541
 
                         E2K_ACTION_XFER_STORE_ENTRYID_PREFIX_LEN,
542
 
                         act->act.xfer.store_entryid->len);
543
 
 
544
 
                if (!e2k_rule_extract_binary (data, len, &act->act.xfer.folder_source_key))
545
 
                        goto lose;
546
 
                /* Likewise */
547
 
                if (act->act.xfer.folder_source_key->len < 1 ||
548
 
                    act->act.xfer.folder_source_key->data[0] != MAPI_FOLDER)
549
 
                        goto lose;
550
 
                memmove (act->act.xfer.folder_source_key->data,
551
 
                         act->act.xfer.folder_source_key->data + 1,
552
 
                         act->act.xfer.folder_source_key->len);
553
 
 
554
 
                *act_ret = act;
555
 
                return TRUE;
556
 
 
557
 
        case E2K_ACTION_REPLY:
558
 
        case E2K_ACTION_OOF_REPLY:
559
 
                /* The reply template GUID is 16 bytes, the entryid
560
 
                 * is the rest.
561
 
                 */
562
 
                if (*len <= 16)
563
 
                        goto lose;
564
 
 
565
 
                act->act.reply.entryid = g_byte_array_sized_new (*len - 16);
566
 
                memcpy (act->act.reply.entryid->data, *data, *len - 16);
567
 
                act->act.reply.entryid->len = *len - 16;
568
 
                memcpy (act->act.reply.reply_template_guid, *data + *len - 16, 16);
569
 
 
570
 
                *act_ret = act;
571
 
                return TRUE;
572
 
 
573
 
        case E2K_ACTION_DEFER:
574
 
                act->act.defer_data = g_byte_array_sized_new (*len);
575
 
                memcpy (act->act.defer_data->data, *data, *len);
576
 
                act->act.defer_data->len = *len;
577
 
 
578
 
                *act_ret = act;
579
 
                return TRUE;
580
 
 
581
 
        case E2K_ACTION_BOUNCE:
582
 
                if (!e2k_rule_extract_uint32 (data, len, &act->act.bounce_code))
583
 
                        goto lose;
584
 
 
585
 
                *act_ret = act;
586
 
                return TRUE;
587
 
 
588
 
        case E2K_ACTION_FORWARD:
589
 
        case E2K_ACTION_DELEGATE:
590
 
        {
591
 
                guint16 nentries, nvalues;
592
 
                gint i, j;
593
 
 
594
 
                if (!e2k_rule_extract_uint16 (data, len, &nentries))
595
 
                        goto lose;
596
 
                act->act.addr_list = e2k_addr_list_new (nentries);
597
 
                for (i = 0; i < nentries; i++) {
598
 
                        /* FIXME: what is this? */
599
 
                        if (*len < 1 || **data != 1)
600
 
                                goto lose;
601
 
                        (*len)--;
602
 
                        (*data)++;
603
 
 
604
 
                        if (!e2k_rule_extract_uint16 (data, len, &nvalues))
605
 
                                goto lose;
606
 
                        act->act.addr_list->entry[i].nvalues = nvalues;
607
 
                        act->act.addr_list->entry[i].propval = g_new0 (E2kPropValue, nvalues);
608
 
 
609
 
                        for (j = 0; j < nvalues; j++) {
610
 
                                if (!e2k_rule_extract_propvalue (data, len, &act->act.addr_list->entry[i].propval[j]))
611
 
                                        goto lose;
612
 
                        }
613
 
                }
614
 
 
615
 
                *act_ret = act;
616
 
                return TRUE;
617
 
        }
618
 
 
619
 
        case E2K_ACTION_TAG:
620
 
                if (!e2k_rule_extract_propvalue (data, len, &act->act.proptag))
621
 
                        goto lose;
622
 
 
623
 
                *act_ret = act;
624
 
                return TRUE;
625
 
 
626
 
        case E2K_ACTION_DELETE:
627
 
                *act_ret = act;
628
 
                return TRUE;
629
 
 
630
 
        case E2K_ACTION_MARK_AS_READ:
631
 
                /* FIXME */
632
 
                return FALSE;
633
 
 
634
 
        default:
635
 
                break;
636
 
        }
637
 
 
638
 
 lose:
639
 
        e2k_action_free (act);
640
 
        return FALSE;
641
 
}
642
 
 
643
 
/**
644
 
 * e2k_actions_extract:
645
 
 * @data: pointer to data pointer
646
 
 * @len: pointer to data length
647
 
 * @actions: pointer to array to store actions in
648
 
 *
649
 
 * Attempts to extract a list of actions from *@data, which contains a
650
 
 * binary-encoded list of actions from a server-side rule.
651
 
 *
652
 
 * On success, *@actions will contain the extracted list, *@data will
653
 
 * be advanced past the end of the restriction data, and *@len will be
654
 
 * decremented accordingly.
655
 
 *
656
 
 * Return value: success or failure
657
 
 **/
658
 
gboolean
659
 
e2k_actions_extract (guint8 **data, gint *len, GPtrArray **actions)
660
 
{
661
 
        GPtrArray *acts;
662
 
        E2kAction *act;
663
 
        guint32 actlen;
664
 
        guint16 nacts;
665
 
        gint i;
666
 
 
667
 
        if (!e2k_rule_extract_uint32 (data, len, &actlen))
668
 
                return FALSE;
669
 
        if (actlen > *len)
670
 
                return FALSE;
671
 
 
672
 
        if (!e2k_rule_extract_uint16 (data, len, &nacts))
673
 
                return FALSE;
674
 
 
675
 
        acts = g_ptr_array_new ();
676
 
        for (i = 0; i < nacts; i++) {
677
 
                if (!extract_action (data, len, &act)) {
678
 
                        e2k_actions_free (acts);
679
 
                        return FALSE;
680
 
                } else
681
 
                        g_ptr_array_add (acts, act);
682
 
        }
683
 
 
684
 
        *actions = acts;
685
 
        return TRUE;
686
 
}
687
 
 
688
 
static void
689
 
append_action (GByteArray *ba, E2kAction *act)
690
 
{
691
 
        gint actlen_offset, actlen;
692
 
        gchar type;
693
 
 
694
 
        /* Save space for length */
695
 
        actlen_offset = ba->len;
696
 
        e2k_rule_append_uint16 (ba, 0);
697
 
 
698
 
        e2k_rule_append_byte (ba, act->type);
699
 
        e2k_rule_append_uint32 (ba, act->flavor);
700
 
        e2k_rule_append_uint32 (ba, act->flags);
701
 
 
702
 
        switch (act->type) {
703
 
        case E2K_ACTION_MOVE:
704
 
        case E2K_ACTION_COPY:
705
 
                /* FIXME: what is this? */
706
 
                e2k_rule_append_byte (ba, 1);
707
 
 
708
 
                e2k_rule_append_uint16 (ba, act->act.xfer.store_entryid->len +
709
 
                                        E2K_ACTION_XFER_STORE_ENTRYID_PREFIX_LEN);
710
 
                g_byte_array_append (ba, (guint8 *) E2K_ACTION_XFER_STORE_ENTRYID_PREFIX,
711
 
                                     E2K_ACTION_XFER_STORE_ENTRYID_PREFIX_LEN);
712
 
                g_byte_array_append (ba, act->act.xfer.store_entryid->data,
713
 
                                     act->act.xfer.store_entryid->len);
714
 
 
715
 
                e2k_rule_append_uint16 (ba, 49);
716
 
                type = MAPI_FOLDER;
717
 
                g_byte_array_append (ba, (guint8 *) &type, 1);
718
 
                g_byte_array_append (ba, act->act.xfer.folder_source_key->data,
719
 
                                     act->act.xfer.folder_source_key->len);
720
 
                break;
721
 
 
722
 
        case E2K_ACTION_REPLY:
723
 
        case E2K_ACTION_OOF_REPLY:
724
 
                g_byte_array_append (ba, act->act.reply.entryid->data,
725
 
                                     act->act.reply.entryid->len);
726
 
                g_byte_array_append (ba, act->act.reply.reply_template_guid, 16);
727
 
                break;
728
 
 
729
 
        case E2K_ACTION_DEFER:
730
 
                g_byte_array_append (ba, act->act.defer_data->data,
731
 
                                     act->act.defer_data->len);
732
 
                break;
733
 
 
734
 
        case E2K_ACTION_BOUNCE:
735
 
                e2k_rule_append_uint32 (ba, act->act.bounce_code);
736
 
                break;
737
 
 
738
 
        case E2K_ACTION_FORWARD:
739
 
        case E2K_ACTION_DELEGATE:
740
 
        {
741
 
                gint i, j;
742
 
                E2kAddrList *list;
743
 
                E2kAddrEntry *entry;
744
 
 
745
 
                list = act->act.addr_list;
746
 
                e2k_rule_append_uint16 (ba, list->nentries);
747
 
                for (i = 0; i < list->nentries; i++) {
748
 
                        /* FIXME: what is this? */
749
 
                        e2k_rule_append_byte (ba, 1);
750
 
 
751
 
                        entry = &list->entry[i];
752
 
                        e2k_rule_append_uint16 (ba, entry->nvalues);
753
 
                        for (j = 0; j < entry->nvalues; j++)
754
 
                                e2k_rule_append_propvalue (ba, &entry->propval[j]);
755
 
                }
756
 
                break;
757
 
        }
758
 
 
759
 
        case E2K_ACTION_TAG:
760
 
                e2k_rule_append_propvalue (ba, &act->act.proptag);
761
 
                break;
762
 
 
763
 
        case E2K_ACTION_DELETE:
764
 
                break;
765
 
 
766
 
        case E2K_ACTION_MARK_AS_READ:
767
 
                /* FIXME */
768
 
                break;
769
 
 
770
 
        default:
771
 
                break;
772
 
        }
773
 
 
774
 
        actlen = ba->len - actlen_offset - 2;
775
 
        e2k_rule_write_uint16 (ba->data + actlen_offset, actlen);
776
 
}
777
 
 
778
 
/**
779
 
 * e2k_actions_append:
780
 
 * @ba: a buffer into which a server-side rule is being constructed
781
 
 * @actions: the actions to append to @ba
782
 
 *
783
 
 * Appends @actions to @ba as part of a server-side rule.
784
 
 **/
785
 
void
786
 
e2k_actions_append (GByteArray *ba, GPtrArray *actions)
787
 
{
788
 
        gint actlen_offset, actlen, i;
789
 
 
790
 
        /* Save space for length */
791
 
        actlen_offset = ba->len;
792
 
        e2k_rule_append_uint32 (ba, 0);
793
 
 
794
 
        e2k_rule_append_uint16 (ba, actions->len);
795
 
        for (i = 0; i < actions->len; i++)
796
 
                append_action (ba, actions->pdata[i]);
797
 
 
798
 
        actlen = ba->len - actlen_offset - 4;
799
 
        e2k_rule_write_uint32 (ba->data + actlen_offset, actlen);
800
 
}