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

« back to all changes in this revision

Viewing changes to servers/exchange/lib/e2k-utils.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) 2001-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 "e2k-utils.h"
25
 
#include "e2k-autoconfig.h"
26
 
#include "e2k-propnames.h"
27
 
#include "e2k-rule.h"
28
 
 
29
 
#include <libedataserver/e-time-utils.h>
30
 
 
31
 
#include <ctype.h>
32
 
#include <stdlib.h>
33
 
#include <string.h>
34
 
 
35
 
/* Do not internationalize */
36
 
const gchar *e2k_rfc822_months [] = {
37
 
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
38
 
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
39
 
};
40
 
 
41
 
/**
42
 
 * e2k_parse_timestamp:
43
 
 * @timestamp: an ISO8601 timestamp returned by the Exchange server
44
 
 *
45
 
 * Converts @timestamp to a %time_t value. @timestamp must be in one
46
 
 * of the two ISO8601 variants used by Exchange.
47
 
 *
48
 
 * Note that the timestamps used (in most contexts) by Exchange have
49
 
 * millisecond resolution, so converting them to %time_t loses
50
 
 * resolution. Since ISO8601 timestamps can be compared using
51
 
 * strcmp(), it is often best to keep them as strings.
52
 
 *
53
 
 * Return value: the %time_t corresponding to @timestamp, or -1 on
54
 
 * error.
55
 
 **/
56
 
time_t
57
 
e2k_parse_timestamp (const gchar *timestamp)
58
 
{
59
 
        struct tm tm;
60
 
 
61
 
        tm.tm_year = strtoul (timestamp, (gchar **)&timestamp, 10) - 1900;
62
 
        if (*timestamp++ != '-')
63
 
                return -1;
64
 
        tm.tm_mon = strtoul (timestamp, (gchar **)&timestamp, 10) - 1;
65
 
        if (*timestamp++ != '-')
66
 
                return -1;
67
 
        tm.tm_mday = strtoul (timestamp, (gchar **)&timestamp, 10);
68
 
        if (*timestamp++ != 'T')
69
 
                return -1;
70
 
        tm.tm_hour = strtoul (timestamp, (gchar **)&timestamp, 10);
71
 
        if (*timestamp++ != ':')
72
 
                return -1;
73
 
        tm.tm_min = strtoul (timestamp, (gchar **)&timestamp, 10);
74
 
        if (*timestamp++ != ':')
75
 
                return -1;
76
 
        tm.tm_sec = strtoul (timestamp, (gchar **)&timestamp, 10);
77
 
        if (*timestamp != '.' && *timestamp != 'Z')
78
 
                return -1;
79
 
 
80
 
        return e_mktime_utc (&tm);
81
 
}
82
 
 
83
 
/**
84
 
 * e2k_make_timestamp:
85
 
 * @when: the %time_t to convert to an ISO8601 timestamp
86
 
 *
87
 
 * Creates an ISO8601 timestamp (in an format acceptable to Exchange)
88
 
 * corresponding to @when.
89
 
 *
90
 
 * Return value: the timestamp, which the caller must free.
91
 
 **/
92
 
gchar *
93
 
e2k_make_timestamp (time_t when)
94
 
{
95
 
        struct tm *tm;
96
 
 
97
 
        tm = gmtime (&when);
98
 
        return g_strdup_printf ("%04d-%02d-%02dT%02d:%02d:%02dZ",
99
 
                                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
100
 
                                tm->tm_hour, tm->tm_min, tm->tm_sec);
101
 
}
102
 
 
103
 
/**
104
 
 * e2k_make_timestamp_rfc822:
105
 
 * @when: the %time_t to convert to an RFC822 timestamp
106
 
 *
107
 
 * Creates an RFC822 Date header value corresponding to @when, in the
108
 
 * locale timezone.
109
 
 *
110
 
 * Return value: the timestamp, which the caller must free.
111
 
 **/
112
 
gchar *
113
 
e2k_make_timestamp_rfc822 (time_t when)
114
 
{
115
 
        struct tm tm;
116
 
        gint offset;
117
 
 
118
 
        e_localtime_with_offset (when, &tm, &offset);
119
 
        offset = (offset / 3600) * 100 + (offset / 60) % 60;
120
 
 
121
 
        return g_strdup_printf ("%02d %s %04d %02d:%02d:%02d %+05d",
122
 
                                tm.tm_mday, e2k_rfc822_months[tm.tm_mon],
123
 
                                tm.tm_year + 1900,
124
 
                                tm.tm_hour, tm.tm_min, tm.tm_sec,
125
 
                                offset);
126
 
}
127
 
 
128
 
/* SYSTIME_OFFSET is the number of minutes between the Windows epoch
129
 
 * (1601-01-01T00:00:00Z) and the time_t epoch (1970-01-01T00:00:00Z):
130
 
 * 369 years, 89 of which are leap years.
131
 
 */
132
 
#define SYSTIME_OFFSET 194074560UL
133
 
 
134
 
/**
135
 
 * e2k_systime_to_time_t:
136
 
 * @systime: a MAPI PT_SYSTIME value (minutes since Windows epoch)
137
 
 *
138
 
 * Converts the MAPI PT_SYSTIME value @systime to a corresponding
139
 
 * %time_t value (assuming it is within the valid range of a %time_t).
140
 
 *
141
 
 * Return value: a %time_t corresponding to @systime.
142
 
 **/
143
 
time_t
144
 
e2k_systime_to_time_t (guint32 systime)
145
 
{
146
 
        return (systime - SYSTIME_OFFSET) * 60;
147
 
}
148
 
 
149
 
/**
150
 
 * e2k_systime_from_time_t:
151
 
 * @tt: a %time_t value
152
 
 *
153
 
 * Converts the %time_t value @tt to a corresponding MAPI PT_SYSTIME
154
 
 * value, losing some precision if @tt does not fall on a minute
155
 
 * boundary.
156
 
 *
157
 
 * Return value: the Windows systime value corresponding to @tt
158
 
 **/
159
 
guint32
160
 
e2k_systime_from_time_t (time_t tt)
161
 
{
162
 
        return (tt / 60) + SYSTIME_OFFSET;
163
 
}
164
 
 
165
 
/**
166
 
 * e2k_filetime_to_time_t:
167
 
 * @filetime: a Windows FILETIME value (100ns intervals since
168
 
 * Windows epoch)
169
 
 *
170
 
 * Converts the Windows FILETIME value @filetime to a corresponding
171
 
 * %time_t value (assuming it is within the valid range of a %time_t),
172
 
 * truncating to a second boundary.
173
 
 *
174
 
 * Return value: a %time_t corresponding to @filetime.
175
 
 **/
176
 
time_t
177
 
e2k_filetime_to_time_t (guint64 filetime)
178
 
{
179
 
        return (time_t)(filetime / 10000000 - SYSTIME_OFFSET * 60);
180
 
}
181
 
 
182
 
/**
183
 
 * e2k_filetime_from_time_t:
184
 
 * @tt: a %time_t value
185
 
 *
186
 
 * Converts the %time_t value @tt to a corresponding Windows FILETIME
187
 
 * value.
188
 
 *
189
 
 * Return value: the Windows FILETIME value corresponding to @tt
190
 
 **/
191
 
guint64
192
 
e2k_filetime_from_time_t (time_t tt)
193
 
{
194
 
        return (((guint64)tt) + ((guint64)SYSTIME_OFFSET) * 60) * 10000000;
195
 
}
196
 
 
197
 
/**
198
 
 * e2k_lf_to_crlf:
199
 
 * @in: input text in UNIX ("\n") format
200
 
 *
201
 
 * Creates a copy of @in with all LFs converted to CRLFs.
202
 
 *
203
 
 * Return value: the converted text, which the caller must free.
204
 
 **/
205
 
gchar *
206
 
e2k_lf_to_crlf (const gchar *in)
207
 
{
208
 
        gint len;
209
 
        const gchar *s;
210
 
        gchar *out, *d;
211
 
 
212
 
        g_return_val_if_fail (in != NULL, NULL);
213
 
 
214
 
        len = strlen (in);
215
 
        for (s = strchr (in, '\n'); s; s = strchr (s + 1, '\n'))
216
 
                len++;
217
 
 
218
 
        out = g_malloc (len + 1);
219
 
        for (s = in, d = out; *s; s++) {
220
 
                if (*s == '\n')
221
 
                        *d++ = '\r';
222
 
                *d++ = *s;
223
 
        }
224
 
        *d = '\0';
225
 
 
226
 
        return out;
227
 
}
228
 
 
229
 
/**
230
 
 * e2k_crlf_to_lf:
231
 
 * @in: input text in network ("\r\n") format
232
 
 *
233
 
 * Creates a copy of @in with all CRLFs converted to LFs. (Actually,
234
 
 * it just strips CRs, so any raw CRs will be removed.)
235
 
 *
236
 
 * Return value: the converted text, which the caller must free.
237
 
 **/
238
 
gchar *
239
 
e2k_crlf_to_lf (const gchar *in)
240
 
{
241
 
        gint len;
242
 
        const gchar *s;
243
 
        gchar *out;
244
 
        GString *str;
245
 
 
246
 
        g_return_val_if_fail (in != NULL, NULL);
247
 
 
248
 
        str = g_string_new ("");
249
 
 
250
 
        len = strlen (in);
251
 
        for (s = in; *s; s++) {
252
 
                if (*s != '\r')
253
 
                        str = g_string_append_c (str, *s);
254
 
        }
255
 
 
256
 
        out = str->str;
257
 
        g_string_free (str, FALSE);
258
 
 
259
 
        return out;
260
 
}
261
 
 
262
 
/**
263
 
 * e2k_strdup_with_trailing_slash:
264
 
 * @path: a URI or path
265
 
 *
266
 
 * Copies @path, appending a "/" to it if and only if it did not
267
 
 * already end in "/".
268
 
 *
269
 
 * Return value: the path, which the caller must free
270
 
 **/
271
 
gchar *
272
 
e2k_strdup_with_trailing_slash (const gchar *path)
273
 
{
274
 
        gchar *p;
275
 
 
276
 
        if (!path || !*path)
277
 
                return NULL;
278
 
 
279
 
        p = strrchr (path, '/');
280
 
        if (p && !p[1])
281
 
                return g_strdup (path);
282
 
        else
283
 
                return g_strdup_printf ("%s/", path);
284
 
}
285
 
 
286
 
/**
287
 
 * e2k_entryid_to_dn:
288
 
 * @entryid: an Exchange entryid
289
 
 *
290
 
 * Finds an Exchange 5.5 DN inside a binary entryid property (such as
291
 
 * #PR_STORE_ENTRYID or an element of #PR_DELEGATES_ENTRYIDS).
292
 
 *
293
 
 * Return value: the entryid, which is a pointer into @entryid's data.
294
 
 **/
295
 
const gchar *
296
 
e2k_entryid_to_dn (GByteArray *entryid)
297
 
{
298
 
        gchar *p;
299
 
 
300
 
        p = ((gchar *)entryid->data) + entryid->len - 1;
301
 
        if (*p == 0) {
302
 
                while (*(p - 1) && p > (gchar *)entryid->data)
303
 
                        p--;
304
 
                if (*p == '/')
305
 
                        return p;
306
 
        }
307
 
        return NULL;
308
 
}
309
 
 
310
 
static void
311
 
append_permanenturl_section (GString *url, guint8 *entryid)
312
 
{
313
 
        gint i = 0;
314
 
 
315
 
        /* First part */
316
 
        while (i < 16)
317
 
                g_string_append_printf (url, "%02x", entryid[i++]);
318
 
 
319
 
        /* Replace 0s with a single '-' */
320
 
        g_string_append_c (url, '-');
321
 
        while (i < 22 && entryid[i] == 0)
322
 
                i++;
323
 
 
324
 
        /* Last part; note that if the first non-0 byte can be
325
 
         * expressed in a single hex digit, we do so. (ie, the 0
326
 
         * in the 16's place was also accumulated into the
327
 
         * preceding '-'.)
328
 
         */
329
 
        if (i < 22 && entryid[i] < 0x10)
330
 
                g_string_append_printf (url, "%01x", entryid[i++]);
331
 
        while (i < 22)
332
 
                g_string_append_printf (url, "%02x", entryid[i++]);
333
 
}
334
 
 
335
 
#define E2K_PERMANENTURL_INFIX "-FlatUrlSpace-"
336
 
#define E2K_PERMANENTURL_INFIX_LEN (sizeof (E2K_PERMANENTURL_INFIX) - 1)
337
 
 
338
 
/**
339
 
 * e2k_entryid_to_permanenturl:
340
 
 * @entryid: an ENTRYID (specifically, a PR_SOURCE_KEY)
341
 
 * @base_uri: base URI of the store containing @entryid
342
 
 *
343
 
 * Creates a permanenturl based on @entryid and @base_uri.
344
 
 *
345
 
 * Return value: the permanenturl, which the caller must free.
346
 
 **/
347
 
gchar *
348
 
e2k_entryid_to_permanenturl (GByteArray *entryid, const gchar *base_uri)
349
 
{
350
 
        GString *url;
351
 
        gchar *ret;
352
 
 
353
 
        g_return_val_if_fail (entryid->len == 22 || entryid->len == 44, NULL);
354
 
 
355
 
        url = g_string_new (base_uri);
356
 
        if (url->str[url->len - 1] != '/')
357
 
                g_string_append_c (url, '/');
358
 
        g_string_append (url, E2K_PERMANENTURL_INFIX);
359
 
        g_string_append_c (url, '/');
360
 
 
361
 
        append_permanenturl_section (url, entryid->data);
362
 
        if (entryid->len > 22) {
363
 
                g_string_append_c (url, '/');
364
 
                append_permanenturl_section (url, entryid->data + 22);
365
 
        }
366
 
 
367
 
        ret = url->str;
368
 
        g_string_free (url, FALSE);
369
 
        return ret;
370
 
}
371
 
 
372
 
#define HEXVAL(c) (isdigit (c) ? (c) - '0' : g_ascii_tolower (c) - 'a' + 10)
373
 
 
374
 
static gboolean
375
 
append_entryid_section (GByteArray *entryid, const gchar **permanenturl)
376
 
{
377
 
        const gchar *p;
378
 
        guint8 buf[44], byte;
379
 
        gint endlen;
380
 
 
381
 
        p = *permanenturl;
382
 
        if (strspn (p, "0123456789abcdefABCDEF") != 32)
383
 
                return FALSE;
384
 
        if (p[32] != '-')
385
 
                return FALSE;
386
 
        endlen = strspn (p + 33, "0123456789abcdefABCDEF");
387
 
        if (endlen > 6)
388
 
                return FALSE;
389
 
 
390
 
        /* Expand to the full form by replacing the "-" with "0"s */
391
 
        memcpy (buf, p, 32);
392
 
        memset (buf + 32, '0', sizeof (buf) - 32 - endlen);
393
 
        memcpy (buf + sizeof (buf) - endlen, p + 33, endlen);
394
 
 
395
 
        p = (gchar *) buf;
396
 
        while (p < (gchar *) buf + sizeof (buf)) {
397
 
                byte = (HEXVAL (*p) << 4) + HEXVAL (*(p + 1));
398
 
                g_byte_array_append (entryid, &byte, 1);
399
 
                p += 2;
400
 
        }
401
 
 
402
 
        *permanenturl += 33 + endlen;
403
 
        return TRUE;
404
 
}
405
 
 
406
 
/**
407
 
 * e2k_permanenturl_to_entryid:
408
 
 * @permanenturl: an Exchange permanenturl
409
 
 *
410
 
 * Creates an ENTRYID (specifically, a PR_SOURCE_KEY) based on
411
 
 * @permanenturl
412
 
 *
413
 
 * Return value: the entryid
414
 
 **/
415
 
GByteArray *
416
 
e2k_permanenturl_to_entryid (const gchar *permanenturl)
417
 
{
418
 
        GByteArray *entryid;
419
 
 
420
 
        permanenturl = strstr (permanenturl, E2K_PERMANENTURL_INFIX);
421
 
        if (!permanenturl)
422
 
                return NULL;
423
 
        permanenturl += E2K_PERMANENTURL_INFIX_LEN;
424
 
 
425
 
        entryid = g_byte_array_new ();
426
 
        while (*permanenturl++ == '/') {
427
 
                if (!append_entryid_section (entryid, &permanenturl)) {
428
 
                        g_byte_array_free (entryid, TRUE);
429
 
                        return NULL;
430
 
                }
431
 
        }
432
 
 
433
 
        return entryid;
434
 
}
435
 
 
436
 
/**
437
 
 * e2k_ascii_strcase_equal
438
 
 * @v: a string
439
 
 * @v2: another string
440
 
 *
441
 
 * ASCII-case-insensitive comparison function for use with #GHashTable.
442
 
 *
443
 
 * Return value: %TRUE if @v and @v2 are ASCII-case-insensitively
444
 
 * equal, %FALSE if not.
445
 
 **/
446
 
gint
447
 
e2k_ascii_strcase_equal (gconstpointer v, gconstpointer v2)
448
 
{
449
 
        return !g_ascii_strcasecmp (v, v2);
450
 
}
451
 
 
452
 
/**
453
 
 * e2k_ascii_strcase_hash
454
 
 * @v: a string
455
 
 *
456
 
 * ASCII-case-insensitive hash function for use with #GHashTable.
457
 
 *
458
 
 * Return value: An ASCII-case-insensitive hashing of @v.
459
 
 **/
460
 
guint
461
 
e2k_ascii_strcase_hash (gconstpointer v)
462
 
{
463
 
        /* case-insensitive g_str_hash */
464
 
 
465
 
        const guchar *p = v;
466
 
        guint h = g_ascii_tolower (*p);
467
 
 
468
 
        if (h) {
469
 
                for (p += 1; *p != '\0'; p++)
470
 
                        h = (h << 5) - h + g_ascii_tolower (*p);
471
 
        }
472
 
 
473
 
        return h;
474
 
}
475
 
 
476
 
/**
477
 
 * e2k_restriction_folders_only:
478
 
 * @rn: a restriction
479
 
 *
480
 
 * Examines @rn, and determines if it can only return folders
481
 
 *
482
 
 * Return value: %TRUE if @rn will cause only folders to be returned
483
 
 **/
484
 
gboolean
485
 
e2k_restriction_folders_only (E2kRestriction *rn)
486
 
{
487
 
        gint i;
488
 
 
489
 
        if (!rn)
490
 
                return FALSE;
491
 
 
492
 
        switch (rn->type) {
493
 
        case E2K_RESTRICTION_PROPERTY:
494
 
                if (strcmp (rn->res.property.pv.prop.name,
495
 
                            E2K_PR_DAV_IS_COLLECTION) != 0)
496
 
                        return FALSE;
497
 
 
498
 
                /* return TRUE if it's "= TRUE" or "!= FALSE" */
499
 
                return (rn->res.property.relop == E2K_RELOP_EQ) ==
500
 
                        (rn->res.property.pv.value != NULL);
501
 
 
502
 
        case E2K_RESTRICTION_AND:
503
 
                for (i = 0; i < rn->res.and.nrns; i++) {
504
 
                        if (e2k_restriction_folders_only (rn->res.and.rns[i]))
505
 
                                return TRUE;
506
 
                }
507
 
                return FALSE;
508
 
 
509
 
        case E2K_RESTRICTION_OR:
510
 
                for (i = 0; i < rn->res.or.nrns; i++) {
511
 
                        if (!e2k_restriction_folders_only (rn->res.or.rns[i]))
512
 
                                return FALSE;
513
 
                }
514
 
                return TRUE;
515
 
 
516
 
        case E2K_RESTRICTION_NOT:
517
 
                return !e2k_restriction_folders_only (rn->res.not.rn);
518
 
 
519
 
        case E2K_RESTRICTION_COMMENT:
520
 
                return e2k_restriction_folders_only (rn->res.comment.rn);
521
 
 
522
 
        default:
523
 
                return FALSE;
524
 
        }
525
 
}
526
 
 
527
 
/* From MAPIDEFS.H */
528
 
static const gchar MAPI_ONE_OFF_UID[] = {
529
 
        0x81, 0x2b, 0x1f, 0xa4, 0xbe, 0xa3, 0x10, 0x19,
530
 
        0x9d, 0x6e, 0x00, 0xdd, 0x01, 0x0f, 0x54, 0x02
531
 
};
532
 
#define MAPI_ONE_OFF_UNICODE      0x8000
533
 
#define MAPI_ONE_OFF_NO_RICH_INFO 0x0001
534
 
#define MAPI_ONE_OFF_MYSTERY_FLAG 0x1000
535
 
 
536
 
/**
537
 
 * e2k_entryid_generate_oneoff:
538
 
 * @display_name: the display name of the user
539
 
 * @email: the email address
540
 
 * @unicode: %TRUE to generate a Unicode ENTRYID (in which case
541
 
 * @display_name should be UTF-8), %FALSE for an ASCII ENTRYID.
542
 
 *
543
 
 * Constructs a "one-off" ENTRYID value that can be used as a MAPI
544
 
 * recipient (eg, for a message forwarding server-side rule),
545
 
 * corresponding to @display_name and @email.
546
 
 *
547
 
 * Return value: the recipient ENTRYID
548
 
 **/
549
 
GByteArray *
550
 
e2k_entryid_generate_oneoff (const gchar *display_name, const gchar *email, gboolean unicode)
551
 
{
552
 
        GByteArray *entryid;
553
 
 
554
 
        entryid = g_byte_array_new ();
555
 
 
556
 
        e2k_rule_append_uint32 (entryid, 0);
557
 
        g_byte_array_append (entryid, (guint8 *) MAPI_ONE_OFF_UID, sizeof (MAPI_ONE_OFF_UID));
558
 
        e2k_rule_append_uint16 (entryid, 0);
559
 
        e2k_rule_append_uint16 (entryid,
560
 
                                MAPI_ONE_OFF_NO_RICH_INFO |
561
 
                                MAPI_ONE_OFF_MYSTERY_FLAG |
562
 
                                (unicode ? MAPI_ONE_OFF_UNICODE : 0));
563
 
 
564
 
        if (unicode) {
565
 
                e2k_rule_append_unicode (entryid, display_name);
566
 
                e2k_rule_append_unicode (entryid, "SMTP");
567
 
                e2k_rule_append_unicode (entryid, email);
568
 
        } else {
569
 
                e2k_rule_append_string (entryid, display_name);
570
 
                e2k_rule_append_string (entryid, "SMTP");
571
 
                e2k_rule_append_string (entryid, email);
572
 
        }
573
 
 
574
 
        return entryid;
575
 
}
576
 
 
577
 
static const gchar MAPI_LOCAL_UID[] = {
578
 
        0xdc, 0xa7, 0x40, 0xc8, 0xc0, 0x42, 0x10, 0x1a,
579
 
        0xb4, 0xb9, 0x08, 0x00, 0x2b, 0x2f, 0xe1, 0x82
580
 
};
581
 
 
582
 
/**
583
 
 * e2k_entryid_generate_local:
584
 
 * @exchange_dn: the Exchange 5.5-style DN of the local user
585
 
 *
586
 
 * Constructs an ENTRYID value that can be used as a MAPI
587
 
 * recipient (eg, for a message forwarding server-side rule),
588
 
 * corresponding to the local user identified by @exchange_dn.
589
 
 *
590
 
 * Return value: the recipient ENTRYID
591
 
 **/
592
 
GByteArray *
593
 
e2k_entryid_generate_local (const gchar *exchange_dn)
594
 
{
595
 
        GByteArray *entryid;
596
 
 
597
 
        entryid = g_byte_array_new ();
598
 
 
599
 
        e2k_rule_append_uint32 (entryid, 0);
600
 
        g_byte_array_append (entryid, (guint8 *) MAPI_LOCAL_UID, sizeof (MAPI_LOCAL_UID));
601
 
        e2k_rule_append_uint16 (entryid, 1);
602
 
        e2k_rule_append_uint16 (entryid, 0);
603
 
        e2k_rule_append_string (entryid, exchange_dn);
604
 
 
605
 
        return entryid;
606
 
}
607
 
 
608
 
static const gchar MAPI_CONTACT_UID[] = {
609
 
        0xfe, 0x42, 0xaa, 0x0a, 0x18, 0xc7, 0x1a, 0x10,
610
 
        0xe8, 0x85, 0x0b, 0x65, 0x1c, 0x24, 0x00, 0x00
611
 
};
612
 
 
613
 
/**
614
 
 * e2k_entryid_generate_contact:
615
 
 * @contact_entryid: the #PR_ENTRYID of an item in the user's Contacts
616
 
 * folder.
617
 
 * @nth_address: which of the contact's email addresses to use.
618
 
 *
619
 
 * Constructs an ENTRYID value that can be used as a MAPI recipient
620
 
 * (eg, for a message forwarding server-side rule), corresponding to
621
 
 * the Contacts folder entry identified by @contact_entryid.
622
 
 *
623
 
 * Return value: the recipient ENTRYID
624
 
 **/
625
 
GByteArray *
626
 
e2k_entryid_generate_contact (GByteArray *contact_entryid, gint nth_address)
627
 
{
628
 
        GByteArray *entryid;
629
 
 
630
 
        entryid = g_byte_array_new ();
631
 
 
632
 
        e2k_rule_append_uint32 (entryid, 0);
633
 
        g_byte_array_append (entryid, (guint8 *) MAPI_CONTACT_UID, sizeof (MAPI_CONTACT_UID));
634
 
        e2k_rule_append_uint32 (entryid, 3);
635
 
        e2k_rule_append_uint32 (entryid, 4);
636
 
        e2k_rule_append_uint32 (entryid, nth_address);
637
 
        e2k_rule_append_uint32 (entryid, contact_entryid->len);
638
 
        g_byte_array_append (entryid, contact_entryid->data, contact_entryid->len);
639
 
 
640
 
        return entryid;
641
 
}
642
 
 
643
 
/**
644
 
 * e2k_search_key_generate:
645
 
 * @addrtype: the type of @address (usually "SMTP" or "EX")
646
 
 * @address: the address data
647
 
 *
648
 
 * Constructs a PR_SEARCH_KEY value for @address
649
 
 *
650
 
 * Return value: the search key
651
 
 **/
652
 
GByteArray *
653
 
e2k_search_key_generate (const gchar *addrtype, const gchar *address)
654
 
{
655
 
        GByteArray *search_key;
656
 
        guint8 *p;
657
 
 
658
 
        search_key = g_byte_array_new ();
659
 
        g_byte_array_append (search_key, (guint8 *) addrtype, strlen (addrtype));
660
 
        g_byte_array_append (search_key, (guint8 *) ":", 1);
661
 
        g_byte_array_append (search_key, (guint8 *) address, strlen (address));
662
 
        g_byte_array_append (search_key, (guint8 *) "", 1);
663
 
 
664
 
        for (p = search_key->data; *p; p++)
665
 
                *p = g_ascii_toupper (*p);
666
 
 
667
 
        return search_key;
668
 
}