f3d1d61ed713266a36de4345bba4707bdfc70be0
[claws.git] / src / plugins / tnef_parse / tnef_dump.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net>
4  * and the Claws Mail Team
5  *
6  * This file Copyright (C) 2002-2007 Randall Hand <yerase@yerot.com> 
7  * Thanks to him for allowing redistribution of this code as GPLv3.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23  
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #include "claws-features.h"
27 #endif
28
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <ctype.h>
32
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <gtk/gtk.h>
36 #include "common/claws.h"
37 #include "common/version.h"
38 #include "main.h"
39 #include "plugin.h"
40 #include "procmime.h"
41 #include "utils.h"
42
43 #include <tnef-types.h>
44 #include <ytnef.h>
45 #include <mapi.h>
46 #include <mapidefs.h>
47
48 #include "tnef_dump.h"
49
50 #define PRODID "PRODID:-//The Gauntlet//" PACKAGE " TNEF Parser " VERSION "//EN\n"
51
52 static unsigned char GetRruleCount(unsigned char a, unsigned char b) {
53     return ((a << 8) | b);
54 }
55
56 static unsigned char GetRruleMonthNum(unsigned char a, unsigned char b) {
57     switch (a) {
58         case 0x00:
59             switch (b) {
60                 case 0x00:
61                     // Jan
62                     return(1);
63                 case 0xA3:
64                     // May
65                     return(5);
66                 case 0xAE:
67                     // Nov
68                     return(11);
69             }
70             break;
71         case 0x60:
72             switch (b) {
73                 case 0xAE:
74                     // Feb
75                     return(2);
76                 case 0x51:
77                     // Jun
78                     return(6);
79             }
80             break;
81         case 0xE0:
82             switch (b) {
83                 case 0x4B:
84                     // Mar
85                     return(3);
86                 case 0x56:
87                     // Sep
88                     return(9);
89             }
90             break;
91         case 0x40:
92             switch (b) {
93                 case 0xFA:
94                     // Apr
95                     return(4);
96             }
97             break;
98         case 0x20:
99             if (b == 0xFA) {
100                 // Jul
101                 return(7);
102             }
103             break;
104         case 0x80:
105             if (b == 0xA8) {
106                 // Aug
107                 return(8);
108             }
109             break;
110         case 0xA0:
111             if (b == 0xFF) {
112                 // Oct
113                 return(10);
114             }
115             break;
116         case 0xC0:
117             if (b == 0x56) {
118                 return(12);
119             }
120     }
121
122     // Error
123     return(0);
124 }
125
126 static char * GetRruleDayname(unsigned char a) {
127     static char daystring[25];
128
129     *daystring = 0;
130
131     if (a & 0x01) {
132         strcat(daystring, "SU,");
133     }
134     if (a & 0x02) {
135         strcat(daystring, "MO,");
136     }
137     if (a & 0x04) {
138         strcat(daystring, "TU,");
139     }
140     if (a & 0x08) {
141         strcat(daystring, "WE,");
142     }
143     if (a & 0x10) {
144         strcat(daystring, "TH,");
145     }
146     if (a & 0x20) {
147         strcat(daystring, "FR,");
148     }
149     if (a & 0x40) {
150         strcat(daystring, "SA,");
151     }
152
153     if (strlen(daystring)) {
154         daystring[strlen(daystring) - 1] = 0;
155     }
156
157     return(daystring);
158 }
159
160 static void PrintRrule(FILE *fptr, char *recur_data, int size, TNEFStruct TNEF) {
161     variableLength *filename;
162
163     if (size < 0x1F) {
164         return;
165     }
166
167     fprintf(fptr, "RRULE:FREQ=");
168
169     if (recur_data[0x04] == 0x0A) {
170         fprintf(fptr, "DAILY");
171
172         if (recur_data[0x16] == 0x23 || recur_data[0x16] == 0x22 ||
173                 recur_data[0x16] == 0x21) {
174             if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
175                     PROP_TAG(PT_I2, 0x0011))) != MAPI_UNDEFINED) {
176                 fprintf(fptr, ";INTERVAL=%d", *(filename->data));
177             }
178             if (recur_data[0x16] == 0x22 || recur_data[0x16] == 0x21) {
179                 fprintf(fptr, ";COUNT=%d",
180                     GetRruleCount(recur_data[0x1B], recur_data[0x1A]));
181             }
182         } else if (recur_data[0x16] == 0x3E) {
183             fprintf(fptr, ";BYDAY=MO,TU,WE,TH,FR");
184             if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) {
185                 fprintf(fptr, ";COUNT=%d",
186                     GetRruleCount(recur_data[0x1F], recur_data[0x1E]));
187             }
188         }
189     } else if (recur_data[0x04] == 0x0B) {
190         fprintf(fptr, "WEEKLY;INTERVAL=%d;BYDAY=%s",
191             recur_data[0x0E], GetRruleDayname(recur_data[0x16]));
192         if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) {
193             fprintf(fptr, ";COUNT=%d",
194                 GetRruleCount(recur_data[0x1F], recur_data[0x1E]));
195         }
196     } else if (recur_data[0x04] == 0x0C) {
197         fprintf(fptr, "MONTHLY");
198         if (recur_data[0x06] == 0x02) {
199             fprintf(fptr, ";INTERVAL=%d;BYMONTHDAY=%d", recur_data[0x0E],
200                 recur_data[0x16]);
201             if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) {
202                 fprintf(fptr, ";COUNT=%d", GetRruleCount(recur_data[0x1F],
203                     recur_data[0x1E]));
204             }
205         } else if (recur_data[0x06] == 0x03) {
206             fprintf(fptr, ";BYDAY=%s;BYSETPOS=%d;INTERVAL=%d",
207                 GetRruleDayname(recur_data[0x16]),
208                 recur_data[0x1A] == 0x05 ? -1 : recur_data[0x1A],
209                 recur_data[0x0E]);
210             if (recur_data[0x1E] == 0x22 || recur_data[0x1E] == 0x21) {
211                 fprintf(fptr, ";COUNT=%d", GetRruleCount(recur_data[0x23],
212                     recur_data[0x22]));
213             }
214         }
215     } else if (recur_data[0x04] == 0x0D) {
216         fprintf(fptr, "YEARLY;BYMONTH=%d",
217                 GetRruleMonthNum(recur_data[0x0A], recur_data[0x0B]));
218         if (recur_data[0x06] == 0x02) {
219             fprintf(fptr, ";BYMONTHDAY=%d", recur_data[0x16]);
220         } else if (recur_data[0x06] == 0x03) {
221             fprintf(fptr, ";BYDAY=%s;BYSETPOS=%d",
222                 GetRruleDayname(recur_data[0x16]),
223                 recur_data[0x1A] == 0x05 ? -1 : recur_data[0x1A]);
224         }
225         if (recur_data[0x1E] == 0x22 || recur_data[0x1E] == 0x21) {
226             fprintf(fptr, ";COUNT=%d", GetRruleCount(recur_data[0x23],
227                 recur_data[0x22]));
228         }
229     }
230     fprintf(fptr, "\n");
231 }
232
233 static void fprintProperty(TNEFStruct TNEF, FILE *FPTR, DWORD PROPTYPE, DWORD PROPID, char TEXT[]) {
234     variableLength *vl;
235     if ((vl=MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PROPTYPE, PROPID))) != MAPI_UNDEFINED) {
236         if (vl->size > 0) {
237             if ((vl->size == 1) && (vl->data[0] == 0)) {
238             } else {
239                 fprintf(FPTR, TEXT, vl->data);
240             }
241         }
242     }
243 }
244
245 static void fprintUserProp(TNEFStruct TNEF, FILE *FPTR, DWORD PROPTYPE, DWORD PROPID, char TEXT[]) {
246     variableLength *vl;
247     if ((vl=MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PROPTYPE, PROPID))) != MAPI_UNDEFINED) {
248         if (vl->size > 0) {
249             if ((vl->size == 1) && (vl->data[0] == 0)) {
250             } else {
251                 fprintf(FPTR, TEXT, vl->data);
252             }
253         }
254     }
255 }
256
257 static void quotedfprint(FILE *FPTR, variableLength *VL) {
258     int index;
259
260     for (index=0;index<VL->size-1; index++) {
261         if (VL->data[index] == '\n') {
262             fprintf(FPTR, "=0A");
263         } else if (VL->data[index] == '\r') {
264         } else {
265             fprintf(FPTR, "%c", VL->data[index]);
266         }
267     }
268 }
269
270 static void Cstylefprint(FILE *FPTR, variableLength *VL) {
271     int index;
272
273     for (index=0;index<VL->size-1; index++) {
274         if (VL->data[index] == '\n') {
275             fprintf(FPTR, "\\n");
276         } else if (VL->data[index] == '\r') {
277             // Print nothing.
278         } else if (VL->data[index] == ';') {
279             fprintf(FPTR, "\\;");
280         } else if (VL->data[index] == ',') {
281             fprintf(FPTR, "\\,");
282         } else if (VL->data[index] == '\\') {
283             fprintf(FPTR, "\\");
284         } else {
285             fprintf(FPTR, "%c", VL->data[index]);
286         }
287     }
288 }
289
290 static void PrintRTF(FILE *fptr, variableLength *VL) {
291     int index;
292     char *byte;
293     int brace_ct;
294     int key;
295
296     key = 0;
297     brace_ct = 0;
298
299     for(index = 0, byte=VL->data; index < VL->size; index++, byte++) {
300         if (*byte == '}') {
301             brace_ct--;
302             key = 0;
303             continue;
304         }
305         if (*byte == '{') {
306             brace_ct++;
307             continue;
308         }
309         if (*byte == '\\') {
310             key = 1;
311         }
312         if (isspace(*byte)) {
313             key = 0;
314         }
315         if ((brace_ct == 1) && (key == 0)) {
316             if (*byte == '\n') {
317                 fprintf(fptr, "\\n");
318             } else if (*byte == '\r') {
319                 // Print nothing.
320             } else if (*byte == ';') {
321                 fprintf(fptr, "\\;");
322             } else if (*byte == ',') {
323                 fprintf(fptr, "\\,");
324             } else if (*byte == '\\') {
325                 fprintf(fptr, "\\");
326             } else {
327                 fprintf(fptr, "%c", *byte );
328             }
329         }
330     }
331     fprintf(fptr, "\n");
332 }
333
334 gboolean SaveVCalendar(FILE *fptr, TNEFStruct TNEF) {
335     variableLength *filename;
336     char *charptr, *charptr2;
337     int index;
338     DDWORD *ddword_ptr;
339     DDWORD ddword_val;
340     dtr thedate;
341
342         fprintf(fptr, "BEGIN:VCALENDAR\n");
343         if (TNEF.messageClass[0] != 0) {
344             charptr2=TNEF.messageClass;
345             charptr=charptr2;
346             while (*charptr != 0) {
347                 if (*charptr == '.') {
348                     charptr2 = charptr;
349                 }
350                 charptr++;
351             }
352             if (strcmp(charptr2, ".MtgCncl") == 0) {
353                 fprintf(fptr, "METHOD:CANCEL\n");
354             } else {
355                 fprintf(fptr, "METHOD:REQUEST\n");
356             }
357         } else {
358             fprintf(fptr, "METHOD:REQUEST\n");
359         }
360         fprintf(fptr, PRODID);
361         fprintf(fptr, "VERSION:2.0\n");
362         fprintf(fptr, "BEGIN:VEVENT\n");
363
364         // UID
365         // After alot of comparisons, I'm reasonably sure this is totally
366         // wrong.  But it's not really necessary.
367         //
368         // I think it only exists to connect future modification entries to
369         // this entry. so as long as it's incorrectly interpreted the same way
370         // every time, it should be ok :)
371         filename = NULL;
372         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
373                         PROP_TAG(PT_BINARY, 0x3))) == MAPI_UNDEFINED) {
374             if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
375                             PROP_TAG(PT_BINARY, 0x23))) == MAPI_UNDEFINED) {
376                 filename = NULL;
377             }
378         }
379         if (filename!=NULL) {
380             fprintf(fptr, "UID:");
381             for(index=0;index<filename->size;index++) {
382                 fprintf(fptr,"%02X", (unsigned char)filename->data[index]);
383             }
384             fprintf(fptr,"\n");
385         }
386
387         // Sequence
388         filename = NULL;
389         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
390                         PROP_TAG(PT_LONG, 0x8201))) != MAPI_UNDEFINED) {
391             ddword_ptr = (DDWORD*)filename->data;
392             fprintf(fptr, "SEQUENCE:%i\n", (int) *ddword_ptr);
393         }
394         if ((filename=MAPIFindProperty(&(TNEF.MapiProperties),
395                         PROP_TAG(PT_BINARY, PR_SENDER_SEARCH_KEY)))
396                 != MAPI_UNDEFINED) {
397             charptr = filename->data;
398             charptr2 = strstr(charptr, ":");
399             if (charptr2 == NULL)
400                 charptr2 = charptr;
401             else
402                 charptr2++;
403             fprintf(fptr, "ORGANIZER;CN=\"%s\":MAILTO:%s\n",
404                     charptr2, charptr2);
405         }
406
407         // Required Attendees
408         if ((filename = MAPIFindUserProp(&(TNEF.MapiProperties),
409                         PROP_TAG(PT_STRING8, 0x823b))) != MAPI_UNDEFINED) {
410                 // We have a list of required participants, so
411                 // write them out.
412             if (filename->size > 1) {
413                 charptr = filename->data-1;
414                 charptr2=strstr(charptr+1, ";");
415                 while (charptr != NULL) {
416                     charptr++;
417                     charptr2 = strstr(charptr, ";");
418                     if (charptr2 != NULL) {
419                         *charptr2 = 0;
420                     }
421                     while (*charptr == ' ')
422                         charptr++;
423                     fprintf(fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;");
424                     fprintf(fptr, "ROLE=REQ-PARTICIPANT;RSVP=TRUE;");
425                     fprintf(fptr, "CN=\"%s\":MAILTO:%s\n",
426                                 charptr, charptr);
427                     charptr = charptr2;
428                 }
429             }
430             // Optional attendees
431             if ((filename = MAPIFindUserProp(&(TNEF.MapiProperties),
432                             PROP_TAG(PT_STRING8, 0x823c))) != MAPI_UNDEFINED) {
433                     // The list of optional participants
434                 if (filename->size > 1) {
435                     charptr = filename->data-1;
436                     charptr2=strstr(charptr+1, ";");
437                     while (charptr != NULL) {
438                         charptr++;
439                         charptr2 = strstr(charptr, ";");
440                         if (charptr2 != NULL) {
441                             *charptr2 = 0;
442                         }
443                         while (*charptr == ' ')
444                             charptr++;
445                         fprintf(fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;");
446                         fprintf(fptr, "ROLE=OPT-PARTICIPANT;RSVP=TRUE;");
447                         fprintf(fptr, "CN=\"%s\":MAILTO:%s\n",
448                                 charptr, charptr);
449                         charptr = charptr2;
450                     }
451                 }
452             }
453         } else if ((filename = MAPIFindUserProp(&(TNEF.MapiProperties),
454                         PROP_TAG(PT_STRING8, 0x8238))) != MAPI_UNDEFINED) {
455             if (filename->size > 1) {
456                 charptr = filename->data-1;
457                 charptr2=strstr(charptr+1, ";");
458                 while (charptr != NULL) {
459                     charptr++;
460                     charptr2 = strstr(charptr, ";");
461                     if (charptr2 != NULL) {
462                         *charptr2 = 0;
463                     }
464                     while (*charptr == ' ')
465                         charptr++;
466                     fprintf(fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;");
467                     fprintf(fptr, "ROLE=REQ-PARTICIPANT;RSVP=TRUE;");
468                     fprintf(fptr, "CN=\"%s\":MAILTO:%s\n",
469                                 charptr, charptr);
470                     charptr = charptr2;
471                 }
472             }
473
474         }
475         // Summary
476         filename = NULL;
477         if((filename=MAPIFindProperty(&(TNEF.MapiProperties),
478                         PROP_TAG(PT_STRING8, PR_CONVERSATION_TOPIC)))
479                 != MAPI_UNDEFINED) {
480             fprintf(fptr, "SUMMARY:");
481             Cstylefprint(fptr, filename);
482             fprintf(fptr, "\n");
483         }
484
485         // Description
486         if ((filename=MAPIFindProperty(&(TNEF.MapiProperties),
487                                 PROP_TAG(PT_BINARY, PR_RTF_COMPRESSED)))
488                 != MAPI_UNDEFINED) {
489             variableLength buf;
490             if ((buf.data = DecompressRTF(filename, &(buf.size))) != NULL) {
491                 fprintf(fptr, "DESCRIPTION:");
492                 PrintRTF(fptr, &buf);
493                 free(buf.data);
494             }
495
496         }
497
498         // Location
499         filename = NULL;
500         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
501                         PROP_TAG(PT_STRING8, 0x0002))) == MAPI_UNDEFINED) {
502             if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
503                             PROP_TAG(PT_STRING8, 0x8208))) == MAPI_UNDEFINED) {
504                 filename = NULL;
505             }
506         }
507         if (filename != NULL) {
508             fprintf(fptr,"LOCATION: %s\n", filename->data);
509         }
510         // Date Start
511         filename = NULL;
512         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
513                         PROP_TAG(PT_SYSTIME, 0x820d))) == MAPI_UNDEFINED) {
514             if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
515                             PROP_TAG(PT_SYSTIME, 0x8516))) == MAPI_UNDEFINED) {
516                 filename=NULL;
517             }
518         }
519         if (filename != NULL) {
520             fprintf(fptr, "DTSTART:");
521             MAPISysTimetoDTR(filename->data, &thedate);
522             fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
523                     thedate.wYear, thedate.wMonth, thedate.wDay,
524                     thedate.wHour, thedate.wMinute, thedate.wSecond);
525         }
526         // Date End
527         filename = NULL;
528         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
529                         PROP_TAG(PT_SYSTIME, 0x820e))) == MAPI_UNDEFINED) {
530             if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
531                             PROP_TAG(PT_SYSTIME, 0x8517))) == MAPI_UNDEFINED) {
532                 filename=NULL;
533             }
534         }
535         if (filename != NULL) {
536             fprintf(fptr, "DTEND:");
537             MAPISysTimetoDTR(filename->data, &thedate);
538             fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
539                     thedate.wYear, thedate.wMonth, thedate.wDay,
540                     thedate.wHour, thedate.wMinute, thedate.wSecond);
541         }
542         // Date Stamp
543         filename = NULL;
544         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
545                         PROP_TAG(PT_SYSTIME, 0x8202))) != MAPI_UNDEFINED) {
546             fprintf(fptr, "CREATED:");
547             MAPISysTimetoDTR(filename->data, &thedate);
548             fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
549                     thedate.wYear, thedate.wMonth, thedate.wDay,
550                     thedate.wHour, thedate.wMinute, thedate.wSecond);
551         }
552         // Class
553         filename = NULL;
554         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
555                         PROP_TAG(PT_BOOLEAN, 0x8506))) != MAPI_UNDEFINED) {
556             ddword_ptr = (DDWORD*)filename->data;
557             ddword_val = SwapDDWord((BYTE*)ddword_ptr);
558             fprintf(fptr, "CLASS:" );
559             if (*ddword_ptr == 1) {
560                 fprintf(fptr,"PRIVATE\n");
561             } else {
562                 fprintf(fptr,"PUBLIC\n");
563             }
564         }
565         // Recurrence
566         filename = NULL;
567         if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
568                         PROP_TAG(PT_BINARY, 0x8216))) != MAPI_UNDEFINED) {
569             PrintRrule(fptr, filename->data, filename->size, TNEF);
570         }
571
572         // Wrap it up
573         fprintf(fptr, "END:VEVENT\n");
574         fprintf(fptr, "END:VCALENDAR\n");
575         return TRUE;
576 }
577
578         
579
580 gboolean SaveVTask(FILE *fptr, TNEFStruct TNEF) {
581     variableLength *filename;
582     char *charptr, *charptr2;
583     dtr thedate;
584     DDWORD *ddword_ptr;
585     DDWORD ddword_val;
586
587         fprintf(fptr, "BEGIN:VCALENDAR\n");
588         fprintf(fptr, PRODID);
589         fprintf(fptr, "VERSION:2.0\n");
590         fprintf(fptr, "METHOD:PUBLISH\n");
591         filename = NULL;
592
593         fprintf(fptr, "BEGIN:VTODO\n");
594         if (TNEF.messageID[0] != 0) {
595             fprintf(fptr,"UID:%s\n", TNEF.messageID);
596         }
597         filename = MAPIFindUserProp(&(TNEF.MapiProperties), \
598                         PROP_TAG(PT_STRING8, 0x8122));
599         if (filename != MAPI_UNDEFINED) {
600             fprintf(fptr, "ORGANIZER:%s\n", filename->data);
601         }
602
603
604         if ((filename = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_DISPLAY_TO))) != MAPI_UNDEFINED) {
605             filename = MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x811f));
606         }
607         if ((filename != MAPI_UNDEFINED) && (filename->size > 1)) {
608             charptr = filename->data-1;
609             charptr2=strstr(charptr+1, ";");
610             while (charptr != NULL) {
611                 charptr++;
612                 charptr2 = strstr(charptr, ";");
613                 if (charptr2 != NULL) {
614                     *charptr2 = 0;
615                 }
616                 while (*charptr == ' ')
617                     charptr++;
618                 fprintf(fptr, "ATTENDEE;CN=%s;ROLE=REQ-PARTICIPANT:%s\n", charptr, charptr);
619                 charptr = charptr2;
620             }
621         }
622
623         if (TNEF.subject.size > 0) {
624             fprintf(fptr,"SUMMARY:");
625             Cstylefprint(fptr,&(TNEF.subject));
626             fprintf(fptr,"\n");
627         }
628
629         if (TNEF.body.size > 0) {
630             fprintf(fptr,"DESCRIPTION:");
631             Cstylefprint(fptr,&(TNEF.body));
632             fprintf(fptr,"\n");
633         }
634
635         filename = MAPIFindProperty(&(TNEF.MapiProperties), \
636                     PROP_TAG(PT_SYSTIME, PR_CREATION_TIME));
637         if (filename != MAPI_UNDEFINED) {
638             fprintf(fptr, "DTSTAMP:");
639             MAPISysTimetoDTR(filename->data, &thedate);
640             fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
641                     thedate.wYear, thedate.wMonth, thedate.wDay,
642                     thedate.wHour, thedate.wMinute, thedate.wSecond);
643         }
644
645         filename = MAPIFindUserProp(&(TNEF.MapiProperties), \
646                     PROP_TAG(PT_SYSTIME, 0x8517));
647         if (filename != MAPI_UNDEFINED) {
648             fprintf(fptr, "DUE:");
649             MAPISysTimetoDTR(filename->data, &thedate);
650             fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
651                     thedate.wYear, thedate.wMonth, thedate.wDay,
652                     thedate.wHour, thedate.wMinute, thedate.wSecond);
653         }
654         filename = MAPIFindProperty(&(TNEF.MapiProperties), \
655                     PROP_TAG(PT_SYSTIME, PR_LAST_MODIFICATION_TIME));
656         if (filename != MAPI_UNDEFINED) {
657             fprintf(fptr, "LAST-MODIFIED:");
658             MAPISysTimetoDTR(filename->data, &thedate);
659             fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
660                     thedate.wYear, thedate.wMonth, thedate.wDay,
661                     thedate.wHour, thedate.wMinute, thedate.wSecond);
662         }
663         // Class
664         filename = MAPIFindUserProp(&(TNEF.MapiProperties), \
665                         PROP_TAG(PT_BOOLEAN, 0x8506));
666         if (filename != MAPI_UNDEFINED) {
667             ddword_ptr = (DDWORD*)filename->data;
668             ddword_val = SwapDDWord((BYTE*)ddword_ptr);
669             fprintf(fptr, "CLASS:" );
670             if (*ddword_ptr == 1) {
671                 fprintf(fptr,"PRIVATE\n");
672             } else {
673                 fprintf(fptr,"PUBLIC\n");
674             }
675         }
676         fprintf(fptr, "END:VTODO\n");
677         fprintf(fptr, "END:VCALENDAR\n");
678         fclose(fptr);
679         return TRUE;
680 }
681
682 gboolean SaveVCard(FILE *fptr, TNEFStruct TNEF) {
683     variableLength *vl;
684     variableLength *pobox, *street, *city, *state, *zip, *country;
685     dtr thedate;
686     int boolean;
687
688     if ((vl = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_DISPLAY_NAME))) == MAPI_UNDEFINED) {
689         vl=MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_COMPANY_NAME));
690     }
691
692         fprintf(fptr, "BEGIN:VCARD\n");
693         fprintf(fptr, "VERSION:2.1\n");
694         if (vl != MAPI_UNDEFINED) {
695             fprintf(fptr, "FN:%s\n", vl->data);
696         }
697         fprintProperty(TNEF, fptr, PT_STRING8, PR_NICKNAME, "NICKNAME:%s\n");
698         fprintUserProp(TNEF, fptr, PT_STRING8, 0x8554, "MAILER:Microsoft Outlook %s\n");
699         fprintProperty(TNEF, fptr, PT_STRING8, PR_SPOUSE_NAME, "X-EVOLUTION-SPOUSE:%s\n");
700         fprintProperty(TNEF, fptr, PT_STRING8, PR_MANAGER_NAME, "X-EVOLUTION-MANAGER:%s\n");
701         fprintProperty(TNEF, fptr, PT_STRING8, PR_ASSISTANT, "X-EVOLUTION-ASSISTANT:%s\n");
702
703         // Organizational
704         if ((vl=MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_COMPANY_NAME))) != MAPI_UNDEFINED) {
705             if (vl->size > 0) {
706                 if ((vl->size == 1) && (vl->data[0] == 0)) {
707                 } else {
708                     fprintf(fptr,"ORG:%s", vl->data);
709                     if ((vl=MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_DEPARTMENT_NAME))) != MAPI_UNDEFINED) {
710                         fprintf(fptr,";%s", vl->data);
711                     }
712                     fprintf(fptr, "\n");
713                 }
714             }
715         }
716
717         fprintProperty(TNEF, fptr, PT_STRING8, PR_OFFICE_LOCATION, "X-EVOLUTION-OFFICE:%s\n");
718         fprintProperty(TNEF, fptr, PT_STRING8, PR_TITLE, "TITLE:%s\n");
719         fprintProperty(TNEF, fptr, PT_STRING8, PR_PROFESSION, "ROLE:%s\n");
720         fprintProperty(TNEF, fptr, PT_STRING8, PR_BODY, "NOTE:%s\n");
721         if (TNEF.body.size > 0) {
722             fprintf(fptr, "NOTE;QUOTED-PRINTABLE:");
723             quotedfprint(fptr, &(TNEF.body));
724             fprintf(fptr,"\n");
725         }
726
727
728         // Business Address
729         boolean = 0;
730         if ((pobox = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_POST_OFFICE_BOX))) != MAPI_UNDEFINED) {
731             boolean = 1;
732         }
733         if ((street = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_STREET_ADDRESS))) != MAPI_UNDEFINED) {
734             boolean = 1;
735         }
736         if ((city = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_LOCALITY))) != MAPI_UNDEFINED) {
737             boolean = 1;
738         }
739         if ((state = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) {
740             boolean = 1;
741         }
742         if ((zip = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_POSTAL_CODE))) != MAPI_UNDEFINED) {
743             boolean = 1;
744         }
745         if ((country = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_COUNTRY))) != MAPI_UNDEFINED) {
746             boolean = 1;
747         }
748         if (boolean == 1) {
749             fprintf(fptr, "ADR;QUOTED-PRINTABLE;WORK:");
750             if (pobox != MAPI_UNDEFINED) {
751                 quotedfprint(fptr, pobox);
752             }
753             fprintf(fptr, ";;");
754             if (street != MAPI_UNDEFINED) {
755                 quotedfprint(fptr, street);
756             }
757             fprintf(fptr, ";");
758             if (city != MAPI_UNDEFINED) {
759                 quotedfprint(fptr, city);
760             }
761             fprintf(fptr, ";");
762             if (state != MAPI_UNDEFINED) {
763                 quotedfprint(fptr, state);
764             }
765             fprintf(fptr, ";");
766             if (zip != MAPI_UNDEFINED) {
767                 quotedfprint(fptr, zip);
768             }
769             fprintf(fptr, ";");
770             if (country != MAPI_UNDEFINED) {
771                 quotedfprint(fptr, country);
772             }
773             fprintf(fptr,"\n");
774             if ((vl = MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x801b))) != MAPI_UNDEFINED) {
775                 fprintf(fptr, "LABEL;QUOTED-PRINTABLE;WORK:");
776                 quotedfprint(fptr, vl);
777                 fprintf(fptr,"\n");
778             }
779         }
780
781         // Home Address
782         boolean = 0;
783         if ((pobox = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_HOME_ADDRESS_POST_OFFICE_BOX))) != MAPI_UNDEFINED) {
784             boolean = 1;
785         }
786         if ((street = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_HOME_ADDRESS_STREET))) != MAPI_UNDEFINED) {
787             boolean = 1;
788         }
789         if ((city = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_HOME_ADDRESS_CITY))) != MAPI_UNDEFINED) {
790             boolean = 1;
791         }
792         if ((state = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_HOME_ADDRESS_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) {
793             boolean = 1;
794         }
795         if ((zip = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_HOME_ADDRESS_POSTAL_CODE))) != MAPI_UNDEFINED) {
796             boolean = 1;
797         }
798         if ((country = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_HOME_ADDRESS_COUNTRY))) != MAPI_UNDEFINED) {
799             boolean = 1;
800         }
801         if (boolean == 1) {
802             fprintf(fptr, "ADR;QUOTED-PRINTABLE;HOME:");
803             if (pobox != MAPI_UNDEFINED) {
804                 quotedfprint(fptr, pobox);
805             }
806             fprintf(fptr, ";;");
807             if (street != MAPI_UNDEFINED) {
808                 quotedfprint(fptr, street);
809             }
810             fprintf(fptr, ";");
811             if (city != MAPI_UNDEFINED) {
812                 quotedfprint(fptr, city);
813             }
814             fprintf(fptr, ";");
815             if (state != MAPI_UNDEFINED) {
816                 quotedfprint(fptr, state);
817             }
818             fprintf(fptr, ";");
819             if (zip != MAPI_UNDEFINED) {
820                 quotedfprint(fptr, zip);
821             }
822             fprintf(fptr, ";");
823             if (country != MAPI_UNDEFINED) {
824                 quotedfprint(fptr, country);
825             }
826             fprintf(fptr,"\n");
827             if ((vl = MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x801a))) != MAPI_UNDEFINED) {
828                 fprintf(fptr, "LABEL;QUOTED-PRINTABLE;WORK:");
829                 quotedfprint(fptr, vl);
830                 fprintf(fptr,"\n");
831             }
832         }
833
834         // Other Address
835         boolean = 0;
836         if ((pobox = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_OTHER_ADDRESS_POST_OFFICE_BOX))) != MAPI_UNDEFINED) {
837             boolean = 1;
838         }
839         if ((street = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_OTHER_ADDRESS_STREET))) != MAPI_UNDEFINED) {
840             boolean = 1;
841         }
842         if ((city = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_OTHER_ADDRESS_CITY))) != MAPI_UNDEFINED) {
843             boolean = 1;
844         }
845         if ((state = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_OTHER_ADDRESS_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) {
846             boolean = 1;
847         }
848         if ((zip = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_OTHER_ADDRESS_POSTAL_CODE))) != MAPI_UNDEFINED) {
849             boolean = 1;
850         }
851         if ((country = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_OTHER_ADDRESS_COUNTRY))) != MAPI_UNDEFINED) {
852             boolean = 1;
853         }
854         if (boolean == 1) {
855             fprintf(fptr, "ADR;QUOTED-PRINTABLE;OTHER:");
856             if (pobox != MAPI_UNDEFINED) {
857                 quotedfprint(fptr, pobox);
858             }
859             fprintf(fptr, ";;");
860             if (street != MAPI_UNDEFINED) {
861                 quotedfprint(fptr, street);
862             }
863             fprintf(fptr, ";");
864             if (city != MAPI_UNDEFINED) {
865                 quotedfprint(fptr, city);
866             }
867             fprintf(fptr, ";");
868             if (state != MAPI_UNDEFINED) {
869                 quotedfprint(fptr, state);
870             }
871             fprintf(fptr, ";");
872             if (zip != MAPI_UNDEFINED) {
873                 quotedfprint(fptr, zip);
874             }
875             fprintf(fptr, ";");
876             if (country != MAPI_UNDEFINED) {
877                 quotedfprint(fptr, country);
878             }
879             fprintf(fptr,"\n");
880         }
881
882
883         fprintProperty(TNEF, fptr, PT_STRING8, PR_CALLBACK_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-CALLBACK:%s\n");
884         fprintProperty(TNEF, fptr, PT_STRING8, PR_PRIMARY_TELEPHONE_NUMBER, "TEL;PREF:%s\n");
885         fprintProperty(TNEF, fptr, PT_STRING8, PR_MOBILE_TELEPHONE_NUMBER, "TEL;CELL:%s\n");
886         fprintProperty(TNEF, fptr, PT_STRING8, PR_RADIO_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-RADIO:%s\n");
887         fprintProperty(TNEF, fptr, PT_STRING8, PR_CAR_TELEPHONE_NUMBER, "TEL;CAR:%s\n");
888         fprintProperty(TNEF, fptr, PT_STRING8, PR_OTHER_TELEPHONE_NUMBER, "TEL;VOICE:%s\n");
889         fprintProperty(TNEF, fptr, PT_STRING8, PR_PAGER_TELEPHONE_NUMBER, "TEL;PAGER:%s\n");
890         fprintProperty(TNEF, fptr, PT_STRING8, PR_TELEX_NUMBER, "TEL;X-EVOLUTION-TELEX:%s\n");
891         fprintProperty(TNEF, fptr, PT_STRING8, PR_ISDN_NUMBER, "TEL;ISDN:%s\n");
892         fprintProperty(TNEF, fptr, PT_STRING8, PR_HOME2_TELEPHONE_NUMBER, "TEL;HOME:%s\n");
893         fprintProperty(TNEF, fptr, PT_STRING8, PR_TTYTDD_PHONE_NUMBER, "TEL;X-EVOLUTION-TTYTDD:%s\n");
894         fprintProperty(TNEF, fptr, PT_STRING8, PR_HOME_TELEPHONE_NUMBER, "TEL;HOME;VOICE:%s\n");
895         fprintProperty(TNEF, fptr, PT_STRING8, PR_ASSISTANT_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-ASSISTANT:%s\n");
896         fprintProperty(TNEF, fptr, PT_STRING8, PR_COMPANY_MAIN_PHONE_NUMBER, "TEL;WORK:%s\n");
897         fprintProperty(TNEF, fptr, PT_STRING8, PR_BUSINESS_TELEPHONE_NUMBER, "TEL;WORK:%s\n");
898         fprintProperty(TNEF, fptr, PT_STRING8, PR_BUSINESS2_TELEPHONE_NUMBER, "TEL;WORK;VOICE:%s\n");
899         fprintProperty(TNEF, fptr, PT_STRING8, PR_PRIMARY_FAX_NUMBER, "TEL;PREF;FAX:%s\n");
900         fprintProperty(TNEF, fptr, PT_STRING8, PR_BUSINESS_FAX_NUMBER, "TEL;WORK;FAX:%s\n");
901         fprintProperty(TNEF, fptr, PT_STRING8, PR_HOME_FAX_NUMBER, "TEL;HOME;FAX:%s\n");
902
903
904         // Email addresses
905         if ((vl=MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x8083))) == MAPI_UNDEFINED) {
906             vl=MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x8084));
907         }
908         if (vl != MAPI_UNDEFINED) {
909             if (vl->size > 0)
910                 fprintf(fptr, "EMAIL:%s\n", vl->data);
911         }
912         if ((vl=MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x8093))) == MAPI_UNDEFINED) {
913             vl=MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x8094));
914         }
915         if (vl != MAPI_UNDEFINED) {
916             if (vl->size > 0)
917                 fprintf(fptr, "EMAIL:%s\n", vl->data);
918         }
919         if ((vl=MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x80a3))) == MAPI_UNDEFINED) {
920             vl=MAPIFindUserProp(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, 0x80a4));
921         }
922         if (vl != MAPI_UNDEFINED) {
923             if (vl->size > 0)
924                 fprintf(fptr, "EMAIL:%s\n", vl->data);
925         }
926
927         fprintProperty(TNEF, fptr, PT_STRING8, PR_BUSINESS_HOME_PAGE, "URL:%s\n");
928         fprintUserProp(TNEF, fptr, PT_STRING8, 0x80d8, "FBURL:%s\n");
929
930
931
932         //Birthday
933         if ((vl=MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_SYSTIME, PR_BIRTHDAY))) != MAPI_UNDEFINED) {
934             fprintf(fptr, "BDAY:");
935             MAPISysTimetoDTR(vl->data, &thedate);
936             fprintf(fptr, "%i-%02i-%02i\n", thedate.wYear, thedate.wMonth, thedate.wDay);
937         }
938
939         //Anniversary
940         if ((vl=MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_SYSTIME, PR_WEDDING_ANNIVERSARY))) != MAPI_UNDEFINED) {
941             fprintf(fptr, "X-EVOLUTION-ANNIVERSARY:");
942             MAPISysTimetoDTR(vl->data, &thedate);
943             fprintf(fptr, "%i-%02i-%02i\n", thedate.wYear, thedate.wMonth, thedate.wDay);
944         }
945         fprintf(fptr, "END:VCARD\n");
946         return TRUE;
947 }