1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
/* Copyright (C) 2002-2004 Novell, Inc.
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.
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.
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.
20
/* e2k-action.c: Exchange server-side rule actions */
28
#include "e2k-action.h"
29
#include "e2k-propnames.h"
30
#include "e2k-restriction.h"
32
#include "e2k-utils.h"
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)
40
copy_bytearray (GByteArray *ba)
44
copy = g_byte_array_sized_new (ba->len);
46
memcpy (copy->data, ba->data, copy->len);
52
xfer_action (E2kActionType type, GByteArray *store_entryid,
53
GByteArray *folder_source_key)
57
act = g_new0 (E2kAction, 1);
59
act->act.xfer.store_entryid = copy_bytearray (store_entryid);
60
act->act.xfer.folder_source_key = copy_bytearray (folder_source_key);
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
70
* Creates a rule action to move a message into the indicated folder
72
* Return value: the new rule action
75
e2k_action_move (GByteArray *store_entryid, GByteArray *folder_source_key)
77
return xfer_action (E2K_ACTION_MOVE, store_entryid, folder_source_key);
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
85
* Creates a rule action to copy a message into the indicated folder
87
* Return value: the new rule action
90
e2k_action_copy (GByteArray *store_entryid, GByteArray *folder_source_key)
92
return xfer_action (E2K_ACTION_COPY, store_entryid, folder_source_key);
96
reply_action (E2kActionType type, GByteArray *template_entryid,
97
guint8 template_guid[16])
101
act = g_new0 (E2kAction, 1);
103
act->act.reply.entryid = copy_bytearray (template_entryid);
104
memcpy (act->act.reply.reply_template_guid, template_guid, 16);
111
* @template_entryid: The entryid of the reply template
112
* @template_guid: The GUID of the reply template
114
* Creates a rule action to reply to a message using the indicated
117
* Return value: the new rule action
120
e2k_action_reply (GByteArray *template_entryid, guint8 template_guid[16])
122
return reply_action (E2K_ACTION_REPLY, template_entryid, template_guid);
126
* e2k_action_oof_reply:
127
* @template_entryid: The entryid of the reply template
128
* @template_guid: The GUID of the reply template
130
* Creates a rule action to send an Out-of-Office reply to a message
131
* using the indicated template
133
* Return value: the new rule action
136
e2k_action_oof_reply (GByteArray *template_entryid, guint8 template_guid[16])
138
return reply_action (E2K_ACTION_OOF_REPLY, template_entryid, template_guid);
143
* @data: data identifying the deferred action
145
* Creates a rule action to defer processing on a message
147
* Return value: the new rule action
150
e2k_action_defer (GByteArray *data)
154
act = g_new0 (E2kAction, 1);
155
act->type = E2K_ACTION_DEFER;
156
act->act.defer_data = copy_bytearray (data);
163
* @bounce_code: a bounce code
165
* Creates a rule action to bounce a message
167
* Return value: the new rule action
170
e2k_action_bounce (E2kActionBounceCode bounce_code)
174
act = g_new0 (E2kAction, 1);
175
act->type = E2K_ACTION_BOUNCE;
176
act->act.bounce_code = bounce_code;
182
forward_action (E2kActionType type, E2kAddrList *list)
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);
189
act = g_new0 (E2kAction, 1);
191
act->act.addr_list = list;
197
* e2k_action_forward:
198
* @list: a list of recipients
200
* Creates a rule action to forward a message to the indicated list of
203
* Return value: the new rule action
206
e2k_action_forward (E2kAddrList *list)
208
return forward_action (E2K_ACTION_FORWARD, list);
212
* e2k_action_delegate:
213
* @list: a list of recipients
215
* Creates a rule action to delegate a meeting request to the
216
* indicated list of recipients
218
* Return value: the new rule action
221
e2k_action_delegate (E2kAddrList *list)
223
return forward_action (E2K_ACTION_DELEGATE, list);
228
* @propname: a MAPI property name
229
* @type: the type of @propname
230
* @value: the value for @propname
232
* Creates a rule action to set the given property to the given value
235
* Return value: the new rule action
238
e2k_action_tag (const gchar *propname, E2kPropType type, gpointer value)
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? */
254
* Creates a rule action to permanently delete a message (ie, not just
255
* move it to the trash).
257
* Return value: the new rule action
260
e2k_action_delete (void)
264
act = g_new0 (E2kAction, 1);
265
act->type = E2K_ACTION_DELETE;
272
* @nentries: the number of entries
274
* Creates an address list for a forward or delegate rule, with
277
* Return value: the new address list
280
e2k_addr_list_new (gint nentries)
284
list = g_malloc0 (sizeof (E2kAddrList) +
285
(nentries - 1) * sizeof (E2kAddrEntry));
286
list->nentries = nentries;
292
addr_entry_set_core (E2kPropValue *pv, GByteArray *entryid,
293
const gchar *display_name, const gchar *email_type,
294
const gchar *email_addr)
296
e2k_rule_prop_set (&pv[0].prop, PR_ENTRYID);
297
pv[0].type = E2K_PROP_TYPE_BINARY;
298
pv[0].value = entryid;
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);
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);
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);
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);
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);
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);
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" */
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);
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);
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
345
* Sets entry number @entry_num of @list to refer to the indicated
346
* local Exchange user.
349
e2k_addr_list_set_local (E2kAddrList *list, gint entry_num,
350
const gchar *display_name,
351
const gchar *exchange_dn,
356
list->entry[entry_num].nvalues = 12;
357
list->entry[entry_num].propval = pv = g_new0 (E2kPropValue, 12);
359
addr_entry_set_core (pv, e2k_entryid_generate_local (exchange_dn),
360
display_name, "EX", exchange_dn);
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");
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);
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
378
* Sets entry number @entry_num of @list to refer to the indicated
379
* "one-off" SMTP user.
382
e2k_addr_list_set_oneoff (E2kAddrList *list, gint entry_num,
383
const gchar *display_name, const gchar *email)
387
list->entry[entry_num].nvalues = 12;
388
list->entry[entry_num].propval = pv = g_new0 (E2kPropValue, 12);
390
addr_entry_set_core (pv, e2k_entryid_generate_oneoff (display_name, email, TRUE),
391
display_name, "SMTP", email);
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);
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);
403
* e2k_addr_list_free:
404
* @list: the address list
406
* Frees @list and all its entries.
409
e2k_addr_list_free (E2kAddrList *list)
414
for (i = 0; i < list->nentries; i++) {
415
entry = &list->entry[i];
417
for (j = 0; j < entry->nvalues; j++)
418
e2k_rule_free_propvalue (&entry->propval[j]);
419
g_free (entry->propval);
431
e2k_action_free (E2kAction *act)
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);
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);
448
case E2K_ACTION_DEFER:
449
if (act->act.defer_data)
450
g_byte_array_free (act->act.defer_data, TRUE);
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);
460
e2k_rule_free_propvalue (&act->act.proptag);
464
/* Nothing to free */
473
* @actions: an array of #E2kAction
475
* Frees @actions and all of its elements
478
e2k_actions_free (GPtrArray *actions)
482
for (i = 0; i < actions->len; i++)
483
e2k_action_free (actions->pdata[i]);
484
g_ptr_array_free (actions, TRUE);
488
extract_action (guint8 **data, gint *len, E2kAction **act_ret)
495
if (!e2k_rule_extract_uint16 (data, len, &actlen))
510
act = g_new0 (E2kAction, 1);
515
if (!e2k_rule_extract_uint32 (data, len, &act->flavor))
517
if (!e2k_rule_extract_uint32 (data, len, &act->flags))
521
case E2K_ACTION_MOVE:
522
case E2K_ACTION_COPY:
523
/* FIXME: what is this? */
524
if (*len < 1 || **data != 1)
529
if (!e2k_rule_extract_binary (data, len, &act->act.xfer.store_entryid))
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)
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);
544
if (!e2k_rule_extract_binary (data, len, &act->act.xfer.folder_source_key))
547
if (act->act.xfer.folder_source_key->len < 1 ||
548
act->act.xfer.folder_source_key->data[0] != MAPI_FOLDER)
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);
557
case E2K_ACTION_REPLY:
558
case E2K_ACTION_OOF_REPLY:
559
/* The reply template GUID is 16 bytes, the entryid
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);
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;
581
case E2K_ACTION_BOUNCE:
582
if (!e2k_rule_extract_uint32 (data, len, &act->act.bounce_code))
588
case E2K_ACTION_FORWARD:
589
case E2K_ACTION_DELEGATE:
591
guint16 nentries, nvalues;
594
if (!e2k_rule_extract_uint16 (data, len, &nentries))
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)
604
if (!e2k_rule_extract_uint16 (data, len, &nvalues))
606
act->act.addr_list->entry[i].nvalues = nvalues;
607
act->act.addr_list->entry[i].propval = g_new0 (E2kPropValue, nvalues);
609
for (j = 0; j < nvalues; j++) {
610
if (!e2k_rule_extract_propvalue (data, len, &act->act.addr_list->entry[i].propval[j]))
620
if (!e2k_rule_extract_propvalue (data, len, &act->act.proptag))
626
case E2K_ACTION_DELETE:
630
case E2K_ACTION_MARK_AS_READ:
639
e2k_action_free (act);
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
649
* Attempts to extract a list of actions from *@data, which contains a
650
* binary-encoded list of actions from a server-side rule.
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.
656
* Return value: success or failure
659
e2k_actions_extract (guint8 **data, gint *len, GPtrArray **actions)
667
if (!e2k_rule_extract_uint32 (data, len, &actlen))
672
if (!e2k_rule_extract_uint16 (data, len, &nacts))
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);
681
g_ptr_array_add (acts, act);
689
append_action (GByteArray *ba, E2kAction *act)
691
gint actlen_offset, actlen;
694
/* Save space for length */
695
actlen_offset = ba->len;
696
e2k_rule_append_uint16 (ba, 0);
698
e2k_rule_append_byte (ba, act->type);
699
e2k_rule_append_uint32 (ba, act->flavor);
700
e2k_rule_append_uint32 (ba, act->flags);
703
case E2K_ACTION_MOVE:
704
case E2K_ACTION_COPY:
705
/* FIXME: what is this? */
706
e2k_rule_append_byte (ba, 1);
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);
715
e2k_rule_append_uint16 (ba, 49);
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);
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);
729
case E2K_ACTION_DEFER:
730
g_byte_array_append (ba, act->act.defer_data->data,
731
act->act.defer_data->len);
734
case E2K_ACTION_BOUNCE:
735
e2k_rule_append_uint32 (ba, act->act.bounce_code);
738
case E2K_ACTION_FORWARD:
739
case E2K_ACTION_DELEGATE:
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);
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]);
760
e2k_rule_append_propvalue (ba, &act->act.proptag);
763
case E2K_ACTION_DELETE:
766
case E2K_ACTION_MARK_AS_READ:
774
actlen = ba->len - actlen_offset - 2;
775
e2k_rule_write_uint16 (ba->data + actlen_offset, actlen);
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
783
* Appends @actions to @ba as part of a server-side rule.
786
e2k_actions_append (GByteArray *ba, GPtrArray *actions)
788
gint actlen_offset, actlen, i;
790
/* Save space for length */
791
actlen_offset = ba->len;
792
e2k_rule_append_uint32 (ba, 0);
794
e2k_rule_append_uint16 (ba, actions->len);
795
for (i = 0; i < actions->len; i++)
796
append_action (ba, actions->pdata[i]);
798
actlen = ba->len - actlen_offset - 4;
799
e2k_rule_write_uint32 (ba->data + actlen_offset, actlen);