ba2402ceeac023bf078fb58d2768e215014711d1
[jelmer/openchange.git] / utils / openchangeclient.c
1 /*
2    Stand-alone MAPI application
3
4    OpenChange Project
5
6    Copyright (C) Julien Kerihuel 2007-2010
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 "libmapi/libmapi_private.h"
24 #include "libmapi/mapi_nameid.h"
25 #include "libocpf/ocpf.h"
26 #include <popt.h>
27 #include <param.h>
28
29 #include "openchangeclient.h"
30 #include "openchange-tools.h"
31
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34 #include <dirent.h>
35 #include <fcntl.h>
36 #include <time.h>
37 #include <ctype.h>
38
39 /**
40  * init sendmail struct
41  */
42
43 static void init_oclient(struct oclient *oclient)
44 {
45         oclient->mapi_ctx = NULL;
46
47         /* update and delete parameter */
48         oclient->update = NULL;
49         oclient->delete = NULL;
50
51         /* properties list */
52         oclient->props = NULL;
53         
54         /* email related parameter */
55         oclient->subject = NULL;
56         oclient->pr_body = NULL;
57         oclient->pr_html_inline = NULL;
58         oclient->attach = NULL;
59         oclient->attach_num = 0;
60         oclient->store_folder = NULL;
61         
62         /* appointment related parameters */
63         oclient->location = NULL;
64         oclient->dtstart = NULL;
65         oclient->dtend = NULL;
66         oclient->busystatus = -1;
67         oclient->label = -1;
68         oclient->private = false;
69         oclient->freebusy = NULL;
70         oclient->force = false;
71         oclient->summary = false;
72
73         /* contact related parameters */
74         oclient->email = NULL;
75         oclient->full_name = NULL;
76         oclient->card_name = NULL;
77
78         /* task related parameters */
79         oclient->importance = -1;
80         oclient->taskstatus = -1;
81
82         /* note related parameters */
83         oclient->color = -1;
84         oclient->width = -1;
85         oclient->height = -1;
86
87         /* pf related parameters */
88         oclient->pf = false;
89
90         /* folder related parameters */
91         oclient->folder = NULL;
92         oclient->folder_name = NULL;
93         oclient->folder_comment = NULL;
94
95         /* ocpf related parameters */
96         oclient->ocpf_files = NULL;
97         oclient->ocpf_dump = NULL;
98 }
99
100 static enum MAPISTATUS openchangeclient_getdir(TALLOC_CTX *mem_ctx,
101                                                mapi_object_t *obj_container,
102                                                mapi_object_t *obj_child,
103                                                const char *path)
104 {
105         enum MAPISTATUS         retval;
106         struct SPropTagArray    *SPropTagArray = NULL;
107         struct SRowSet          SRowSet;
108         mapi_object_t           obj_htable;
109         mapi_object_t           obj_folder;
110         char                    **folder  = NULL;
111         const char              *name;
112         const uint64_t          *fid;
113         bool                    found = false;
114         uint32_t                index;
115         uint32_t                i;
116
117         /* Step 1. Extract the folder list from full path */
118         folder = str_list_make(mem_ctx, path, "/");
119         mapi_object_copy(&obj_folder, obj_container);
120
121         for (i = 0; folder[i]; i++) {
122                 found = false;
123
124                 mapi_object_init(&obj_htable);
125                 retval = GetHierarchyTable(&obj_folder, &obj_htable, 0, NULL);
126                 MAPI_RETVAL_IF(retval, GetLastError(), folder);
127
128                 SPropTagArray = set_SPropTagArray(mem_ctx, 0x2,
129                                                   PR_DISPLAY_NAME_UNICODE,
130                                                   PR_FID);
131                 retval = SetColumns(&obj_htable, SPropTagArray);
132                 MAPIFreeBuffer(SPropTagArray);
133                 MAPI_RETVAL_IF(retval, retval, folder);
134
135                 while (((retval = QueryRows(&obj_htable, 0x32, TBL_ADVANCE, &SRowSet)) != MAPI_E_NOT_FOUND) && SRowSet.cRows) {
136                         for (index = 0; (index < SRowSet.cRows) && (found == false); index++) {
137                                 fid = (const uint64_t *)find_SPropValue_data(&SRowSet.aRow[index], PR_FID);
138                                 name = (const char *)find_SPropValue_data(&SRowSet.aRow[index], PR_DISPLAY_NAME_UNICODE);
139                                 if (name && fid && !strcmp(name, folder[i])) {
140                                         retval = OpenFolder(&obj_folder, *fid, obj_child);
141                                         MAPI_RETVAL_IF(retval, retval, folder);
142
143                                         found = true;
144                                         mapi_object_copy(&obj_folder, obj_child);
145                                 }
146                         }
147                 }
148
149                 mapi_object_release(&obj_htable);
150         }
151
152         talloc_free(folder);
153         MAPI_RETVAL_IF(found == false, MAPI_E_NOT_FOUND, NULL);
154
155         return MAPI_E_SUCCESS;
156 }
157
158
159 static enum MAPISTATUS openchangeclient_getpfdir(TALLOC_CTX *mem_ctx, 
160                                                  mapi_object_t *obj_store,
161                                                  mapi_object_t *obj_child,
162                                                  const char *name)
163 {
164         enum MAPISTATUS         retval;
165         mapi_object_t           obj_pf;
166         mapi_id_t               id_pf;
167
168         retval = GetDefaultPublicFolder(obj_store, &id_pf, olFolderPublicIPMSubtree);
169         if (retval != MAPI_E_SUCCESS) return retval;
170         
171         mapi_object_init(&obj_pf);
172         retval = OpenFolder(obj_store, id_pf, &obj_pf);
173         if (retval != MAPI_E_SUCCESS) return retval;
174         
175         retval = openchangeclient_getdir(mem_ctx, &obj_pf, obj_child, name);
176         if (retval != MAPI_E_SUCCESS) return retval;
177
178         return MAPI_E_SUCCESS;
179 }
180
181 /**
182  * read a file and store it in the appropriate structure element
183  */
184
185 static bool oclient_read_file(TALLOC_CTX *mem_ctx, const char *filename, 
186                               struct oclient *oclient, uint32_t mapitag)
187 {
188         struct stat     sb;
189         int             fd;
190
191         if ((fd = open(filename, O_RDONLY)) == -1) {
192                 printf("Error while opening %s\n", filename);
193                 return false;
194         }
195         /* stat the file */
196         if (fstat(fd, &sb) != 0) {
197                 close(fd);
198                 return false;
199         }
200
201         switch (mapitag) {
202         case PR_HTML:
203                 oclient->pr_html.lpb = talloc_size(mem_ctx, sb.st_size);
204                 oclient->pr_html.cb = read(fd, oclient->pr_html.lpb, sb.st_size);
205                 close(fd);
206                 break;
207         case PR_ATTACH_DATA_BIN:
208                 oclient->attach[oclient->attach_num].filename = talloc_strdup(mem_ctx, filename);
209                 oclient->attach[oclient->attach_num].bin.lpb = talloc_size(mem_ctx, sb.st_size);
210                 oclient->attach[oclient->attach_num].bin.cb = sb.st_size;
211                 if ((oclient->attach[oclient->attach_num].bin.lpb = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (void *) -1) {
212                         perror("mmap");
213                         close(fd);
214                         return false;
215                 }
216                 oclient->attach[oclient->attach_num].fd = fd;
217                 printf("filename = %s (size = %u / %u)\n", filename, oclient->attach[oclient->attach_num].bin.cb, (uint32_t)sb.st_size);
218                 close(fd);
219                 break;
220         default:
221                 printf("unsupported MAPITAG: %s\n", get_proptag_name(mapitag));
222                 close(fd);
223                 return false;
224                 break;
225         }
226
227         return true;
228 }
229
230 /**
231  * Parse attachments and load their content
232  */
233 static bool oclient_parse_attachments(TALLOC_CTX *mem_ctx, const char *filename,
234                                       struct oclient *oclient)
235 {
236         char            **filenames;
237         char            *tmp = NULL;
238         uint32_t        j;
239
240         if ((tmp = strtok((char *)filename, ";")) == NULL) {
241                 printf("Invalid string format [;]\n");
242                 return false;
243         }
244
245         filenames = talloc_array(mem_ctx, char *, 2);
246         filenames[0] = strdup(tmp);
247
248         for (j = 1; (tmp = strtok(NULL, ";")) != NULL; j++) {
249                 filenames = talloc_realloc(mem_ctx, filenames, char *, j+2);
250                 filenames[j] = strdup(tmp);
251         }
252         filenames[j] = 0;
253         oclient->attach = talloc_array(mem_ctx, struct attach, j);
254
255         for (j = 0; filenames[j]; j++) {
256                 oclient->attach_num = j;
257                 if (oclient_read_file(mem_ctx, filenames[j], oclient, PR_ATTACH_DATA_BIN) == false) {
258                         return false;
259                 }
260         }
261
262         return true;
263 }
264
265
266 static const char *get_filename(const char *filename)
267 {
268         const char *substr;
269
270         if (!filename) return NULL;
271
272         substr = rindex(filename, '/');
273         if (substr) return substr + 1;
274
275         return filename;
276 }
277
278
279 /**
280  * build unique ID from folder and message
281  */
282 static char *build_uniqueID(TALLOC_CTX *mem_ctx, mapi_object_t *obj_folder,
283                             mapi_object_t *obj_message)
284 {
285         char                    *id;
286         struct SPropTagArray    *SPropTagArray;
287         struct SPropValue       *lpProps;
288         uint32_t                count;
289         const uint64_t          *mid;
290         const uint64_t          *fid;
291
292         /* retrieve the folder ID */
293         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_FID);
294         GetProps(obj_folder, 0, SPropTagArray, &lpProps, &count);
295         MAPIFreeBuffer(SPropTagArray);
296         if (GetLastError() != MAPI_E_SUCCESS) return NULL;
297         fid = (const uint64_t *)get_SPropValue_data(lpProps);
298
299         /* retrieve the message ID */
300         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_MID);
301         GetProps(obj_message, 0, SPropTagArray, &lpProps, &count);
302         MAPIFreeBuffer(SPropTagArray);
303         if (GetLastError() != MAPI_E_SUCCESS) return NULL;
304         mid = (const uint64_t *)get_SPropValue_data(lpProps);
305
306         if (!fid || !mid) return NULL;
307
308         id = talloc_asprintf(mem_ctx, "%"PRIX64"/%"PRIX64, *fid, *mid);
309         return id;
310 }
311
312
313 /**
314  * fetch the user INBOX
315  */
316
317 #define MAX_READ_SIZE   0x1000
318
319 static bool store_attachment(mapi_object_t obj_attach, const char *filename, uint32_t size, struct oclient *oclient)
320 {
321         TALLOC_CTX      *mem_ctx;
322         enum MAPISTATUS retval;
323         char            *path;
324         mapi_object_t   obj_stream;
325         uint16_t        read_size;
326         int             fd;
327         DIR             *dir;
328         unsigned char   buf[MAX_READ_SIZE];
329
330         if (!filename || !size) return false;
331
332         mapi_object_init(&obj_stream);
333
334         mem_ctx = talloc_named(NULL, 0, "store_attachment");
335
336         if (!(dir = opendir(oclient->store_folder))) {
337                 if (mkdir(oclient->store_folder, 0700) == -1) return false;
338         } else {
339                 closedir(dir);
340         }
341
342         path = talloc_asprintf(mem_ctx, "%s/%s", oclient->store_folder, filename);
343         if ((fd = open(path, O_CREAT|O_WRONLY, S_IWUSR|S_IRUSR)) == -1) {
344                 goto error;
345         }
346         talloc_free(path);
347
348         retval = OpenStream(&obj_attach, PR_ATTACH_DATA_BIN, 0, &obj_stream);
349         if (retval != MAPI_E_SUCCESS) return false;
350
351         read_size = 0;
352         do {
353                 retval = ReadStream(&obj_stream, buf, MAX_READ_SIZE, &read_size);
354                 if (retval != MAPI_E_SUCCESS) goto error;
355                 write(fd, buf, read_size);
356         } while (read_size);
357         
358         close(fd);
359         mapi_object_release(&obj_stream);
360         talloc_free(mem_ctx);
361         return true;
362
363 error:
364         mapi_object_release(&obj_stream);
365         close(fd);
366         talloc_free(mem_ctx);
367         return false;
368 }
369
370 static enum MAPISTATUS openchangeclient_fetchmail(mapi_object_t *obj_store, 
371                                                   struct oclient *oclient)
372 {
373         enum MAPISTATUS                 retval;
374         bool                            status;
375         TALLOC_CTX                      *mem_ctx;
376         mapi_object_t                   obj_tis;
377         mapi_object_t                   obj_inbox;
378         mapi_object_t                   obj_message;
379         mapi_object_t                   obj_table;
380         mapi_object_t                   obj_tb_attach;
381         mapi_object_t                   obj_attach;
382         uint64_t                        id_inbox;
383         struct SPropTagArray            *SPropTagArray;
384         struct SRowSet                  rowset;
385         struct SRowSet                  rowset_attach;
386         uint32_t                        i, j;
387         uint32_t                        count;
388         const uint8_t                   *has_attach;
389         const uint32_t                  *attach_num;
390         const char                      *attach_filename;
391         const uint32_t                  *attach_size;
392         
393         mem_ctx = talloc_named(NULL, 0, "openchangeclient_fetchmail");
394
395         mapi_object_init(&obj_tis);
396         mapi_object_init(&obj_inbox);
397         mapi_object_init(&obj_table);
398
399         if (oclient->pf == true) {
400                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_inbox, oclient->folder);
401                 MAPI_RETVAL_IF(retval, GetLastError(), mem_ctx);
402         } else {
403                 if (oclient->folder) {
404                         retval = GetDefaultFolder(obj_store, &id_inbox, olFolderTopInformationStore);
405                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
406
407                         retval = OpenFolder(obj_store, id_inbox, &obj_tis);
408                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
409
410                         retval = openchangeclient_getdir(mem_ctx, &obj_tis, &obj_inbox, oclient->folder);
411                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
412                 } else {
413                         retval = GetReceiveFolder(obj_store, &id_inbox, NULL);
414                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
415
416                         retval = OpenFolder(obj_store, id_inbox, &obj_inbox);
417                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
418                 }
419         }
420
421         retval = GetContentsTable(&obj_inbox, &obj_table, 0, &count);
422         MAPI_RETVAL_IF(retval, retval, mem_ctx);
423
424         printf("MAILBOX (%u messages)\n", count);
425         if (!count) goto end;
426
427         SPropTagArray = set_SPropTagArray(mem_ctx, 0x5,
428                                           PR_FID,
429                                           PR_MID,
430                                           PR_INST_ID,
431                                           PR_INSTANCE_NUM,
432                                           PR_SUBJECT_UNICODE);
433         retval = SetColumns(&obj_table, SPropTagArray);
434         MAPIFreeBuffer(SPropTagArray);
435         MAPI_RETVAL_IF(retval, retval, mem_ctx);
436
437         while ((retval = QueryRows(&obj_table, count, TBL_ADVANCE, &rowset)) != MAPI_E_NOT_FOUND && rowset.cRows) {
438                 count -= rowset.cRows;
439                 for (i = 0; i < rowset.cRows; i++) {
440                         mapi_object_init(&obj_message);
441                         retval = OpenMessage(obj_store,
442                                              rowset.aRow[i].lpProps[0].value.d,
443                                              rowset.aRow[i].lpProps[1].value.d,
444                                              &obj_message, 0);
445                         if (GetLastError() == MAPI_E_SUCCESS) {
446                                 if (oclient->summary) {
447                                         mapidump_message_summary(&obj_message);
448                                 } else {
449                                         struct SPropValue       *lpProps;
450                                         struct SRow             aRow;
451                                         
452                                         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_HASATTACH);
453                                         lpProps = NULL;
454                                         retval = GetProps(&obj_message, 0, SPropTagArray, &lpProps, &count);
455                                         MAPIFreeBuffer(SPropTagArray);
456                                         if (retval != MAPI_E_SUCCESS) return retval;
457                                         
458                                         aRow.ulAdrEntryPad = 0;
459                                         aRow.cValues = count;
460                                         aRow.lpProps = lpProps;
461                                         
462                                         retval = octool_message(mem_ctx, &obj_message);
463                                         
464                                         has_attach = (const uint8_t *) get_SPropValue_SRow_data(&aRow, PR_HASATTACH);
465                                         
466                                         /* If we have attachments, retrieve them */
467                                         if (has_attach && *has_attach) {
468                                                 mapi_object_init(&obj_tb_attach);
469                                                 retval = GetAttachmentTable(&obj_message, &obj_tb_attach);
470                                                 if (retval == MAPI_E_SUCCESS) {
471                                                         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_ATTACH_NUM);
472                                                         retval = SetColumns(&obj_tb_attach, SPropTagArray);
473                                                         if (retval != MAPI_E_SUCCESS) return retval;
474                                                         MAPIFreeBuffer(SPropTagArray);
475                                                         
476                                                         retval = QueryRows(&obj_tb_attach, 0xa, TBL_ADVANCE, &rowset_attach);
477                                                         if (retval != MAPI_E_SUCCESS) return retval;
478                                                         
479                                                         for (j = 0; j < rowset_attach.cRows; j++) {
480                                                                 attach_num = (const uint32_t *)find_SPropValue_data(&(rowset_attach.aRow[j]), PR_ATTACH_NUM);
481                                                                 retval = OpenAttach(&obj_message, *attach_num, &obj_attach);
482                                                                 if (retval == MAPI_E_SUCCESS) {
483                                                                         struct SPropValue       *lpProps2;
484                                                                         uint32_t                count2;
485                                                                         
486                                                                         SPropTagArray = set_SPropTagArray(mem_ctx, 0x4, 
487                                                                                                           PR_ATTACH_FILENAME,
488                                                                                                           PR_ATTACH_LONG_FILENAME,
489                                                                                                           PR_ATTACH_SIZE,
490                                                                                                           PR_ATTACH_CONTENT_ID);
491                                                                         lpProps2 = NULL;
492                                                                         retval = GetProps(&obj_attach, MAPI_UNICODE, SPropTagArray, &lpProps2, &count2);
493                                                                         MAPIFreeBuffer(SPropTagArray);
494                                                                         if (retval != MAPI_E_SUCCESS) return retval;
495                                                                         
496                                                                         aRow.ulAdrEntryPad = 0;
497                                                                         aRow.cValues = count2;
498                                                                         aRow.lpProps = lpProps2;
499                                                                         
500                                                                         attach_filename = get_filename(octool_get_propval(&aRow, PR_ATTACH_LONG_FILENAME));
501                                                                         if (!attach_filename || (attach_filename && !strcmp(attach_filename, ""))) {
502                                                                                 attach_filename = get_filename(octool_get_propval(&aRow, PR_ATTACH_FILENAME));
503                                                                         }
504                                                                         attach_size = (const uint32_t *) octool_get_propval(&aRow, PR_ATTACH_SIZE);
505                                                                         printf("[%u] %s (%u Bytes)\n", j, attach_filename, attach_size ? *attach_size : 0);
506                                                                         fflush(0);
507                                                                         if (oclient->store_folder) {
508                                                                                 status = store_attachment(obj_attach, attach_filename, attach_size ? *attach_size : 0, oclient);
509                                                                                 if (status == false) {
510                                                                                         printf("A Problem was encountered while storing attachments on the filesystem\n");
511                                                                                         MAPI_RETVAL_IF(status == false, MAPI_E_UNABLE_TO_COMPLETE, mem_ctx);
512                                                                                         
513                                                                                 }
514                                                                         }
515                                                                         MAPIFreeBuffer(lpProps2);
516                                                                 }
517                                                         }
518                                                         errno = 0;
519                                                 }
520                                                 MAPIFreeBuffer(lpProps);
521                                         }
522                                 }
523                         }
524                         mapi_object_release(&obj_message);
525                 }
526         }
527  end:
528         mapi_object_release(&obj_table);
529         mapi_object_release(&obj_inbox);
530         mapi_object_release(&obj_tis);
531
532         talloc_free(mem_ctx);
533
534         errno = 0;
535         return MAPI_E_SUCCESS;
536 }
537
538 /**
539  * send a mail to a user whom belongs to the Exchange organization
540  */
541
542 static char **get_cmdline_recipients(TALLOC_CTX *mem_ctx, const char *recipients)
543 {
544         char            **usernames;
545         char            *tmp = NULL;
546         uint32_t        j = 0;
547
548         /* no recipients */
549         if (!recipients) {
550                 return NULL;
551         }
552
553         if ((tmp = strtok((char *)recipients, ",")) == NULL) {
554                 DEBUG(2, ("Invalid recipient string format\n"));
555                 return NULL;
556         }
557         
558         usernames = talloc_array(mem_ctx, char *, 2);
559         usernames[0] = strdup(tmp);
560         
561         for (j = 1; (tmp = strtok(NULL, ",")) != NULL; j++) {
562                 usernames = talloc_realloc(mem_ctx, usernames, char *, j+2);
563                 usernames[j] = strdup(tmp);
564         }
565         usernames[j] = 0;
566
567         return (usernames);
568 }
569
570 /**
571  * We set external recipients at the end of aRow
572  */
573 static bool set_external_recipients(TALLOC_CTX *mem_ctx, struct SRowSet *SRowSet, const char *username, enum ulRecipClass RecipClass)
574 {
575         uint32_t                last;
576         struct SPropValue       SPropValue;
577
578         SRowSet->aRow = talloc_realloc(mem_ctx, SRowSet->aRow, struct SRow, SRowSet->cRows + 1);
579         last = SRowSet->cRows;
580         SRowSet->aRow[last].cValues = 0;
581         SRowSet->aRow[last].lpProps = talloc_zero(mem_ctx, struct SPropValue);
582         
583         /* PR_OBJECT_TYPE */
584         SPropValue.ulPropTag = PR_OBJECT_TYPE;
585         SPropValue.value.l = MAPI_MAILUSER;
586         SRow_addprop(&(SRowSet->aRow[last]), SPropValue);
587
588         /* PR_DISPLAY_TYPE */
589         SPropValue.ulPropTag = PR_DISPLAY_TYPE;
590         SPropValue.value.l = 0;
591         SRow_addprop(&(SRowSet->aRow[last]), SPropValue);
592
593         /* PR_GIVEN_NAME */
594         SPropValue.ulPropTag = PR_GIVEN_NAME_UNICODE;
595         SPropValue.value.lpszA = username;
596         SRow_addprop(&(SRowSet->aRow[last]), SPropValue);
597
598         /* PR_DISPLAY_NAME */
599         SPropValue.ulPropTag = PR_DISPLAY_NAME_UNICODE;
600         SPropValue.value.lpszA = username;
601         SRow_addprop(&(SRowSet->aRow[last]), SPropValue);
602
603         /* PR_7BIT_DISPLAY_NAME */
604         SPropValue.ulPropTag = PR_7BIT_DISPLAY_NAME_UNICODE;
605         SPropValue.value.lpszA = username;
606         SRow_addprop(&(SRowSet->aRow[last]), SPropValue);
607
608         /* PR_SMTP_ADDRESS */
609         SPropValue.ulPropTag = PR_SMTP_ADDRESS_UNICODE;
610         SPropValue.value.lpszA = username;
611         SRow_addprop(&(SRowSet->aRow[last]), SPropValue);
612
613         /* PR_ADDRTYPE */
614         SPropValue.ulPropTag = PR_ADDRTYPE_UNICODE;
615         SPropValue.value.lpszA = "SMTP";
616         SRow_addprop(&(SRowSet->aRow[last]), SPropValue);
617
618         SetRecipientType(&(SRowSet->aRow[last]), RecipClass);
619
620         SRowSet->cRows += 1;
621         return true;
622 }
623
624 static bool set_usernames_RecipientType(TALLOC_CTX *mem_ctx, uint32_t *index, struct SRowSet *rowset, 
625                                         char **usernames, struct PropertyTagArray_r *flaglist,
626                                         enum ulRecipClass RecipClass)
627 {
628         uint32_t        i;
629         uint32_t        count = *index;
630         static uint32_t counter = 0;
631
632         if (count == 0) counter = 0;
633         if (!usernames) return false;
634
635         for (i = 0; usernames[i]; i++) {
636                 if (flaglist->aulPropTag[count] == MAPI_UNRESOLVED) {
637                         set_external_recipients(mem_ctx, rowset, usernames[i], RecipClass);
638                 }
639                 if (flaglist->aulPropTag[count] == MAPI_RESOLVED) {
640                         SetRecipientType(&(rowset->aRow[counter]), RecipClass);
641                         counter++;
642                 }
643                 count++;
644         }
645         
646         *index = count;
647         
648         return true;
649 }
650
651 static char **collapse_recipients(TALLOC_CTX *mem_ctx, struct oclient *oclient)
652 {
653         uint32_t        count;
654         uint32_t        i;
655         char            **usernames;
656
657         if (!oclient->mapi_to && !oclient->mapi_cc && !oclient->mapi_bcc) return NULL;
658
659         count = 0;
660         for (i = 0; oclient->mapi_to && oclient->mapi_to[i]; i++,  count++);
661         for (i = 0; oclient->mapi_cc && oclient->mapi_cc[i]; i++,  count++);
662         for (i = 0; oclient->mapi_bcc && oclient->mapi_bcc[i]; i++, count++);
663
664         usernames = talloc_array(mem_ctx, char *, count + 1);
665         count = 0;
666
667         for (i = 0; oclient->mapi_to && oclient->mapi_to[i]; i++, count++) {
668                 usernames[count] = talloc_strdup(mem_ctx, oclient->mapi_to[i]);
669         }
670
671         for (i = 0; oclient->mapi_cc && oclient->mapi_cc[i]; i++, count++) {
672                 usernames[count] = talloc_strdup(mem_ctx, oclient->mapi_cc[i]);
673         }
674
675         for (i = 0; oclient->mapi_bcc && oclient->mapi_bcc[i]; i++, count++) {
676                 usernames[count] = talloc_strdup(mem_ctx, oclient->mapi_bcc[i]);
677         }
678
679         usernames[count++] = 0;
680
681         return usernames;
682 }
683
684 /**
685  * Write a stream with MAX_READ_SIZE chunks
686  */
687
688 #define MAX_READ_SIZE   0x1000
689
690 static bool openchangeclient_stream(TALLOC_CTX *mem_ctx, mapi_object_t obj_parent, 
691                                     mapi_object_t obj_stream, uint32_t mapitag, 
692                                     uint32_t access_flags, struct Binary_r bin)
693 {
694         enum MAPISTATUS retval;
695         DATA_BLOB       stream;
696         uint32_t        size;
697         uint32_t        offset;
698         uint16_t        read_size;
699
700         /* Open a stream on the parent for the given property */
701         retval = OpenStream(&obj_parent, mapitag, access_flags, &obj_stream);
702         fprintf (stderr, "openstream: retval = %s (0x%.8x)\n",
703                  mapi_get_errstr (retval), retval);
704
705         if (retval != MAPI_E_SUCCESS) return false;
706
707         /* WriteStream operation */
708         printf("We are about to write %u bytes in the stream\n", bin.cb);
709         size = MAX_READ_SIZE;
710         offset = 0;
711         while (offset <= bin.cb) {
712                 stream.length = size;
713                 stream.data = talloc_size(mem_ctx, size);
714                 memcpy(stream.data, bin.lpb + offset, size);
715                 
716                 retval = WriteStream(&obj_stream, &stream, &read_size);
717                 talloc_free(stream.data);
718                 if (retval != MAPI_E_SUCCESS) return false;
719                 printf(".");
720                 fflush(0);
721
722                 /* Exit when there is nothing left to write */
723                 if (!read_size) {
724                         mapi_object_release(&obj_stream);
725                         return true;
726                 }
727                 
728                 offset += read_size;
729
730                 if ((offset + size) > bin.cb) {
731                         size = bin.cb - offset;
732                 }
733         }
734
735         mapi_object_release(&obj_stream);
736
737         return true;
738 }
739
740
741 #define SETPROPS_COUNT  4
742
743 /**
744  * Send a mail
745  */
746
747 static enum MAPISTATUS openchangeclient_sendmail(TALLOC_CTX *mem_ctx, 
748                                                  mapi_object_t *obj_store, 
749                                                  struct oclient *oclient)
750 {
751         enum MAPISTATUS                 retval;
752         struct SPropTagArray            *SPropTagArray;
753         struct SPropValue               SPropValue;
754         struct SRowSet                  *SRowSet = NULL;
755         struct PropertyTagArray_r       *flaglist = NULL;
756         mapi_id_t                       id_outbox;
757         mapi_object_t                   obj_outbox;
758         mapi_object_t                   obj_message;
759         mapi_object_t                   obj_stream;
760         uint32_t                        index = 0;
761         uint32_t                        msgflag;
762         struct SPropValue               props[SETPROPS_COUNT];
763         uint32_t                        prop_count = 0;
764         uint32_t                        editor = 0;
765
766         mapi_object_init(&obj_outbox);
767         mapi_object_init(&obj_message);
768
769         if (oclient->pf == true) {
770                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_outbox, oclient->folder);
771                 if (retval != MAPI_E_SUCCESS) return retval;
772         } else {
773                 /* Get Sent Items folder but should be using olFolderOutbox */
774                 retval = GetDefaultFolder(obj_store, &id_outbox, olFolderOutbox);
775                 if (retval != MAPI_E_SUCCESS) return retval;
776
777                 /* Open outbox folder */
778                 retval = OpenFolder(obj_store, id_outbox, &obj_outbox);
779                 if (retval != MAPI_E_SUCCESS) return retval;
780         }
781
782         /* Create the message */
783         retval = CreateMessage(&obj_outbox, &obj_message);
784         if (retval != MAPI_E_SUCCESS) return retval;
785
786         /* Recipients operations */
787         SPropTagArray = set_SPropTagArray(mem_ctx, 0xA,
788                                           PR_ENTRYID,
789                                           PR_DISPLAY_NAME_UNICODE,
790                                           PR_OBJECT_TYPE,
791                                           PR_DISPLAY_TYPE,
792                                           PR_TRANSMITTABLE_DISPLAY_NAME_UNICODE,
793                                           PR_EMAIL_ADDRESS_UNICODE,
794                                           PR_ADDRTYPE_UNICODE,
795                                           PR_SEND_RICH_INFO,
796                                           PR_7BIT_DISPLAY_NAME_UNICODE,
797                                           PR_SMTP_ADDRESS_UNICODE);
798
799         oclient->usernames = collapse_recipients(mem_ctx, oclient);
800
801         /* ResolveNames */
802         retval = ResolveNames(mapi_object_get_session(&obj_message), (const char **)oclient->usernames, 
803                               SPropTagArray, &SRowSet, &flaglist, MAPI_UNICODE);
804         MAPIFreeBuffer(SPropTagArray);
805         if (retval != MAPI_E_SUCCESS) return retval;
806
807         if (!SRowSet) {
808                 SRowSet = talloc_zero(mem_ctx, struct SRowSet);
809         }
810
811         set_usernames_RecipientType(mem_ctx, &index, SRowSet, oclient->mapi_to, flaglist, MAPI_TO);
812         set_usernames_RecipientType(mem_ctx, &index, SRowSet, oclient->mapi_cc, flaglist, MAPI_CC);
813         set_usernames_RecipientType(mem_ctx, &index, SRowSet, oclient->mapi_bcc, flaglist, MAPI_BCC);
814
815         SPropValue.ulPropTag = PR_SEND_INTERNET_ENCODING;
816         SPropValue.value.l = 0;
817         SRowSet_propcpy(mem_ctx, SRowSet, SPropValue);
818
819         /* ModifyRecipients operation */
820         retval = ModifyRecipients(&obj_message, SRowSet);
821         MAPIFreeBuffer(SRowSet);
822         MAPIFreeBuffer(flaglist);
823         if (retval != MAPI_E_SUCCESS) return retval;
824
825         /* set message properties */
826         msgflag = MSGFLAG_UNSENT;
827         oclient->subject = (!oclient->subject) ? "" : oclient->subject;
828         set_SPropValue_proptag(&props[0], PR_SUBJECT_UNICODE, 
829                                (const void *)oclient->subject);
830         set_SPropValue_proptag(&props[1], PR_MESSAGE_FLAGS, 
831                                (const void *)&msgflag);
832         prop_count = 2;
833
834         /* Set PR_BODY or PR_HTML or inline PR_HTML */
835         if (oclient->pr_body) {
836                 editor = EDITOR_FORMAT_PLAINTEXT;
837                 set_SPropValue_proptag(&props[3], PR_MSG_EDITOR_FORMAT, (const void *)&editor);
838
839                 if (strlen(oclient->pr_body) > MAX_READ_SIZE) {
840                         struct Binary_r bin;
841
842                         bin.lpb = (uint8_t *)oclient->pr_body;
843                         bin.cb = strlen(oclient->pr_body);
844                         openchangeclient_stream(mem_ctx, obj_message, obj_stream, PR_BODY, 2, bin);
845                 } else {
846                         set_SPropValue_proptag(&props[2], PR_BODY_UNICODE, 
847                                                                    (const void *)oclient->pr_body);
848                         prop_count++;
849                 }
850         } else if (oclient->pr_html_inline) {
851                 editor = EDITOR_FORMAT_HTML;
852                 set_SPropValue_proptag(&props[3], PR_MSG_EDITOR_FORMAT, (const void *)&editor);
853
854                 if (strlen(oclient->pr_html_inline) > MAX_READ_SIZE) {
855                         struct Binary_r bin;
856                         
857                         bin.lpb = (uint8_t *)oclient->pr_html_inline;
858                         bin.cb = strlen(oclient->pr_html_inline);
859
860                         openchangeclient_stream(mem_ctx, obj_message, obj_stream, PR_HTML, 2, bin);
861                 } else {
862                         struct SBinary_short bin;
863                         
864                         bin.cb = strlen(oclient->pr_html_inline);
865                         bin.lpb = (uint8_t *)oclient->pr_html_inline;
866                         set_SPropValue_proptag(&props[2], PR_HTML, (void *)&bin);
867                         prop_count++;
868                 }
869                 
870         } else if (&oclient->pr_html) {
871                 editor = EDITOR_FORMAT_HTML;
872                 set_SPropValue_proptag(&props[3], PR_MSG_EDITOR_FORMAT, (const void *)&editor);
873
874                 if (oclient->pr_html.cb <= MAX_READ_SIZE) {
875                         struct SBinary_short bin;
876
877                         bin.cb = oclient->pr_html.cb;
878                         bin.lpb = oclient->pr_html.lpb;
879
880                         set_SPropValue_proptag(&props[2], PR_HTML, (void *)&bin);
881                         prop_count++;
882                 } else {
883                         mapi_object_init(&obj_stream);
884                         openchangeclient_stream(mem_ctx, obj_message, obj_stream, PR_HTML, 2, oclient->pr_html);
885                 }
886         }
887
888         retval = SetProps(&obj_message, 0, props, prop_count);
889         if (retval != MAPI_E_SUCCESS) return retval;
890
891         /* attachment related code */
892         if (oclient->attach) {
893                 uint32_t        i;
894
895                 for (i = 0; oclient->attach[i].filename; i++) {
896                         mapi_object_t           obj_attach;
897                         mapi_object_t           obj_stream;
898                         struct SPropValue       props_attach[4];
899                         uint32_t                count_props_attach;
900
901                         mapi_object_init(&obj_attach);
902
903                         retval = CreateAttach(&obj_message, &obj_attach);
904                         if (retval != MAPI_E_SUCCESS) return retval;
905                 
906                         props_attach[0].ulPropTag = PR_ATTACH_METHOD;
907                         props_attach[0].value.l = ATTACH_BY_VALUE;
908                         props_attach[1].ulPropTag = PR_RENDERING_POSITION;
909                         props_attach[1].value.l = 0;
910                         props_attach[2].ulPropTag = PR_ATTACH_FILENAME;
911                         printf("Sending %s:\n", oclient->attach[i].filename);
912                         props_attach[2].value.lpszA = get_filename(oclient->attach[i].filename);
913                         props_attach[3].ulPropTag = PR_ATTACH_CONTENT_ID;
914                         props_attach[3].value.lpszA = get_filename(oclient->attach[i].filename);
915                         count_props_attach = 4;
916
917                         /* SetProps */
918                         retval = SetProps(&obj_attach, 0, props_attach, count_props_attach);
919                         if (retval != MAPI_E_SUCCESS) return retval;
920
921                         /* Stream operations */
922                         mapi_object_init(&obj_stream);
923                         openchangeclient_stream(mem_ctx, obj_attach, obj_stream, PR_ATTACH_DATA_BIN, 2, oclient->attach[i].bin);
924
925                         /* Save changes on attachment */
926                         retval = SaveChangesAttachment(&obj_message, &obj_attach, KeepOpenReadWrite);
927                         if (retval != MAPI_E_SUCCESS) return retval;
928
929                         mapi_object_release(&obj_attach);
930                 }
931         }
932
933         if (oclient->pf) {
934                 retval = SaveChangesMessage(&obj_outbox, &obj_message, KeepOpenReadOnly);
935                 if (retval != MAPI_E_SUCCESS) return retval;
936
937         } else {
938                 /* Submit the message */
939                 retval = SubmitMessage(&obj_message);
940                 if (retval != MAPI_E_SUCCESS) return retval;
941         }
942
943         mapi_object_release(&obj_message);
944         mapi_object_release(&obj_outbox);
945
946         return MAPI_E_SUCCESS;
947 }
948
949 /**
950  * delete a mail from user INBOX
951  */
952 static bool openchangeclient_deletemail(TALLOC_CTX *mem_ctx,
953                                         mapi_object_t *obj_store, 
954                                         struct oclient *oclient)
955 {
956         enum MAPISTATUS         retval;
957         struct SPropTagArray    *SPropTagArray;
958         struct SRowSet          SRowSet;
959         mapi_id_t               id_inbox;
960         mapi_id_t               *id_messages;
961         uint32_t                count_messages;
962         uint32_t                count_rows;
963         mapi_object_t           obj_inbox;
964         mapi_object_t           obj_table;
965         uint32_t                len;
966         uint32_t                i;
967
968         if (!oclient->subject) {
969                 printf("You need to specify at least a message subject pattern\n");
970                 MAPI_RETVAL_IF(!oclient->subject, MAPI_E_INVALID_PARAMETER, NULL);
971         }
972
973         mapi_object_init(&obj_inbox);
974         mapi_object_init(&obj_table);
975
976         if (oclient->pf == true) {
977                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_inbox, oclient->folder);
978                 if (retval != MAPI_E_SUCCESS) return retval;
979         } else {
980                 retval = GetReceiveFolder(obj_store, &id_inbox, NULL);
981                 if (retval != MAPI_E_SUCCESS) return false;
982
983                 retval = OpenFolder(obj_store, id_inbox, &obj_inbox);
984                 if (retval != MAPI_E_SUCCESS) return false;
985         }
986
987         retval = GetContentsTable(&obj_inbox, &obj_table, 0, NULL);
988         if (retval != MAPI_E_SUCCESS) return false;
989
990         SPropTagArray = set_SPropTagArray(mem_ctx, 0x5,
991                                           PR_FID,
992                                           PR_MID,
993                                           PR_INST_ID,
994                                           PR_INSTANCE_NUM,
995                                           PR_SUBJECT_UNICODE);
996         retval = SetColumns(&obj_table, SPropTagArray);
997         if (retval != MAPI_E_SUCCESS) return false;
998         
999         while ((retval = QueryRows(&obj_table, 0x10, TBL_ADVANCE, &SRowSet)) == MAPI_E_SUCCESS) {
1000                 count_rows = SRowSet.cRows;
1001                 if (!count_rows) break;
1002                 id_messages = talloc_array(mem_ctx, uint64_t, count_rows);
1003                 count_messages = 0;
1004                 
1005                 len = strlen(oclient->subject);
1006
1007                 for (i = 0; i < count_rows; i++) {
1008                         if (!strncmp(SRowSet.aRow[i].lpProps[4].value.lpszA, oclient->subject, len)) {
1009                                 id_messages[count_messages] = SRowSet.aRow[i].lpProps[1].value.d;
1010                                 count_messages++;
1011                         }
1012                 }
1013                 if (count_messages) {
1014                         retval = DeleteMessage(&obj_inbox, id_messages, count_messages);
1015                         if (retval != MAPI_E_SUCCESS) return false;
1016                 }
1017         }
1018
1019         mapi_object_release(&obj_table);
1020         mapi_object_release(&obj_inbox);
1021
1022         return true;
1023 }
1024
1025
1026 static enum MAPISTATUS check_conflict_date(struct oclient *oclient,
1027                                            mapi_object_t *obj,
1028                                            struct FILETIME *ft)
1029 {
1030         enum MAPISTATUS         retval;
1031         mapi_object_t           obj_store;
1032         struct mapi_session     *session;
1033         struct mapi_session     *session2;
1034         bool                    conflict;
1035                         
1036         session = mapi_object_get_session(obj);
1037         retval = MapiLogonEx(oclient->mapi_ctx, &session2, session->profile->profname, session->profile->password);
1038         MAPI_RETVAL_IF(retval, retval, NULL);
1039
1040         mapi_object_init(&obj_store);
1041         retval = OpenPublicFolder(session2, &obj_store);
1042         MAPI_RETVAL_IF(retval, retval, NULL);
1043
1044         retval = IsFreeBusyConflict(&obj_store, ft, &conflict);
1045         Logoff(&obj_store);
1046
1047         if (conflict == true) {
1048                 printf("[WARNING]: This start date conflicts with another appointment\n");
1049                 return MAPI_E_INVALID_PARAMETER;
1050         }       
1051
1052         return MAPI_E_SUCCESS;
1053 }
1054
1055 /**
1056  * Send appointment
1057  */
1058
1059 static enum MAPISTATUS appointment_SetProps(TALLOC_CTX *mem_ctx, 
1060                                             mapi_object_t *obj_folder,
1061                                             mapi_object_t *obj_message, 
1062                                             struct oclient *oclient)
1063 {
1064         enum MAPISTATUS         retval;
1065         struct SPropValue       *lpProps;
1066         struct FILETIME         *start_date;
1067         struct FILETIME         *end_date;
1068         uint32_t                cValues = 0;
1069         NTTIME                  nt;
1070         struct tm               tm;
1071         uint32_t                flag;
1072         uint8_t                 flag2;
1073
1074         cValues = 0;
1075         lpProps = talloc_array(mem_ctx, struct SPropValue, 2);
1076
1077         if (oclient->subject) {
1078                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_CONVERSATION_TOPIC_UNICODE, 
1079                                (const void *) oclient->subject);
1080                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_NORMALIZED_SUBJECT_UNICODE,
1081                                (const void *) oclient->subject);
1082         }
1083         if (oclient->pr_body) {
1084                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_BODY_UNICODE, (const void *)oclient->pr_body);
1085         }
1086         if (oclient->location) {
1087                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidLocation, (const void *)oclient->location);
1088         }
1089         if (oclient->dtstart) {
1090                 if (!strptime(oclient->dtstart, DATE_FORMAT, &tm)) {
1091                         printf("Invalid date format: yyyy-mm-dd hh:mm:ss (e.g.: 2007-09-17 10:00:00)\n");
1092                         return MAPI_E_INVALID_PARAMETER;
1093                 }
1094                 unix_to_nt_time(&nt, mktime(&tm));
1095                 start_date = talloc(mem_ctx, struct FILETIME);
1096                 start_date->dwLowDateTime = (nt << 32) >> 32;
1097                 start_date->dwHighDateTime = (nt >> 32);
1098
1099                 retval = check_conflict_date(oclient, obj_folder, start_date);
1100                 if (oclient->force == false) {
1101                         MAPI_RETVAL_IF(retval, retval, NULL);
1102                 }
1103
1104                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_START_DATE, (const void *)start_date);
1105                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidCommonStart, (const void *)start_date);
1106                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidAppointmentStartWhole, (const void *) start_date);
1107         }
1108         if (oclient->dtend) {
1109                 if (!strptime(oclient->dtend, DATE_FORMAT, &tm)) {
1110                         printf("Invalid date format: yyyy-mm-dd hh:mm:ss (e.g.:2007-09-17 18:30:00)\n");
1111                         return MAPI_E_INVALID_PARAMETER;
1112                 }
1113                 unix_to_nt_time(&nt, mktime(&tm));
1114                 end_date = talloc(mem_ctx, struct FILETIME);
1115                 end_date->dwLowDateTime = (nt << 32) >> 32;
1116                 end_date->dwHighDateTime = (nt >> 32);
1117
1118                 retval = check_conflict_date(oclient, obj_folder, end_date);
1119                 if (oclient->force == false) {
1120                         MAPI_RETVAL_IF(retval, retval, NULL);
1121                 }
1122
1123                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_END_DATE, (const void *) end_date);
1124                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidCommonEnd, (const void *) end_date);
1125                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidAppointmentEndWhole, (const void *) end_date);
1126         }
1127
1128         if (!oclient->update) {
1129                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_MESSAGE_CLASS_UNICODE, (const void *)"IPM.Appointment");
1130
1131                 flag = 1;
1132                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_MESSAGE_FLAGS, (const void *)&flag);
1133
1134                 flag= MEETING_STATUS_NONMEETING;
1135                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidAppointmentStateFlags, (const void *) &flag);
1136
1137                 flag = 30;
1138                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidReminderDelta, (const void *)&flag);
1139                 
1140                 /* WARNING needs to replace private */
1141                 flag2 = oclient->private;
1142                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidPrivate, (const void *)&flag2);
1143
1144                 oclient->label = (oclient->label == -1) ? 0 : oclient->label;
1145                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidAppointmentColor, (const void *) &oclient->label);
1146
1147                 oclient->busystatus = (oclient->busystatus == -1) ? 0 : oclient->busystatus;
1148                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidBusyStatus, (const void *) &oclient->busystatus);
1149         } else {
1150                 if (oclient->busystatus != -1) {
1151                         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidBusyStatus, (const void *) &oclient->busystatus);
1152                 }
1153                 if (oclient->label != -1) {
1154                         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidAppointmentColor, (const void *) &oclient->label);
1155                 }
1156         }
1157
1158         flag = (oclient->private == true) ? 2 : 0;
1159         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_SENSITIVITY, (const void *)&flag);
1160         
1161         retval = SetProps(obj_message, 0, lpProps, cValues);
1162         MAPIFreeBuffer(lpProps);
1163         MAPI_RETVAL_IF(retval, retval, NULL);
1164
1165         return MAPI_E_SUCCESS;
1166 }
1167
1168
1169 static bool openchangeclient_sendappointment(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
1170 {
1171         enum MAPISTATUS         retval;
1172         mapi_object_t           obj_calendar;
1173         mapi_object_t           obj_message;
1174         mapi_id_t               id_calendar;
1175         char                    *uniq_id;
1176
1177         mapi_object_init(&obj_calendar);
1178
1179         if (oclient->pf == true) {
1180                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_calendar, oclient->folder);
1181                 if (retval != MAPI_E_SUCCESS) return false;
1182         } else {
1183                 /* Open Calendar default folder */
1184                 retval = GetDefaultFolder(obj_store, &id_calendar, olFolderCalendar);
1185                 if (retval != MAPI_E_SUCCESS) return false;
1186                 
1187                 retval = OpenFolder(obj_store, id_calendar, &obj_calendar);
1188                 if (retval != MAPI_E_SUCCESS) return false;
1189         }
1190
1191         /* Create calendar message */
1192         mapi_object_init(&obj_message);
1193         retval = CreateMessage(&obj_calendar, &obj_message);
1194         if (retval != MAPI_E_SUCCESS) return false;
1195
1196         /* Set calendar message properties */
1197         retval = appointment_SetProps(mem_ctx, &obj_calendar, &obj_message, oclient);
1198         if (retval != MAPI_E_SUCCESS) return false;
1199
1200         retval = SaveChangesMessage(&obj_calendar, &obj_message, KeepOpenReadOnly);
1201         if (retval != MAPI_E_SUCCESS) return false;
1202
1203         /* Fetch and Display the message unique ID */
1204         uniq_id = build_uniqueID(mem_ctx, &obj_calendar, &obj_message);
1205         printf("    %-25s: %s\n", "Unique ID", uniq_id);
1206         fflush(0);
1207         talloc_free(uniq_id);
1208
1209         mapi_object_release(&obj_message);
1210         mapi_object_release(&obj_calendar);
1211         
1212         return true;
1213 }
1214
1215 /**
1216  * Create a contact
1217  */
1218 static enum MAPISTATUS contact_SetProps(TALLOC_CTX *mem_ctx,
1219                                         mapi_object_t *obj_folder,
1220                                         mapi_object_t *obj_message,
1221                                         struct oclient *oclient)
1222 {
1223         enum MAPISTATUS         retval;
1224         struct SPropValue       *lpProps;
1225         struct mapi_nameid      *nameid;
1226         struct SPropTagArray    *SPropTagArray;
1227         uint32_t                cValues = 0;
1228
1229         /* Build the list of named properties we want to set */
1230         nameid = mapi_nameid_new(mem_ctx);
1231         retval = mapi_nameid_string_add(nameid, "urn:schemas:contacts:fileas", PS_PUBLIC_STRINGS);
1232         if (retval != MAPI_E_SUCCESS) {
1233                 talloc_free(nameid);
1234                 return retval;
1235         }
1236
1237         /* GetIDsFromNames and map property types */
1238         SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
1239         retval = GetIDsFromNames(obj_folder, nameid->count,
1240                                  nameid->nameid, 0, &SPropTagArray);
1241         if (retval != MAPI_E_SUCCESS) {
1242                 talloc_free(nameid);
1243                 return retval;
1244         }
1245         mapi_nameid_SPropTagArray(nameid, SPropTagArray);
1246         MAPIFreeBuffer(nameid);
1247
1248         cValues = 0;
1249         lpProps = talloc_array(mem_ctx, struct SPropValue, 2);
1250
1251         if (oclient->card_name) {
1252                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_NORMALIZED_SUBJECT_UNICODE, (const void *)oclient->card_name);
1253                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidFileUnder, (const void *)oclient->card_name);
1254                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, SPropTagArray->aulPropTag[0], (const void *)oclient->card_name);
1255         }
1256         if (oclient->full_name) {
1257                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_DISPLAY_NAME_UNICODE, (const void *)oclient->full_name);
1258         }
1259         if (oclient->email) {
1260                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidEmail1OriginalDisplayName, (const void *)oclient->email);
1261                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidEmail1EmailAddress, (const void *)oclient->email);
1262         }
1263         if (!oclient->update) {
1264                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_MESSAGE_CLASS_UNICODE, (const void *)"IPM.Contact");
1265         }
1266         retval = SetProps(obj_message, 0, lpProps, cValues);
1267         MAPIFreeBuffer(SPropTagArray);
1268         MAPIFreeBuffer(lpProps);
1269         MAPI_RETVAL_IF(retval, retval, NULL);
1270         
1271         return MAPI_E_SUCCESS;
1272 }
1273
1274 static bool openchangeclient_sendcontact(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
1275 {
1276         enum MAPISTATUS         retval;
1277         mapi_object_t           obj_contact;
1278         mapi_object_t           obj_message;
1279         mapi_id_t               id_contact;     
1280         char                    *uniq_id;
1281
1282         mapi_object_init(&obj_contact);
1283
1284         if (oclient->pf == true) {
1285                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_contact, oclient->folder);
1286                 if (retval != MAPI_E_SUCCESS) return retval;
1287         } else {
1288                 /* Open Contact default folder */
1289                 retval = GetDefaultFolder(obj_store, &id_contact, olFolderContacts);
1290                 if (retval != MAPI_E_SUCCESS) return false;
1291
1292                 retval = OpenFolder(obj_store, id_contact, &obj_contact);
1293                 if (retval != MAPI_E_SUCCESS) return false;
1294         }
1295
1296         /* Create contact message */
1297         mapi_object_init(&obj_message);
1298         retval = CreateMessage(&obj_contact, &obj_message);
1299         if (retval != MAPI_E_SUCCESS) return false;
1300
1301         /* Set contact message properties */
1302         retval = contact_SetProps(mem_ctx, &obj_contact, &obj_message, oclient);
1303         if (retval != MAPI_E_SUCCESS) return false;
1304
1305         retval = SaveChangesMessage(&obj_contact, &obj_message, KeepOpenReadOnly);
1306         if (retval != MAPI_E_SUCCESS) return false;
1307
1308         /* Fetch and Display the message unique ID */
1309         uniq_id = build_uniqueID(mem_ctx, &obj_contact, &obj_message);
1310         printf("    %-25s: %s\n", "Unique ID", uniq_id);
1311         fflush(0);
1312         talloc_free(uniq_id);
1313
1314         mapi_object_release(&obj_message);
1315         mapi_object_release(&obj_contact);
1316
1317         return true;
1318 }
1319
1320 /**
1321  * Create task
1322  */
1323 static enum MAPISTATUS task_SetProps(TALLOC_CTX *mem_ctx,
1324                                         mapi_object_t *obj_message,
1325                                         struct oclient *oclient)
1326 {
1327         enum MAPISTATUS         retval;
1328         struct SPropValue       *lpProps;
1329         struct FILETIME         *start_date;
1330         struct FILETIME         *end_date;
1331         uint32_t                cValues = 0;
1332         NTTIME                  nt;
1333         struct tm               tm;
1334
1335         cValues = 0;
1336         lpProps = talloc_array(mem_ctx, struct SPropValue, 2);
1337
1338         if (oclient->card_name) {
1339                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_CONVERSATION_TOPIC_UNICODE, (const void *)oclient->card_name);
1340                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_NORMALIZED_SUBJECT_UNICODE, (const void *)oclient->card_name);
1341         }
1342
1343         if (oclient->dtstart) {
1344                 if (!strptime(oclient->dtstart, DATE_FORMAT, &tm)) {
1345                         printf("Invalid date format (e.g.: 2007-06-01 22:30:00)\n");
1346                         return MAPI_E_INVALID_PARAMETER;
1347                 }
1348                 unix_to_nt_time(&nt, mktime(&tm));
1349                 start_date = talloc(mem_ctx, struct FILETIME);
1350                 start_date->dwLowDateTime = (nt << 32) >> 32;
1351                 start_date->dwHighDateTime = (nt >> 32);                
1352                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidTaskStartDate, (const void *)start_date);
1353         }
1354
1355         if (oclient->dtend) {
1356                 if (!strptime(oclient->dtend, DATE_FORMAT, &tm)) {
1357                         printf("Invalid date format (e.g.: 2007-06-01 22:30:00)\n");
1358                         return MAPI_E_INVALID_PARAMETER;
1359                 }
1360                 unix_to_nt_time(&nt, mktime(&tm));
1361                 end_date = talloc(mem_ctx, struct FILETIME);
1362                 end_date->dwLowDateTime = (nt << 32) >> 32;
1363                 end_date->dwHighDateTime = (nt >> 32);
1364                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidTaskDueDate, (const void *)end_date);
1365         }
1366
1367         if (oclient->pr_body) {
1368                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_BODY_UNICODE, (const void *)oclient->pr_body);
1369         }
1370
1371         if (!oclient->update) {
1372                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_MESSAGE_CLASS_UNICODE, (const void *)"IPM.Task");
1373                 oclient->importance = (oclient->importance == -1) ? 1 : oclient->importance;
1374                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_IMPORTANCE, (const void *)&oclient->importance);
1375                 oclient->taskstatus = (oclient->taskstatus == -1) ? 0 : oclient->taskstatus;
1376                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidTaskStatus, (const void *)&oclient->taskstatus);
1377         } else {
1378                 if (oclient->importance != -1) {
1379                         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_IMPORTANCE, (const void *)&oclient->importance);
1380                 }
1381                 if (oclient->taskstatus != -1) {
1382                         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidTaskStatus, (const void *)&oclient->taskstatus);
1383                 }
1384         }
1385
1386         retval = SetProps(obj_message, 0, lpProps, cValues);
1387         MAPIFreeBuffer(lpProps);
1388         MAPI_RETVAL_IF(retval, retval, NULL);
1389
1390         return MAPI_E_SUCCESS;
1391 }
1392
1393 static bool openchangeclient_sendtask(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
1394 {
1395         enum MAPISTATUS         retval;
1396         mapi_object_t           obj_task;
1397         mapi_object_t           obj_message;
1398         mapi_id_t               id_task;        
1399         char                    *uniq_id;
1400
1401         mapi_object_init(&obj_task);
1402
1403         if (oclient->pf == true) {
1404                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_task, oclient->folder);
1405                 if (retval != MAPI_E_SUCCESS) return retval;
1406         } else {
1407                 /* Open Contact default folder */
1408                 retval = GetDefaultFolder(obj_store, &id_task, olFolderTasks);
1409                 if (retval != MAPI_E_SUCCESS) return false;
1410
1411                 retval = OpenFolder(obj_store, id_task, &obj_task);
1412                 if (retval != MAPI_E_SUCCESS) return false;
1413         }
1414
1415         /* Create contact message */
1416         mapi_object_init(&obj_message);
1417         retval = CreateMessage(&obj_task, &obj_message);
1418         if (retval != MAPI_E_SUCCESS) return false;
1419
1420         /* Set contact properties */
1421         retval = task_SetProps(mem_ctx, &obj_message, oclient);
1422
1423         retval = SaveChangesMessage(&obj_task, &obj_message, KeepOpenReadOnly);
1424         if (retval != MAPI_E_SUCCESS) return false;
1425
1426         /* Fetch and Display the message unique ID */
1427         uniq_id = build_uniqueID(mem_ctx, &obj_task, &obj_message);
1428         printf("    %-25s: %s\n", "Unique ID", uniq_id);
1429         fflush(0);
1430         talloc_free(uniq_id);
1431
1432         mapi_object_release(&obj_message);
1433         mapi_object_release(&obj_task);
1434
1435         return true;
1436 }
1437
1438
1439 /**
1440  * Send notes
1441  */
1442 static enum MAPISTATUS note_SetProps(TALLOC_CTX *mem_ctx,
1443                                         mapi_object_t *obj_message,
1444                                         struct oclient *oclient)
1445 {
1446         enum MAPISTATUS         retval;
1447         struct SPropValue       *lpProps;
1448         uint32_t                cValues = 0;
1449         uint32_t                value;
1450
1451         cValues = 0;
1452         lpProps = talloc_array(mem_ctx, struct SPropValue, 2);
1453
1454         if (oclient->card_name) {
1455                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_CONVERSATION_TOPIC_UNICODE, (const void *)oclient->card_name);
1456                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_SUBJECT_UNICODE, (const void *)oclient->card_name);
1457                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_NORMALIZED_SUBJECT_UNICODE, (const void *)oclient->card_name);
1458                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_BODY_UNICODE, (const void *)oclient->card_name);
1459         }
1460
1461         if (!oclient->update) {
1462                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_MESSAGE_CLASS_UNICODE, (const void *)"IPM.StickyNote");
1463
1464                 value = 1;
1465                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_MESSAGE_FLAGS, (const void *)&value);
1466
1467                 value = 768;
1468                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PR_ICON_INDEX, (const void *)&value);
1469                 
1470                 value = 272;
1471                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidSideEffects, (const void *)&value);
1472
1473                 oclient->color = (oclient->color == -1) ? olYellow : oclient->color;
1474                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidNoteColor, (const void *)&oclient->color);
1475
1476                 oclient->width = (oclient->width == -1) ? 166 : oclient->width;
1477                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidNoteWidth, (const void *)&oclient->width);
1478
1479                 oclient->height = (oclient->height == -1) ? 200 : oclient->height;
1480                 lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidNoteHeight, (const void *)&oclient->height);
1481
1482         } else {
1483                 if (oclient->color != -1) {
1484                         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidNoteColor, (const void *)&oclient->color);
1485                 }
1486                 if (oclient->width != -1) {
1487                         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidNoteWidth, (const void *)&oclient->width);
1488                 }
1489                 if (oclient->height != -1) {
1490                         lpProps = add_SPropValue(mem_ctx, lpProps, &cValues, PidLidNoteHeight, (const void *)&oclient->height);
1491                 }
1492         }
1493
1494         
1495         retval = SetProps(obj_message, 0, lpProps, cValues);
1496         MAPIFreeBuffer(lpProps);
1497         MAPI_RETVAL_IF(retval, retval, NULL);
1498         
1499         return MAPI_E_SUCCESS;
1500 }
1501
1502 static bool openchangeclient_sendnote(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
1503 {
1504         enum MAPISTATUS         retval;
1505         mapi_object_t           obj_note;
1506         mapi_object_t           obj_message;
1507         mapi_id_t               id_note;        
1508         char                    *uniq_id;
1509
1510         mapi_object_init(&obj_note);
1511
1512         if (oclient->pf == true) {
1513                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_note, oclient->folder);
1514                 if (retval != MAPI_E_SUCCESS) return retval;
1515         } else {
1516                 /* Open Contact default folder */
1517                 retval = GetDefaultFolder(obj_store, &id_note, olFolderNotes);
1518                 if (retval != MAPI_E_SUCCESS) return false;
1519
1520                 retval = OpenFolder(obj_store, id_note, &obj_note);
1521                 if (retval != MAPI_E_SUCCESS) return false;
1522         }
1523
1524         /* Create contact message */
1525         mapi_object_init(&obj_message);
1526         retval = CreateMessage(&obj_note, &obj_message);
1527         if (retval != MAPI_E_SUCCESS) return false;
1528
1529         /* Set Note message properties */
1530         retval = note_SetProps(mem_ctx, &obj_message, oclient);
1531         if (retval != MAPI_E_SUCCESS) return false;
1532
1533         retval = SaveChangesMessage(&obj_note, &obj_message, KeepOpenReadOnly);
1534         if (retval != MAPI_E_SUCCESS) return false;
1535
1536         /* Fetch and Display the message unique ID */
1537         uniq_id = build_uniqueID(mem_ctx, &obj_note, &obj_message);
1538         printf("    %-25s: %s\n", "Unique ID", uniq_id);
1539         fflush(0);
1540         talloc_free(uniq_id);
1541
1542         mapi_object_release(&obj_message);
1543         mapi_object_release(&obj_note);
1544
1545         return true;
1546 }
1547
1548
1549 static const char *get_container_class(TALLOC_CTX *mem_ctx, mapi_object_t *parent, mapi_id_t folder_id)
1550 {
1551         enum MAPISTATUS         retval;
1552         mapi_object_t           obj_folder;
1553         struct SPropTagArray    *SPropTagArray;
1554         struct SPropValue       *lpProps;
1555         uint32_t                count;
1556
1557         mapi_object_init(&obj_folder);
1558         retval = OpenFolder(parent, folder_id, &obj_folder);
1559         if (retval != MAPI_E_SUCCESS) return false;
1560
1561         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_CONTAINER_CLASS);
1562         retval = GetProps(&obj_folder, MAPI_UNICODE, SPropTagArray, &lpProps, &count);
1563         MAPIFreeBuffer(SPropTagArray);
1564         mapi_object_release(&obj_folder);
1565         if ((lpProps[0].ulPropTag != PR_CONTAINER_CLASS) || (retval != MAPI_E_SUCCESS)) {
1566                 errno = 0;
1567                 return IPF_NOTE;
1568         }
1569         return lpProps[0].value.lpszA;
1570 }
1571
1572 static bool get_child_folders(TALLOC_CTX *mem_ctx, mapi_object_t *parent, mapi_id_t folder_id, int count)
1573 {
1574         enum MAPISTATUS         retval;
1575         bool                    ret;
1576         mapi_object_t           obj_folder;
1577         mapi_object_t           obj_htable;
1578         struct SPropTagArray    *SPropTagArray;
1579         struct SRowSet          rowset;
1580         const char              *name;
1581         const char              *comment;
1582         const uint32_t          *total;
1583         const uint32_t          *unread;
1584         const uint32_t          *child;
1585         uint32_t                index;
1586         const uint64_t          *fid;
1587         int                     i;
1588
1589         mapi_object_init(&obj_folder);
1590         retval = OpenFolder(parent, folder_id, &obj_folder);
1591         if (retval != MAPI_E_SUCCESS) return false;
1592
1593         mapi_object_init(&obj_htable);
1594         retval = GetHierarchyTable(&obj_folder, &obj_htable, 0, NULL);
1595         if (retval != MAPI_E_SUCCESS) return false;
1596
1597         SPropTagArray = set_SPropTagArray(mem_ctx, 0x6,
1598                                           PR_DISPLAY_NAME_UNICODE,
1599                                           PR_FID,
1600                                           PR_COMMENT_UNICODE,
1601                                           PR_CONTENT_UNREAD,
1602                                           PR_CONTENT_COUNT,
1603                                           PR_FOLDER_CHILD_COUNT);
1604         retval = SetColumns(&obj_htable, SPropTagArray);
1605         MAPIFreeBuffer(SPropTagArray);
1606         if (retval != MAPI_E_SUCCESS) return false;
1607         
1608         while (((retval = QueryRows(&obj_htable, 0x32, TBL_ADVANCE, &rowset)) != MAPI_E_NOT_FOUND) && rowset.cRows) {
1609                 for (index = 0; index < rowset.cRows; index++) {
1610                         fid = (const uint64_t *)find_SPropValue_data(&rowset.aRow[index], PR_FID);
1611                         name = (const char *)find_SPropValue_data(&rowset.aRow[index], PR_DISPLAY_NAME_UNICODE);
1612                         comment = (const char *)find_SPropValue_data(&rowset.aRow[index], PR_COMMENT_UNICODE);
1613                         total = (const uint32_t *)find_SPropValue_data(&rowset.aRow[index], PR_CONTENT_COUNT);
1614                         unread = (const uint32_t *)find_SPropValue_data(&rowset.aRow[index], PR_CONTENT_UNREAD);
1615                         child = (const uint32_t *)find_SPropValue_data(&rowset.aRow[index], PR_FOLDER_CHILD_COUNT);
1616
1617                         for (i = 0; i < count; i++) {
1618                                 printf("|   ");
1619                         }
1620                         printf("|---+ %-15s : %-20s (Total: %u / Unread: %u - Container class: %s) [FID: 0x%016"PRIx64"]\n", 
1621                                name, comment?comment:"", total?*total:0, unread?*unread:0,
1622                                get_container_class(mem_ctx, parent, *fid), *fid);
1623                         if (child && *child) {
1624                                 ret = get_child_folders(mem_ctx, &obj_folder, *fid, count + 1);
1625                                 if (ret == false) return ret;
1626                         }
1627                         
1628                 }
1629         }
1630         mapi_object_release(&obj_htable);
1631         mapi_object_release(&obj_folder);
1632
1633         return true;
1634 }
1635
1636 static bool get_child_folders_pf(TALLOC_CTX *mem_ctx, mapi_object_t *parent, mapi_id_t folder_id, int count)
1637 {
1638         enum MAPISTATUS         retval;
1639         bool                    ret;
1640         mapi_object_t           obj_folder;
1641         mapi_object_t           obj_htable;
1642         struct SPropTagArray    *SPropTagArray;
1643         struct SRowSet          rowset;
1644         const char              *name;
1645         const uint32_t          *child;
1646         uint32_t                index;
1647         const uint64_t          *fid;
1648         int                     i;
1649
1650         mapi_object_init(&obj_folder);
1651         retval = OpenFolder(parent, folder_id, &obj_folder);
1652         if (retval != MAPI_E_SUCCESS) return false;
1653
1654         mapi_object_init(&obj_htable);
1655         retval = GetHierarchyTable(&obj_folder, &obj_htable, 0, NULL);
1656         if (retval != MAPI_E_SUCCESS) return false;
1657
1658         SPropTagArray = set_SPropTagArray(mem_ctx, 0x3,
1659                                           PR_DISPLAY_NAME_UNICODE,
1660                                           PR_FID,
1661                                           PR_FOLDER_CHILD_COUNT);
1662         retval = SetColumns(&obj_htable, SPropTagArray);
1663         MAPIFreeBuffer(SPropTagArray);
1664         if (retval != MAPI_E_SUCCESS) return false;
1665         
1666         while (((retval = QueryRows(&obj_htable, 0x32, TBL_ADVANCE, &rowset)) != MAPI_E_NOT_FOUND) && rowset.cRows) {
1667                 for (index = 0; index < rowset.cRows; index++) {
1668                         fid = (const uint64_t *)find_SPropValue_data(&rowset.aRow[index], PR_FID);
1669                         name = (const char *)find_SPropValue_data(&rowset.aRow[index], PR_DISPLAY_NAME_UNICODE);
1670                         child = (const uint32_t *)find_SPropValue_data(&rowset.aRow[index], PR_FOLDER_CHILD_COUNT);
1671
1672                         for (i = 0; i < count; i++) {
1673                                 printf("|   ");
1674                         }
1675                         printf("|---+ %-15s [FID: 0x%016"PRIx64"]\n", name, *fid);
1676                         if (*child) {
1677                                 ret = get_child_folders_pf(mem_ctx, &obj_folder, *fid, count + 1);
1678                                 if (ret == false) return ret;
1679                         }
1680                         
1681                 }
1682         }
1683         return true;
1684 }
1685
1686
1687 static bool openchangeclient_pf(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store)
1688 {
1689         enum MAPISTATUS                 retval;
1690         mapi_id_t                       id_pubroot;
1691
1692         retval = GetDefaultPublicFolder(obj_store, &id_pubroot, olFolderPublicRoot);
1693         if (retval != MAPI_E_SUCCESS) return false;
1694
1695         return get_child_folders_pf(mem_ctx, obj_store, id_pubroot, 0);
1696 }
1697
1698
1699 static bool openchangeclient_mailbox(TALLOC_CTX *mem_ctx, 
1700                                      mapi_object_t *obj_store)
1701 {
1702         enum MAPISTATUS                 retval;
1703         mapi_id_t                       id_mailbox;
1704         struct SPropTagArray            *SPropTagArray;
1705         struct SPropValue               *lpProps;
1706         uint32_t                        cValues;
1707         const char                      *mailbox_name;
1708
1709         /* Retrieve the mailbox folder name */
1710         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_DISPLAY_NAME_UNICODE);
1711         retval = GetProps(obj_store, MAPI_UNICODE, SPropTagArray, &lpProps, &cValues);
1712         MAPIFreeBuffer(SPropTagArray);
1713         if (retval != MAPI_E_SUCCESS) return false;
1714
1715         if (lpProps[0].value.lpszW) {
1716                 mailbox_name = lpProps[0].value.lpszW;
1717         } else {
1718                 return false;
1719         }
1720
1721         /* Prepare the directory listing */
1722         retval = GetDefaultFolder(obj_store, &id_mailbox, olFolderTopInformationStore);
1723         if (retval != MAPI_E_SUCCESS) return false;
1724
1725         printf("+ %s\n", mailbox_name);
1726         return get_child_folders(mem_ctx, obj_store, id_mailbox, 0);
1727 }
1728
1729 static bool openchangeclient_fetchitems(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, const char *item,
1730                                         struct oclient *oclient)
1731 {
1732         enum MAPISTATUS                 retval;
1733         mapi_object_t                   obj_tis;
1734         mapi_object_t                   obj_folder;
1735         mapi_object_t                   obj_table;
1736         mapi_object_t                   obj_message;
1737         mapi_id_t                       fid;
1738         uint32_t                        olFolder = 0;
1739         struct SRowSet                  SRowSet;
1740         struct SPropTagArray            *SPropTagArray;
1741         struct mapi_SPropValue_array    properties_array;
1742         uint32_t                        count;
1743         uint32_t                        i;
1744         char                            *id;
1745         
1746         if (!item) return false;
1747
1748         mapi_object_init(&obj_tis);
1749         mapi_object_init(&obj_folder);
1750
1751         for (i = 0; defaultFolders[i].olFolder; i++) {
1752                 if (!strncasecmp(defaultFolders[i].container_class, item, strlen(defaultFolders[i].container_class))) {
1753                         olFolder = defaultFolders[i].olFolder;
1754                 }
1755         }
1756         
1757         if (!olFolder) return false;
1758
1759         if (oclient->pf == true) {
1760                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_folder, oclient->folder);
1761                 if (retval != MAPI_E_SUCCESS) return retval;
1762         } else {
1763                 if (oclient->folder) {
1764                         retval = GetDefaultFolder(obj_store, &fid, olFolderTopInformationStore);
1765                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
1766
1767                         retval = OpenFolder(obj_store, fid, &obj_tis);
1768                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
1769
1770                         retval = openchangeclient_getdir(mem_ctx, &obj_tis, &obj_folder, oclient->folder);
1771                         MAPI_RETVAL_IF(retval, retval, mem_ctx);
1772                 } else {
1773                         retval = GetDefaultFolder(obj_store, &fid, olFolder);
1774                         if (retval != MAPI_E_SUCCESS) return false;
1775
1776                         /* We now open the folder */
1777                         retval = OpenFolder(obj_store, fid, &obj_folder);
1778                         if (retval != MAPI_E_SUCCESS) return false;
1779                 }
1780         }
1781
1782         /* Operations on the  folder */
1783         mapi_object_init(&obj_table);
1784         retval = GetContentsTable(&obj_folder, &obj_table, 0, &count);
1785         if (retval != MAPI_E_SUCCESS) return false;
1786
1787         printf("MAILBOX (%u messages)\n", count);
1788         if (!count) {
1789                 mapi_object_release(&obj_table);
1790                 mapi_object_release(&obj_folder);
1791                 mapi_object_release(&obj_tis);
1792
1793                 return true;
1794         }
1795
1796         SPropTagArray = set_SPropTagArray(mem_ctx, 0x8,
1797                                           PR_FID,
1798                                           PR_MID,
1799                                           PR_INST_ID,
1800                                           PR_INSTANCE_NUM,
1801                                           PR_SUBJECT_UNICODE,
1802                                           PR_MESSAGE_CLASS_UNICODE,
1803                                           PR_RULE_MSG_PROVIDER,
1804                                           PR_RULE_MSG_NAME);
1805         retval = SetColumns(&obj_table, SPropTagArray);
1806         MAPIFreeBuffer(SPropTagArray);
1807         if (retval != MAPI_E_SUCCESS) return false;
1808
1809         while ((retval = QueryRows(&obj_table, count, TBL_ADVANCE, &SRowSet)) != MAPI_E_NOT_FOUND && SRowSet.cRows) {
1810                 count -= SRowSet.cRows;
1811                 for (i = 0; i < SRowSet.cRows; i++) {
1812                         mapi_object_init(&obj_message);
1813                         retval = OpenMessage(&obj_folder, 
1814                                              SRowSet.aRow[i].lpProps[0].value.d,
1815                                              SRowSet.aRow[i].lpProps[1].value.d,
1816                                              &obj_message, 0);
1817                         if (retval != MAPI_E_NOT_FOUND) {
1818                                 if (oclient->summary) {
1819                                         mapidump_message_summary(&obj_message);
1820                                 } else {
1821                                         retval = GetPropsAll(&obj_message, MAPI_UNICODE, &properties_array);
1822                                         if (retval == MAPI_E_SUCCESS) {
1823                                                 id = talloc_asprintf(mem_ctx, ": %"PRIX64"/%"PRIX64,
1824                                                                      SRowSet.aRow[i].lpProps[0].value.d,
1825                                                                      SRowSet.aRow[i].lpProps[1].value.d);
1826                                                 mapi_SPropValue_array_named(&obj_message, 
1827                                                                             &properties_array);
1828                                                 switch (olFolder) {
1829                                                 case olFolderInbox:
1830                                                   mapidump_message(&properties_array, id, NULL);
1831                                                         break;
1832                                                 case olFolderCalendar:
1833                                                         mapidump_appointment(&properties_array, id);
1834                                                         break;
1835                                                 case olFolderContacts:
1836                                                         mapidump_contact(&properties_array, id);
1837                                                         break;
1838                                                 case olFolderTasks:
1839                                                         mapidump_task(&properties_array, id);
1840                                                         break;
1841                                                 case olFolderNotes:
1842                                                         mapidump_note(&properties_array, id);
1843                                                         break;
1844                                                 }
1845                                                 talloc_free(id);
1846                                         }
1847                                 }
1848                                 mapi_object_release(&obj_message);
1849                         }
1850                 }
1851         }
1852         
1853         mapi_object_release(&obj_table);
1854         mapi_object_release(&obj_folder);
1855         mapi_object_release(&obj_tis);
1856
1857         return true;
1858 }
1859
1860 /**
1861  * Update Item
1862  *
1863  * Edit the existing item specified on command line.
1864  * The function first loops over the mailbox, looking for the folder
1865  * ID, then it looks for the particular message ID. It finally opens
1866  * it, set properties and save the message.
1867  *
1868  */
1869 static enum MAPISTATUS folder_lookup(TALLOC_CTX *mem_ctx,
1870                                      uint64_t sfid,
1871                                      mapi_object_t *obj_parent,
1872                                      mapi_id_t folder_id,
1873                                      mapi_object_t *obj_ret)
1874 {
1875         enum MAPISTATUS         retval;
1876         mapi_object_t           obj_folder;
1877         mapi_object_t           obj_htable;
1878         struct SPropTagArray    *SPropTagArray;
1879         struct SRowSet          SRowSet;
1880         uint32_t                i;
1881         const uint64_t          *fid;
1882
1883         mapi_object_init(&obj_folder);
1884         retval = OpenFolder(obj_parent, folder_id, &obj_folder);
1885         if (retval != MAPI_E_SUCCESS) return retval;
1886
1887         mapi_object_init(&obj_htable);
1888         retval = GetHierarchyTable(&obj_folder, &obj_htable, 0, NULL);
1889         if (retval != MAPI_E_SUCCESS) return retval;
1890
1891         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_FID);
1892         retval = SetColumns(&obj_htable, SPropTagArray);
1893         MAPIFreeBuffer(SPropTagArray);
1894         if (retval != MAPI_E_SUCCESS) return retval;
1895
1896         while (((retval = QueryRows(&obj_htable, 0x32, TBL_ADVANCE, &SRowSet)) != MAPI_E_NOT_FOUND && SRowSet.cRows)) {
1897                 for (i = 0; i < SRowSet.cRows; i++) {
1898                         fid = (const uint64_t *)find_SPropValue_data(&SRowSet.aRow[i], PR_FID);
1899                         if (fid && *fid == sfid) {
1900                                 retval = OpenFolder(&obj_folder, *fid, obj_ret);
1901                                 mapi_object_release(&obj_htable);
1902                                 mapi_object_release(&obj_folder);
1903                                 return MAPI_E_SUCCESS;
1904                         } else if (fid) {
1905                                 retval = folder_lookup(mem_ctx, sfid, &obj_folder, *fid, obj_ret);
1906                                 if (retval == MAPI_E_SUCCESS) {
1907                                         mapi_object_release(&obj_htable);
1908                                         mapi_object_release(&obj_folder);
1909                                         return MAPI_E_SUCCESS;
1910                                 }
1911                         }
1912                 }
1913         }
1914
1915         mapi_object_release(&obj_htable);
1916         mapi_object_release(&obj_folder);
1917
1918         errno = MAPI_E_NOT_FOUND;
1919         return MAPI_E_NOT_FOUND;
1920 }
1921
1922 static enum MAPISTATUS message_lookup(TALLOC_CTX *mem_ctx, 
1923                                       uint64_t smid,
1924                                       mapi_object_t *obj_folder, 
1925                                       mapi_object_t *obj_message)
1926 {
1927         enum MAPISTATUS         retval;
1928         mapi_object_t           obj_htable;
1929         struct SPropTagArray    *SPropTagArray;
1930         struct SRowSet          SRowSet;
1931         uint32_t                i;
1932         const uint64_t          *fid;
1933         const uint64_t          *mid;
1934
1935         mapi_object_init(&obj_htable);
1936         retval = GetContentsTable(obj_folder, &obj_htable, 0, NULL);
1937         if (retval != MAPI_E_SUCCESS) return retval;
1938
1939         SPropTagArray = set_SPropTagArray(mem_ctx, 0x2, PR_FID, PR_MID);
1940         retval = SetColumns(&obj_htable, SPropTagArray);
1941         MAPIFreeBuffer(SPropTagArray);
1942         if (retval != MAPI_E_SUCCESS) return retval;
1943
1944         while (((retval = QueryRows(&obj_htable, 0x32, TBL_ADVANCE, &SRowSet)) != MAPI_E_NOT_FOUND) && SRowSet.cRows) {
1945                 for (i = 0; i < SRowSet.cRows; i++) {
1946                         fid = (const uint64_t *)find_SPropValue_data(&SRowSet.aRow[i], PR_FID);
1947                         mid = (const uint64_t *)find_SPropValue_data(&SRowSet.aRow[i], PR_MID);
1948                         if (mid && *mid == smid) {
1949                                 retval = OpenMessage(obj_folder, *fid, *mid, obj_message, ReadWrite);
1950                                 mapi_object_release(&obj_htable);
1951                                 return retval;
1952                         }
1953                 }
1954         }
1955
1956         mapi_object_release(&obj_htable);
1957
1958         errno = MAPI_E_NOT_FOUND;
1959         return MAPI_E_NOT_FOUND;
1960 }
1961
1962 static bool openchangeclient_updateitem(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store,
1963                                         struct oclient *oclient, const char *container_class)
1964 {
1965         enum MAPISTATUS         retval;
1966         mapi_object_t           obj_folder;
1967         mapi_object_t           obj_message;
1968         mapi_id_t               id_tis;
1969         char                    *fid_str;
1970         uint64_t                fid;
1971         uint64_t                mid;
1972         const char              *item = NULL;
1973
1974         item = oclient->update;
1975
1976         if (!item) {
1977                 DEBUG(0, ("Missing ID\n"));
1978                 errno = MAPI_E_INVALID_PARAMETER;
1979                 return false;
1980         }
1981
1982         if (!container_class) {
1983                 DEBUG(0, ("Missing container class\n"));
1984                 errno = MAPI_E_INVALID_PARAMETER;
1985                 return false;
1986         }
1987
1988         fid_str = strsep((char **)&item, "/");
1989         if (!fid_str || !item) {
1990                 DEBUG(0, ("    Invalid ID: %s\n", fid_str ? fid_str : "null"));
1991                 errno = MAPI_E_INVALID_PARAMETER;
1992                 return false;
1993         }
1994
1995         fid = strtoull(fid_str, NULL, 16);
1996         mid = strtoull(item, NULL, 16);
1997
1998         /* Step 1: search the folder from Top Information Store */
1999         mapi_object_init(&obj_folder);
2000         retval = GetDefaultFolder(obj_store, &id_tis, olFolderTopInformationStore);
2001         if (retval != MAPI_E_SUCCESS) return false;
2002
2003         retval = folder_lookup(mem_ctx, fid, obj_store, id_tis, &obj_folder);
2004         if (retval != MAPI_E_SUCCESS) return false;
2005
2006         /* Step 2: search the message */
2007         mapi_object_init(&obj_message);
2008         retval = message_lookup(mem_ctx, mid, &obj_folder, &obj_message);
2009         if (retval != MAPI_E_SUCCESS) return false;
2010
2011         /* Step 3: edit the message */
2012         if (!strcmp(container_class, IPF_APPOINTMENT)) {
2013                 retval = appointment_SetProps(mem_ctx, &obj_folder, &obj_message, oclient);
2014         } else if (!strcmp(container_class, IPF_CONTACT)) {
2015                 retval = contact_SetProps(mem_ctx, &obj_folder, &obj_message, oclient);
2016         } else if (!strcmp(container_class, IPF_TASK)) {
2017                 retval = task_SetProps(mem_ctx, &obj_message, oclient);
2018         } else if (!strcmp(container_class, IPF_STICKYNOTE)) {
2019                 retval = note_SetProps(mem_ctx, &obj_message, oclient);
2020         }
2021
2022         if (retval != MAPI_E_SUCCESS) return false;
2023
2024         /* Step 4: save the message */
2025         retval = SaveChangesMessage(&obj_folder, &obj_message, KeepOpenReadOnly);
2026         if (retval != MAPI_E_SUCCESS) return false;
2027
2028         mapi_object_release(&obj_message);
2029         mapi_object_release(&obj_folder);
2030
2031         return true;
2032 }
2033
2034 /**
2035  * Delete an item given its unique ID
2036  */
2037 static bool openchangeclient_deleteitems(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, 
2038                                          struct oclient *oclient)
2039 {
2040         enum MAPISTATUS         retval;
2041         mapi_object_t           obj_folder;
2042         mapi_object_t           obj_message;
2043         mapi_id_t               id_tis;
2044         char                    *fid_str;
2045         uint64_t                fid;
2046         uint64_t                mid;
2047         const char              *item = NULL;
2048
2049         item = oclient->delete;
2050
2051         if (!item) {
2052                 DEBUG(0, ("Missing ID\n"));
2053                 errno = MAPI_E_INVALID_PARAMETER;
2054                 return false;
2055         }
2056         
2057         fid_str = strsep((char **)&item, "/");
2058         if (!fid_str || !item) {
2059                 DEBUG(0, ("    Invalid ID: %s\n", fid_str ? fid_str : "null"));
2060                 errno = MAPI_E_INVALID_PARAMETER;
2061                 return false;
2062         }
2063
2064         fid = strtoull(fid_str, NULL, 16);
2065         mid = strtoull(item, NULL, 16);
2066
2067         /* Step 1: search the folder from Top Information Store */
2068         mapi_object_init(&obj_folder);
2069         retval = GetDefaultFolder(obj_store, &id_tis, olFolderTopInformationStore);
2070         if (retval != MAPI_E_SUCCESS) return false;
2071
2072         retval = folder_lookup(mem_ctx, fid, obj_store, id_tis, &obj_folder);
2073         if (retval != MAPI_E_SUCCESS) return false;
2074         
2075         /* Step 2: search the message within returned folder */
2076         mapi_object_init(&obj_message);
2077         retval = message_lookup(mem_ctx, mid, &obj_folder, &obj_message);
2078         if (retval != MAPI_E_SUCCESS) return false;
2079
2080         /* Step 3: delete the message */
2081         retval = DeleteMessage(&obj_folder, &mid, 1);
2082         if (retval != MAPI_E_SUCCESS) return false;
2083
2084         mapi_object_release(&obj_message);
2085         mapi_object_release(&obj_folder);
2086
2087         return true;
2088 }
2089
2090
2091 /**
2092  * Dump email
2093  * 
2094  * Assume msg is received in Inbox folder since we only register
2095  * notifications for this folder.
2096  *
2097  */
2098
2099 static enum MAPISTATUS openchangeclient_findmail(mapi_object_t *obj_store, 
2100                                                    mapi_id_t msgid)
2101 {
2102         enum MAPISTATUS                 retval;
2103         TALLOC_CTX                      *mem_ctx;
2104         struct SRowSet                  SRowSet;
2105         struct SPropValue               *lpProp;
2106         struct mapi_SPropValue_array    properties_array;
2107         mapi_id_t                       fid;
2108         const mapi_id_t                 *mid;
2109         mapi_object_t                   obj_inbox;
2110         mapi_object_t                   obj_table;
2111         mapi_object_t                   obj_message;
2112         struct SPropTagArray            *SPropTagArray = NULL;
2113         uint32_t                        count;
2114         uint32_t                        i;
2115         char                            *id;
2116
2117         mem_ctx = talloc_named(NULL, 0, "openchangeclient_findmail");
2118
2119         /* Get Inbox folder */
2120         retval = GetDefaultFolder(obj_store, &fid, olFolderInbox);
2121         MAPI_RETVAL_IF(retval, GetLastError(), mem_ctx);
2122
2123         /* Open Inbox */
2124         mapi_object_init(&obj_inbox);
2125         retval = OpenFolder(obj_store, fid, &obj_inbox);
2126         MAPI_RETVAL_IF(retval, GetLastError(), mem_ctx);
2127
2128         /* Retrieve contents table */
2129         mapi_object_init(&obj_table);
2130         retval = GetContentsTable(&obj_inbox, &obj_table, 0, &count);
2131         MAPI_RETVAL_IF(retval, GetLastError(), mem_ctx);
2132
2133         SPropTagArray = set_SPropTagArray(mem_ctx, 0x2,
2134                                           PR_FID,
2135                                           PR_MID);
2136         retval = SetColumns(&obj_table, SPropTagArray);
2137         MAPIFreeBuffer(SPropTagArray);
2138         MAPI_RETVAL_IF(retval, GetLastError(), mem_ctx);
2139
2140         while ((retval = QueryRows(&obj_table, 0xa, TBL_ADVANCE, &SRowSet)) != MAPI_E_NOT_FOUND && SRowSet.cRows) {
2141                 for (i = 0; i < SRowSet.cRows; i++) {
2142                         lpProp = get_SPropValue_SRowSet(&SRowSet, PR_MID);
2143                         if (lpProp != NULL) {
2144                                 mid = (const uint64_t *)get_SPropValue(lpProp, PR_MID);
2145                                 if (*mid == msgid) {
2146                                         mapi_object_init(&obj_message);
2147                                         retval = OpenMessage(obj_store,
2148                                                              SRowSet.aRow[i].lpProps[0].value.d,
2149                                                              SRowSet.aRow[i].lpProps[1].value.d,
2150                                                              &obj_message, 0);
2151                                         if (GetLastError() == MAPI_E_SUCCESS) {
2152                                                 retval = GetPropsAll(&obj_message, MAPI_UNICODE, &properties_array);
2153                                                 if (retval != MAPI_E_SUCCESS) return retval;
2154                                                 id = talloc_asprintf(mem_ctx, ": %"PRIX64"/%"PRIX64,
2155                                                                      SRowSet.aRow[i].lpProps[0].value.d,
2156                                                                      SRowSet.aRow[i].lpProps[1].value.d);
2157                                                 mapidump_message(&properties_array, id, NULL);
2158                                                 mapi_object_release(&obj_message);
2159                                                 talloc_free(id);
2160
2161                                                 goto end;
2162                                         }
2163                                         mapi_object_release(&obj_message);
2164                                 }
2165                         }
2166                 }
2167         }
2168 end:
2169         mapi_object_release(&obj_table);
2170         mapi_object_release(&obj_inbox);
2171
2172         talloc_free(mem_ctx);
2173         return MAPI_E_SUCCESS;
2174 }
2175
2176
2177 static int callback(uint16_t NotificationType, void *NotificationData, void *private_data)
2178 {
2179         struct NewMailNotification      *newmail;
2180         struct HierarchyTableChange     *htable;
2181         struct ContentsTableChange      *ctable;
2182         struct ContentsTableChange      *stable;
2183
2184         switch(NotificationType) {
2185         case fnevNewMail:
2186         case fnevNewMail|fnevMbit:
2187                 DEBUG(0, ("[+] New mail Received\n"));
2188                 newmail = (struct NewMailNotification *) NotificationData;
2189                 mapidump_newmail(newmail, "\t");
2190                 openchangeclient_findmail((mapi_object_t *)private_data, newmail->MID);
2191                 mapi_errstr("openchangeclient_findmail", GetLastError());
2192                 break;
2193         case fnevObjectCreated:
2194                 DEBUG(0, ("[+] Folder Created\n"));
2195                 break;
2196         case fnevObjectDeleted:
2197                 DEBUG(0, ("[+] Folder Deleted\n"));
2198                 break;
2199         case fnevObjectModified:
2200         case fnevTbit|fnevObjectModified:
2201         case fnevUbit|fnevObjectModified:
2202         case fnevTbit|fnevUbit|fnevObjectModified:
2203                 DEBUG(0, ("[+] Folder Modified\n"));
2204                 break;
2205         case fnevObjectMoved:
2206                 DEBUG(0, ("[+] Folder Moved\n"));
2207                 break;
2208         case fnevObjectCopied:
2209                 DEBUG(0, ("[+] Folder Copied\n"));
2210                 break;
2211         case fnevSearchComplete:
2212                 DEBUG(0, ("[+] Search complete in search folder\n"));
2213                 break;
2214         case fnevTableModified:
2215                 htable = (struct HierarchyTableChange *) NotificationData;
2216                 DEBUG(0, ("[+] Hierarchy Table: "));
2217                 switch (htable->TableEvent) {
2218                 case TABLE_CHANGED:
2219                         DEBUG(0, (" changed\n"));
2220                         break;
2221                 case TABLE_ROW_ADDED:
2222                         DEBUG(0, ("row added\n"));
2223                         break;
2224                 case TABLE_ROW_DELETED:
2225                         DEBUG(0, ("row deleted\n"));
2226                         break;
2227                 case TABLE_ROW_MODIFIED:
2228                         DEBUG(0, ("row modified\n"));
2229                         break;
2230                 case TABLE_RESTRICT_DONE:
2231                         DEBUG(0, ("restriction done\n"));
2232                         break;
2233                 default:
2234                         DEBUG(0, ("\n"));
2235                         break;
2236                 }
2237                 break;
2238         case fnevStatusObjectModified:
2239                 DEBUG(0, ("[+] ICS Notification\n"));
2240                 break;
2241         case fnevMbit|fnevObjectCreated:
2242                 DEBUG(0, ("[+] Message created\n"));
2243                 break;
2244         case fnevMbit|fnevObjectDeleted:
2245                 DEBUG(0, ("[+] Message deleted\n"));
2246         case fnevMbit|fnevObjectModified:
2247                 DEBUG(0, ("[+] Message modified\n"));
2248         case fnevMbit|fnevObjectMoved:
2249                 DEBUG(0, ("[+] Message moved\n"));
2250         case fnevMbit|fnevObjectCopied:
2251                 DEBUG(0, ("[+] Message copied\n"));
2252         case fnevMbit|fnevTableModified:
2253                 ctable = (struct ContentsTableChange *) NotificationData;
2254                 DEBUG(0, ("[+] Contents Table: "));
2255                 switch (ctable->TableEvent) {
2256                 case TABLE_CHANGED:
2257                         DEBUG(0, (" changed\n"));
2258                         break;
2259                 case TABLE_ROW_ADDED:
2260                         DEBUG(0, ("row added\n"));
2261                         break;
2262                 case TABLE_ROW_DELETED:
2263                         DEBUG(0, ("row deleted\n"));
2264                         break;
2265                 case TABLE_ROW_MODIFIED:
2266                         DEBUG(0, ("row modified\n"));
2267                         break;
2268                 case TABLE_RESTRICT_DONE:
2269                         DEBUG(0, ("restriction done\n"));
2270                         break;
2271                 default:
2272                         DEBUG(0, ("\n"));
2273                         break;
2274                 }
2275                 break;
2276         case fnevMbit|fnevSbit|fnevObjectDeleted:
2277                 DEBUG(0, ("[+] A message is no longer part of a search folder\n"));
2278                 break;
2279         case fnevMbit|fnevSbit|fnevObjectModified:
2280                 DEBUG(0, ("[+] A property on a message in a search folder has changed\n"));
2281         case fnevMbit|fnevSbit|fnevTableModified:
2282                 stable = (struct ContentsTableChange *) NotificationData;
2283                 DEBUG(0, ("[+] Search Table: "));
2284                 switch (stable->TableEvent) {
2285                 case TABLE_CHANGED:
2286                         DEBUG(0, (" changed\n"));
2287                         break;
2288                 case TABLE_ROW_ADDED:
2289                         DEBUG(0, ("row added\n"));
2290                         break;
2291                 case TABLE_ROW_DELETED:
2292                         DEBUG(0, ("row deleted\n"));
2293                         break;
2294                 case TABLE_ROW_MODIFIED:
2295                         DEBUG(0, ("row modified\n"));
2296                         break;
2297                 case TABLE_RESTRICT_DONE:
2298                         DEBUG(0, ("restriction done\n"));
2299                         break;
2300                 default:
2301                         DEBUG(0, ("\n"));
2302                         break;
2303                 }
2304                 break;
2305         default:
2306                 printf("[+] Unsupported notification (0x%x)\n", NotificationType);
2307                 break;
2308         }
2309
2310         return 0;
2311 }
2312
2313
2314 static bool openchangeclient_notifications(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
2315 {
2316         enum MAPISTATUS         retval;
2317         mapi_object_t           obj_inbox;
2318         mapi_id_t               fid;
2319         uint32_t                ulConnection;
2320         uint16_t                ulEventMask;
2321         uint32_t                notification = 0;
2322         struct mapi_session     *session;
2323
2324         /* Register notification */
2325         session = mapi_object_get_session(obj_store);
2326         retval = RegisterNotification(session);
2327         if (retval != MAPI_E_SUCCESS) return false;
2328
2329         if (oclient->pf == true) {
2330                 retval = openchangeclient_getpfdir(mem_ctx, obj_store, &obj_inbox, oclient->folder);
2331                 if (retval != MAPI_E_SUCCESS) return retval;
2332         } else {
2333                 /* Retrieve Inbox folder ID */
2334                 retval = GetDefaultFolder(obj_store, &fid, olFolderInbox);
2335                 if (retval != MAPI_E_SUCCESS) return false;
2336
2337                 /* Open Inbox folder */
2338                 mapi_object_init(&obj_inbox);
2339                 retval = OpenFolder(obj_store, fid, &obj_inbox);
2340                 if (retval != MAPI_E_SUCCESS) return false;
2341         }
2342
2343         /* subscribe Inbox to receive newmail notifications */
2344         ulEventMask = fnevNewMail|fnevObjectCreated|fnevObjectDeleted|
2345                 fnevObjectModified|fnevObjectMoved|fnevObjectCopied|
2346                 fnevSearchComplete|fnevTableModified|fnevStatusObjectModified;
2347         retval = Subscribe(obj_store, &ulConnection, ulEventMask, true, (mapi_notify_callback_t)callback,
2348                 (void*) obj_store);
2349         retval = Subscribe(&obj_inbox, &ulConnection, ulEventMask, true, (mapi_notify_callback_t)callback,
2350                 (void*) obj_store);
2351         if (retval != MAPI_E_SUCCESS) return false;
2352
2353         /* wait for notifications: infinite loop */
2354         retval = RegisterAsyncNotification(mapi_object_get_session(obj_store), &notification);
2355         if( retval == MAPI_E_NOT_INITIALIZED ) {
2356                 retval = MonitorNotification(mapi_object_get_session(obj_store), (void *)obj_store, NULL);
2357         }
2358         if (retval != MAPI_E_SUCCESS) return false;
2359
2360         retval = Unsubscribe(mapi_object_get_session(obj_store), ulConnection);
2361         if (retval != MAPI_E_SUCCESS) return false;
2362
2363         mapi_object_release(&obj_inbox);
2364
2365         return true;
2366 }
2367
2368
2369 static bool openchangeclient_mkdir(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
2370 {
2371         enum MAPISTATUS         retval;
2372         mapi_object_t           obj_folder;
2373         mapi_object_t           obj_child;
2374         mapi_object_t           obj_tis;
2375         mapi_id_t               id_inbox;
2376
2377         mapi_object_init(&obj_tis);
2378         mapi_object_init(&obj_folder);
2379         mapi_object_init(&obj_child);
2380
2381         if (oclient->folder) {
2382                 retval = GetDefaultFolder(obj_store, &id_inbox, olFolderTopInformationStore);
2383                 if (retval != MAPI_E_SUCCESS) return false;
2384
2385                 retval = OpenFolder(obj_store, id_inbox, &obj_tis);
2386                 if (retval != MAPI_E_SUCCESS) return false;
2387
2388                 retval = openchangeclient_getdir(mem_ctx, &obj_tis, &obj_folder, oclient->folder);
2389                 if (retval != MAPI_E_SUCCESS) return false;
2390         } else {
2391                 retval = GetDefaultFolder(obj_store, &id_inbox, olFolderInbox);
2392                 if (retval != MAPI_E_SUCCESS) return false;
2393
2394                 retval = OpenFolder(obj_store, id_inbox, &obj_folder);
2395                 if (retval != MAPI_E_SUCCESS) return false;
2396         }
2397
2398         retval = CreateFolder(&obj_folder, FOLDER_GENERIC, oclient->folder_name, 
2399                               oclient->folder_comment, OPEN_IF_EXISTS, &obj_child);
2400         if (retval != MAPI_E_SUCCESS) return false;
2401
2402         mapi_object_release(&obj_child);
2403         mapi_object_release(&obj_folder);
2404         mapi_object_release(&obj_tis);
2405
2406         return true;
2407 }
2408
2409
2410 static bool openchangeclient_rmdir(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
2411 {
2412         enum MAPISTATUS         retval;
2413         mapi_object_t           obj_folder;
2414         mapi_object_t           obj_child;
2415         mapi_object_t           obj_tis;
2416         mapi_id_t               id_inbox;
2417
2418         mapi_object_init(&obj_tis);
2419         mapi_object_init(&obj_folder);
2420         mapi_object_init(&obj_child);
2421
2422         if (oclient->folder) {
2423                 printf("Removing folder within %s\n", oclient->folder);
2424                 retval = GetDefaultFolder(obj_store, &id_inbox, olFolderTopInformationStore);
2425                 if (retval != MAPI_E_SUCCESS) return false;
2426                 
2427                 retval = OpenFolder(obj_store, id_inbox, &obj_tis);
2428                 if (retval != MAPI_E_SUCCESS) return false;
2429
2430                 retval = openchangeclient_getdir(mem_ctx, &obj_tis, &obj_folder, oclient->folder);
2431                 if (retval != MAPI_E_SUCCESS) return false;
2432         } else {
2433                 retval = GetDefaultFolder(obj_store, &id_inbox, olFolderInbox);
2434                 if (retval != MAPI_E_SUCCESS) return false;
2435                 
2436                 retval = OpenFolder(obj_store, id_inbox, &obj_folder);
2437                 if (retval != MAPI_E_SUCCESS) return false;
2438         }
2439         
2440         retval = openchangeclient_getdir(mem_ctx, &obj_folder, &obj_child, oclient->folder_name);
2441         if (retval != MAPI_E_SUCCESS) return false;
2442         
2443         retval = EmptyFolder(&obj_child);
2444         if (retval != MAPI_E_SUCCESS) return false;
2445         
2446         printf("obj_child fid = 0x%"PRIx64"\n", mapi_object_get_id(&obj_child));
2447
2448         retval = DeleteFolder(&obj_folder, mapi_object_get_id(&obj_child),
2449                               DEL_FOLDERS, NULL);
2450         if (retval != MAPI_E_SUCCESS) return false;
2451         
2452         mapi_object_release(&obj_child);
2453         mapi_object_release(&obj_folder);
2454         mapi_object_release(&obj_tis);
2455         
2456         return true;
2457 }
2458
2459 static bool openchangeclient_userlist(TALLOC_CTX *mem_ctx, 
2460                                       struct mapi_session *session)
2461 {
2462         struct SPropTagArray    *SPropTagArray;
2463         struct SRowSet          *SRowSet;
2464         uint32_t                i;
2465         uint32_t                count;
2466         uint8_t                 ulFlags;
2467         uint32_t                rowsFetched = 0;
2468         uint32_t                totalRecs = 0;
2469
2470         GetGALTableCount(session, &totalRecs);
2471         printf("Total Number of entries in GAL: %d\n", totalRecs);
2472
2473         SPropTagArray = set_SPropTagArray(mem_ctx, 0xc,
2474                                           PR_INSTANCE_KEY,
2475                                           PR_ENTRYID,
2476                                           PR_DISPLAY_NAME_UNICODE,
2477                                           PR_EMAIL_ADDRESS_UNICODE,
2478                                           PR_DISPLAY_TYPE,
2479                                           PR_OBJECT_TYPE,
2480                                           PR_ADDRTYPE_UNICODE,
2481                                           PR_OFFICE_TELEPHONE_NUMBER_UNICODE,
2482                                           PR_OFFICE_LOCATION_UNICODE,
2483                                           PR_TITLE_UNICODE,
2484                                           PR_COMPANY_NAME_UNICODE,
2485                                           PR_ACCOUNT_UNICODE);
2486
2487         count = 0x7;
2488         ulFlags = TABLE_START;
2489         do {
2490                 count += 0x2;
2491                 GetGALTable(session, SPropTagArray, &SRowSet, count, ulFlags);
2492                 if ((!SRowSet) || (!(SRowSet->aRow))) {
2493                         return false;
2494                 }
2495                 rowsFetched = SRowSet->cRows;
2496                 if (rowsFetched) {
2497                         for (i = 0; i < rowsFetched; i++) {
2498                                 mapidump_PAB_entry(&SRowSet->aRow[i]);
2499                         }
2500                 }
2501                 ulFlags = TABLE_CUR;
2502                 MAPIFreeBuffer(SRowSet);
2503         } while (rowsFetched == count);
2504         mapi_errstr("GetPABTable", GetLastError());
2505
2506         MAPIFreeBuffer(SPropTagArray);
2507
2508         return true;
2509 }
2510
2511
2512 static bool openchangeclient_ocpf_syntax(struct oclient *oclient)
2513 {
2514         int                     ret;
2515         struct ocpf_file        *element;
2516         uint32_t                context_id;
2517
2518         /* Sanity checks */
2519         if (!oclient->ocpf_files || !oclient->ocpf_files->next) {
2520                 errno = MAPI_E_INVALID_PARAMETER;
2521                 return false;
2522         }
2523
2524         /* Step 1. Initialize OCPF context */
2525         ret = ocpf_init();
2526         if (ret == -1) {
2527                 errno = MAPI_E_CALL_FAILED;
2528                 return false;
2529         }
2530
2531         /* Step2. Parse OCPF files */
2532         for (element = oclient->ocpf_files; element->next; element = element->next) {
2533           ret = ocpf_new_context(element->filename, &context_id, OCPF_FLAGS_READ);
2534                 if (ret == -1) {
2535                         errno = MAPI_E_INVALID_PARAMETER;
2536                         return false;
2537                 }
2538                 ret = ocpf_parse(context_id);
2539                 if (ret == -1) {
2540                         DEBUG(0, ("ocpf_parse failed ...\n"));
2541                         errno = MAPI_E_INVALID_PARAMETER;
2542                         return false;
2543                 }
2544
2545                 /* Dump OCPF contents */
2546                 ocpf_dump(context_id);
2547
2548                 ret = ocpf_del_context(context_id);
2549         }
2550
2551
2552         /* Step4. Release OCPF context */
2553         ret = ocpf_release();
2554         if (ret == -1) {
2555                 errno = MAPI_E_CALL_FAILED;
2556                 return false;
2557         }
2558
2559         return true;
2560 }
2561
2562
2563 static bool openchangeclient_ocpf_sender(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
2564 {
2565         enum MAPISTATUS         retval;
2566         int                     ret;
2567         struct ocpf_file        *element;
2568         mapi_object_t           obj_folder;
2569         mapi_object_t           obj_message;
2570         uint32_t                cValues = 0;
2571         struct SPropValue       *lpProps;
2572         uint32_t                context_id;
2573
2574         /* Sanity Check */
2575         if (!oclient->ocpf_files || !oclient->ocpf_files->next) {
2576                 errno = MAPI_E_INVALID_PARAMETER;
2577                 return false;
2578         }
2579
2580         /* Step1. Initialize OCPF context */
2581         ret = ocpf_init();
2582         if (ret == -1) {
2583                 errno = MAPI_E_CALL_FAILED;
2584                 return false;
2585         }
2586
2587         /* Step2. Parse OCPF files */
2588         for (element = oclient->ocpf_files; element->next; element = element->next) {
2589           ret = ocpf_new_context(element->filename, &context_id, OCPF_FLAGS_READ);
2590                 ret = ocpf_parse(context_id);
2591                 if (ret == -1) {
2592                         errno = MAPI_E_INVALID_PARAMETER;
2593                         return false;
2594                 }
2595         }
2596
2597         /* Step3. Open destination folder using ocpf API */
2598         mapi_object_init(&obj_folder);
2599         retval = ocpf_OpenFolder(context_id, obj_store, &obj_folder);
2600         if (retval != MAPI_E_SUCCESS) return false;
2601
2602         /* Step4. Create the message */
2603         mapi_object_init(&obj_message);
2604         retval = CreateMessage(&obj_folder, &obj_message);
2605         if (retval != MAPI_E_SUCCESS) return false;
2606
2607         /* Step5, Set message recipients */
2608         retval = ocpf_set_Recipients(mem_ctx, context_id, &obj_message);
2609         if (retval != MAPI_E_SUCCESS && GetLastError() != MAPI_E_NOT_FOUND) return false;
2610         errno = MAPI_E_SUCCESS;
2611
2612         /* Step6. Set message properties */
2613         retval = ocpf_set_SPropValue(mem_ctx, context_id, &obj_folder, &obj_message);
2614         if (retval != MAPI_E_SUCCESS) return false;
2615
2616         /* Step7. Set message properties */
2617         lpProps = ocpf_get_SPropValue(context_id, &cValues);
2618
2619         retval = SetProps(&obj_message, 0, lpProps, cValues);
2620         MAPIFreeBuffer(lpProps);
2621         if (retval != MAPI_E_SUCCESS) return false;
2622
2623         /* Step8. Save message */
2624         retval = SaveChangesMessage(&obj_folder, &obj_message, KeepOpenReadOnly);
2625         if (retval != MAPI_E_SUCCESS) return false;
2626
2627         mapi_object_release(&obj_message);
2628         mapi_object_release(&obj_folder);
2629
2630         ocpf_del_context(context_id);
2631
2632         return true;
2633 }
2634
2635
2636 static bool openchangeclient_ocpf_dump(TALLOC_CTX *mem_ctx, mapi_object_t *obj_store, struct oclient *oclient)
2637 {
2638         enum MAPISTATUS                 retval;
2639         int                             ret;
2640         mapi_object_t                   obj_folder;
2641         mapi_object_t                   obj_message;
2642         mapi_id_t                       id_tis;
2643         const char                      *fid_str;
2644         uint64_t                        fid;
2645         uint64_t                        mid;
2646         const char                      *item = NULL;
2647         char                            *filename = NULL;
2648         struct mapi_SPropValue_array    lpProps;
2649         uint32_t                        context_id;
2650
2651
2652         /* retrieve the FID/MID for ocpf_dump parameter */
2653         item = oclient->ocpf_dump;
2654
2655         fid_str = strsep((char **)&item, "/");
2656         if (!fid_str || !item) {
2657                 DEBUG(0, ("    Invalid ID: %s\n", fid_str ? fid_str : "null"));
2658                 errno = MAPI_E_INVALID_PARAMETER;
2659                 return false;
2660         }
2661
2662         fid = strtoull(fid_str, NULL, 16);
2663         mid = strtoull(item, NULL, 16);
2664
2665         /* Step 1. search the folder from Top Information Store */
2666         mapi_object_init(&obj_folder);
2667         retval = GetDefaultFolder(obj_store, &id_tis, olFolderTopInformationStore);
2668         if (retval != MAPI_E_SUCCESS) return false;
2669
2670         retval = folder_lookup(mem_ctx, fid, obj_store, id_tis, &obj_folder);
2671         if (retval != MAPI_E_SUCCESS) return false;
2672
2673         /* Step 2. search the message */
2674         mapi_object_init(&obj_message);
2675         retval = message_lookup(mem_ctx, mid, &obj_folder, &obj_message);
2676         if (retval != MAPI_E_SUCCESS) return false;
2677
2678         /* Step 3. retrieve all message properties */
2679         retval = GetPropsAll(&obj_message, MAPI_UNICODE, &lpProps);
2680
2681         /* Step 4. save the message */
2682         ret = ocpf_init();
2683
2684         filename = talloc_asprintf(mem_ctx, "%"PRIx64".ocpf", mid);
2685         DEBUG(0, ("OCPF output file: %s\n", filename));
2686
2687         ret = ocpf_new_context(filename, &context_id, OCPF_FLAGS_CREATE);
2688         talloc_free(filename);
2689         ret = ocpf_write_init(context_id, fid);
2690
2691         ret = ocpf_write_auto(context_id, &obj_message, &lpProps);
2692         if (ret == OCPF_SUCCESS) {
2693                 ret = ocpf_write_commit(context_id);
2694         } 
2695
2696         ret = ocpf_del_context(context_id);
2697
2698         ret = ocpf_release();
2699
2700         mapi_object_release(&obj_message);
2701         mapi_object_release(&obj_folder);
2702
2703         return true;
2704 }
2705
2706
2707 static bool openchangeclient_freebusy(mapi_object_t *obj_store, struct oclient *oclient)
2708 {
2709         enum MAPISTATUS                 retval;
2710         struct SRow                     aRow;
2711         const char                      *message_name;
2712         uint32_t                        i;
2713         const uint32_t                  *publish_start;
2714         const uint32_t                  *publish_end;
2715         const struct LongArray_r        *busy_months;
2716         const struct BinaryArray_r      *busy_events;
2717         const struct LongArray_r        *tentative_months;
2718         const struct BinaryArray_r      *tentative_events;
2719         const struct LongArray_r        *oof_months;
2720         const struct BinaryArray_r      *oof_events;
2721         uint32_t                        year;
2722         uint32_t                        event_year;
2723
2724         /* Step 1. Retrieve FreeBusy data for the given user */
2725         retval = GetUserFreeBusyData(obj_store, oclient->freebusy, &aRow);
2726         if (retval != MAPI_E_SUCCESS) return false;
2727
2728         /* Step 2. Dump properties */
2729         message_name = (const char *) find_SPropValue_data(&aRow, PR_NORMALIZED_SUBJECT);
2730         publish_start = (const uint32_t *) find_SPropValue_data(&aRow, PR_FREEBUSY_PUBLISH_START);
2731         publish_end = (const uint32_t *) find_SPropValue_data(&aRow, PR_FREEBUSY_PUBLISH_END);
2732         busy_months = (const struct LongArray_r *) find_SPropValue_data(&aRow, PR_SCHDINFO_MONTHS_BUSY);
2733         busy_events = (const struct BinaryArray_r *) find_SPropValue_data(&aRow, PR_SCHDINFO_FREEBUSY_BUSY);
2734         tentative_months = (const struct LongArray_r *) find_SPropValue_data(&aRow, PR_SCHDINFO_MONTHS_TENTATIVE);
2735         tentative_events = (const struct BinaryArray_r *) find_SPropValue_data(&aRow, PR_SCHDINFO_FREEBUSY_TENTATIVE);
2736         oof_months = (const struct LongArray_r *) find_SPropValue_data(&aRow, PR_SCHDINFO_MONTHS_OOF);
2737         oof_events = (const struct BinaryArray_r *) find_SPropValue_data(&aRow, PR_SCHDINFO_FREEBUSY_OOF);
2738
2739         year = GetFreeBusyYear(publish_start);
2740
2741         DEBUG(0, ("FreeBusy (%s):\n", message_name));
2742         mapidump_date_SPropValue(aRow.lpProps[1], "* FreeBusy Last Modification Time", "\t");
2743         mapidump_freebusy_date(*publish_start, "\t* FreeBusy Publishing Start:");
2744         mapidump_freebusy_date(*publish_end, "\t *FreeBusy Publishing End:  ");
2745
2746         if (busy_months && ((*(const uint32_t *) busy_months) != MAPI_E_NOT_FOUND) &&
2747             busy_events && ((*(const uint32_t *) busy_events) != MAPI_E_NOT_FOUND)) {
2748                 DEBUG(0, ("\t* Busy Events:\n"));
2749                 for (i = 0; i < busy_months->cValues; i++) {
2750                         event_year = mapidump_freebusy_year(busy_months->lpl[i], year);
2751                         DEBUG(0, ("\t\t* %s %u:\n", mapidump_freebusy_month(busy_months->lpl[i], event_year), event_year)); 
2752                         mapidump_freebusy_event(&busy_events->lpbin[i], busy_months->lpl[i], event_year, "\t\t\t* ");
2753                 }
2754         }
2755
2756         if (tentative_months && ((*(const uint32_t *) tentative_months) != MAPI_E_NOT_FOUND) &&
2757             tentative_events && ((*(const uint32_t *) tentative_events) != MAPI_E_NOT_FOUND)) {
2758                 DEBUG(0, ("\t* Tentative Events:\n"));
2759                 for (i = 0; i < tentative_months->cValues; i++) {
2760                         event_year = mapidump_freebusy_year(tentative_months->lpl[i], year);
2761                         DEBUG(0, ("\t\t* %s %u:\n", mapidump_freebusy_month(tentative_months->lpl[i], event_year), event_year));
2762                         mapidump_freebusy_event(&tentative_events->lpbin[i], tentative_months->lpl[i], event_year, "\t\t\t* ");
2763                 }
2764         }
2765
2766         if (oof_months && ((*(const uint32_t *) oof_months) != MAPI_E_NOT_FOUND) &&
2767             oof_events && ((*(const uint32_t *) oof_events) != MAPI_E_NOT_FOUND)) {
2768                 DEBUG(0, ("\t* Out Of Office Events:\n"));
2769                 for (i = 0; i < oof_months->cValues; i++) {
2770                         event_year = mapidump_freebusy_year(oof_months->lpl[i], year);
2771                         DEBUG(0, ("\t\t* %s %u:\n", mapidump_freebusy_month(oof_months->lpl[i], event_year), event_year));
2772                         mapidump_freebusy_event(&oof_events->lpbin[i], oof_months->lpl[i], event_year, "\t\t\t* ");
2773                 }
2774         }
2775
2776         MAPIFreeBuffer(aRow.lpProps);
2777
2778         return true;
2779 }
2780
2781
2782 static void list_argument(const char *label, struct oc_element *oc_items)
2783 {
2784         uint32_t        i;
2785
2786         printf("Use one of the following %s values:\n", label);
2787         for (i = 0; oc_items[i].status; i++) {
2788                 printf("%s\n", oc_items[i].status);
2789         }
2790 }
2791
2792
2793 static uint32_t oc_get_argument(const char *name, struct oc_element *oc_items, const char *label)
2794 {
2795         uint32_t        i;
2796
2797         for (i = 0; oc_items[i].status; i++) {
2798                 if (!strncasecmp(oc_items[i].status, name, strlen(oc_items[i].status))) {
2799                         return oc_items[i].index;
2800                 }
2801         }
2802         list_argument(label, oc_items);
2803         exit (1);
2804 }
2805
2806
2807 int main(int argc, const char *argv[])
2808 {
2809         TALLOC_CTX              *mem_ctx;
2810         enum MAPISTATUS         retval;
2811         struct mapi_session     *session = NULL;
2812         mapi_object_t           obj_store;
2813         struct oclient          oclient;
2814         poptContext             pc;
2815         int                     opt;
2816         bool                    opt_sendmail = false;
2817         bool                    opt_sendappointment = false;
2818         bool                    opt_sendcontact = false;
2819         bool                    opt_sendtask = false;
2820         bool                    opt_sendnote = false;
2821         bool                    opt_fetchmail = false;
2822         bool                    opt_deletemail = false;
2823         bool                    opt_mailbox = false;
2824         bool                    opt_dumpdata = false;
2825         bool                    opt_notifications = false;
2826         bool                    opt_mkdir = false;
2827         bool                    opt_rmdir = false;
2828         bool                    opt_userlist = false;
2829         bool                    opt_ocpf_syntax = false;
2830         bool                    opt_ocpf_sender = false;
2831         const char              *opt_profdb = NULL;
2832         char                    *opt_profname = NULL;
2833         const char              *opt_username = NULL;
2834         const char              *opt_password = NULL;
2835         const char              *opt_attachments = NULL;
2836         const char              *opt_fetchitems = NULL;
2837         const char              *opt_html_file = NULL;
2838         const char              *opt_mapi_to = NULL;
2839         const char              *opt_mapi_cc = NULL;
2840         const char              *opt_mapi_bcc = NULL;
2841         const char              *opt_debug = NULL;
2842
2843         enum {OPT_PROFILE_DB=1000, OPT_PROFILE, OPT_SENDMAIL, OPT_PASSWORD, OPT_SENDAPPOINTMENT, 
2844               OPT_SENDCONTACT, OPT_SENDTASK, OPT_FETCHMAIL, OPT_STOREMAIL,  OPT_DELETEMAIL, 
2845               OPT_ATTACH, OPT_HTML_INLINE, OPT_HTML_FILE, OPT_MAPI_TO, OPT_MAPI_CC, 
2846               OPT_MAPI_BCC, OPT_MAPI_SUBJECT, OPT_MAPI_BODY, OPT_MAILBOX, 
2847               OPT_FETCHITEMS, OPT_MAPI_LOCATION, OPT_MAPI_STARTDATE, OPT_MAPI_ENDDATE, 
2848               OPT_MAPI_BUSYSTATUS, OPT_NOTIFICATIONS, OPT_DEBUG, OPT_DUMPDATA, 
2849               OPT_MAPI_EMAIL, OPT_MAPI_FULLNAME, OPT_MAPI_CARDNAME,
2850               OPT_MAPI_TASKSTATUS, OPT_MAPI_IMPORTANCE, OPT_MAPI_LABEL, OPT_PF, 
2851               OPT_FOLDER, OPT_MAPI_COLOR, OPT_SENDNOTE, OPT_MKDIR, OPT_RMDIR,
2852               OPT_FOLDER_NAME, OPT_FOLDER_COMMENT, OPT_USERLIST, OPT_MAPI_PRIVATE,
2853               OPT_UPDATE, OPT_DELETEITEMS, OPT_OCPF_FILE, OPT_OCPF_SYNTAX,
2854               OPT_OCPF_SENDER, OPT_OCPF_DUMP, OPT_FREEBUSY, OPT_FORCE, OPT_FETCHSUMMARY,
2855               OPT_USERNAME };
2856
2857         struct poptOption long_options[] = {
2858                 POPT_AUTOHELP
2859                 {"database", 'f', POPT_ARG_STRING, NULL, OPT_PROFILE_DB, "set the profile database path", NULL },
2860                 {"pf", 0, POPT_ARG_NONE, NULL, OPT_PF, "access public folders instead of mailbox", NULL },
2861                 {"profile", 'p', POPT_ARG_STRING, NULL, OPT_PROFILE, "set the profile name", NULL },
2862                 {"password", 'P', POPT_ARG_STRING, NULL, OPT_PASSWORD, "set the profile password", NULL },
2863                 {"username", 0, POPT_ARG_STRING, NULL, OPT_USERNAME, "set the username of the mailbox to use", NULL },
2864                 {"sendmail", 'S', POPT_ARG_NONE, NULL, OPT_SENDMAIL, "send a mail", NULL },
2865                 {"sendappointment", 0, POPT_ARG_NONE, NULL, OPT_SENDAPPOINTMENT, "send an appointment", NULL },
2866                 {"sendcontact", 0, POPT_ARG_NONE, NULL, OPT_SENDCONTACT, "send a contact", NULL },
2867                 {"sendtask", 0, POPT_ARG_NONE, NULL, OPT_SENDTASK, "send a task", NULL },
2868                 {"sendnote", 0, POPT_ARG_NONE, NULL, OPT_SENDNOTE, "send a note", NULL },
2869                 {"fetchmail", 'F', POPT_ARG_NONE, NULL, OPT_FETCHMAIL, "fetch user INBOX mails", NULL },
2870                 {"fetchsummary", 0, POPT_ARG_NONE, NULL, OPT_FETCHSUMMARY, "fetch message summaries only", NULL },
2871                 {"storemail", 'G', POPT_ARG_STRING, NULL, OPT_STOREMAIL, "retrieve a mail on the filesystem", NULL },
2872                 {"fetch-items", 'i', POPT_ARG_STRING, NULL, OPT_FETCHITEMS, "fetch specified user INBOX items", NULL },
2873                 {"freebusy", 0, POPT_ARG_STRING, NULL, OPT_FREEBUSY, "display free / busy information for the specified user", NULL },
2874                 {"force", 0, POPT_ARG_NONE, NULL, OPT_FORCE, "force openchangeclient behavior in some circumstances", NULL },
2875                 {"delete", 0, POPT_ARG_STRING, NULL, OPT_DELETEITEMS, "delete a message given its unique ID", NULL },
2876                 {"update", 'u', POPT_ARG_STRING, NULL, OPT_UPDATE, "update the specified item", NULL },
2877                 {"mailbox", 'm', POPT_ARG_NONE, NULL, OPT_MAILBOX, "list mailbox folder summary", NULL },
2878                 {"deletemail", 'D', POPT_ARG_NONE, NULL, OPT_DELETEMAIL, "delete a mail from user INBOX", NULL },
2879                 {"attachments", 'A', POPT_ARG_STRING, NULL, OPT_ATTACH, "send a list of attachments", NULL },
2880                 {"html-inline", 'I', POPT_ARG_STRING, NULL, OPT_HTML_INLINE, "send PR_HTML content", NULL },
2881                 {"html-file", 'W', POPT_ARG_STRING, NULL, OPT_HTML_FILE, "use HTML file as content", NULL },
2882                 {"to", 't', POPT_ARG_STRING, NULL, OPT_MAPI_TO, "set the To recipients", NULL },
2883                 {"cc", 'c', POPT_ARG_STRING, NULL, OPT_MAPI_CC, "set the Cc recipients", NULL },
2884                 {"bcc", 'b', POPT_ARG_STRING, NULL, OPT_MAPI_BCC, "set the Bcc recipients", NULL },
2885                 {"subject", 's', POPT_ARG_STRING, NULL, OPT_MAPI_SUBJECT, "set the mail subject", NULL },
2886                 {"body", 'B', POPT_ARG_STRING, NULL, OPT_MAPI_BODY, "set the mail body", NULL },
2887                 {"location", 0, POPT_ARG_STRING, NULL, OPT_MAPI_LOCATION, "set the item location", NULL },
2888                 {"label", 0, POPT_ARG_STRING, NULL, OPT_MAPI_LABEL, "set the event label", NULL },
2889                 {"dtstart", 0, POPT_ARG_STRING, NULL, OPT_MAPI_STARTDATE, "set the event start date", NULL },
2890                 {"dtend", 0, POPT_ARG_STRING, NULL, OPT_MAPI_ENDDATE, "set the event end date", NULL },
2891                 {"busystatus", 0, POPT_ARG_STRING, NULL, OPT_MAPI_BUSYSTATUS, "set the item busy status", NULL },
2892                 {"taskstatus", 0, POPT_ARG_STRING, NULL, OPT_MAPI_TASKSTATUS, "set the task status", NULL },
2893                 {"importance", 0, POPT_ARG_STRING, NULL, OPT_MAPI_IMPORTANCE, "Set the item importance", NULL },
2894                 {"email", 0, POPT_ARG_STRING, NULL, OPT_MAPI_EMAIL, "set the email address", NULL },
2895                 {"fullname", 0, POPT_ARG_STRING, NULL, OPT_MAPI_FULLNAME, "set the full name", NULL },
2896                 {"cardname", 0, POPT_ARG_STRING, NULL, OPT_MAPI_CARDNAME, "set a contact card name", NULL },
2897                 {"color", 0, POPT_ARG_STRING, NULL, OPT_MAPI_COLOR, "set the note color", NULL },
2898                 {"notifications", 0, POPT_ARG_NONE, NULL, OPT_NOTIFICATIONS, "monitor INBOX newmail notifications", NULL },
2899                 {"folder", 0, POPT_ARG_STRING, NULL, OPT_FOLDER, "set the folder to use instead of inbox", NULL },
2900                 {"mkdir", 0, POPT_ARG_NONE, NULL, OPT_MKDIR, "create a folder", NULL },
2901                 {"rmdir", 0, POPT_ARG_NONE, NULL, OPT_RMDIR, "delete a folder", NULL },
2902                 {"userlist", 0, POPT_ARG_NONE, NULL, OPT_USERLIST, "list Address Book entries", NULL },
2903                 {"folder-name", 0, POPT_ARG_STRING, NULL, OPT_FOLDER_NAME, "set the folder name", NULL },
2904                 {"folder-comment", 0, POPT_ARG_STRING, NULL, OPT_FOLDER_COMMENT, "set the folder comment", NULL },
2905                 {"debuglevel", 'd', POPT_ARG_STRING, NULL, OPT_DEBUG, "set Debug Level", NULL },
2906                 {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMPDATA, "dump the hex data", NULL },
2907                 {"private", 0, POPT_ARG_NONE, NULL, OPT_MAPI_PRIVATE, "set the private flag on messages", NULL },
2908                 {"ocpf-file", 0, POPT_ARG_STRING, NULL, OPT_OCPF_FILE, "set OCPF file", NULL },
2909                 {"ocpf-dump", 0, POPT_ARG_STRING, NULL, OPT_OCPF_DUMP, "dump message into OCPF file", NULL },
2910                 {"ocpf-syntax", 0, POPT_ARG_NONE, NULL, OPT_OCPF_SYNTAX, "check OCPF files syntax", NULL },
2911                 {"ocpf-sender", 0, POPT_ARG_NONE, NULL, OPT_OCPF_SENDER, "send message using OCPF files contents", NULL },
2912                 POPT_OPENCHANGE_VERSION
2913                 {NULL, 0, 0, NULL, 0, NULL, NULL}
2914         };
2915
2916         mem_ctx = talloc_named(NULL, 0, "openchangeclient");
2917
2918         init_oclient(&oclient);
2919
2920         pc = poptGetContext("openchangeclient", argc, argv, long_options, 0);
2921
2922         while ((opt = poptGetNextOpt(pc)) != -1) {
2923                 switch (opt) {
2924                 case OPT_PF:
2925                         oclient.pf = true;
2926                         break;
2927                 case OPT_FOLDER:
2928                         oclient.folder = poptGetOptArg(pc);
2929                         break;
2930                 case OPT_DEBUG:
2931                         opt_debug = poptGetOptArg(pc);
2932                         break;
2933                 case OPT_DUMPDATA:
2934                         opt_dumpdata = true;
2935                         break;
2936                 case OPT_USERLIST:
2937                         opt_userlist = true;
2938                         break;
2939                 case OPT_MKDIR:
2940                         opt_mkdir = true;
2941                         break;
2942                 case OPT_RMDIR:
2943                         opt_rmdir = true;
2944                         break;
2945                 case OPT_FOLDER_NAME:
2946                         oclient.folder_name = poptGetOptArg(pc);
2947                         break;
2948                 case OPT_FOLDER_COMMENT:
2949                         oclient.folder_comment = poptGetOptArg(pc);
2950                         break;
2951                 case OPT_NOTIFICATIONS:
2952                         opt_notifications = true;
2953                         break;
2954                 case OPT_PROFILE_DB:
2955                         opt_profdb = poptGetOptArg(pc);
2956                         break;
2957                 case OPT_PROFILE:
2958                         opt_profname = talloc_strdup(mem_ctx, poptGetOptArg(pc));
2959                         break;
2960                 case OPT_PASSWORD:
2961                         opt_password = poptGetOptArg(pc);
2962                         break;
2963                 case OPT_USERNAME:
2964                         opt_username = talloc_strdup(mem_ctx, poptGetOptArg(pc));
2965                         break;
2966                 case OPT_MAILBOX:
2967                         opt_mailbox = true;
2968                         break;
2969                 case OPT_FETCHITEMS:
2970                         opt_fetchitems = poptGetOptArg(pc);
2971                         break;
2972                 case OPT_FETCHSUMMARY:
2973                         oclient.summary = true;
2974                         break;
2975                 case OPT_DELETEITEMS:
2976                         oclient.delete = poptGetOptArg(pc);
2977                         break;
2978                 case OPT_FREEBUSY:
2979                         oclient.freebusy = poptGetOptArg(pc);
2980                         break;
2981                 case OPT_UPDATE:
2982                         oclient.update = poptGetOptArg(pc);
2983                         break;
2984                 case OPT_SENDMAIL:
2985                         opt_sendmail = true;
2986                         break;
2987                 case OPT_SENDAPPOINTMENT:
2988                         opt_sendappointment = true;
2989                         break;
2990                 case OPT_SENDCONTACT:
2991                         opt_sendcontact = true;
2992                         break;
2993                 case OPT_SENDTASK:
2994                         opt_sendtask = true;
2995                         break;
2996                 case OPT_SENDNOTE:
2997                         opt_sendnote = true;
2998                         break;
2999                 case OPT_FETCHMAIL:
3000                         opt_fetchmail = true;
3001                         break;
3002                 case OPT_STOREMAIL:
3003                         oclient.store_folder = poptGetOptArg(pc);
3004                         break;
3005                 case OPT_DELETEMAIL:
3006                         opt_deletemail = true;
3007                         break;
3008                 case OPT_ATTACH:
3009                         opt_attachments = poptGetOptArg(pc);
3010                         break;
3011                 case OPT_HTML_INLINE:
3012                         oclient.pr_html_inline = poptGetOptArg(pc);
3013                         break;
3014                 case OPT_HTML_FILE:
3015                         opt_html_file = poptGetOptArg(pc);
3016                         break;
3017                 case OPT_MAPI_TO:
3018                         opt_mapi_to = poptGetOptArg(pc);
3019                         break;
3020                 case OPT_MAPI_CC:
3021                         opt_mapi_cc = poptGetOptArg(pc);
3022                         break;
3023                 case OPT_MAPI_BCC:
3024                         opt_mapi_bcc = poptGetOptArg(pc);
3025                         break;
3026                 case OPT_MAPI_SUBJECT:
3027                         oclient.subject = poptGetOptArg(pc);
3028                         break;
3029                 case OPT_MAPI_BODY:
3030                         oclient.pr_body = poptGetOptArg(pc);
3031                         break;
3032                 case OPT_MAPI_LOCATION:
3033                         oclient.location = poptGetOptArg(pc);
3034                         break;
3035                 case OPT_MAPI_STARTDATE:
3036                         oclient.dtstart = poptGetOptArg(pc);
3037                         break;
3038                 case OPT_MAPI_ENDDATE:
3039                         oclient.dtend = poptGetOptArg(pc);
3040                         break;
3041                 case OPT_MAPI_BUSYSTATUS:
3042                         oclient.busystatus = oc_get_argument(poptGetOptArg(pc),
3043                                                              oc_busystatus,
3044                                                              "busystatus");
3045                         break;
3046                 case OPT_MAPI_LABEL:
3047                         oclient.label = oc_get_argument(poptGetOptArg(pc),
3048                                                         oc_label,
3049                                                         "label");
3050                         break;
3051                 case OPT_MAPI_IMPORTANCE:
3052                         oclient.importance = oc_get_argument(poptGetOptArg(pc), 
3053                                                              oc_importance, 
3054                                                              "importance");
3055                         break;
3056                 case OPT_MAPI_TASKSTATUS:
3057                         oclient.taskstatus = oc_get_argument(poptGetOptArg(pc),
3058                                                              oc_taskstatus,
3059                                                              "taskstatus");
3060                         break;
3061                 case OPT_MAPI_COLOR:
3062                         oclient.color = oc_get_argument(poptGetOptArg(pc),
3063                                                         oc_color,
3064                                                         "color");
3065                         break;
3066                 case OPT_MAPI_EMAIL:
3067                         oclient.email = poptGetOptArg(pc);
3068                         break;
3069                 case OPT_MAPI_FULLNAME:
3070                         oclient.full_name = poptGetOptArg(pc);
3071                         break;
3072                 case OPT_MAPI_CARDNAME:
3073                         oclient.card_name = poptGetOptArg(pc);
3074                         break;
3075                 case OPT_MAPI_PRIVATE:
3076                         oclient.private = true;
3077                         break;
3078                 case OPT_OCPF_FILE:
3079                 {
3080                         struct ocpf_file        *element;
3081                         
3082                         if (!oclient.ocpf_files) {
3083                                 oclient.ocpf_files = talloc_zero(mem_ctx, struct ocpf_file);
3084                         }
3085                         
3086                         element = talloc_zero(mem_ctx, struct ocpf_file);
3087                         element->filename = talloc_strdup(mem_ctx, poptGetOptArg(pc));
3088                         DLIST_ADD(oclient.ocpf_files, element);
3089                         break;
3090                 }
3091                 case OPT_OCPF_SYNTAX:
3092                         opt_ocpf_syntax = true;
3093                         break;
3094                 case OPT_OCPF_SENDER:
3095                         opt_ocpf_sender = true;
3096                         break;
3097                 case OPT_OCPF_DUMP:
3098                         oclient.ocpf_dump = poptGetOptArg(pc);
3099                         break;
3100                 case OPT_FORCE:
3101                         oclient.force = true;
3102                         break;
3103                 }
3104         }
3105
3106         /* Sanity check on options */
3107
3108         if (!opt_profdb) {
3109                 opt_profdb = talloc_asprintf(mem_ctx, DEFAULT_PROFDB, getenv("HOME"));
3110         }
3111
3112         if (opt_sendmail && !opt_mapi_to && !opt_mapi_cc && !opt_mapi_bcc) {
3113                 printf("You need to specify at least one recipient\n");
3114                 exit (1);
3115         }
3116
3117         if (opt_sendmail && (!oclient.pr_body && !oclient.pr_html_inline && !opt_html_file)) {
3118                 printf("No body specified (body, html-inline or html-file)\n");
3119                 exit (1);
3120         }
3121
3122         if ((opt_sendmail && oclient.pf == true && !oclient.folder) ||
3123             (oclient.pf == true && !oclient.folder && !opt_mailbox && !oclient.freebusy)) {
3124                 printf("--folder option is mandatory\n");
3125                 exit (1);
3126         }
3127
3128         if (opt_html_file && oclient.pr_body) {
3129                 printf("PR_BODY and PR_HTML can't be set at the same time\n");
3130                 exit (1);
3131         }
3132
3133         if (oclient.pr_body && oclient.pr_html_inline) {
3134                 printf("Inline HTML and PR_BODY content can't be set simulteanously\n");
3135                 exit (1);
3136         }
3137
3138         if (opt_html_file && oclient.pr_html_inline) {
3139                 printf("PR_HTML from file and stdin can't be specified at the same time\n");
3140                 exit (1);
3141         }
3142         
3143         if (opt_html_file) {
3144                 oclient_read_file(mem_ctx, opt_html_file, &oclient, PR_HTML);
3145         }
3146
3147         if (opt_attachments) {
3148                 if (oclient_parse_attachments(mem_ctx, opt_attachments, &oclient) == false) {
3149                         printf("Unable to parse one of the specified attachments\n");
3150                         exit (1);
3151                 }
3152         }
3153
3154         if (opt_mkdir && !oclient.folder_name) {
3155                 printf("mkdir requires --folder-name to be defined\n");
3156                 exit (1);
3157         }
3158
3159         /* One of the rare options which doesn't require MAPI to get
3160          *   initialized 
3161          */
3162         if (opt_ocpf_syntax) {
3163                 bool ret = openchangeclient_ocpf_syntax(&oclient);
3164                 mapi_errstr("OCPF Syntax", GetLastError());
3165                 if (ret != true) {
3166                         exit(1);
3167                 }
3168                 exit (0);
3169         }
3170         
3171         /**
3172          * Initialize MAPI subsystem
3173          */
3174
3175         retval = MAPIInitialize(&oclient.mapi_ctx, opt_profdb);
3176         if (retval != MAPI_E_SUCCESS) {
3177                 mapi_errstr("MAPIInitialize", GetLastError());
3178                 exit (1);
3179         }
3180
3181         /* debug options */
3182         SetMAPIDumpData(oclient.mapi_ctx, opt_dumpdata);
3183
3184         if (opt_debug) {
3185                 SetMAPIDebugLevel(oclient.mapi_ctx, atoi(opt_debug));
3186         }
3187         
3188         /* If no profile is specified try to load the default one from
3189          * the database 
3190          */
3191
3192         if (!opt_profname) {
3193                 retval = GetDefaultProfile(oclient.mapi_ctx, &opt_profname);
3194                 if (retval != MAPI_E_SUCCESS) {
3195                         mapi_errstr("GetDefaultProfile", GetLastError());
3196                         exit (1);
3197                 }
3198         }
3199
3200         retval = MapiLogonEx(oclient.mapi_ctx, &session, opt_profname, opt_password);
3201         talloc_free(opt_profname);
3202         if (retval != MAPI_E_SUCCESS) {
3203                 mapi_errstr("MapiLogonEx", GetLastError());
3204                 exit (1);
3205         }
3206
3207         if (opt_userlist) {
3208                 if (false == openchangeclient_userlist(mem_ctx, session)) {
3209                         exit(1);
3210                 } else {
3211                         exit(0);
3212                 }
3213         }
3214
3215         /**
3216          * Open Default Message Store
3217          */
3218
3219         mapi_object_init(&obj_store);
3220         if (oclient.pf == true) {
3221                 retval = OpenPublicFolder(session, &obj_store);
3222                 if (retval != MAPI_E_SUCCESS) {
3223                         mapi_errstr("OpenPublicFolder", GetLastError());
3224                         exit (1);
3225                 }
3226         } else if (opt_username) {
3227                 retval = OpenUserMailbox(session, opt_username, &obj_store);
3228                 if (retval != MAPI_E_SUCCESS) {
3229                         mapi_errstr("OpenUserMailbox", GetLastError());
3230                         exit (1);
3231                 }
3232         } else {
3233                 retval = OpenMsgStore(session, &obj_store);
3234                 if (retval != MAPI_E_SUCCESS) {
3235                         mapi_errstr("OpenMsgStore", GetLastError());
3236                         exit (1);
3237                 }
3238         }
3239
3240         /**
3241          * OCPF sending command
3242          */
3243         if (opt_ocpf_sender) {
3244                 bool ret = openchangeclient_ocpf_sender(mem_ctx, &obj_store, &oclient);
3245                 mapi_errstr("OCPF Sender", GetLastError());
3246                 if (ret != true) {
3247                         goto end;
3248                 }
3249         }
3250
3251         if (oclient.ocpf_dump) {
3252                 bool ret = openchangeclient_ocpf_dump(mem_ctx, &obj_store, &oclient);
3253                 mapi_errstr("OCPF Dump", GetLastError());
3254                 if (ret != true) {
3255                         goto end;
3256                 }
3257         }
3258
3259         if (opt_fetchitems) {
3260                 bool ret = openchangeclient_fetchitems(mem_ctx, &obj_store, opt_fetchitems, &oclient);
3261                 mapi_errstr("fetchitems", GetLastError());
3262                 if (ret != true) {
3263                         goto end;
3264                 }
3265         }
3266
3267         if (oclient.delete) {
3268                 bool ret = openchangeclient_deleteitems(mem_ctx, &obj_store, &oclient);
3269                 mapi_errstr("deleteitems", GetLastError());
3270                 if (ret != true) {
3271                         goto end;
3272                 }
3273         }
3274
3275         if (opt_mailbox) {
3276                 if (oclient.pf == true) {
3277                         bool ret = openchangeclient_pf(mem_ctx, &obj_store);
3278                         mapi_errstr("public folder", GetLastError());
3279                         if (ret != true) {
3280                                 goto end;
3281                         }
3282                 } else {
3283                         bool ret = openchangeclient_mailbox(mem_ctx, &obj_store);
3284                         mapi_errstr("mailbox", GetLastError());
3285                         if (ret != true) {
3286                                 goto end;
3287                         }
3288                 }
3289         }
3290
3291         /* MAPI email operations */
3292         if (opt_sendmail) {
3293                 /* recipients management */
3294                 oclient.mapi_to = get_cmdline_recipients(mem_ctx, opt_mapi_to);
3295                 oclient.mapi_cc = get_cmdline_recipients(mem_ctx, opt_mapi_cc);
3296                 oclient.mapi_bcc = get_cmdline_recipients(mem_ctx, opt_mapi_bcc);
3297
3298                 retval = openchangeclient_sendmail(mem_ctx, &obj_store, &oclient);
3299                 mapi_errstr("sendmail", GetLastError());
3300                 if (retval != true) {
3301                         goto end;
3302                 }
3303         }
3304
3305         if (opt_fetchmail) {
3306                 retval = openchangeclient_fetchmail(&obj_store, &oclient);
3307                 mapi_errstr("fetchmail", GetLastError());
3308                 if (retval != true) {
3309                         goto end;
3310                 }
3311         }
3312
3313         if (opt_deletemail) {
3314                 bool ret = openchangeclient_deletemail(mem_ctx, &obj_store, &oclient);
3315                 mapi_errstr("deletemail", GetLastError());
3316                 if (ret != true) {
3317                         goto end;
3318                 }
3319         }
3320
3321         /* MAPI calendar operations */
3322         if (opt_sendappointment) {
3323                 bool ret;
3324                 if (!oclient.dtstart && !oclient.update) {
3325                         printf("You need to specify a start date (e.g: 2007-06-01 22:30:00)\n");
3326                         goto end;
3327                 }
3328                 
3329                 if (!oclient.dtend && !oclient.update) {
3330                         printf("Setting default end date\n");
3331                         oclient.dtend = oclient.dtstart;
3332                 }
3333
3334                 if (!oclient.update) {
3335                         ret = openchangeclient_sendappointment(mem_ctx, &obj_store, &oclient);
3336                         mapi_errstr("sendappointment", GetLastError());
3337                 } else {
3338                         ret = openchangeclient_updateitem(mem_ctx, &obj_store, &oclient, IPF_APPOINTMENT);
3339                         mapi_errstr("update appointment", GetLastError());
3340                 }
3341                 if (ret != true) {
3342                         goto end;
3343                 }
3344         }
3345
3346         if (oclient.freebusy) {
3347                 bool ret = openchangeclient_freebusy(&obj_store, &oclient);
3348                 mapi_errstr("freebusy", GetLastError());
3349
3350                 if (ret != true) {
3351                         goto end;
3352                 }
3353         }
3354
3355         /* MAPI contact operations */
3356         if (opt_sendcontact) {
3357                 bool ret;
3358                 if (!oclient.update) {
3359                         ret = openchangeclient_sendcontact(mem_ctx, &obj_store, &oclient);
3360                         mapi_errstr("sendcontact", GetLastError());
3361                 } else {
3362                         ret = openchangeclient_updateitem(mem_ctx, &obj_store, &oclient, IPF_CONTACT);
3363                         mapi_errstr("update contact", GetLastError());
3364                 }
3365                 if (ret != true) {
3366                         goto end;
3367                 }
3368         }
3369
3370         /* MAPI task operations */
3371         if (opt_sendtask) {
3372                 bool ret;
3373                 if (!oclient.dtstart && !oclient.update) {
3374                         printf("You need to specify a start date (e.g: 2007-06-01 22:30:00)\n");
3375                         goto end;
3376                 }
3377                 
3378                 if (!oclient.dtend && !oclient.update) {
3379                         printf("Setting default end date\n");
3380                         oclient.dtend = oclient.dtstart;
3381                 }
3382
3383                 if (!oclient.update) {
3384                         ret = openchangeclient_sendtask(mem_ctx, &obj_store, &oclient);
3385                         mapi_errstr("sendtask", GetLastError());
3386                 } else {
3387                         ret = openchangeclient_updateitem(mem_ctx, &obj_store, &oclient, IPF_TASK);
3388                         mapi_errstr("update task", GetLastError());
3389                 }
3390                 if (ret != true) {
3391                         goto end;
3392                 }
3393         }
3394
3395         /* MAPI note operations */
3396         if (opt_sendnote) {
3397                 bool ret;
3398                 if (!oclient.update) {
3399                         ret = openchangeclient_sendnote(mem_ctx, &obj_store, &oclient);
3400                         mapi_errstr("sendnote", GetLastError());
3401                 } else {
3402                         ret = openchangeclient_updateitem(mem_ctx, &obj_store, &oclient, IPF_STICKYNOTE);
3403                         mapi_errstr("update note", GetLastError());
3404                 }
3405                 if (ret != true) {
3406                         goto end;
3407                 }
3408         }
3409         
3410         /* Monitor newmail notifications */
3411         if (opt_notifications) {
3412                 openchangeclient_notifications(mem_ctx, &obj_store, &oclient);
3413                 mapi_errstr("notifications", GetLastError());
3414                 if (retval != true) {
3415                         goto end;
3416                 }
3417         }
3418
3419         /* Folder operations */
3420         if (opt_mkdir) {
3421                 openchangeclient_mkdir(mem_ctx, &obj_store, &oclient);
3422                 mapi_errstr("mkdir", GetLastError());
3423                 if (retval != true) {
3424                         goto end;
3425                 }
3426         }
3427
3428         if (opt_rmdir) {
3429                 openchangeclient_rmdir(mem_ctx, &obj_store, &oclient);
3430                 mapi_errstr("rmdir", GetLastError());
3431                 if (retval != true) {
3432                         goto end;
3433                 }
3434         }
3435
3436         /* Uninitialize MAPI subsystem */
3437 end:
3438
3439         poptFreeContext(pc);
3440
3441         mapi_object_release(&obj_store);
3442
3443         MAPIUninitialize(oclient.mapi_ctx);
3444
3445         talloc_free(mem_ctx);
3446
3447         return 0;
3448 }