Merge trunk changes (from r2196 up to 2259) into branch
[jelmer/openchange.git] / libmapi / mapidump.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2008.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "libmapi/libmapi.h"
21 #include "libmapi/libmapi_private.h"
22 #include "libmapi/mapidump.h"
23 #include <time.h>
24
25 #ifdef ENABLE_ASSERTS
26 #include <assert.h>
27 #define OC_ASSERT(x) assert(x)
28 #else
29 #define OC_ASSERT(x)
30 #endif
31
32 /**
33    \file mapidump.c
34
35    \brief Functions for displaying various data structures, mainly for debugging
36  */
37
38 /**
39   Output one property tag and value
40
41   \param lpProp the property to print
42   \param sep a separator / spacer to insert in front of the label
43 */
44 _PUBLIC_ void mapidump_SPropValue(struct SPropValue lpProp, const char *sep)
45 {
46         const char                      *proptag;
47         const void                      *data;
48         TALLOC_CTX                      *mem_ctx = NULL;
49         const struct StringArray_r      *StringArray_r = NULL;
50         const struct WStringArray_r     *WStringArray_r = NULL;
51         const struct BinaryArray_r      *BinaryArray_r = NULL;
52         const struct LongArray_r        *LongArray_r = NULL;
53         uint32_t                        i;
54
55         proptag = get_proptag_name(lpProp.ulPropTag);
56         if (!proptag) {
57                 mem_ctx = talloc_named(NULL, 0, "mapidump_SPropValue");
58                 proptag = talloc_asprintf(mem_ctx, "0x%.8x", lpProp.ulPropTag);
59         }
60         
61
62         switch(lpProp.ulPropTag & 0xFFFF) {
63         case PT_SHORT:
64                 data = get_SPropValue_data(&lpProp);
65                 printf("%s%s: 0x%x\n", sep?sep:"", proptag, (*(const uint16_t *)data));
66                 break;
67         case PT_LONG:
68         case PT_OBJECT:
69                 data = get_SPropValue_data(&lpProp);
70                 printf("%s%s: %u\n", sep?sep:"", proptag, (*(const uint32_t *)data));
71                 break;
72         case PT_DOUBLE:
73                 data = get_SPropValue_data(&lpProp);
74                 printf("%s%s: %f\n", sep?sep:"", proptag, (*(const double *)data));
75                 break;
76         case PT_BOOLEAN:
77                 data = get_SPropValue_data(&lpProp);
78                 printf("%s%s: 0x%x\n", sep?sep:"", proptag, (*(const uint8_t *)data));
79                 break;
80         case PT_I8:
81                 data = get_SPropValue_data(&lpProp);
82                 printf("%s%s: %.16"PRIx64"\n", sep?sep:"", proptag, (*(const uint64_t *)data));
83                 break;
84         case PT_STRING8:
85         case PT_UNICODE:
86                 data = get_SPropValue_data(&lpProp);
87                 printf("%s%s:", sep?sep:"", proptag);
88                 if (data && ((*(const uint16_t *)data) == 0x0000)) {
89                         /* its an empty string */
90                         printf("\n");
91                 } else if (data && ((*(const uint32_t *)data) != MAPI_E_NOT_FOUND)) {
92                         /* its a valid string */
93                         printf(" %s\n", (const char *)data);
94                 } else {
95                         /* its a null or otherwise problematic string */
96                         printf(" (NULL)\n");
97                 }
98                 break;
99         case PT_SYSTIME:
100                 mapidump_date_SPropValue(lpProp, proptag, sep);
101                 break;
102         case PT_ERROR:
103                 data = get_SPropValue_data(&lpProp);
104                 printf("%s%s_ERROR: 0x%.8x\n", sep?sep:"", proptag, (*(const uint32_t *)data));
105                 break;
106         case PT_CLSID:
107         {
108                 const uint8_t *ab = get_SPropValue_data(&lpProp);
109                 printf("%s%s: ", sep?sep:"", proptag);
110                 for (i = 0; i < 15; ++i) {
111                         printf("%02x ", ab[i]);
112                 }
113                 printf("%x\n", ab[15]);
114                 break;
115         }
116         case PT_SVREID:
117         case PT_BINARY:
118                 data = get_SPropValue_data(&lpProp);
119                 if (data) {
120                         printf("%s%s:\n", sep?sep:"", proptag);
121                         dump_data(0, ((const struct Binary_r *)data)->lpb, ((const struct Binary_r *)data)->cb);
122                 } else {
123                         printf("%s%s: (NULL)\n", sep?sep:"", proptag);
124                 }
125                 break;
126         case PT_MV_LONG:
127                 LongArray_r = (const struct LongArray_r *) get_SPropValue_data(&lpProp);
128                 printf("%s%s ", sep?sep:"", proptag);
129                 for (i = 0; i < LongArray_r->cValues - 1; i++) {
130                         printf("0x%.8x, ", LongArray_r->lpl[i]);
131                 }
132                 printf("0x%.8x\n", LongArray_r->lpl[i]);
133                 break;
134         case PT_MV_STRING8:
135                 StringArray_r = (const struct StringArray_r *) get_SPropValue_data(&lpProp);
136                 printf("%s%s: ", sep?sep:"", proptag);
137                 for (i = 0; i < StringArray_r->cValues - 1; i++) {
138                         printf("%s, ", StringArray_r->lppszA[i]);
139                 }
140                 printf("%s\n", StringArray_r->lppszA[i]);
141                 break;
142         case PT_MV_UNICODE:
143                 WStringArray_r = (const struct WStringArray_r *) get_SPropValue_data(&lpProp);
144                 printf("%s%s: ", sep?sep:"", proptag);
145                 for (i = 0; i < WStringArray_r->cValues - 1; i++) {
146                         printf("%s, ", WStringArray_r->lppszW[i]);
147                 }
148                 printf("%s\n", WStringArray_r->lppszW[i]);
149                 break;
150         case PT_MV_BINARY:
151                 BinaryArray_r = (const struct BinaryArray_r *) get_SPropValue_data(&lpProp);
152                 printf("%s%s: ARRAY(%d)\n", sep?sep:"", proptag, BinaryArray_r->cValues);
153                 for (i = 0; i < BinaryArray_r->cValues; i++) {
154                         printf("\tPT_MV_BINARY [%d]:\n", i);
155                         dump_data(0, BinaryArray_r->lpbin[i].lpb, BinaryArray_r->lpbin[i].cb);
156                 }
157                 break;
158         default:
159                 /* If you hit this assert, you'll need to implement whatever type is missing */
160                 OC_ASSERT(0);
161                 break;
162         }
163
164         if (mem_ctx) {
165                 talloc_free(mem_ctx);
166         }
167
168 }
169
170 _PUBLIC_ void mapidump_SPropTagArray(struct SPropTagArray *SPropTagArray)
171 {
172         uint32_t        count;
173         const char      *proptag;
174
175         if (!SPropTagArray) return;
176         if (!SPropTagArray->cValues) return;
177
178         for (count = 0; count != SPropTagArray->cValues; count++) {
179                 proptag = get_proptag_name(SPropTagArray->aulPropTag[count]);
180                 if (proptag) {
181                         printf("%s\n", proptag);
182                 } else {
183                         printf("0x%.8x\n", SPropTagArray->aulPropTag[count]);
184                 }
185         }
186 }
187
188 _PUBLIC_ void mapidump_SRowSet(struct SRowSet *SRowSet, const char *sep)
189 {
190         uint32_t                i;
191
192         /* Sanity checks */
193         if (!SRowSet) return;
194         if (!SRowSet->cRows) return;
195
196         for (i = 0; i < SRowSet->cRows; i++) {
197                 mapidump_SRow(&(SRowSet->aRow[i]), sep);
198         }
199 }
200
201 _PUBLIC_ void mapidump_SRow(struct SRow *aRow, const char *sep)
202 {
203         uint32_t                i;
204
205         for (i = 0; i < aRow->cValues; i++) {
206                 mapidump_SPropValue(aRow->lpProps[i], sep);
207         }
208 }
209
210 /**
211   Output a row of the public address book
212   
213   \param aRow one row of the public address book (Global Address List)
214   
215   This function is usually used with GetGALTable, which can obtain several
216   rows at once - you'll need to iterate over the rows.
217   
218   The SRow is assumed to contain entries for PR_ADDRTYPE_UNICODE, PR_DISPLAY_NAME_UNICODE,
219   PR_EMAIL_ADDRESS_UNICODE and PR_ACCOUNT_UNICODE.
220 */
221 _PUBLIC_ void mapidump_PAB_entry(struct SRow *aRow)
222 {
223         const char      *addrtype;
224         const char      *name;
225         const char      *email;
226         const char      *account;
227
228         addrtype = (const char *)find_SPropValue_data(aRow, PR_ADDRTYPE_UNICODE);
229         name = (const char *)find_SPropValue_data(aRow, PR_DISPLAY_NAME_UNICODE);
230         email = (const char *)find_SPropValue_data(aRow, PR_EMAIL_ADDRESS_UNICODE);
231         account = (const char *)find_SPropValue_data(aRow, PR_ACCOUNT_UNICODE);
232
233         printf("[%s] %s:\n\tName: %-25s\n\tEmail: %-25s\n", 
234                addrtype, account, name, email);
235         fflush(0);
236 }
237
238
239 _PUBLIC_ void mapidump_Recipients(const char **usernames, struct SRowSet *rowset, struct SPropTagArray *flaglist)
240 {
241         uint32_t                i;
242         uint32_t                j;
243
244         for (i = 0, j= 0; i < flaglist->cValues; i++) {
245                 switch (flaglist->aulPropTag[i]) {
246                 case MAPI_UNRESOLVED:
247                         printf("\tUNRESOLVED (%s)\n", usernames[i]);
248                         break;
249                 case MAPI_AMBIGUOUS:
250                         printf("\tAMBIGUOUS (%s)\n", usernames[i]);
251                         break;
252                 case MAPI_RESOLVED:
253                         printf("\tRESOLVED (%s)\n", usernames[i]);
254                         mapidump_SRow(&rowset->aRow[j], "\t\t[+] ");
255                         j++;
256                         break;
257                 default:
258                         break;
259                 }
260         }
261 }
262
263 _PUBLIC_ void mapidump_date(struct mapi_SPropValue_array *properties, uint32_t mapitag, const char *label)
264 {
265         TALLOC_CTX              *mem_ctx;
266         NTTIME                  time;
267         const struct FILETIME   *filetime;
268         const char              *date;
269
270         mem_ctx = talloc_named(NULL, 0, "mapidump_date");
271
272         filetime = (const struct FILETIME *) find_mapi_SPropValue_data(properties, mapitag);
273         if (filetime) {
274                 time = filetime->dwHighDateTime;
275                 time = time << 32;
276                 time |= filetime->dwLowDateTime;
277                 date = nt_time_string(mem_ctx, time);
278                 printf("\t%-15s:   %s\n", label, date);
279                 fflush(0);
280         }
281
282         talloc_free(mem_ctx);
283 }
284
285 /**
286   \details This function dumps a property containing a date / time to standard output
287   
288   If the property does not contain a PT_SYSTIME type value, then no output will occur.
289   
290   \param lpProp the property to dump
291   \param label the label to display prior to the time (e.g. the property tag)
292   \param sep a separator / spacer to insert in front of the label
293   
294   \note Prior to OpenChange 0.9, this function took 2 arguments, assuming a default separator of
295   a tab. You can get the old behaviour by using "\t" for sep.
296 */
297 _PUBLIC_ void mapidump_date_SPropValue(struct SPropValue lpProp, const char *label, const char *sep)
298 {
299         TALLOC_CTX              *mem_ctx;
300         NTTIME                  time;
301         const struct FILETIME           *filetime;
302         const char              *date;
303
304         mem_ctx = talloc_named(NULL, 0, "mapidump_date_SPropValue");
305
306         filetime = (const struct FILETIME *) get_SPropValue_data(&lpProp);
307         if (filetime) {
308                 time = filetime->dwHighDateTime;
309                 time = time << 32;
310                 time |= filetime->dwLowDateTime;
311                 date = nt_time_string(mem_ctx, time);
312                 printf("%s%s:   %s\n", sep, label, date);
313                 fflush(0);
314         }
315
316         talloc_free(mem_ctx);
317 }
318
319 /**
320    \details This function dumps message information retrieved from
321    OpenMessage call. It provides a quick method to print message
322    summaries with information such as subject and recipients.
323
324    \param obj_message pointer to the MAPI message object to use
325  */
326 _PUBLIC_ void mapidump_message_summary(mapi_object_t *obj_message)
327 {
328         mapi_object_message_t           *msg;
329         int                             *recipient_type;
330         const char                      *recipient;
331         int                             i;
332
333         if (!obj_message) return;
334         if (!obj_message->private_data) return;
335
336         msg = (mapi_object_message_t *) obj_message->private_data;
337
338         printf("Subject: ");
339         if (msg->SubjectPrefix) {
340                 printf("[%s] ", msg->SubjectPrefix);
341         }
342
343         if (msg->NormalizedSubject) {
344                 printf("%s", msg->NormalizedSubject);
345         }
346         printf("\n");
347
348         if (!&(msg->SRowSet)) return;
349         for (i = 0; i < msg->SRowSet.cRows; i++) {
350                 recipient_type = (int *) find_SPropValue_data(&(msg->SRowSet.aRow[i]), PR_RECIPIENT_TYPE);
351                 recipient = (const char *) find_SPropValue_data(&(msg->SRowSet.aRow[i]), PR_SMTP_ADDRESS_UNICODE);
352                 if (!recipient) {
353                         recipient = (const char *) find_SPropValue_data(&(msg->SRowSet.aRow[i]), PR_SMTP_ADDRESS);
354                 }
355                 if (recipient_type && recipient) {
356                         switch (*recipient_type) {
357                         case MAPI_ORIG:
358                                 printf("From: %s\n", recipient);
359                                 break;
360                         case MAPI_TO:
361                                 printf("To: %s\n", recipient);
362                                 break;
363                         case MAPI_CC:
364                                 printf("Cc: %s\n", recipient);
365                                 break;
366                         case MAPI_BCC:
367                                 printf("Bcc: %s\n", recipient);
368                                 break;
369                         }
370                 }
371         }
372         printf("\n");
373 }
374
375 /**
376    \details This function dumps the properties relating to an email message to standard output
377
378    The expected way to obtain the properties array is to use OpenMessage() to obtain the
379    message object, then to use GetPropsAll() to obtain all the properties.
380
381    \param properties array of message properties
382    \param id identification to display for the message (can be NULL)
383    \param obj_msg pointer to the message MAPI object (can be NULL)
384
385    \sa mapidump_appointment, mapidump_contact, mapidump_task, mapidump_note
386 */
387 _PUBLIC_ void mapidump_message(struct mapi_SPropValue_array *properties, const char *id, mapi_object_t *obj_msg)
388 {
389         const char                      *msgid;
390         const char                      *from;
391         const char                      *to;
392         const char                      *cc;
393         const char                      *bcc;
394         const char                      *subject;
395         const char                      *body;
396         const char                      *codepage;
397         const struct SBinary_short      *html = NULL;
398         const uint8_t                   *has_attach;
399         const uint32_t                  *cp;
400         ssize_t                         len;
401
402         msgid = (const char *)find_mapi_SPropValue_data(properties, PR_INTERNET_MESSAGE_ID);
403         subject = (const char *) find_mapi_SPropValue_data(properties, PR_CONVERSATION_TOPIC);
404         body = (const char *) find_mapi_SPropValue_data(properties, PR_BODY);
405         if (!body) {
406                 body = (const char *) find_mapi_SPropValue_data(properties, PR_BODY_UNICODE);
407                 if (!body) {
408                         html = (const struct SBinary_short *) find_mapi_SPropValue_data(properties, PR_HTML);
409                 }
410         }
411         from = (const char *) find_mapi_SPropValue_data(properties, PR_SENT_REPRESENTING_NAME);
412         to = (const char *) find_mapi_SPropValue_data(properties, PR_DISPLAY_TO);
413         cc = (const char *) find_mapi_SPropValue_data(properties, PR_DISPLAY_CC);
414         bcc = (const char *) find_mapi_SPropValue_data(properties, PR_DISPLAY_BCC);
415
416         has_attach = (const uint8_t *)find_mapi_SPropValue_data(properties, PR_HASATTACH);
417
418         cp = (const uint32_t *)find_mapi_SPropValue_data(properties, PR_MESSAGE_CODEPAGE);
419         switch (cp ? *cp : 0) {
420         case CP_USASCII:
421                 codepage = "CP_USASCII";
422                 break;
423         case CP_UNICODE:
424                 codepage = "CP_UNICODE";
425                 break;
426         case CP_JAUTODETECT:
427                 codepage = "CP_JAUTODETECT";
428                 break;
429         case CP_KAUTODETECT:
430                 codepage = "CP_KAUTODETECT";
431                 break;
432         case CP_ISO2022JPESC:
433                 codepage = "CP_ISO2022JPESC";
434                 break;
435         case CP_ISO2022JPSIO:
436                 codepage = "CP_ISO2022JPSIO";
437                 break;
438         default:
439                 codepage = "";
440                 break;
441         }
442
443         printf("+-------------------------------------+\n");
444         printf("message id: %s %s\n", msgid ? msgid : "", id?id:"");
445         if (obj_msg) {
446                 mapidump_message_summary(obj_msg);
447         } else {
448                 printf("subject: %s\n", subject ? subject : "");
449                 printf("From: %s\n", from ? from : "");
450                 printf("To:  %s\n", to ? to : "");
451                 printf("Cc:  %s\n", cc ? cc : "");
452                 printf("Bcc: %s\n", bcc ? bcc : "");
453         }
454         if (has_attach) {
455                 printf("Attachment: %s\n", *has_attach ? "True" : "False");
456         }
457         printf("Codepage: %s\n", codepage);
458         printf("Body:\n");
459         fflush(0);
460         if (body) {
461                 printf("%s\n", body);
462         } else if (html) {
463                 len = write(1, html->lpb, html->cb);
464                 len = write(1, "\n", 1);
465                 fflush(0);
466         }
467 }
468
469 /**
470    \details This function dumps the properties relating to an appointment to standard output
471
472    The expected way to obtain the properties array is to use OpenMessage() to obtain the
473    appointment object, then to use GetPropsAll() to obtain all the properties.
474
475    \param properties array of appointment properties
476    \param id identification to display for the appointment (can be NULL)
477
478    \sa mapidump_message, mapidump_contact, mapidump_task, mapidump_note
479 */
480 _PUBLIC_ void mapidump_appointment(struct mapi_SPropValue_array *properties, const char *id)
481 {
482         const struct mapi_SLPSTRArray   *contacts = NULL;
483         const char              *subject = NULL;
484         const char              *location= NULL;
485         const char              *timezone = NULL;
486         const uint32_t          *status;
487         const uint8_t           *priv = NULL;
488         uint32_t                i;
489
490         contacts = (const struct mapi_SLPSTRArray *)find_mapi_SPropValue_data(properties, PidLidContacts);
491         subject = (const char *)find_mapi_SPropValue_data(properties, PR_CONVERSATION_TOPIC);
492         timezone = (const char *)find_mapi_SPropValue_data(properties, PidLidTimeZoneDescription);
493         location = (const char *)find_mapi_SPropValue_data(properties, PidLidLocation);
494         status = (const uint32_t *)find_mapi_SPropValue_data(properties, PidLidBusyStatus);
495         priv = (const uint8_t *)find_mapi_SPropValue_data(properties, PidLidPrivate);
496
497         printf("|== %s ==| %s\n", subject?subject:"", id?id:"");
498         fflush(0);
499
500         if (location) {
501                 printf("\tLocation: %s\n", location);
502                 fflush(0);
503         }
504
505         mapidump_date(properties, PR_START_DATE, "Start time");
506         mapidump_date(properties, PR_END_DATE, "End time");
507
508         if (timezone) {
509                 printf("\tTimezone: %s\n", timezone);
510                 fflush(0);
511         }
512
513         printf("\tPrivate: %s\n", (priv && (*priv == true)) ? "True" : "False");
514         fflush(0);
515
516         if (status) {
517                 printf("\tStatus: %s\n", get_task_status(*status));
518                 fflush(0);
519         }
520
521         if (contacts) {
522                 printf("\tContacts:\n");
523                 fflush(0);
524                 for (i = 0; i < contacts->cValues; i++) {
525                         printf("\t\tContact: %s\n", contacts->strings[i].lppszA);
526                         fflush(0);
527                 }
528         }       
529 }
530
531 /**
532    \details This function dumps the properties relating to a contact (address book entry)
533    to standard output
534
535    The expected way to obtain the properties array is to use OpenMessage() to obtain the
536    contact object, then to use GetPropsAll() to obtain all the properties.
537
538    \param properties array of contact properties
539    \param id identification to display for the contact (can be NULL)
540
541    \sa mapidump_message, mapidump_appointment, mapidump_task, mapidump_note
542 */
543 _PUBLIC_ void mapidump_contact(struct mapi_SPropValue_array *properties, const char *id)
544 {
545         const char      *card_name =NULL;
546         const char      *topic =NULL;
547         const char      *full_name = NULL;
548         const char      *given_name = NULL;
549         const char      *surname = NULL;
550         const char      *company = NULL;
551         const char      *email = NULL;
552         const char      *title = NULL;
553         const char      *office_phone = NULL;
554         const char      *home_phone = NULL;
555         const char      *mobile_phone = NULL;
556         const char      *postal_address = NULL;
557         const char      *street_address = NULL;
558         const char      *locality = NULL;
559         const char      *state = NULL;
560         const char      *country = NULL;
561         const char      *department = NULL;
562         const char      *business_fax = NULL;
563         const char      *business_home_page = NULL;
564
565         card_name = (const char *)find_mapi_SPropValue_data(properties, PidLidFileUnder);
566         topic = (const char *)find_mapi_SPropValue_data(properties, PR_CONVERSATION_TOPIC);
567         company = (const char *)find_mapi_SPropValue_data(properties, PR_COMPANY_NAME);
568         title = (const char *)find_mapi_SPropValue_data(properties, PR_TITLE);
569         full_name = (const char *)find_mapi_SPropValue_data(properties, PR_DISPLAY_NAME);
570         given_name = (const char *)find_mapi_SPropValue_data(properties, PR_GIVEN_NAME);
571         surname = (const char *)find_mapi_SPropValue_data(properties, PR_SURNAME);
572         department = (const char *)find_mapi_SPropValue_data(properties, PR_DEPARTMENT_NAME);
573         email = (const char *)find_mapi_SPropValue_data(properties, PidLidEmail1OriginalDisplayName);
574         office_phone = (const char *)find_mapi_SPropValue_data(properties, PR_OFFICE_TELEPHONE_NUMBER);
575         home_phone = (const char *)find_mapi_SPropValue_data(properties, PR_HOME_TELEPHONE_NUMBER);
576         mobile_phone = (const char *)find_mapi_SPropValue_data(properties, PR_MOBILE_TELEPHONE_NUMBER);
577         business_fax = (const char *)find_mapi_SPropValue_data(properties, PR_BUSINESS_FAX_NUMBER);
578         business_home_page = (const char *)find_mapi_SPropValue_data(properties, PR_BUSINESS_HOME_PAGE);
579         postal_address = (const char*)find_mapi_SPropValue_data(properties, PR_POSTAL_ADDRESS);
580         street_address = (const char*)find_mapi_SPropValue_data(properties, PR_STREET_ADDRESS);
581         locality = (const char*)find_mapi_SPropValue_data(properties, PR_LOCALITY);
582         state = (const char*)find_mapi_SPropValue_data(properties, PR_STATE_OR_PROVINCE);
583         country = (const char*)find_mapi_SPropValue_data(properties, PR_COUNTRY);
584
585         if (card_name) 
586                 printf("|== %s ==| %s\n", card_name, id?id:"");
587         else if (topic)
588                 printf("|== %s ==| %s\n", topic, id?id:"");
589         else 
590           printf("|== <Unknown> ==| %s\n", id?id:"");
591         fflush(0);
592         if (topic) printf("Topic: %s\n", topic);
593         fflush(0);
594         if (full_name)
595                 printf("Full Name: %s\n", full_name);
596         else if (given_name && surname)
597                 printf("Full Name: %s %s\n", given_name, surname); // initials? l10n?
598         fflush(0);
599         if (title) printf("Job Title: %s\n", title);
600         fflush(0);
601         if (department) printf("Department: %s\n", department);
602         fflush(0);
603         if (company) printf("Company: %s\n", company);
604         fflush(0);
605         if (email) printf("E-mail: %s\n", email);
606         fflush(0);
607         if (office_phone) printf("Office phone number: %s\n", office_phone);
608         fflush(0);
609         if (home_phone) printf("Work phone number: %s\n", home_phone);
610         fflush(0);
611         if (mobile_phone) printf("Mobile phone number: %s\n", mobile_phone);
612         fflush(0);
613         if (business_fax) printf("Business fax number: %s\n", business_fax);
614         fflush(0);
615         if (business_home_page) printf("Business home page: %s\n", business_home_page);
616         fflush(0);
617         if (postal_address) printf("Postal address: %s\n", postal_address);
618         fflush(0);
619         if (street_address) printf("Street address: %s\n", street_address);
620         fflush(0);
621         if (locality) printf("Locality: %s\n", locality);
622         fflush(0);
623         if (state) printf("State / Province: %s\n", state);
624         fflush(0);
625         if (country) printf("Country: %s\n", country);
626         fflush(0);
627
628         printf("\n");
629 }
630
631 _PUBLIC_ const char *get_task_status(uint32_t status)
632 {
633         switch (status) {
634         case olTaskNotStarted:
635                 return ("Not Started");
636         case olTaskInProgress:
637                 return ("In Progress");
638         case olTaskComplete:
639                 return ("Completed");
640         case olTaskWaiting:
641                 return ("Waiting on someone else");
642         case olTaskDeferred:
643                 return ("Deferred");
644         }
645
646         return NULL;
647 }
648
649 _PUBLIC_ const char *get_importance(uint32_t importance)
650 {
651         switch (importance) {
652         case IMPORTANCE_LOW:
653                 return ("Low");
654         case IMPORTANCE_NORMAL:
655                 return ("Normal");
656         case IMPORTANCE_HIGH:
657                 return ("High");
658         }
659         return NULL;
660 }
661
662 /**
663    \details This function dumps the properties relating to a task (to-do list entry)
664    to standard output
665
666    The expected way to obtain the properties array is to use OpenMessage() to obtain the
667    task object, then to use GetPropsAll() to obtain all the properties.
668
669    \param properties array of task properties
670    \param id identification to display for the task (can be NULL)
671
672    \sa mapidump_message, mapidump_appointment, mapidump_contact, mapidump_note
673 */
674 _PUBLIC_ void mapidump_task(struct mapi_SPropValue_array *properties, const char *id)
675 {
676         const struct mapi_SLPSTRArray   *contacts = NULL;
677         const char                      *subject = NULL;
678         const char                      *body = NULL;
679         const double                    *complete = 0;
680         const uint32_t                  *status;
681         const uint32_t                  *importance;
682         const uint8_t                   *private;
683         uint32_t                        i;
684
685         contacts = (const struct mapi_SLPSTRArray *)find_mapi_SPropValue_data(properties, PidLidContacts);
686         subject = (const char *)find_mapi_SPropValue_data(properties, PR_CONVERSATION_TOPIC);
687         body = (const char *)find_mapi_SPropValue_data(properties, PR_BODY);
688         complete = (const double *)find_mapi_SPropValue_data(properties, PidLidPercentComplete);
689         status = (const uint32_t *)find_mapi_SPropValue_data(properties, PidLidTaskStatus);
690         importance = (const uint32_t *)find_mapi_SPropValue_data(properties, PR_IMPORTANCE);
691         private = (const uint8_t *)find_mapi_SPropValue_data(properties, PidLidPrivate);
692
693         printf("|== %s ==| %s\n", subject?subject:"", id?id:"");
694         fflush(0);
695
696         printf("\tBody: %s\n", body?body:"none");
697         fflush(0);
698
699         if (complete) {
700                 printf("\tComplete: %u %c\n", (uint32_t)(*complete * 100), '%');
701                 fflush(0);
702         }
703
704         if (status) {
705                 printf("\tStatus: %s\n", get_task_status(*status));
706                 fflush(0);
707                 if (*status == olTaskComplete) {
708                         mapidump_date(properties, PidLidTaskDateCompleted, "Date Completed");
709                 }
710         }
711
712         if (importance) {
713                 printf("\tImportance: %s\n", get_importance(*importance));
714                 fflush(0);
715         }
716
717         mapidump_date(properties, PidLidTaskDueDate,"Due Date");
718         mapidump_date(properties, PidLidTaskStartDate, "Start Date");
719
720         if (private) {
721                 printf("\tPrivate: %s\n", (*private == true)?"True":"False");
722                 fflush(0);
723         } else {
724                 printf("\tPrivate: false\n");
725                 fflush(0);
726         }
727
728         if (contacts) {
729                 for (i = 0; i < contacts->cValues; i++) {
730                         printf("\tContact: %s\n", contacts->strings[i].lppszA);
731                         fflush(0);
732                 }
733         }
734 }
735
736 /**
737    \details This function dumps the properties relating to a note to standard output
738
739    The expected way to obtain the properties array is to use OpenMessage() to obtain the
740    note object, then to use GetPropsAll() to obtain all the properties.
741
742    \param properties array of note properties
743    \param id identification to display for the note (can be NULL)
744
745    \sa mapidump_message, mapidump_appointment, mapidump_contact, mapidump_task
746 */
747 _PUBLIC_ void mapidump_note(struct mapi_SPropValue_array *properties, const char *id)
748 {
749         const char              *subject = NULL;
750         const char              *body = NULL;
751
752         subject = (const char *)find_mapi_SPropValue_data(properties, PR_CONVERSATION_TOPIC);
753         body = (const char *)find_mapi_SPropValue_data(properties, PR_BODY);
754
755         printf("|== %s ==| %s\n", subject?subject:"", id?id:"");
756         fflush(0);
757         
758         mapidump_date(properties, PR_CLIENT_SUBMIT_TIME, "Submit Time");
759
760         if (body) {
761                 printf("Content:\n");
762                 printf("%s\n", body);
763                 fflush(0);
764         } else {
765                 body = (const char *)find_mapi_SPropValue_data(properties, PR_BODY_HTML);
766                 if (body) {
767                         printf("Content HTML:\n");
768                         printf("%s\n", body);
769                         fflush(0);
770                 }
771         }
772 }
773
774 _PUBLIC_ void mapidump_msgflags(uint32_t MsgFlags, const char *sep)
775 {
776         uint32_t        i;
777         
778         for (i = 0; mdump_msgflags[i].flag; i++) {
779                 if (MsgFlags & mdump_msgflags[i].flag) {
780                         printf("%s\t%s (0x%x)\n", sep?sep:"", 
781                                mdump_msgflags[i].value, mdump_msgflags[i].flag);
782                         fflush(0);
783                 }
784         }
785
786 }
787
788
789 _PUBLIC_ void mapidump_newmail(struct NewMailNotification *newmail, const char *sep)
790 {
791         printf("%sParent Entry ID: 0x%"PRIx64"\n", sep?sep:"", newmail->FID);
792         fflush(0);
793         printf("%sMessage Entry ID: 0x%"PRIx64"\n", sep?sep:"", newmail->MID);
794         fflush(0);
795         printf("%sMessage flags:\n", sep?sep:"");
796         fflush(0);
797         mapidump_msgflags(newmail->MessageFlags, sep);
798         if (newmail->UnicodeFlag == 0x0) {
799                 printf("%sMessage Class: %s\n", sep?sep:"", newmail->MessageClass.lpszA);
800         } else {
801                 printf("%sMessage Class: %s\n", sep?sep:"", newmail->MessageClass.lpszW);
802         }
803         fflush(0);
804 }
805
806 _PUBLIC_ void mapidump_tags(enum MAPITAGS *Tags, uint16_t TagCount, const char *sep)
807 {
808         uint32_t        i;
809         const char      *proptag;
810         for (i = 0; i < TagCount; i++) {
811                 proptag = get_proptag_name(Tags[i]);
812                 printf("%s Tag: %s\n", sep?sep:"", proptag);
813                 fflush(0);
814         }
815 }
816
817 _PUBLIC_ void mapidump_foldercreated(struct FolderCreatedNotification *data, const char *sep)
818 {
819         if (!data) {
820                 return;
821         }
822         printf("%sParent Folder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->ParentFID);
823         fflush(0);
824         printf("%sFolder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->FID);
825         fflush(0);
826         mapidump_tags (data->Tags, data->TagCount, sep);
827 }
828
829 _PUBLIC_ void mapidump_folderdeleted(struct FolderDeletedNotification *data, const char *sep)
830 {
831         if (!data) {
832                 return;
833         }
834         printf("%sParent Folder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->ParentFID);
835         fflush(0);
836         printf("%sFolder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->FID);
837         fflush(0);
838 }
839
840 _PUBLIC_ void mapidump_foldermoved(struct FolderMoveCopyNotification *data, const char *sep)
841 {
842         if (!data) {
843                 return;
844         }
845         printf("%sParent Folder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->ParentFID);
846         fflush(0);
847         printf("%sFolder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->FID);
848         fflush(0);
849         printf("%sOld Parent Folder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->OldParentFID);
850         fflush(0);
851         printf("%sOld Folder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->OldFID);
852         fflush(0);
853 }
854
855 _PUBLIC_ void mapidump_foldercopied(struct FolderMoveCopyNotification *data, const char *sep)
856 {
857         mapidump_foldermoved(data, sep);
858 }
859
860 _PUBLIC_ void mapidump_messagedeleted(struct MessageDeletedNotification *data, const char *sep)
861 {
862         if (!data) {
863                 return;
864         }
865         printf("%sFolder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->FID);
866         fflush(0);
867         printf("%sMessage Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->MID);
868         fflush(0);
869 }
870
871 _PUBLIC_ void mapidump_messagecreated(struct MessageCreatedNotification *data, const char *sep)
872 {
873         if (!data) {
874                 return;
875         }
876         printf("%sFolder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->FID);
877         fflush(0);
878         printf("%sMessage Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->MID);
879         fflush(0);
880         mapidump_tags (data->Tags, data->TagCount, sep);
881 }
882
883 _PUBLIC_ void mapidump_messagemodified(struct MessageModifiedNotification *data, const char *sep)
884 {
885         mapidump_messagecreated((struct MessageCreatedNotification *)data, sep);
886 }
887
888 _PUBLIC_ void mapidump_messagemoved(struct MessageMoveCopyNotification *data, const char *sep)
889 {
890         if (!data) {
891                 return;
892         }
893         printf("%sFolder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->FID);
894         fflush(0);
895         printf("%sMessage Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->MID);
896         fflush(0);
897         printf("%sOld Parent Folder Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->OldFID);
898         fflush(0);
899         printf("%sOld Message Entry ID: 0x%"PRIx64"\n", sep?sep:"", data->OldMID);
900 }
901
902 _PUBLIC_ void mapidump_messagecopied(struct MessageMoveCopyNotification *data, const char *sep)
903 {
904         mapidump_messagemoved(data, sep);
905 }
906
907 _PUBLIC_ const char *mapidump_freebusy_month(uint32_t month, uint32_t year)
908 {
909         uint32_t        realmonth;
910
911         realmonth = month - (year * 16);
912
913         switch (realmonth) {
914         case 0x1:
915                 return "January";
916         case 0x2:
917                 return "February";
918         case 0x3:
919                 return "March";
920         case 0x4:
921                 return "April";
922         case 0x5:
923                 return "May";
924         case 0x6:
925                 return "June";
926         case 0x7:
927                 return "July";
928         case 0x8:
929                 return "August";
930         case 0x9:
931                 return "September";
932         case 0xa:
933                 return "October";
934         case 0xb:
935                 return "November";
936         case 0xc:
937                 return "December";
938         }
939         return NULL;
940 }
941
942
943 _PUBLIC_ uint32_t mapidump_freebusy_year(uint32_t month, uint32_t year)
944 {
945         uint32_t        realmonth;
946
947         realmonth = month - (year * 16);
948         while (realmonth > 0xc) {
949                 year++;
950                 realmonth = month - (year * 16);
951         }
952
953         return year;
954 }
955
956
957 _PUBLIC_ void mapidump_freebusy_date(uint32_t t, const char *sep)
958 {
959         TALLOC_CTX      *mem_ctx;
960         NTTIME          time;
961         const char      *date;
962
963         mem_ctx = talloc_named(NULL, 0, "mapidump_freebusy_date");
964
965         time = t;
966         time *= 60;
967         time *= 10000000;
968
969         date = nt_time_string(mem_ctx, time);
970         DEBUG(0, ("%s %-30s\n", sep, date));
971         talloc_free((char *)date);
972         talloc_free(mem_ctx);
973 }
974
975
976 _PUBLIC_ void mapidump_freebusy_event(struct Binary_r *bin, uint32_t month, uint32_t year, const char *sep)
977 {
978         uint16_t        event_start;
979         uint16_t        event_end;
980         uint32_t        i;
981         uint32_t        hour;
982         uint32_t        hours;
983         uint32_t        day;
984         const char      *month_name;
985         uint32_t        last;
986         uint32_t        minutes = 0;
987
988         if (!bin) return;
989         /* bin.cb must be a multiple of 4 */
990         if (bin->cb % 4) return;
991
992         year = mapidump_freebusy_year(month, year);
993         month_name = mapidump_freebusy_month(month, year);
994         if (!month_name) return;
995
996         for (i = 0; i < bin->cb; i+= 4) {
997                 event_start = (bin->lpb[i + 1] << 8) | bin->lpb[i];
998                 event_end = (bin->lpb[i + 3] << 8) | bin->lpb[i + 2];
999
1000                 for (hour = 0; hour < 24; hour++) {
1001                         if (!(((event_start - (60 * hour)) % 1440) && (((event_start - (60 * hour)) % 1440) - 30))) {
1002                                 day = ((event_start - (60 * hour)) / 1440) + 1;
1003                                 minutes = (event_start - (60 * hour)) % 1440;
1004                                 last = event_end - event_start;
1005 #if defined (__FreeBSD__)
1006                                 DEBUG(0, ("%s %u %s %u at %.2u%.2u hrs and lasts ", sep ? sep : "", day, month_name, year, hour, minutes));
1007 #else
1008                                 DEBUG(0, ("%s %u %s %u at %.2u%.2u hrs and lasts ", sep ? sep : "", day, month_name, year, hour + daylight, minutes));
1009 #endif
1010                                 if (last < 60) {
1011                                         DEBUG(0, ("%u mins\n", last));
1012                                 } else {
1013                                         hours = last / 60;
1014                                         minutes = last - hours * 60;
1015                                         if (minutes > 0) {
1016                                                 DEBUG(0, ("%u hrs %u mins\n", hours, minutes));
1017                                         } else {
1018                                                 DEBUG(0, ("%u hrs\n", hours));
1019                                         }
1020                                 }
1021                         }
1022                 }
1023         }       
1024 }
1025
1026 /**
1027    \details print the list of languages OpenChange supports
1028  */
1029 _PUBLIC_ void mapidump_languages_list(void)
1030 {
1031         mapi_get_language_list();
1032 }