~ubuntu-branches/debian/jessie/openchange/jessie

« back to all changes in this revision

Viewing changes to .pc/03_no_popt/utils/exchange2mbox.c

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2012-04-12 03:46:04 UTC
  • Revision ID: package-import@ubuntu.com-20120412034604-ouznoux6dcbp1g48
Tags: 1:1.0-2
* Remove unnecessary links.
* Add patch 03_no_popt: Avoid use of samba/popt.h, which is no longer
  present in newer versions of Samba.
* Depend on newer version of pidl with fix for CVE-2012-1182.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Convert Exchange mails to mbox
 
3
 
 
4
   OpenChange Project
 
5
 
 
6
   Copyright (C) Julien Kerihuel 2007
 
7
 
 
8
   This program is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 3 of the License, or
 
11
   (at your option) any later version.
 
12
   
 
13
   This program is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
   
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
 
 
22
#include "libmapi/libmapi.h"
 
23
#include <samba/popt.h>
 
24
#include <ldb.h>
 
25
 
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
 
 
29
#include <fcntl.h>
 
30
#include <unistd.h>
 
31
#include <errno.h>
 
32
#include <time.h>
 
33
 
 
34
#include <param.h>
 
35
#include <magic.h>
 
36
 
 
37
#include <string.h>
 
38
#include <ctype.h>
 
39
 
 
40
#include "openchange-tools.h"
 
41
 
 
42
/* Ugly and lazy but working ... */
 
43
#define DEFAULT_BOUNDARY_BASE   "DocE+STaALJfprDB"
 
44
#define MESSAGEID       "Message-ID: "
 
45
#define MESSAGEID_LEN   11
 
46
 
 
47
/*
 
48
 * how much to request at a time,  and it's complex :-(
 
49
 * This was 4096 - was getting NT_STATUS_BUFFER_TOO_SMALL loading large
 
50
 *                 attachments
 
51
 * It must be less than 16K (Windows API is a signed short)
 
52
 * If you ask for more than windows allows you get nothing.
 
53
 * Asking for too little just dogs the performance
 
54
 *
 
55
 * found the NTSTATUS error by adding debug to the ReadStream code.
 
56
 */
 
57
#define MAX_READ_SIZE   12000
 
58
 
 
59
static int message_error = 0;   /* did we get an error processing message */
 
60
 
 
61
static bool opt_test = false;
 
62
 
 
63
static char boundary_base[128] = DEFAULT_BOUNDARY_BASE;
 
64
 
 
65
static time_t start_time;
 
66
 
 
67
static char *boundary(int index)
 
68
{
 
69
        snprintf(boundary_base, sizeof(boundary_base), "%s_%lu_%d",
 
70
                        DEFAULT_BOUNDARY_BASE, (unsigned long) start_time, index);
 
71
        return boundary_base;
 
72
}
 
73
 
 
74
static void fix_froms(unsigned char *cp, int len)
 
75
{
 
76
        unsigned char *ep = cp + len;
 
77
        for (; cp + 6 < ep; cp++) {
 
78
                if (*cp != '\n')
 
79
                        continue;
 
80
                if (strncmp((char *)cp, "\nFrom ", 6) == 0) {
 
81
                        cp[1] = 'f';
 
82
                        cp += 5;
 
83
                }
 
84
        }
 
85
}
 
86
 
 
87
/*
 
88
 * find a Header at the start of a line (or the start of the text)
 
89
 */
 
90
 
 
91
static char *find_header(char *cp, char *hdr)
 
92
{
 
93
        char *ep;
 
94
        while ((ep = strcasestr(cp, hdr))) {
 
95
                if (ep == cp || ep[-1] == '\n')
 
96
                        return ep;
 
97
                cp = ep + 1;
 
98
        }
 
99
        return NULL;
 
100
}
 
101
 
 
102
 
 
103
/**
 
104
 * delete a message on the exchange server
 
105
 */
 
106
static bool delete_messages(
 
107
        TALLOC_CTX *mem_ctx,
 
108
        struct mapi_session     *session,
 
109
        char **del_msgid, 
 
110
        int del_count)
 
111
{
 
112
        enum MAPISTATUS         retval;
 
113
        mapi_object_t           obj_store;
 
114
        mapi_object_t           obj_inbox;
 
115
        mapi_object_t           obj_table;
 
116
        mapi_id_t               id_inbox;
 
117
        struct SPropTagArray    *SPropTagArray;
 
118
        struct SRowSet          SRowSet;
 
119
        uint32_t                i, j;
 
120
        uint64_t                id_message;
 
121
        struct mapi_profile     *profile;
 
122
 
 
123
        if (!del_count || !del_msgid) {
 
124
                return false;
 
125
        }
 
126
 
 
127
        profile = session->profile;
 
128
 
 
129
        /* Open the default message store */
 
130
        mapi_object_init(&obj_store);
 
131
        retval = OpenMsgStore(session, &obj_store);
 
132
        if (retval != MAPI_E_SUCCESS) return false;
 
133
 
 
134
        /* Open Inbox */
 
135
        retval = GetReceiveFolder(&obj_store, &id_inbox, NULL);
 
136
        if (retval != MAPI_E_SUCCESS) return false;
 
137
 
 
138
        mapi_object_init(&obj_inbox);
 
139
        retval = OpenFolder(&obj_store, id_inbox, &obj_inbox);
 
140
        if (retval != MAPI_E_SUCCESS) return false;
 
141
 
 
142
        mapi_object_init(&obj_table);
 
143
        retval = GetContentsTable(&obj_inbox, &obj_table, 0, NULL);
 
144
        if (retval != MAPI_E_SUCCESS) return false;
 
145
 
 
146
        SPropTagArray = set_SPropTagArray(mem_ctx, 0x3,
 
147
                                          PR_FID,
 
148
                                          PR_MID,
 
149
                                          PR_INTERNET_MESSAGE_ID);
 
150
        retval = SetColumns(&obj_table, SPropTagArray);
 
151
        MAPIFreeBuffer(SPropTagArray);
 
152
 
 
153
        if (retval != MAPI_E_SUCCESS)
 
154
                return false;
 
155
 
 
156
        while ((retval = QueryRows(&obj_table, 0xa, TBL_ADVANCE, &SRowSet)) == MAPI_E_SUCCESS) {
 
157
                if (!SRowSet.cRows)
 
158
                        break;
 
159
 
 
160
                for (i = 0; i < SRowSet.cRows; i++) {
 
161
                        const char      *message_id;
 
162
 
 
163
                        message_id = (const char *)find_SPropValue_data(&(SRowSet.aRow[i]), PR_INTERNET_MESSAGE_ID);
 
164
 
 
165
                        if (!message_id)
 
166
                                continue;
 
167
 
 
168
                        for (j = 0; j < del_count; j++) {
 
169
                                if (strcmp(message_id, del_msgid[j]) == 0) {
 
170
                                        id_message = SRowSet.aRow[i].lpProps[1].value.d;
 
171
                                        retval = DeleteMessage(&obj_inbox, &id_message, 1);
 
172
                                        if (retval == MAPI_E_SUCCESS) {
 
173
                                                printf("%s deleted from the Exchange server\n",
 
174
                                                                del_msgid[j]);
 
175
                                                retval =
 
176
                                                mapi_profile_delete_string_attr(profile->mapi_ctx,
 
177
                                                                profile->profname, "Message-ID", del_msgid[j]);
 
178
                                                if (retval)
 
179
                                                        printf("%s not deleted from profile %s: err=0x%x\n",
 
180
                                                                        del_msgid[j], profile->profname, retval);
 
181
                                        } else {
 
182
                                                printf("%s NOT deleted from the Exchange server\n",
 
183
                                                                del_msgid[j]);
 
184
                                        }
 
185
                                }
 
186
                        }
 
187
                }
 
188
        }
 
189
        
 
190
        mapi_object_release(&obj_table);
 
191
        mapi_object_release(&obj_inbox);
 
192
        mapi_object_release(&obj_store);
 
193
 
 
194
        return true;
 
195
}
 
196
 
 
197
/**
 
198
 * Fetch message ids from the existing mbox
 
199
 */
 
200
static uint32_t update(
 
201
        TALLOC_CTX *mem_ctx, FILE *fp, 
 
202
        struct mapi_session     *session)
 
203
{
 
204
        enum MAPISTATUS         retval;
 
205
        struct mapi_profile     *profile;
 
206
        size_t                  read_size;
 
207
        char                    *line = NULL;
 
208
#if !defined(__FreeBSD__)
 
209
        ssize_t                 size;
 
210
#endif
 
211
        const char              *msgid;
 
212
        char                    *id;
 
213
        char                    **mbox_msgids;
 
214
        char                    **prof_msgids;
 
215
        unsigned int            mbox_count = 0;
 
216
        unsigned int            count;
 
217
        unsigned int            i, j;
 
218
        bool                    found = false;
 
219
        char                    **del_msgids;
 
220
        unsigned int            del_count = 0;
 
221
 
 
222
        profile = session->profile;
 
223
 
 
224
        mbox_msgids = talloc_zero(mem_ctx, char *);
 
225
        /* Add Message-ID attribute to the profile if it is missing */
 
226
#if defined(__FreeBSD__)
 
227
        while ((line = fgetln(fp, &read_size)) != NULL) {
 
228
#else
 
229
        while ((size = getline(&line, &read_size, fp)) != -1) {
 
230
#endif
 
231
                if (line && !strncmp(line, MESSAGEID, strlen(MESSAGEID))) {
 
232
                        msgid = strstr(line, MESSAGEID);
 
233
                        id = talloc_strdup(mem_ctx, msgid + strlen(MESSAGEID));
 
234
                        id[strlen(id) - 1] = 0;
 
235
 
 
236
                        mbox_msgids = talloc_realloc(mem_ctx, mbox_msgids, char *, mbox_count + 2);
 
237
                        mbox_msgids[mbox_count] = talloc_strdup(mem_ctx, id);
 
238
                        mbox_count++;
 
239
 
 
240
                        retval = FindProfileAttr(profile, "Message-ID", id);
 
241
                        if (GetLastError() == MAPI_E_NOT_FOUND) {
 
242
                                errno = 0;
 
243
                                printf("[+] Adding %s to %s\n", id, profile->profname);
 
244
                                retval = mapi_profile_add_string_attr(profile->mapi_ctx, profile->profname, "Message-ID", id);
 
245
                                if (retval != MAPI_E_SUCCESS) {
 
246
                                        mapi_errstr("mapi_profile_add_string_attr", GetLastError());
 
247
#if 0
 
248
                                        talloc_free(profname);
 
249
                                        MAPIUninitialize(profile->mapi_ctx);
 
250
#endif
 
251
                                        return -1;
 
252
                                }
 
253
                        }
 
254
                        talloc_free(id);
 
255
                }
 
256
                
 
257
        }
 
258
        if (line)
 
259
                free(line);
 
260
 
 
261
        /* Remove Message-ID and update Exchange mailbox if a
 
262
         * Message-ID is missing in mbox 
 
263
         */
 
264
        retval = GetProfileAttr(profile, "Message-ID", &count, &prof_msgids);
 
265
        if (retval == MAPI_E_NOT_FOUND) {
 
266
                printf("No Synchonizing is needed at all\n");
 
267
                return MAPI_E_SUCCESS;
 
268
        } else if (retval) {
 
269
                fprintf(stderr, "GetProfileAttr failed - %x\n", retval);
 
270
                return retval;
 
271
        }
 
272
 
 
273
        if (count != mbox_count) {
 
274
                printf("{+] Synchonizing mbox with Exchange mailbox\n");
 
275
 
 
276
                del_msgids = talloc_zero(mem_ctx, char *);
 
277
                del_count = 0;
 
278
 
 
279
                for (i = 0; i < count; i++) {
 
280
                        found = false;
 
281
                        for (j = 0; j < mbox_count; j++) {
 
282
                                if (!strcmp(prof_msgids[i], mbox_msgids[j])) {
 
283
                                        found = true;
 
284
                                }
 
285
                        }
 
286
                        if (found == false) {
 
287
                                del_msgids = talloc_realloc(mem_ctx, del_msgids, char *, del_count + 2);
 
288
                                del_msgids[del_count] = talloc_strdup(mem_ctx, prof_msgids[i]);
 
289
                                del_count++;
 
290
                        }
 
291
                }
 
292
 
 
293
                delete_messages(mem_ctx, session, del_msgids, del_count);
 
294
 
 
295
                talloc_free(del_msgids);
 
296
                del_count = 0;
 
297
        } else {
 
298
                printf("[+] mbox already synchronized with Exchange Mailbox\n");
 
299
        }
 
300
 
 
301
        talloc_free(prof_msgids);
 
302
        talloc_free(mbox_msgids);
 
303
 
 
304
        return MAPI_E_SUCCESS;
 
305
}
 
306
 
 
307
static const char *get_filename(const char *filename)
 
308
{
 
309
        const char *substr;
 
310
 
 
311
        if (!filename) return NULL;
 
312
 
 
313
        substr = rindex(filename, '/');
 
314
        if (substr) return substr;
 
315
 
 
316
        return filename;
 
317
}
 
318
 
 
319
 
 
320
static char *get_base64_attachment(TALLOC_CTX *mem_ctx, mapi_object_t *obj_attach, const uint32_t size, char **magic)
 
321
{
 
322
        enum MAPISTATUS retval;
 
323
        const char      *tmp;
 
324
        char            *ret;
 
325
        mapi_object_t   obj_stream;
 
326
        uint32_t        stream_size;
 
327
        uint16_t        read_size;
 
328
        DATA_BLOB       data;
 
329
        magic_t         cookie = NULL;
 
330
 
 
331
        mapi_object_init(&obj_stream);
 
332
        retval = OpenStream(obj_attach, PR_ATTACH_DATA_BIN, 0, &obj_stream);
 
333
        if (retval != MAPI_E_SUCCESS) {
 
334
                fprintf(stderr, "OpenStream failed %x\n", retval);
 
335
                return NULL;
 
336
        }
 
337
 
 
338
        data.length = 0;
 
339
        data.data = talloc_zero_size(mem_ctx, size);
 
340
 
 
341
        for (stream_size = 0; stream_size < size; ) {
 
342
                /*
 
343
                 * exchange can only handle about 4K chunks at a time,  and don't
 
344
                 * ask for more or you get none
 
345
                 */
 
346
                retval = ReadStream(&obj_stream, data.data + stream_size,
 
347
                                (stream_size + MAX_READ_SIZE < size) ? MAX_READ_SIZE :
 
348
                                        (size - stream_size), &read_size);
 
349
                if ((retval != MAPI_E_SUCCESS) || read_size == 0)
 
350
                        break;
 
351
                stream_size += read_size;
 
352
        }
 
353
        if (retval != MAPI_E_SUCCESS) {
 
354
                fprintf(stderr, "ReadStream failed retval=%x read_size=%d "
 
355
                                "stream_size=%d size=%d\n",
 
356
                                                retval, read_size, stream_size, size);
 
357
                talloc_free(data.data);
 
358
                mapi_object_release(&obj_stream);
 
359
                return NULL;
 
360
        }
 
361
 
 
362
        data.length = stream_size;
 
363
 
 
364
        if (magic) {
 
365
                /* if they want a mime magic string try and autodetect one */
 
366
                cookie = magic_open(MAGIC_MIME);
 
367
                if (cookie == NULL) {
 
368
                        fprintf(stderr, "%s,%d - NULL\n", __FILE__, __LINE__);
 
369
                        printf("%s\n", magic_error(cookie));
 
370
                        talloc_free(data.data);
 
371
                        mapi_object_release(&obj_stream);
 
372
                        return NULL;
 
373
                }
 
374
                if (magic_load(cookie, NULL) == -1) {
 
375
                        fprintf(stderr, "%s,%d - NULL\n", __FILE__, __LINE__);
 
376
                        printf("%s\n", magic_error(cookie));
 
377
                        talloc_free(data.data);
 
378
                        mapi_object_release(&obj_stream);
 
379
                        return NULL;
 
380
                }
 
381
                tmp = magic_buffer(cookie, (void *)data.data, data.length);
 
382
                *magic = talloc_strdup(mem_ctx, tmp);
 
383
                magic_close(cookie);
 
384
        }
 
385
 
 
386
        /* convert attachment to base64 */
 
387
        ret = ldb_base64_encode(mem_ctx, (const char *)data.data, data.length);
 
388
 
 
389
        talloc_free(data.data);
 
390
        mapi_object_release(&obj_stream);
 
391
 
 
392
        return ret;
 
393
}
 
394
 
 
395
 
 
396
#define WRAP_LINES_AT   76
 
397
 
 
398
static void write_base64_data(FILE *fp, const char *buf)
 
399
{
 
400
        int len = strlen(buf);
 
401
        size_t n;
 
402
 
 
403
        while (len > 0) {
 
404
                int chunk = len > WRAP_LINES_AT ? WRAP_LINES_AT : len;
 
405
 
 
406
                n = fwrite(buf, len > WRAP_LINES_AT ? WRAP_LINES_AT : len, 1, fp);
 
407
                if (n != 1)
 
408
                        fprintf(stderr, "Error writing %d bytes of base64 attachment: %d\n",
 
409
                                chunk, ferror(fp));
 
410
                len -= chunk;
 
411
                buf += chunk;
 
412
                fwrite("\n", 1, 1, fp);
 
413
        }
 
414
}
 
415
 
 
416
 
 
417
/*
 
418
 * Read a stream and store it in a DATA_BLOB
 
419
 */
 
420
static enum MAPISTATUS get_stream(TALLOC_CTX *mem_ctx,
 
421
                                         mapi_object_t *obj_stream, 
 
422
                                         DATA_BLOB *body)
 
423
{
 
424
        enum MAPISTATUS retval;
 
425
        uint16_t        read_size;
 
426
        uint8_t         buf[MAX_READ_SIZE];
 
427
 
 
428
        body->length = 0;
 
429
        body->data = talloc_zero(mem_ctx, uint8_t);
 
430
 
 
431
        do {
 
432
                retval = ReadStream(obj_stream, buf, MAX_READ_SIZE, &read_size);
 
433
                MAPI_RETVAL_IF(retval, GetLastError(), body->data);
 
434
                if (read_size) {
 
435
                        body->data = talloc_realloc(mem_ctx, body->data, uint8_t,
 
436
                                                    body->length + read_size);
 
437
                        memcpy(&(body->data[body->length]), buf, read_size);
 
438
                        body->length += read_size;
 
439
                }
 
440
        } while (read_size);
 
441
 
 
442
        errno = 0;
 
443
        return MAPI_E_SUCCESS;
 
444
}
 
445
 
 
446
typedef struct {
 
447
   DATA_BLOB body;
 
448
   char *body_header;
 
449
} body_stuff_t;
 
450
 
 
451
/* Fetch the body, no fancy junk */
 
452
static enum MAPISTATUS get_body(TALLOC_CTX *mem_ctx,
 
453
                                       mapi_object_t *obj_message,
 
454
                                       struct SRow *aRow,
 
455
                                           body_stuff_t body[3],
 
456
                                           int *body_count)
 
457
{
 
458
        mapi_object_t           obj_stream;
 
459
        enum MAPISTATUS                 retval;
 
460
        char *data;
 
461
        const struct SBinary_short      *bin;
 
462
 
 
463
        *body_count = 0;
 
464
        memset(body, 0, sizeof(body));
 
465
 
 
466
        data = octool_get_propval(aRow, PR_BODY);
 
467
        if (data && strlen(data)) {
 
468
                body[*body_count].body.data = talloc_memdup(mem_ctx, data, strlen(data));
 
469
                body[*body_count].body.length = strlen(data);
 
470
                body[*body_count].body_header = "Content-Type: text/plain; charset=us-ascii\n";
 
471
                (*body_count)++;
 
472
        }
 
473
 
 
474
        bin = (const struct SBinary_short *) octool_get_propval(aRow, PR_HTML);
 
475
        if (bin && bin->cb) {
 
476
                body[*body_count].body.data = talloc_memdup(mem_ctx, bin->lpb, bin->cb);
 
477
                body[*body_count].body.length = bin->cb;
 
478
                body[*body_count].body_header = "Content-Type: text/html\n";
 
479
                (*body_count)++;
 
480
        }
 
481
        
 
482
#if 0
 
483
        bin = (const struct SBinary_short *) octool_get_propval(aRow, PR_RTF_COMPRESSED);
 
484
        if (bin && bin->cb) {
 
485
                body[*body_count].body.data = talloc_memdup(mem_ctx, bin->lpb, bin->cb);
 
486
                body[*body_count].body.length = bin->cb;
 
487
                body[*body_count].body_header = "Content-Type: text/rtf\n";
 
488
                (*body_count)++;
 
489
        }
 
490
#endif
 
491
 
 
492
        if (*body_count <= 0) {
 
493
                printf("No HTML or TEXT, generating TEXT body\n");
 
494
                /* generate a body for us ? */
 
495
                mapi_object_init(&obj_stream);
 
496
                retval = OpenStream(obj_message, PR_BODY, 0, &obj_stream);
 
497
                if (retval) {
 
498
                        fprintf(stderr, "Failed to get a message body, making empty one: %x\n", retval);
 
499
                        //message_error = 1;
 
500
                        body[*body_count].body.data = talloc_zero(mem_ctx, uint8_t);
 
501
                        body[*body_count].body.length = 0;
 
502
                        body[*body_count].body_header = "Content-Type: text/plain; charset=us-ascii\n";
 
503
                        (*body_count)++;
 
504
                        body[*body_count].body.length = 0;
 
505
                } else {
 
506
                        retval = get_stream(mem_ctx, &obj_stream, &body[*body_count].body);
 
507
                        if (retval) {
 
508
                                body[*body_count].body.length = 0;
 
509
                                fprintf(stderr, "HTML ERROR1 %x\n", retval);
 
510
                        }
 
511
                }
 
512
                mapi_object_release(&obj_stream);
 
513
                if (body[*body_count].body.length) {
 
514
                        body[*body_count].body_header = "Content-Type: text/plain; charset=us-ascii\n";
 
515
                        (*body_count)++;
 
516
                }
 
517
        }
 
518
 
 
519
        return MAPI_E_SUCCESS;
 
520
}
 
521
 
 
522
/**
 
523
   Sample mbox mail:
 
524
 
 
525
   From Administrator Mon Apr 23 14:43:01 2007
 
526
   Date: Mon Apr 23 14:43:01 2007
 
527
   From: Administrator 
 
528
   To: Julien Kerihuel
 
529
   Subject: This is the subject
 
530
 
 
531
   This is a sample mail
 
532
 
 
533
**/
 
534
 
 
535
static bool message2mbox(TALLOC_CTX *mem_ctx, FILE *fp, 
 
536
                         struct SRow *aRow, mapi_object_t *obj_message,
 
537
                         int base_level)
 
538
{
 
539
        enum MAPISTATUS                 retval;
 
540
        mapi_object_t                   obj_tb_attach;
 
541
        mapi_object_t                   obj_attach;
 
542
        const uint64_t                  *delivery_date;
 
543
        const char                      *date = NULL;
 
544
        const char                      *to = NULL;
 
545
        const char                      *cc = NULL;
 
546
        const char                      *bcc = NULL;
 
547
        const char                      *from = NULL;
 
548
        const char                      *subject = NULL;
 
549
        const char                      *msgid;
 
550
        const char                      *msgheaders = NULL;
 
551
        const char                      *attach_filename;
 
552
        const uint32_t                  *attach_size;
 
553
        char                            *attachment_data;
 
554
        const uint8_t                   *has_attach = NULL;
 
555
        const uint32_t                  *attach_num = NULL;
 
556
        char                            *magic;
 
557
        char                            *line = NULL;
 
558
        struct SPropTagArray            *SPropTagArray = NULL;
 
559
        struct SPropValue               *lpProps;
 
560
        struct SRow                     aRow2;
 
561
        struct SRowSet                  rowset_attach;
 
562
        uint32_t                        count;
 
563
        unsigned int                    i;
 
564
        int                             header_done = 0;
 
565
        body_stuff_t                    body[3];
 
566
        int                             body_count = 0;
 
567
 
 
568
        has_attach = (const uint8_t *) octool_get_propval(aRow, PR_HASATTACH);
 
569
        to = (const char *) octool_get_propval(aRow, PR_DISPLAY_TO);
 
570
        cc = (const char *) octool_get_propval(aRow, PR_DISPLAY_CC);
 
571
        bcc = (const char *) octool_get_propval(aRow, PR_DISPLAY_BCC);
 
572
 
 
573
        delivery_date = (const uint64_t *)octool_get_propval(aRow, PR_MESSAGE_DELIVERY_TIME);
 
574
        if (delivery_date) {
 
575
                date = nt_time_string(mem_ctx, *delivery_date);
 
576
        } else {
 
577
                date = "None";
 
578
        }
 
579
 
 
580
        from = (const char *) octool_get_propval(aRow, PR_SENT_REPRESENTING_NAME);
 
581
        if (from == NULL) {
 
582
                from = "unknown";
 
583
        }
 
584
 
 
585
        subject = (const char*) octool_get_propval(aRow, PR_SUBJECT);
 
586
        msgid = (const char *) octool_get_propval(aRow, PR_INTERNET_MESSAGE_ID);
 
587
 
 
588
        msgheaders = (const char *) octool_get_propval(aRow, PR_TRANSPORT_MESSAGE_HEADERS);
 
589
 
 
590
        retval = get_body(mem_ctx, obj_message, aRow, body, &body_count);
 
591
 
 
592
        /* First line From - but only if base_level == 0 */
 
593
        if (base_level == 0) {
 
594
                char *f, *p;
 
595
                f = talloc_strdup(mem_ctx, from);
 
596
                /* strip out all '"'s, ugly but works */
 
597
                for (p = f; p && *p; ) {
 
598
                        if (*p == '"') {
 
599
                                memmove(p, p+1, strlen(p)); /* gets NUL */
 
600
                                continue;
 
601
                        }
 
602
                        p++;
 
603
                }
 
604
                fprintf(fp, "From \"%s\" %s\n", f, date);
 
605
                talloc_free(f);
 
606
        }
 
607
 
 
608
        if (msgheaders) {
 
609
                char *mhalloc, *mhclean, *mhend, *mhp, *mht;
 
610
                
 
611
                mhalloc = talloc_strdup(mem_ctx, msgheaders);
 
612
 
 
613
                mhclean = mhalloc;
 
614
                do {
 
615
                        /* Skip past the comment Exchange adds to the beginning */
 
616
                        mhclean = strchr(mhclean, '\n');
 
617
                        if (!mhclean)
 
618
                                goto old_code;
 
619
                        mhclean++;
 
620
                } while (isspace(*mhclean));
 
621
                
 
622
                /* Trim off the empty mime parts that Exchange leaves after 
 
623
                   the end of the headers */
 
624
                mhend = strstr(mhclean, "\n------=");
 
625
                if (mhend) {
 
626
                        mhend++;
 
627
                        *mhend = '\0';
 
628
                }
 
629
 
 
630
                /* strip CR/NL */
 
631
                while ((mhend = strchr(mhclean, '\r')))
 
632
                        memmove(mhend, mhend+1, strlen(mhend) /* gets NUL */);
 
633
 
 
634
                /*
 
635
                 * strip Content-* headers (we make our own), be sure to get
 
636
                 * and extended (indented parts) of this header
 
637
                 */
 
638
                while (1) {
 
639
                        /*
 
640
                         * strip some bad-for-us headers (poor mans lookup table below :-)
 
641
                         */
 
642
                        mhend = find_header(mhclean, "Content-");
 
643
                        if (!mhend)
 
644
                                mhend = find_header(mhclean, "X-MS-");
 
645
                        if (!mhend)
 
646
                                mhend = find_header(mhclean, "Lines:");
 
647
                        if (!mhend)
 
648
                                break;
 
649
                        mhp = NULL;
 
650
                        if (mhend) {
 
651
                                mht = mhend;
 
652
                                while ((mhp = strchr(mht, '\n'))) {
 
653
                                        mhp++;
 
654
                                        if (!*mhp || !isspace(*mhp))
 
655
                                                break;
 
656
                                        mht = mhp;
 
657
                                }
 
658
                        }
 
659
                        if (mhp) {
 
660
                                /* match was in the middle of other headers */
 
661
                                memmove(mhend, mhp, strlen(mhp) + 1);
 
662
                        } else if (mhend) {
 
663
                                /* match was at the end of the headers, truncate it */
 
664
                                *mhend = '\0';
 
665
                        }
 
666
                }
 
667
 
 
668
                /* remove any NL's at end of headers */
 
669
                mhp = mhclean + strlen(mhclean);
 
670
                while (mhp > mhclean && mhp[-1] == '\n')
 
671
                        *--mhp = '\0';
 
672
                
 
673
                line = talloc_asprintf(mem_ctx, "%s\n", mhclean);
 
674
                if (line) fwrite(line, strlen(line), 1, fp);
 
675
                talloc_free(line);
 
676
                talloc_free(mhalloc);
 
677
        }
 
678
 
 
679
old_code:
 
680
        if (!msgheaders) {
 
681
                /* Second line: Date */
 
682
                line = talloc_asprintf(mem_ctx, "Date: %s\n", date);
 
683
                if (line) {
 
684
                        fwrite(line, strlen(line), 1, fp);
 
685
                }
 
686
                talloc_free(line);
 
687
 
 
688
                /* Third line From */
 
689
                line = talloc_asprintf(mem_ctx, "From: %s\n", from);
 
690
                if (line) {
 
691
                        fwrite(line, strlen(line), 1, fp);
 
692
                }
 
693
                talloc_free(line);
 
694
 
 
695
                /* To, Cc, Bcc */
 
696
                if (to) {
 
697
                        line = talloc_asprintf(mem_ctx, "To: %s\n", to);
 
698
                        if (line) {
 
699
                                fwrite(line, strlen(line), 1, fp);
 
700
                        }
 
701
                        talloc_free(line);
 
702
                }
 
703
 
 
704
                if (cc) {
 
705
                        line = talloc_asprintf(mem_ctx, "Cc: %s\n", cc);
 
706
                        if (line) {
 
707
                                fwrite(line, strlen(line), 1, fp);
 
708
                        }
 
709
                        talloc_free(line);
 
710
                }
 
711
 
 
712
                if (bcc) {
 
713
                        line = talloc_asprintf(mem_ctx, "Bcc: %s\n", bcc);
 
714
                        if (line) {
 
715
                                fwrite(line, strlen(line), 1, fp);
 
716
                        }
 
717
                        talloc_free(line);
 
718
                }
 
719
 
 
720
                /* Subject */
 
721
                if (subject) {
 
722
                        line = talloc_asprintf(mem_ctx, "Subject: %s\n", subject);
 
723
                        if (line) {
 
724
                                fwrite(line, strlen(line), 1, fp);
 
725
                        }
 
726
                        talloc_free(line);
 
727
                }
 
728
 
 
729
                if (msgid) {
 
730
                        line = talloc_asprintf(mem_ctx, "Message-ID: %s\n", msgid);
 
731
                        if (line) {
 
732
                                fwrite(line, strlen(line), 1, fp);
 
733
                        }
 
734
                        talloc_free(line);
 
735
                }
 
736
        }
 
737
 
 
738
        /* Set multi-type if we have attachment mixed for all things/alternative
 
739
         * for just bodies */
 
740
        if (has_attach && *has_attach) {
 
741
                fprintf(fp, "Content-Type: multipart/mixed; boundary=\"%s\"\n",
 
742
                                boundary(base_level+0));
 
743
        } else if (body_count > 1) {
 
744
                fprintf(fp, "Content-Type: multipart/alternative; boundary=\"%s\"\n",
 
745
                                boundary(base_level+0));
 
746
        }
 
747
 
 
748
        /* body */
 
749
        if (body_count > 0) {
 
750
                if ((has_attach && *has_attach) || body_count > 1) {
 
751
                        /* blank line before content */
 
752
                        if (!header_done) {
 
753
                                fwrite("\n", 1, 1, fp);
 
754
                                header_done = 1;
 
755
                        }
 
756
                        fprintf(fp, "--%s\n", boundary(base_level+0));
 
757
                }
 
758
 
 
759
                /*
 
760
                 * if we have more than 1 body we need to do a multipart alternative
 
761
                 * within the first attachment
 
762
                 */
 
763
                if ((has_attach && *has_attach) && body_count > 1) {
 
764
                        fprintf(fp, "Content-Type: multipart/alternative; boundary=\"%s\"\n", boundary(base_level+1));
 
765
                        fwrite("\n", 1, 1, fp);
 
766
                        fprintf(fp, "\n\n--%s\n", boundary(base_level+1));
 
767
                }
 
768
 
 
769
                /*
 
770
                 * output content type
 
771
                 */
 
772
                fwrite(body[0].body_header, strlen(body[0].body_header), 1, fp);
 
773
                fprintf(fp, "Content-Disposition: inline\n");
 
774
 
 
775
                /* blank after header */
 
776
                fwrite("\n", 1, 1, fp);
 
777
                header_done = 1;
 
778
 
 
779
                fix_froms(body[0].body.data, body[0].body.length);
 
780
                fwrite(body[0].body.data, body[0].body.length, 1, fp);
 
781
                talloc_free(body[0].body.data);
 
782
        }
 
783
 
 
784
        /* blank line before content */
 
785
        if (!header_done) {
 
786
                fwrite("\n", 1, 1, fp);
 
787
                header_done = 1;
 
788
        }
 
789
 
 
790
        /* do the other bodies before attachments */
 
791
        for (i = 1; i < body_count && i < 3; i++) {
 
792
                if (has_attach && *has_attach) {
 
793
                        fprintf(fp, "\n\n--%s\n", boundary(base_level+1));
 
794
                } else {
 
795
                        fprintf(fp, "\n\n--%s\n", boundary(base_level+0));
 
796
                }
 
797
                fwrite(body[i].body_header, strlen(body[i].body_header), 1, fp);
 
798
                fprintf(fp, "Content-Disposition: inline\n");
 
799
                fwrite("\n", 1, 1, fp);
 
800
                fix_froms(body[i].body.data, body[i].body.length);
 
801
                fwrite(body[i].body.data, body[i].body.length, 1, fp);
 
802
        }
 
803
 
 
804
        if (has_attach && *has_attach) {
 
805
                /* close body attachments */
 
806
                if (body_count > 1) {
 
807
                        fprintf(fp, "\n\n--%s--\n", boundary(base_level+1));
 
808
                }
 
809
 
 
810
                mapi_object_init(&obj_tb_attach);
 
811
                retval = GetAttachmentTable(obj_message, &obj_tb_attach);
 
812
                if (retval == MAPI_E_SUCCESS) {
 
813
                        SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_ATTACH_NUM);
 
814
                        retval = SetColumns(&obj_tb_attach, SPropTagArray);
 
815
                        MAPIFreeBuffer(SPropTagArray);
 
816
                        MAPI_RETVAL_IF(retval, retval, NULL);
 
817
                        
 
818
                        retval = QueryRows(&obj_tb_attach, 0xa, TBL_ADVANCE, &rowset_attach);
 
819
                        MAPI_RETVAL_IF(retval, retval, NULL);
 
820
                        
 
821
                        for (i = 0; i < rowset_attach.cRows; i++) {
 
822
                                //attach_num = (const uint32_t *)find_SPropValue_data(&(rowset_attach.aRow[i]), PR_ATTACH_NUM);
 
823
                                uint32_t n = rowset_attach.aRow[i].lpProps[0].value.l;
 
824
                                attach_num = &n;
 
825
                                retval = OpenAttach(obj_message, *attach_num, &obj_attach);
 
826
                                if (retval == MAPI_E_SUCCESS) {
 
827
                                        SPropTagArray = set_SPropTagArray(mem_ctx, 0x5,
 
828
                                                                          PR_ATTACH_FILENAME,
 
829
                                                                          PR_ATTACH_LONG_FILENAME,
 
830
                                                                          PR_ATTACH_SIZE,
 
831
                                                                          PR_ATTACH_MIME_TAG,
 
832
                                                                          PR_ATTACH_METHOD);
 
833
                                        lpProps = NULL;
 
834
                                        retval = GetProps(&obj_attach, MAPI_UNICODE, SPropTagArray, &lpProps, &count);
 
835
                                        MAPIFreeBuffer(SPropTagArray);
 
836
                                        if (retval == MAPI_E_SUCCESS) {
 
837
                                                uint32_t *mp, method = -1;
 
838
 
 
839
                                                aRow2.ulAdrEntryPad = 0;
 
840
                                                aRow2.cValues = count;
 
841
                                                aRow2.lpProps = lpProps;
 
842
 
 
843
                                                mp = (uint32_t *) octool_get_propval(&aRow2, PR_ATTACH_METHOD);
 
844
                                                if (mp)
 
845
                                                        method = *mp;
 
846
 
 
847
                                                attach_filename = get_filename(octool_get_propval(&aRow2, PR_ATTACH_LONG_FILENAME));
 
848
                                                if (!attach_filename || (attach_filename && !strcmp(attach_filename, ""))) {
 
849
                                                        attach_filename = get_filename(octool_get_propval(&aRow2, PR_ATTACH_FILENAME));
 
850
                                                }
 
851
                                                attach_size = (const uint32_t *) octool_get_propval(&aRow2, PR_ATTACH_SIZE);                                            
 
852
 
 
853
                                                attachment_data = NULL;
 
854
                                                switch (method) {
 
855
                                                case ATTACH_BY_VALUE:
 
856
                                                        magic = (char *) octool_get_propval(&aRow2, PR_ATTACH_MIME_TAG);                                                
 
857
                                                        if (magic)
 
858
                                                                magic = talloc_strdup(mem_ctx, magic);
 
859
                                                        attachment_data = get_base64_attachment(mem_ctx,
 
860
                                                                        &obj_attach, *attach_size,
 
861
                                                                        magic ? NULL : &magic);
 
862
                                                        if (attachment_data == NULL) {
 
863
                                                                message_error = 1;
 
864
                                                                fprintf(stderr, "Failed to read attachment for message %s\n", msgid ? msgid : "unknown");
 
865
                                                                break;
 
866
                                                        }
 
867
                                                        fprintf(fp, "\n\n--%s\n", boundary(base_level+0));
 
868
                                                        fprintf(fp, "Content-Disposition: attachment; filename=\"%s\"\n", attach_filename);
 
869
                                                        fprintf(fp, "Content-Type: %s\n", magic);
 
870
                                                        fprintf(fp, "Content-Transfer-Encoding: base64\n\n");
 
871
                                                        write_base64_data(fp, attachment_data);
 
872
                                                        talloc_free(attachment_data);
 
873
                                                        talloc_free(magic);
 
874
                                                        break;
 
875
                                                case ATTACH_BY_REFERENCE:
 
876
                                                        fprintf(stderr,"ATTACH_BY_REFERENCE unsupported\n");
 
877
                                                        message_error = 1;
 
878
                                                        break;
 
879
                                                case ATTACH_BY_REF_RESOLVE:
 
880
                                                        fprintf(stderr,"ATTACH_BY_REF_RESOLVE unsupported\n");
 
881
                                                        message_error = 1;
 
882
                                                        break;
 
883
                                                case ATTACH_BY_REF_ONLY:
 
884
                                                        fprintf(stderr,"ATTACH_BY_REF_ONLY unsupported\n");
 
885
                                                        message_error = 1;
 
886
                                                        break;
 
887
                                                case ATTACH_EMBEDDED_MSG: {
 
888
                                                        mapi_object_t obj_embeddedmsg;
 
889
                                                        struct SPropTagArray    *embTagArray = NULL;
 
890
                                                        struct SPropValue               *embProps;
 
891
                                                        struct SRow                             eRow;
 
892
                                                        uint32_t                                emb_count = 0;
 
893
 
 
894
                                                        mapi_object_init(&obj_embeddedmsg);
 
895
                                                        retval = OpenEmbeddedMessage(&obj_attach,
 
896
                                                                        &obj_embeddedmsg, MAPI_READONLY);
 
897
                                                        if (retval != MAPI_E_SUCCESS) {
 
898
                                                                fprintf(stderr, "Failed to open Embedded msg: %x\n", retval);
 
899
                                                                message_error = 1;
 
900
                                                                break;
 
901
                                                        }
 
902
 
 
903
                                                        embTagArray = set_SPropTagArray(mem_ctx, 0x15,
 
904
                                                                                        PR_INTERNET_MESSAGE_ID,
 
905
                                                                                        PR_INTERNET_MESSAGE_ID_UNICODE,
 
906
                                                                                        PR_CONVERSATION_TOPIC,
 
907
                                                                                        PR_CONVERSATION_TOPIC_UNICODE,
 
908
                                                                                        PR_MESSAGE_DELIVERY_TIME,
 
909
                                                                                        PR_MSG_EDITOR_FORMAT,
 
910
                                                                                        PR_BODY,
 
911
                                                                                        PR_BODY_UNICODE,
 
912
                                                                                        PR_HTML,
 
913
                                                                                        PR_RTF_COMPRESSED,
 
914
                                                                                        PR_RTF_IN_SYNC,
 
915
                                                                                        PR_SENT_REPRESENTING_NAME,
 
916
                                                                                        PR_SENT_REPRESENTING_NAME_UNICODE,
 
917
                                                                                        PR_DISPLAY_TO,
 
918
                                                                                        PR_DISPLAY_TO_UNICODE,
 
919
                                                                                        PR_DISPLAY_CC,
 
920
                                                                                        PR_DISPLAY_CC_UNICODE,
 
921
                                                                                        PR_DISPLAY_BCC,
 
922
                                                                                        PR_DISPLAY_BCC_UNICODE,
 
923
                                                                                        PR_HASATTACH,
 
924
                                                                                        PR_TRANSPORT_MESSAGE_HEADERS);
 
925
                                                        retval = GetProps(&obj_embeddedmsg, MAPI_UNICODE, embTagArray,
 
926
                                                                        &embProps, &emb_count);
 
927
                                                        MAPIFreeBuffer(embTagArray);
 
928
 
 
929
                                                        if (retval != MAPI_E_SUCCESS) {
 
930
                                                                fprintf(stderr, "Failed to get Embedded msg props: %x\n", retval);
 
931
                                                                message_error = 1;
 
932
                                                                break;
 
933
                                                        }
 
934
 
 
935
                                                        /* Build a SRow structure */
 
936
                                                        eRow.ulAdrEntryPad = 0;
 
937
                                                        eRow.cValues = emb_count;
 
938
                                                        eRow.lpProps = embProps;
 
939
 
 
940
                                                        fprintf(fp, "\n\n--%s\n", boundary(base_level+0));
 
941
                                                        fprintf(fp, "Content-Type: message/rfc822\n");
 
942
                                                        fprintf(fp, "Content-Disposition: inline\n");
 
943
                                                        fprintf(fp, "\n");
 
944
 
 
945
                                                        message2mbox(mem_ctx, fp, &eRow, &obj_embeddedmsg,
 
946
                                                                        base_level + 2 /* 0 = main, 1 = alt */);
 
947
                                                        talloc_free(embProps);
 
948
                                                        } break;
 
949
                                                case ATTACH_OLE:
 
950
                                                        fprintf(stderr,"ATTACH_OLE unsupported - "
 
951
                                                                        "allowing message through anyway\n");
 
952
                                                        // message_error = 1;
 
953
                                                        break;
 
954
                                                default:
 
955
                                                        fprintf(stderr, "Unsupported attach method = %d\n", method);
 
956
                                                        message_error = 1;
 
957
                                                        break;
 
958
                                                }
 
959
                                        }
 
960
                                        MAPIFreeBuffer(lpProps);
 
961
                                }
 
962
                        }
 
963
 
 
964
                        line = talloc_asprintf(mem_ctx, "\n\n--%s--\n\n\n", boundary(base_level+0));
 
965
                        if (line) {
 
966
                                fwrite(line, strlen(line), 1, fp);
 
967
                        }
 
968
                        talloc_free(line);
 
969
                }
 
970
        } else if (body_count > 1) {
 
971
                /* close body attachments */
 
972
                fprintf(fp, "\n\n--%s--\n", boundary(base_level+0));
 
973
        }
 
974
        
 
975
        fwrite("\n\n\n", 3, 1, fp);
 
976
 
 
977
        return true;
 
978
}
 
979
 
 
980
 
 
981
 
 
982
int main(int argc, const char *argv[])
 
983
{
 
984
        TALLOC_CTX                      *mem_ctx = NULL;
 
985
        enum MAPISTATUS                 retval;
 
986
        struct mapi_context             *mapi_ctx = NULL;
 
987
        struct mapi_session             *session = NULL;
 
988
        struct mapi_profile             *profile = NULL;
 
989
        mapi_object_t                   obj_store;
 
990
        mapi_object_t                   obj_inbox;
 
991
        mapi_object_t                   obj_table;
 
992
        mapi_object_t                   obj_message;
 
993
        mapi_id_t                       id_inbox;
 
994
        uint32_t                        count;
 
995
        struct SPropTagArray            *SPropTagArray = NULL;
 
996
        struct SPropValue               *lpProps;
 
997
        struct SRow                     aRow;
 
998
        struct SRowSet                  rowset;
 
999
        poptContext                     pc;
 
1000
        int                             opt;
 
1001
        FILE                            *fp;
 
1002
        unsigned int                    i;
 
1003
        const char                      *opt_profdb = NULL;
 
1004
        char                            *opt_profname = NULL;
 
1005
        const char                      *opt_password = NULL;
 
1006
        const char                      *opt_mbox = NULL;
 
1007
        bool                            opt_update = false;
 
1008
        bool                            opt_dumpdata = false;
 
1009
        const char                      *opt_debug = NULL;
 
1010
        const char                      *msgid;
 
1011
 
 
1012
        enum {OPT_PROFILE_DB=1000, OPT_PROFILE, OPT_PASSWORD, OPT_MBOX, OPT_UPDATE,
 
1013
              OPT_DEBUG, OPT_DUMPDATA, OPT_TEST};
 
1014
 
 
1015
        struct poptOption long_options[] = {
 
1016
                POPT_AUTOHELP
 
1017
                {"test", 't', POPT_ARG_NONE, 0, OPT_TEST, "Do not update server, just download messages to mbox", NULL},
 
1018
                {"database", 'f', POPT_ARG_STRING, NULL, OPT_PROFILE_DB, "set the profile database path", "PATH"},
 
1019
                {"profile", 'p', POPT_ARG_STRING, NULL, OPT_PROFILE, "set the profile name", "PROFILE"},
 
1020
                {"password", 'P', POPT_ARG_STRING, NULL, OPT_PASSWORD, "set the profile password", "PASSWORD"},
 
1021
                {"mbox", 'm', POPT_ARG_STRING, NULL, OPT_MBOX, "set the mbox file", "FILENAME"},
 
1022
                {"update", 'u', POPT_ARG_NONE, 0, OPT_UPDATE, "mirror mbox changes back to the Exchange server", NULL},
 
1023
                {"debuglevel", 'd', POPT_ARG_STRING, NULL, OPT_DEBUG, "set the debug level", "LEVEL"},
 
1024
                {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMPDATA, "dump the hex data", NULL},
 
1025
                POPT_OPENCHANGE_VERSION
 
1026
                { NULL, 0, POPT_ARG_NONE, NULL, 0, NULL, NULL }
 
1027
        };
 
1028
 
 
1029
        start_time = time(0);
 
1030
 
 
1031
        mem_ctx = talloc_named(NULL, 0, "exchange2mbox");
 
1032
 
 
1033
        pc = poptGetContext("exchange2mbox", argc, argv, long_options, 0);
 
1034
 
 
1035
        while ((opt = poptGetNextOpt(pc)) != -1) {
 
1036
                switch (opt) {
 
1037
                case OPT_PROFILE_DB:
 
1038
                        opt_profdb = poptGetOptArg(pc);
 
1039
                        break;
 
1040
                case OPT_PROFILE:
 
1041
                        opt_profname = talloc_strdup(mem_ctx, (char *)poptGetOptArg(pc));
 
1042
                        break;
 
1043
                case OPT_PASSWORD:
 
1044
                        opt_password = poptGetOptArg(pc);
 
1045
                        break;
 
1046
                case OPT_MBOX:
 
1047
                        opt_mbox = poptGetOptArg(pc);
 
1048
                        break;
 
1049
                case OPT_UPDATE:
 
1050
                        opt_update = true;
 
1051
                        break;
 
1052
                case OPT_TEST:
 
1053
                        opt_test = true;
 
1054
                        break;
 
1055
                case OPT_DEBUG:
 
1056
                        opt_debug = poptGetOptArg(pc);
 
1057
                        break;
 
1058
                case OPT_DUMPDATA:
 
1059
                        opt_dumpdata = true;
 
1060
                        break;
 
1061
                }
 
1062
        }
 
1063
 
 
1064
        /**
 
1065
         * Sanity checks
 
1066
         */
 
1067
 
 
1068
        if (!opt_profdb) {
 
1069
                opt_profdb = talloc_asprintf(mem_ctx, DEFAULT_PROFDB, getenv("HOME"));
 
1070
        }
 
1071
 
 
1072
        if (!opt_mbox) {
 
1073
                opt_mbox = talloc_asprintf(mem_ctx, DEFAULT_MBOX, getenv("HOME"));
 
1074
        }
 
1075
 
 
1076
        /**
 
1077
         * Open the MBOX
 
1078
         */
 
1079
 
 
1080
        if ((fp = fopen(opt_mbox, "a+")) == NULL) {
 
1081
                perror("fopen");
 
1082
                exit (1);
 
1083
        }
 
1084
 
 
1085
        /**
 
1086
         * Initialize MAPI subsystem
 
1087
         */
 
1088
 
 
1089
        retval = MAPIInitialize(&mapi_ctx, opt_profdb);
 
1090
        if (retval != MAPI_E_SUCCESS) {
 
1091
                mapi_errstr("MAPIInitialize", GetLastError());
 
1092
                exit (1);
 
1093
        }
 
1094
 
 
1095
        /* debug options */
 
1096
        SetMAPIDumpData(mapi_ctx, opt_dumpdata);
 
1097
 
 
1098
        if (opt_debug) {
 
1099
                SetMAPIDebugLevel(mapi_ctx, atoi(opt_debug));
 
1100
        }
 
1101
 
 
1102
        /* if no profile is supplied use the default one */
 
1103
        if (!opt_profname) {
 
1104
                retval = GetDefaultProfile(mapi_ctx, &opt_profname);
 
1105
                if (retval != MAPI_E_SUCCESS) {
 
1106
                        printf("No profile specified and no default profile found\n");
 
1107
                        exit (1);
 
1108
                }
 
1109
        }
 
1110
        
 
1111
        retval = MapiLogonEx(mapi_ctx, &session, opt_profname, opt_password);
 
1112
        talloc_free(opt_profname);
 
1113
        if (retval != MAPI_E_SUCCESS) {
 
1114
                mapi_errstr("MapiLogonEx", GetLastError());
 
1115
                exit (1);
 
1116
        }
 
1117
        profile = session->profile;
 
1118
 
 
1119
        /* not sure about this,  but it works and it's nice to have it there */
 
1120
        profile->mapi_ctx = mapi_ctx;
 
1121
 
 
1122
        /* do the updates now */
 
1123
        if (opt_update == true) {
 
1124
                retval = update(mem_ctx, fp, session);
 
1125
                if (retval != MAPI_E_SUCCESS) {
 
1126
                        printf("Problem encountered during update: %d\n", retval);
 
1127
                        exit (1);
 
1128
                }
 
1129
        }
 
1130
        
 
1131
        /* Open the default message store */
 
1132
        mapi_object_init(&obj_store);
 
1133
        retval = OpenMsgStore(session, &obj_store);
 
1134
        if (retval != MAPI_E_SUCCESS) {
 
1135
                mapi_errstr("OpenMsgStore", GetLastError());
 
1136
                exit (1);
 
1137
        }
 
1138
 
 
1139
        /* Open Inbox */
 
1140
        retval = GetReceiveFolder(&obj_store, &id_inbox, NULL);
 
1141
        MAPI_RETVAL_IF(retval, retval, mem_ctx);
 
1142
 
 
1143
        mapi_object_init(&obj_inbox);
 
1144
        retval = OpenFolder(&obj_store, id_inbox, &obj_inbox);
 
1145
        MAPI_RETVAL_IF(retval, retval, mem_ctx);
 
1146
 
 
1147
        mapi_object_init(&obj_table);
 
1148
        retval = GetContentsTable(&obj_inbox, &obj_table, 0, &count);
 
1149
        MAPI_RETVAL_IF(retval, retval, mem_ctx);
 
1150
 
 
1151
        SPropTagArray = set_SPropTagArray(mem_ctx, 0x5,
 
1152
                                          PR_FID,
 
1153
                                          PR_MID,
 
1154
                                          PR_INST_ID,
 
1155
                                          PR_INSTANCE_NUM,
 
1156
                                          PR_INTERNET_MESSAGE_ID);
 
1157
        retval = SetColumns(&obj_table, SPropTagArray);
 
1158
        MAPIFreeBuffer(SPropTagArray);
 
1159
        MAPI_RETVAL_IF(retval, retval, mem_ctx);
 
1160
 
 
1161
        while ((retval = QueryRows(&obj_table, 0xa, TBL_ADVANCE, &rowset)) != MAPI_E_NOT_FOUND && rowset.cRows) {
 
1162
                for (i = 0; i < rowset.cRows; i++) {
 
1163
                        mapi_object_init(&obj_message);
 
1164
                        retval = OpenMessage(&obj_store, 
 
1165
                                             rowset.aRow[i].lpProps[0].value.d, 
 
1166
                                             rowset.aRow[i].lpProps[1].value.d, 
 
1167
                                             &obj_message, 0);
 
1168
                        if (retval == MAPI_E_SUCCESS) {
 
1169
                                SPropTagArray = set_SPropTagArray(mem_ctx, 0x1b,
 
1170
                                                                  PR_INTERNET_MESSAGE_ID,
 
1171
                                                                  PR_INTERNET_MESSAGE_ID_UNICODE,
 
1172
                                                                  PR_CONVERSATION_TOPIC,
 
1173
                                                                  PR_CONVERSATION_TOPIC_UNICODE,
 
1174
                                                                  PR_MESSAGE_DELIVERY_TIME,
 
1175
                                                                  PR_MSG_EDITOR_FORMAT,
 
1176
                                                                  PR_BODY,
 
1177
                                                                  PR_BODY_UNICODE,
 
1178
                                                                  PR_HTML,
 
1179
                                                                  PR_RTF_COMPRESSED,
 
1180
                                                                  PR_RTF_IN_SYNC,
 
1181
                                                                  PR_SENT_REPRESENTING_NAME,
 
1182
                                                                  PR_SENT_REPRESENTING_NAME_UNICODE,
 
1183
                                                                  PR_DISPLAY_TO,
 
1184
                                                                  PR_DISPLAY_TO_UNICODE,
 
1185
                                                                  PR_DISPLAY_CC,
 
1186
                                                                  PR_DISPLAY_CC_UNICODE,
 
1187
                                                                  PR_DISPLAY_BCC,
 
1188
                                                                  PR_DISPLAY_BCC_UNICODE,
 
1189
                                                                  PR_HASATTACH,
 
1190
                                                                  PR_TRANSPORT_MESSAGE_HEADERS,
 
1191
                                                                  PR_SUBJECT_PREFIX,
 
1192
                                                                  PR_SUBJECT_PREFIX_UNICODE,
 
1193
                                                                  PR_NORMALIZED_SUBJECT,
 
1194
                                                                  PR_NORMALIZED_SUBJECT_UNICODE,
 
1195
                                                                  PR_SUBJECT,
 
1196
                                                                  PR_SUBJECT_UNICODE);
 
1197
                                retval = GetProps(&obj_message, MAPI_UNICODE, SPropTagArray, &lpProps, &count);
 
1198
                                MAPIFreeBuffer(SPropTagArray);
 
1199
                                if (retval != MAPI_E_SUCCESS) {
 
1200
                                        fprintf(stderr, "Badness getting row %d attrs\n", i);
 
1201
                                        exit (1);
 
1202
                                }
 
1203
 
 
1204
                                /* Build a SRow structure */
 
1205
                                aRow.ulAdrEntryPad = 0;
 
1206
                                aRow.cValues = count;
 
1207
                                aRow.lpProps = lpProps;
 
1208
 
 
1209
                                msgid = (const char *) octool_get_propval(&aRow, PR_INTERNET_MESSAGE_ID);
 
1210
                                if (msgid) {
 
1211
                                        retval = FindProfileAttr(profile, "Message-ID", msgid);
 
1212
                                        if (GetLastError() == MAPI_E_NOT_FOUND) {
 
1213
                                                bool ok;
 
1214
                                                
 
1215
                                                message_error = 0;
 
1216
                                                ok = message2mbox(mem_ctx, fp, &aRow, &obj_message, 0);
 
1217
                                                if (!ok) {
 
1218
                                                        printf("Message-ID: %s error, not added to %s\n", msgid, profile->profname);
 
1219
                                                } else if (message_error) {
 
1220
                                                        printf("Message-ID: %s error, ignoring\n", msgid);
 
1221
                                                        fprintf(stderr, "Message-ID: %s error, ignoring message (check with OWA if you can, will retry next time)\n", msgid);
 
1222
                                                } else if (opt_test) {
 
1223
                                                        printf("Message-ID: %s saved but not updated in %s\n", msgid, profile->profname);
 
1224
                                                } else if
 
1225
                                                (mapi_profile_add_string_attr(profile->mapi_ctx, profile->profname, "Message-ID", msgid) != MAPI_E_SUCCESS) {
 
1226
                                                        mapi_errstr("mapi_profile_add_string_attr", GetLastError());
 
1227
                                                } else {
 
1228
                                                        printf("Message-ID: %s added to profile %s\n", msgid, profile->profname);
 
1229
                                                }
 
1230
                                        } else {
 
1231
                                                printf("Message-ID: %s already in profile %s\n", msgid, profile->profname);
 
1232
                                        }
 
1233
                                } else {
 
1234
                                        fprintf(stderr, "%s: message with no msgid cannot be downloaded\n", profile->profname);
 
1235
                                }
 
1236
                                talloc_free(lpProps);
 
1237
                        } else {
 
1238
                                fprintf(stderr, "could not open row %d: retval=%d GetLastError=%d\n", i, retval, GetLastError());
 
1239
                        }
 
1240
                        mapi_object_release(&obj_message);
 
1241
                        errno = 0;
 
1242
                }
 
1243
        }
 
1244
 
 
1245
        fclose(fp);
 
1246
        mapi_object_release(&obj_table);
 
1247
        mapi_object_release(&obj_inbox);
 
1248
        mapi_object_release(&obj_store);
 
1249
        MAPIUninitialize(mapi_ctx);
 
1250
 
 
1251
        talloc_free(mem_ctx);
 
1252
 
 
1253
        return 0;
 
1254
}