Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / servers / exchange / lib / e2k-rule.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Copyright (C) 2003, 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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <string.h>
25
26 #include "e2k-rule.h"
27 #include "e2k-action.h"
28 #include "e2k-properties.h"
29 #include "e2k-propnames.h"
30 #include "e2k-utils.h"
31
32 /**
33  * e2k_rule_prop_set:
34  * @prop: an #E2kRuleProp
35  * @propname: a MAPI property name
36  *
37  * This is a convenience function to set both the %name and %proptag
38  * fields of @prop.
39  **/
40 void
41 e2k_rule_prop_set (E2kRuleProp *prop, const char *propname)
42 {
43         prop->name = propname;
44         prop->proptag = e2k_prop_proptag (propname);
45 }
46
47 /**
48  * e2k_rule_write_uint32:
49  * @ptr: pointer into a binary rule
50  * @val: a uint32 value
51  *
52  * Writes @val into the rule at @ptr
53  **/
54 void
55 e2k_rule_write_uint32 (guint8 *ptr, guint32 val)
56 {
57         *ptr++ = ( val        & 0xFF);
58         *ptr++ = ((val >>  8) & 0xFF);
59         *ptr++ = ((val >> 16) & 0xFF);
60         *ptr++ = ((val >> 24) & 0xFF);
61 }
62
63 /**
64  * e2k_rule_append_uint32:
65  * @ba: a byte array containing a binary rule
66  * @val: a uint32 value
67  *
68  * Appends @val to the rule in @ba
69  **/
70 void
71 e2k_rule_append_uint32 (GByteArray *ba, guint32 val)
72 {
73         g_byte_array_set_size (ba, ba->len + 4);
74         e2k_rule_write_uint32 (ba->data + ba->len - 4, val);
75 }
76
77 /**
78  * e2k_rule_read_uint32:
79  * @ptr: pointer into a binary rule
80  *
81  * Reads a uint32 value from the rule at @ptr
82  *
83  * Return value: the uint32 value
84  **/
85 guint32
86 e2k_rule_read_uint32 (guint8 *ptr)
87 {
88         return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
89 }
90
91 /**
92  * e2k_rule_extract_uint32:
93  * @ptr: pointer to a pointer into a binary rule
94  * @len: pointer to the remaining length of *@ptr
95  * @val: pointer to a uint32 value
96  *
97  * Reads a uint32 value from the rule at **@ptr into *@val and updates
98  * *@ptr and *@len accordingly.
99  *
100  * Return value: success or failure
101  **/
102 gboolean
103 e2k_rule_extract_uint32 (guint8 **ptr, int *len, guint32 *val)
104 {
105         if (*len < 4)
106                 return FALSE;
107
108         *val = e2k_rule_read_uint32 (*ptr);
109
110         *ptr += 4;
111         *len -= 4;
112         return TRUE;
113 }
114
115 /**
116  * e2k_rule_write_uint16:
117  * @ptr: pointer into a binary rule
118  * @val: a uint16 value
119  *
120  * Writes @val into the rule at @ptr
121  **/
122 void
123 e2k_rule_write_uint16 (guint8 *ptr, guint16 val)
124 {
125         *ptr++ = ( val        & 0xFF);
126         *ptr++ = ((val >>  8) & 0xFF);
127 }
128
129 /**
130  * e2k_rule_append_uint16:
131  * @ba: a byte array containing a binary rule
132  * @val: a uint16 value
133  *
134  * Appends @val to the rule in @ba
135  **/
136 void
137 e2k_rule_append_uint16 (GByteArray *ba, guint16 val)
138 {
139         g_byte_array_set_size (ba, ba->len + 2);
140         e2k_rule_write_uint16 (ba->data + ba->len - 2, val);
141 }
142
143 /**
144  * e2k_rule_read_uint16:
145  * @ptr: pointer into a binary rule
146  *
147  * Reads a uint16 value from the rule at @ptr
148  *
149  * Return value: the uint16 value
150  **/
151 guint16
152 e2k_rule_read_uint16 (guint8 *ptr)
153 {
154         return ptr[0] | (ptr[1] << 8);
155 }
156
157 /**
158  * e2k_rule_extract_uint16:
159  * @ptr: pointer to a pointer into a binary rule
160  * @len: pointer to the remaining length of *@ptr
161  * @val: pointer to a uint16 value
162  *
163  * Reads a uint16 value from the rule at **@ptr into *@val and updates
164  * *@ptr and *@len accordingly.
165  *
166  * Return value: success or failure
167  **/
168 gboolean
169 e2k_rule_extract_uint16 (guint8 **ptr, int *len, guint16 *val)
170 {
171         if (*len < 2)
172                 return FALSE;
173
174         *val = e2k_rule_read_uint16 (*ptr);
175
176         *ptr += 2;
177         *len -= 2;
178         return TRUE;
179 }
180
181 /**
182  * e2k_rule_append_byte:
183  * @ba: a byte array containing a binary rule
184  * @val: a byte value
185  *
186  * Appends @val to the rule in @ba
187  **/
188 void
189 e2k_rule_append_byte (GByteArray *ba, guint8 val)
190 {
191         g_byte_array_append (ba, &val, 1);
192 }
193
194 /**
195  * e2k_rule_extract_byte:
196  * @ptr: pointer to a pointer into a binary rule
197  * @len: pointer to the remaining length of *@ptr
198  * @val: pointer to a byte value
199  *
200  * Reads a byte value from the rule at **@ptr into *@val and updates
201  * *@ptr and *@len accordingly.
202  *
203  * Return value: success or failure
204  **/
205 gboolean
206 e2k_rule_extract_byte (guint8 **ptr, int *len, guint8 *val)
207 {
208         if (*len < 1)
209                 return FALSE;
210
211         *val = **ptr;
212
213         *ptr += 1;
214         *len -= 1;
215         return TRUE;
216 }
217
218 /**
219  * e2k_rule_append_string:
220  * @ba: a byte array containing a binary rule
221  * @str: a (Windows) locale-encoded string
222  *
223  * Appends @str to the rule in @ba
224  **/
225 void
226 e2k_rule_append_string (GByteArray *ba, const char *str)
227 {
228         /* FIXME: verify encoding */
229         g_byte_array_append (ba, str, strlen (str) + 1);
230 }
231
232 /**
233  * e2k_rule_extract_string:
234  * @ptr: pointer to a pointer into a binary rule
235  * @len: pointer to the remaining length of *@ptr
236  * @str: pointer to a string pointer
237  *
238  * Reads a (Windows) locale-encoded string from the rule at **@ptr
239  * into *@str and updates *@ptr and *@len accordingly.
240  *
241  * Return value: success or failure
242  **/
243 gboolean
244 e2k_rule_extract_string (guint8 **ptr, int *len, char **str)
245 {
246         int slen;
247
248         for (slen = 0; slen < *len; slen++) {
249                 if ((*ptr)[slen] == '\0') {
250                         *str = g_strdup (*ptr);
251                         *ptr += slen + 1;
252                         *len -= slen + 1;
253                         return TRUE;
254                 }
255         }
256
257         return FALSE;
258 }
259
260 /**
261  * e2k_rule_append_unicode:
262  * @ba: a byte array containing a binary rule
263  * @str: a UTF-8 string
264  *
265  * Appends @str to the rule in @ba
266  **/
267 void
268 e2k_rule_append_unicode (GByteArray *ba, const char *str)
269 {
270         gunichar2 *utf16;
271         int i;
272
273         utf16 = g_utf8_to_utf16 (str, -1, NULL, NULL, NULL);
274         g_return_if_fail (utf16 != NULL);
275
276         for (i = 0; utf16[i]; i++)
277                 e2k_rule_append_uint16 (ba, utf16[i]);
278         e2k_rule_append_uint16 (ba, 0);
279         g_free (utf16);
280 }
281
282 /**
283  * e2k_rule_extract_unicode:
284  * @ptr: pointer to a pointer into a binary rule
285  * @len: pointer to the remaining length of *@ptr
286  * @str: pointer to a string pointer
287  *
288  * Reads a Unicode-encoded string from the rule at **@ptr into *@str
289  * and updates *@ptr and *@len accordingly.
290  *
291  * Return value: success or failure
292  **/
293 gboolean
294 e2k_rule_extract_unicode (guint8 **ptr, int *len, char **str)
295 {
296         guint8 *start, *end;
297         gunichar2 *utf16;
298
299         start = *ptr;
300         end = *ptr + *len;
301
302         for (; *ptr < end - 1; (*ptr) += 2) {
303                 if ((*ptr)[0] == '\0' && (*ptr)[1] == '\0') {
304                         *ptr += 2;
305                         *len -= *ptr - start;
306
307                         utf16 = g_memdup (start, *ptr - start);
308                         *str = g_utf16_to_utf8 (utf16, -1, NULL, NULL, NULL);
309                         g_free (utf16);
310                         return TRUE;
311                 }
312         }
313         return FALSE;
314 }
315
316 /**
317  * e2k_rule_append_binary:
318  * @ba: a byte array containing a binary rule
319  * @data: binary data
320  *
321  * Appends @data (with a 2-byte length prefix) to the rule in @ba
322  **/
323 void
324 e2k_rule_append_binary (GByteArray *ba, GByteArray *data)
325 {
326         e2k_rule_append_uint16 (ba, data->len);
327         g_byte_array_append (ba, data->data, data->len);
328 }
329
330 /**
331  * e2k_rule_extract_binary:
332  * @ptr: pointer to a pointer into a binary rule
333  * @len: pointer to the remaining length of *@ptr
334  * @data: pointer to a #GByteArray
335  *
336  * Reads binary data (preceded by a 2-byte length) from the rule at
337  * **@ptr into *@data and updates *@ptr and *@len accordingly.
338  *
339  * Return value: success or failure
340  **/
341 gboolean
342 e2k_rule_extract_binary (guint8 **ptr, int *len, GByteArray **data)
343 {
344         guint16 datalen;
345
346         if (!e2k_rule_extract_uint16 (ptr, len, &datalen))
347                 return FALSE;
348         if (*len < datalen)
349                 return FALSE;
350
351         *data = g_byte_array_sized_new (datalen);
352         memcpy ((*data)->data, *ptr, datalen);
353         (*data)->len = datalen;
354
355         *ptr += datalen;
356         *len -= datalen;
357         return TRUE;
358 }
359
360 #define E2K_PT_UNICODE_RULE 0x84b0
361
362 /**
363  * e2k_rule_append_proptag:
364  * @ba: a byte array containing a binary rule
365  * @prop: an #E2kRuleProp
366  *
367  * Appends a representation of @prop to the rule in @ba
368  **/
369 void
370 e2k_rule_append_proptag (GByteArray *ba, E2kRuleProp *prop)
371 {
372         guint32 proptag = prop->proptag;
373
374         if (E2K_PROPTAG_TYPE (proptag) == E2K_PT_STRING8 ||
375             E2K_PROPTAG_TYPE (proptag) == E2K_PT_UNICODE)
376                 proptag = E2K_PROPTAG_ID (proptag) | E2K_PT_UNICODE_RULE;
377
378         e2k_rule_append_uint32 (ba, proptag);
379 }
380
381 /**
382  * e2k_rule_extract_proptag:
383  * @ptr: pointer to a pointer into a binary rule
384  * @len: pointer to the remaining length of *@ptr
385  * @prop: poitner to an #E2kRuleProp
386  *
387  * Reads a proptag from the rule at **@ptr into *@prop and updates
388  * *@ptr and *@len accordingly.
389  *
390  * Return value: success or failure
391  **/
392 gboolean
393 e2k_rule_extract_proptag (guint8 **ptr, int *len, E2kRuleProp *prop)
394 {
395         if (!e2k_rule_extract_uint32 (ptr, len, &prop->proptag))
396                 return FALSE;
397
398         if (E2K_PROPTAG_TYPE (prop->proptag) == E2K_PT_UNICODE_RULE)
399                 prop->proptag = E2K_PROPTAG_ID (prop->proptag) | E2K_PT_UNICODE;
400         prop->name = e2k_proptag_prop (prop->proptag);
401
402         return TRUE;
403 }
404
405
406 /**
407  * e2k_rule_append_propvalue:
408  * @ba: a byte array containing a binary rule
409  * @pv: an #E2kPropValue
410  *
411  * Appends a representation of @pv (the proptag and its value) to the
412  * rule in @ba
413  **/
414 void
415 e2k_rule_append_propvalue (GByteArray *ba, E2kPropValue *pv)
416 {
417         g_return_if_fail (pv->prop.proptag != 0);
418
419         e2k_rule_append_proptag (ba, &pv->prop);
420
421         switch (E2K_PROPTAG_TYPE (pv->prop.proptag)) {
422         case E2K_PT_UNICODE:
423         case E2K_PT_STRING8:
424                 e2k_rule_append_unicode (ba, pv->value);
425                 break;
426
427         case E2K_PT_BINARY:
428                 e2k_rule_append_binary (ba, pv->value);
429                 break;
430
431         case E2K_PT_LONG:
432                 e2k_rule_append_uint32 (ba, GPOINTER_TO_UINT (pv->value));
433                 break;
434
435         case E2K_PT_BOOLEAN:
436                 e2k_rule_append_byte (ba, GPOINTER_TO_UINT (pv->value));
437                 break;
438
439         default:
440                 /* FIXME */
441                 break;
442         }
443 }
444
445 /**
446  * e2k_rule_extract_propvalue:
447  * @ptr: pointer to a pointer into a binary rule
448  * @len: pointer to the remaining length of *@ptr
449  * @pv: pointer to an #E2kPropValue
450  *
451  * Reads a representation of an #E2kPropValue from the rule at **@ptr
452  * into *@pv and updates *@ptr and *@len accordingly.
453  *
454  * Return value: success or failure
455  **/
456 gboolean
457 e2k_rule_extract_propvalue (guint8 **ptr, int *len, E2kPropValue *pv)
458 {
459         if (!e2k_rule_extract_proptag (ptr, len, &pv->prop))
460                 return FALSE;
461
462         switch (E2K_PROPTAG_TYPE (pv->prop.proptag)) {
463         case E2K_PT_UNICODE:
464         case E2K_PT_STRING8:
465                 pv->type = E2K_PROP_TYPE_STRING;
466                 return e2k_rule_extract_unicode (ptr, len, (char **)&pv->value);
467
468         case E2K_PT_BINARY:
469                 pv->type = E2K_PROP_TYPE_BINARY;
470                 return e2k_rule_extract_binary (ptr, len, (GByteArray **)&pv->value);
471
472         case E2K_PT_SYSTIME:
473         {
474                 guint64 temp;
475
476                 if (*len < 8)
477                         return FALSE;
478
479                 memcpy (&temp, *ptr, 8);
480                 *ptr += 8;
481                 *len -= 8;
482
483                 temp = GUINT64_FROM_LE (temp);
484                 pv->type = E2K_PROP_TYPE_DATE;
485                 pv->value = e2k_make_timestamp (e2k_filetime_to_time_t (temp));
486                 return TRUE;
487         }
488
489         case E2K_PT_LONG:
490         {
491                 guint32 temp;
492
493                 if (!e2k_rule_extract_uint32 (ptr, len, &temp))
494                         return FALSE;
495                 pv->type = E2K_PROP_TYPE_INT;
496                 pv->value = GUINT_TO_POINTER (temp);
497                 return TRUE;
498         }
499
500         case E2K_PT_BOOLEAN:
501         {
502                 guint8 temp;
503
504                 if (!e2k_rule_extract_byte (ptr, len, &temp))
505                         return FALSE;
506                 pv->type = E2K_PROP_TYPE_BOOL;
507                 pv->value = GUINT_TO_POINTER ((guint)temp);
508                 return TRUE;
509         }
510
511         default:
512                 /* FIXME */
513                 return FALSE;
514         }
515 }
516
517 /**
518  * e2k_rule_free_propvalue:
519  * @pv: an #E2kPropValue
520  *
521  * Frees @pv
522  **/
523 void
524 e2k_rule_free_propvalue (E2kPropValue *pv)
525 {
526         if (pv->type == E2K_PROP_TYPE_STRING ||
527             pv->type == E2K_PROP_TYPE_DATE)
528                 g_free (pv->value);
529         else if (pv->type == E2K_PROP_TYPE_BINARY && pv->value)
530                 g_byte_array_free (pv->value, TRUE);
531 }
532
533
534 /**
535  * e2k_rule_free:
536  * @rule: an #E2kRule
537  *
538  * Frees @rule
539  **/
540 void
541 e2k_rule_free (E2kRule *rule)
542 {
543         if (rule->name)
544                 g_free (rule->name);
545         if (rule->condition)
546                 e2k_restriction_unref (rule->condition);
547         if (rule->actions)
548                 e2k_actions_free (rule->actions);
549         if (rule->provider)
550                 g_free (rule->provider);
551         if (rule->provider_data)
552                 g_byte_array_free (rule->provider_data, TRUE);
553 }
554
555 /**
556  * e2k_rules_free:
557  * @rules: an #E2kRules structure
558  *
559  * Frees @rules and the rules it contains
560  **/
561 void
562 e2k_rules_free (E2kRules *rules)
563 {
564         int i;
565
566         for (i = 0; i < rules->rules->len; i++)
567                 e2k_rule_free (rules->rules->pdata[i]);
568         g_ptr_array_free (rules->rules, TRUE);
569         g_free (rules);
570 }
571
572 /**
573  * e2k_rules_from_binary:
574  * @rules_data: binary-encoded rules data
575  *
576  * Extract rules from @rules_data and returns them in an #E2kRules
577  * structure.
578  *
579  * Return value: the rules, or %NULL on error.
580  **/
581 E2kRules *
582 e2k_rules_from_binary (GByteArray *rules_data)
583 {
584         guint8 *data;
585         int len, i;
586         guint32 nrules, pdlen;
587         E2kRules *rules;
588         E2kRule *rule;
589
590         data = rules_data->data;
591         len = rules_data->len;
592
593         if (len < 9)
594                 return NULL;
595         if (*data != 2)
596                 return NULL;
597         data++;
598         len--;
599
600         rules = g_new0 (E2kRules, 1);
601         rules->version = 2;
602
603         if (!e2k_rule_extract_uint32 (&data, &len, &nrules) ||
604             !e2k_rule_extract_uint32 (&data, &len, &rules->codepage)) {
605                 g_free (rules);
606                 return NULL;
607         }
608
609         rules->rules = g_ptr_array_new ();
610         for (i = 0; i < nrules; i++) {
611                 rule = g_new0 (E2kRule, 1);
612                 g_ptr_array_add (rules->rules, rule);
613
614                 if (!e2k_rule_extract_uint32 (&data, &len, &rule->sequence) ||
615                     !e2k_rule_extract_uint32 (&data, &len, &rule->state) ||
616                     !e2k_rule_extract_uint32 (&data, &len, &rule->user_flags) ||
617                     !e2k_rule_extract_uint32 (&data, &len, &rule->condition_lcid) ||
618                     !e2k_restriction_extract (&data, &len, &rule->condition) ||
619                     !e2k_actions_extract (&data, &len, &rule->actions) ||
620                     !e2k_rule_extract_string (&data, &len, &rule->provider) ||
621                     !e2k_rule_extract_string (&data, &len, &rule->name) ||
622                     !e2k_rule_extract_uint32 (&data, &len, &rule->level))
623                         goto error;
624
625                 /* The provider data has a 4-byte length, unlike the
626                  * binary fields in a condition or rule.
627                  */
628                 if (!e2k_rule_extract_uint32 (&data, &len, &pdlen))
629                         goto error;
630                 if (len < pdlen)
631                         goto error;
632                 rule->provider_data = g_byte_array_sized_new (pdlen);
633                 rule->provider_data->len = pdlen;
634                 memcpy (rule->provider_data->data, data, pdlen);
635                 data += pdlen;
636                 len -= pdlen;
637         }
638
639         return rules;
640
641  error:
642         e2k_rules_free (rules);
643         return NULL;
644 }
645
646 /**
647  * e2k_rules_to_binary:
648  * @rules: an #E2kRules structure
649  *
650  * Encodes @rules into binary form
651  *
652  * Return value: the binary-encoded rules
653  **/
654 GByteArray *
655 e2k_rules_to_binary (E2kRules *rules)
656 {
657         GByteArray *ba;
658         E2kRule *rule;
659         int i;
660
661         ba = g_byte_array_new ();
662         e2k_rule_append_byte (ba, rules->version);
663         e2k_rule_append_uint32 (ba, rules->rules->len);
664         e2k_rule_append_uint32 (ba, rules->codepage);
665
666         for (i = 0; i < rules->rules->len; i++) {
667                 rule = rules->rules->pdata[i];
668
669                 e2k_rule_append_uint32 (ba, rule->sequence);
670                 e2k_rule_append_uint32 (ba, rule->state);
671                 e2k_rule_append_uint32 (ba, rule->user_flags);
672                 e2k_rule_append_uint32 (ba, rule->condition_lcid);
673                 e2k_restriction_append (ba, rule->condition);
674                 e2k_actions_append (ba, rule->actions);
675                 e2k_rule_append_string (ba, rule->provider);
676                 e2k_rule_append_string (ba, rule->name);
677                 e2k_rule_append_uint32 (ba, rule->level);
678
679                 /* The provider data has a 4-byte length, unlike the
680                  * binary fields in a condition or rule.
681                  */
682                 e2k_rule_append_uint32 (ba, rule->provider_data->len);
683                 g_byte_array_append (ba, rule->provider_data->data,
684                                      rule->provider_data->len);
685         }
686
687         return ba;
688 }