2013-02-20 [colin] 3.9.0cvs83
[claws.git] / src / plugins / tnef_parse / ytnef.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2008 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 <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include "ytnef.h"
34 #include "tnef-errors.h"
35 #include "mapi.h"
36 #include "mapidefs.h"
37 #include "mapitags.h"
38 #include "config.h"
39
40 #include <glib.h>
41 #include <glib/gstdio.h>
42
43 #define RTF_PREBUF "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript \\fdecor MS Sans SerifSymbolArialTimes New RomanCourier{\\colortbl\\red0\\green0\\blue0\n\r\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx"
44 #define DEBUG(lvl, curlvl, msg) \
45         if ((lvl) >= (curlvl)) \
46             printf("DEBUG(%i/%i): %s\n", curlvl, lvl,  msg);
47 #define DEBUG1(lvl, curlvl, msg, var1) \
48         if ((lvl) >= (curlvl)) { \
49             printf("DEBUG(%i/%i):", curlvl, lvl); \
50             printf(msg, var1); \
51             printf("\n"); \
52         }
53 #define DEBUG2(lvl, curlvl, msg, var1, var2) \
54         if ((lvl) >= (curlvl)) { \
55             printf("DEBUG(%i/%i):", curlvl, lvl); \
56             printf(msg, var1, var2); \
57             printf("\n"); \
58         }
59 #define DEBUG3(lvl, curlvl, msg, var1, var2, var3) \
60         if ((lvl) >= (curlvl)) { \
61             printf("DEBUG(%i/%i):", curlvl, lvl); \
62             printf(msg, var1, var2,var3); \
63             printf("\n"); \
64         }
65
66 #ifndef MIN
67 #define MIN(x,y) (((x)<(y))?(x):(y))
68 #endif
69
70 void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p);
71 void SetFlip(void);
72
73 int TNEFDefaultHandler STD_ARGLIST;
74 int TNEFAttachmentFilename STD_ARGLIST;
75 int TNEFAttachmentSave STD_ARGLIST;
76 int TNEFDetailedPrint STD_ARGLIST;
77 int TNEFHexBreakdown STD_ARGLIST;
78 int TNEFBody STD_ARGLIST;
79 int TNEFRendData STD_ARGLIST;
80 int TNEFDateHandler STD_ARGLIST;
81 int TNEFPriority  STD_ARGLIST;
82 int TNEFVersion  STD_ARGLIST;
83 int TNEFMapiProperties STD_ARGLIST;
84 int TNEFIcon STD_ARGLIST;
85 int TNEFSubjectHandler STD_ARGLIST;
86 int TNEFFromHandler STD_ARGLIST;
87 int TNEFRecipTable STD_ARGLIST;
88 int TNEFAttachmentMAPI STD_ARGLIST;
89 int TNEFSentFor STD_ARGLIST;
90 int TNEFMessageClass STD_ARGLIST;
91 int TNEFMessageID STD_ARGLIST;
92 int TNEFParentID STD_ARGLIST;
93 int TNEFOriginalMsgClass STD_ARGLIST;
94 int TNEFCodePage STD_ARGLIST;
95
96
97 BYTE *TNEFFileContents=NULL;
98 DWORD TNEFFileContentsSize;
99 BYTE *TNEFFileIcon=NULL;
100 DWORD TNEFFileIconSize;
101
102 TNEFHandler TNEFList[] = {
103         {attNull,                    "Null",                        TNEFDefaultHandler},
104         {attFrom,                    "From",                        TNEFFromHandler},
105         {attSubject,                 "Subject",                     TNEFSubjectHandler},
106         {attDateSent,                "Date Sent",                   TNEFDateHandler},
107         {attDateRecd,                "Date Received",               TNEFDateHandler},
108         {attMessageStatus,           "Message Status",              TNEFDefaultHandler},
109         {attMessageClass,            "Message Class",               TNEFMessageClass},
110         {attMessageID,               "Message ID",                  TNEFMessageID},
111         {attParentID,                "Parent ID",                   TNEFParentID},
112         {attConversationID,          "Conversation ID",             TNEFDefaultHandler},
113         {attBody,                    "Body",                        TNEFBody},
114         {attPriority,                "Priority",                    TNEFPriority},
115         {attAttachData,              "Attach Data",                 TNEFAttachmentSave},
116         {attAttachTitle,             "Attach Title",                TNEFAttachmentFilename},
117         {attAttachMetaFile,          "Attach Meta-File",            TNEFIcon},
118         {attAttachCreateDate,        "Attachment Create Date",      TNEFDateHandler},
119         {attAttachModifyDate,        "Attachment Modify Date",      TNEFDateHandler},
120         {attDateModified,            "Date Modified",               TNEFDateHandler},
121         {attAttachTransportFilename, "Attachment Transport name",   TNEFDefaultHandler},
122         {attAttachRenddata,          "Attachment Display info",     TNEFRendData},
123         {attMAPIProps,               "MAPI Properties",             TNEFMapiProperties},
124         {attRecipTable,              "Recip Table",                 TNEFRecipTable},
125         {attAttachment,              "Attachment",                  TNEFAttachmentMAPI},
126         {attTnefVersion,             "TNEF Version",                TNEFVersion},
127         {attOemCodepage,             "OEM CodePage",                TNEFCodePage},
128         {attOriginalMessageClass,    "Original Message Class",      TNEFOriginalMsgClass},
129         {attOwner,                   "Owner",                       TNEFDefaultHandler},
130         {attSentFor,                 "Sent For",                    TNEFSentFor},
131         {attDelegate,                "Delegate",                    TNEFDefaultHandler},
132         {attDateStart,               "Date Start",                  TNEFDateHandler},
133         {attDateEnd,                 "Date End",                    TNEFDateHandler},
134         {attAidOwner,                "Aid Owner",                   TNEFDefaultHandler},
135         {attRequestRes,              "Request Response",            TNEFDefaultHandler} };
136
137
138 WORD SwapWord(BYTE *p) 
139 {
140     WORD *word_ptr;
141 #ifdef WORDS_BIGENDIAN
142     BYTE bytes[2];
143     bytes[0] = p[1];
144     bytes[1] = p[0];
145     word_ptr = (WORD*)&(bytes[0]);
146 #else
147     word_ptr = (WORD*)p;
148 #endif
149     return *word_ptr;
150 }
151
152 DWORD SwapDWord(BYTE *p)
153 {
154     DWORD *dword_ptr;
155 #ifdef WORDS_BIGENDIAN
156     BYTE bytes[4];
157     bytes[0] = p[3];
158     bytes[1] = p[2];
159     bytes[2] = p[1];
160     bytes[3] = p[0];
161     dword_ptr = (DWORD*)&(bytes[0]);
162 #else
163     dword_ptr = (DWORD*)p;
164 #endif
165     return *dword_ptr;
166 }
167
168 DDWORD SwapDDWord(BYTE *p)
169 {
170     DDWORD *ddword_ptr;
171 #ifdef WORDS_BIGENDIAN
172     BYTE bytes[8];
173     bytes[0] = p[7];
174     bytes[1] = p[6];
175     bytes[2] = p[5];
176     bytes[3] = p[4];
177     bytes[4] = p[3];
178     bytes[5] = p[2];
179     bytes[6] = p[1];
180     bytes[7] = p[0];
181     ddword_ptr = (DDWORD*)&(bytes[0]);
182 #else
183     ddword_ptr = (DDWORD*)p;
184 #endif
185     return *ddword_ptr;
186 }
187
188 /* convert 16-bit unicode to UTF8 unicode */
189 char* to_utf8(int len, char* buf)
190 {
191     int i, j = 0;
192     /* worst case length */
193     char *utf8 = malloc(3 * len/2 + 1);
194
195     for (i=0; i<len-1; i+=2) {
196         unsigned int c = SwapWord(buf+i);
197         if (c <= 0x007f) {
198             utf8[j++] = 0x00 | ((c & 0x007f) >> 0);
199         }
200         else if (c < 0x07ff) {
201             utf8[j++] = 0xc0 | ((c & 0x07c0) >> 6);
202             utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
203         }
204         else {
205             utf8[j++] = 0xe0 | ((c & 0xf000) >> 12);
206             utf8[j++] = 0x80 | ((c & 0x0fc0) >> 6);
207             utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
208         }
209     }
210
211     /* just in case the original was not null terminated */
212     utf8[j++] = '\0';
213
214     return utf8;
215 }
216
217
218 // -----------------------------------------------------------------------------
219 int TNEFDefaultHandler STD_ARGLIST {
220     if (TNEF->Debug >= 1) 
221         printf("%s: [%i] %s\n", TNEFList[id].name, size, data);
222     return 0;
223 }
224
225 // -----------------------------------------------------------------------------
226 int TNEFCodePage STD_ARGLIST {
227     TNEF->CodePage.size = size;
228     TNEF->CodePage.data = calloc(size, sizeof(BYTE));
229     memcpy(TNEF->CodePage.data, data, size);
230     return 0;
231 }
232
233 // -----------------------------------------------------------------------------
234 int TNEFParentID STD_ARGLIST {
235     memcpy(TNEF->parentID, data, MIN(size,sizeof(TNEF->parentID)));
236     return 0;
237 }
238 // -----------------------------------------------------------------------------
239 int TNEFMessageID STD_ARGLIST {
240     memcpy(TNEF->messageID, data, MIN(size,sizeof(TNEF->messageID)));
241     return 0;
242 }
243 // -----------------------------------------------------------------------------
244 int TNEFBody STD_ARGLIST {
245     TNEF->body.size = size;
246     TNEF->body.data = calloc(size, sizeof(BYTE));
247     memcpy(TNEF->body.data, data, size);
248     return 0;
249 }
250 // -----------------------------------------------------------------------------
251 int TNEFOriginalMsgClass STD_ARGLIST {
252     TNEF->OriginalMessageClass.size = size;
253     TNEF->OriginalMessageClass.data = calloc(size, sizeof(BYTE));
254     memcpy(TNEF->OriginalMessageClass.data, data, size);
255     return 0;
256 }
257 // -----------------------------------------------------------------------------
258 int TNEFMessageClass STD_ARGLIST {
259     memcpy(TNEF->messageClass, data, MIN(size,sizeof(TNEF->messageClass)));
260     return 0;
261 }
262 // -----------------------------------------------------------------------------
263 int TNEFFromHandler STD_ARGLIST {
264     TNEF->from.data = calloc(size, sizeof(BYTE));
265     TNEF->from.size = size;
266     memcpy(TNEF->from.data, data,size);
267     return 0;
268 }
269 // -----------------------------------------------------------------------------
270 int TNEFSubjectHandler STD_ARGLIST {
271     TNEF->subject.data = calloc(size, sizeof(BYTE));
272     TNEF->subject.size = size;
273     memcpy(TNEF->subject.data, data,size);
274     return 0;
275 }
276
277 // -----------------------------------------------------------------------------
278 int TNEFRendData STD_ARGLIST {
279     Attachment *p;
280     // Find the last attachment.
281     p = &(TNEF->starting_attach);
282     while (p->next!=NULL) p=p->next;
283
284     // Add a new one
285     p->next = calloc(1,sizeof(Attachment));
286     p=p->next;
287
288     TNEFInitAttachment(p);
289     
290     memcpy(&(p->RenderData), data, sizeof(renddata));
291     return 0;
292 }
293
294 // -----------------------------------------------------------------------------
295 int TNEFVersion STD_ARGLIST {
296     WORD major;
297     WORD minor;
298     major = SwapWord(data+2);
299     minor = SwapWord(data);
300            
301     sprintf(TNEF->version, "TNEF%i.%i", major, minor);
302     return 0;
303 }
304
305 // -----------------------------------------------------------------------------
306 int TNEFIcon STD_ARGLIST {
307     Attachment *p;
308     // Find the last attachment.
309     p = &(TNEF->starting_attach);
310     while (p->next!=NULL) p=p->next;
311
312     p->IconData.size = size;
313     p->IconData.data = calloc(size, sizeof(BYTE));
314     memcpy(p->IconData.data, data, size);
315     return 0;
316 }
317
318 // -----------------------------------------------------------------------------
319 int TNEFRecipTable STD_ARGLIST {
320     DWORD count;
321     BYTE *d;
322     int current_row;
323     int propcount;
324     int current_prop;
325
326     d = data;
327     count = SwapDWord(d);
328     d += 4;
329 //    printf("Recipient Table containing %u rows\n", count);
330
331     return 0;
332
333     for(current_row=0; current_row<count; current_row++) {
334         propcount = SwapDWord(d);
335         if (TNEF->Debug >= 1) 
336             printf("> Row %i contains %i properties\n", current_row, propcount);
337         d+=4;
338         for(current_prop=0; current_prop<propcount; current_prop++) {
339
340
341         }
342     }
343     return 0;
344 }
345 // -----------------------------------------------------------------------------
346 int TNEFAttachmentMAPI STD_ARGLIST {
347     Attachment *p;
348     // Find the last attachment.
349     //
350     p = &(TNEF->starting_attach);
351     while (p->next!=NULL) p=p->next;
352     TNEFFillMapi(TNEF, data, size, &(p->MAPI));
353
354     return 0;
355 }
356 // -----------------------------------------------------------------------------
357 int TNEFMapiProperties STD_ARGLIST {
358     TNEFFillMapi(TNEF, data, size, &(TNEF->MapiProperties));
359     return 0;
360 }
361
362 void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) {
363     int i,j;
364     DWORD num;
365     BYTE *d;
366     MAPIProperty *mp;
367     DWORD type;
368     DWORD length;
369     variableLength *vl;
370
371     WORD temp_word;
372     DWORD temp_dword;
373     DDWORD temp_ddword;
374     int count=-1;
375     int offset;
376     
377     d = data;
378     p->count = SwapDWord(data);
379     d += 4;
380     p->properties = calloc(p->count, sizeof(MAPIProperty));
381     mp = p->properties;
382
383     for(i=0; i<p->count; i++) {
384         if (count == -1) {
385             mp->id = SwapDWord(d);
386             d+=4;
387             mp->custom = 0;
388             mp->count = 1;
389             mp->namedproperty = 0;
390             length = -1;
391             if (PROP_ID(mp->id) >= 0x8000) {
392                 // Read the GUID
393                 memcpy(&(mp->guid[0]), d, 16);
394                 d+=16;
395     
396                 length = SwapDWord(d);
397                 d+=sizeof(DWORD);
398                 if (length > 0) {
399                     mp->namedproperty = length;
400                     mp->propnames = calloc(length, sizeof(variableLength));
401                     while (length > 0) {
402                         type = SwapDWord(d);
403                         mp->propnames[length-1].data = calloc(type, sizeof(BYTE));
404                         mp->propnames[length-1].size = type;
405                         d+=4;
406                         for(j=0; j<(type>>1); j++) {
407                             mp->propnames[length-1].data[j] = d[j*2];
408                         }
409                         d += type + ((type % 4) ? (4 - type%4) : 0);
410                         length--;
411                     }
412                 } else {
413                     // READ the type
414                     type = SwapDWord(d);
415                     d+=sizeof(DWORD);
416                     mp->id = PROP_TAG(PROP_TYPE(mp->id), type);
417                 }
418                 mp->custom = 1;
419             }
420             
421             //printf("Type id = %04x\n", PROP_TYPE(mp->id));
422             if (PROP_TYPE(mp->id) & MV_FLAG) {
423                 mp->id = PROP_TAG(PROP_TYPE(mp->id) - MV_FLAG, PROP_ID(mp->id));
424                 mp->count = SwapDWord(d);
425                 d+=4;
426                 count = 0;
427             }
428             mp->data = calloc(mp->count, sizeof(variableLength));
429             vl = mp->data;
430         } else {
431             i--;
432             count++;
433             vl = &(mp->data[count]);
434         }
435
436         switch (PROP_TYPE(mp->id)) {
437             case PT_BINARY:
438             case PT_OBJECT:
439             case PT_STRING8:
440             case PT_UNICODE:
441                 // First number of objects (assume 1 for now)
442                 if (count == -1) {
443                     vl->size = SwapDWord(d);
444                     d+=4;
445                 }
446                 // now size of object
447                 vl->size = SwapDWord(d);
448                 d+=4;
449
450                 // now actual object
451                 if (PROP_TYPE(mp->id) == PT_UNICODE) {
452                     vl->data = to_utf8(vl->size, d);
453                 }
454                 else {
455                     vl->data = calloc(vl->size, sizeof(BYTE));
456                     memcpy(vl->data, d, vl->size);
457                 }
458
459                 // Make sure to read in a multiple of 4
460                 num = vl->size;
461                 offset = ((num % 4) ? (4 - num%4) : 0);
462                 d += num + ((num % 4) ? (4 - num%4) : 0);
463                 break;
464
465             case PT_I2:
466                 // Read in 2 bytes, but proceed by 4 bytes
467                 vl->size = 2;
468                 vl->data = calloc(vl->size, sizeof(WORD));
469                 temp_word = SwapWord(d);
470                 memcpy(vl->data, &temp_word, vl->size);
471                 d += 4;
472                 break;
473             case PT_BOOLEAN:
474             case PT_LONG:
475             case PT_R4:
476             case PT_CURRENCY:
477             case PT_APPTIME:
478             case PT_ERROR:
479                 vl->size = 4;
480                 vl->data = calloc(vl->size, sizeof(BYTE));
481                 temp_dword = SwapDWord(d);
482                 memcpy(vl->data, &temp_dword, vl->size);
483                 d += 4;
484                 break;
485             case PT_DOUBLE:
486             case PT_I8:
487             case PT_SYSTIME:
488                 vl->size = 8;
489                 vl->data = calloc(vl->size, sizeof(BYTE));
490                 temp_ddword = SwapDDWord(d);
491                 memcpy(vl->data, &temp_ddword, vl->size);
492                 d+=8;
493                 break;
494         }
495         if (count == (mp->count-1)) {
496             count = -1;
497         }
498         if (count == -1) {
499             mp++;
500         }
501     }
502     if ((d-data) < size) {
503         if (TNEF->Debug >= 1)  {
504             printf("ERROR DURING MAPI READ\n");
505             printf("Read %i bytes, Expected %i bytes\n", (d-data), size);
506             printf("%i bytes missing\n", size - (d-data));
507         }
508     } else if ((d-data) > size){
509         if (TNEF->Debug >= 1)  {
510             printf("ERROR DURING MAPI READ\n");
511             printf("Read %i bytes, Expected %i bytes\n", (d-data), size);
512             printf("%i bytes extra\n", (d-data)-size);
513         }
514     }
515     return;
516 }
517 // -----------------------------------------------------------------------------
518 int TNEFSentFor STD_ARGLIST {
519     WORD name_length, addr_length;
520     BYTE *d;
521
522     d=data;
523
524     while ((d-data)<size) {
525         name_length = SwapWord(d);
526         d+=sizeof(WORD);
527         if (TNEF->Debug >= 1) 
528             printf("Sent For : %s", d);
529         d+=name_length;
530
531         addr_length = SwapWord(d);
532         d+=sizeof(WORD);
533         if (TNEF->Debug >= 1) 
534             printf("<%s>\n", d);
535         d+=addr_length;
536     }
537     return 0;
538 }
539 // -----------------------------------------------------------------------------
540 int TNEFDateHandler STD_ARGLIST {
541     dtr *Date;
542     Attachment *p;
543     WORD *tmp_src, *tmp_dst;
544     int i;
545
546     p = &(TNEF->starting_attach);
547     switch (TNEFList[id].id) {
548         case attDateSent: Date = &(TNEF->dateSent); break;
549         case attDateRecd: Date = &(TNEF->dateReceived); break;
550         case attDateModified: Date = &(TNEF->dateModified); break;
551         case attDateStart: Date = &(TNEF->DateStart); break;
552         case attDateEnd:  Date = &(TNEF->DateEnd); break;
553         case attAttachCreateDate:
554             while (p->next!=NULL) p=p->next;
555             Date = &(p->CreateDate);
556             break;
557         case attAttachModifyDate:
558             while (p->next!=NULL) p=p->next;
559             Date = &(p->ModifyDate);
560             break;
561         default:
562             if (TNEF->Debug >= 1)
563                 printf("MISSING CASE\n");
564             return YTNEF_UNKNOWN_PROPERTY;
565     }
566
567     tmp_src = (WORD*)data;
568     tmp_dst = (WORD*)Date;
569     for(i=0;i<sizeof(dtr)/sizeof(WORD);i++) {
570         *tmp_dst++ = SwapWord((BYTE*)tmp_src++);
571     }
572     return 0;
573 }
574
575 void TNEFPrintDate(dtr Date) {
576     char days[7][15] = {"Sunday", "Monday", "Tuesday", 
577             "Wednesday", "Thursday", "Friday", "Saturday"};
578     char months[12][15] = {"January", "February", "March", "April", "May",
579             "June", "July", "August", "September", "October", "November",
580             "December"};
581
582     if (Date.wDayOfWeek < 7) 
583         printf("%s ", days[Date.wDayOfWeek]);
584     
585     if ((Date.wMonth < 13) && (Date.wMonth>0)) 
586         printf("%s ", months[Date.wMonth-1]);
587
588     printf("%hu, %hu ", Date.wDay, Date.wYear);
589
590     if (Date.wHour>12) 
591         printf("%hu:%02hu:%02hu pm", (Date.wHour-12), 
592                 Date.wMinute, Date.wSecond);
593     else if (Date.wHour == 12) 
594         printf("%hu:%02hu:%02hu pm", (Date.wHour), 
595                 Date.wMinute, Date.wSecond);
596     else
597         printf("%hu:%02hu:%02hu am", Date.wHour, 
598                 Date.wMinute, Date.wSecond);
599 }
600 // -----------------------------------------------------------------------------
601 int TNEFHexBreakdown STD_ARGLIST {
602     int i;
603     if (TNEF->Debug == 0) 
604         return 0;
605
606     printf("%s: [%i bytes] \n", TNEFList[id].name, size);
607
608     for(i=0; i<size; i++) {
609         printf("%02x ", data[i]);
610         if ((i+1)%16 == 0) printf("\n");
611     }
612     printf("\n");
613     return 0;
614 }
615     
616 // -----------------------------------------------------------------------------
617 int TNEFDetailedPrint STD_ARGLIST {
618     int i;
619     if (TNEF->Debug == 0) 
620         return 0;
621
622     printf("%s: [%i bytes] \n", TNEFList[id].name, size);
623
624     for(i=0; i<size; i++) {
625         printf("%c", data[i]);
626     }
627     printf("\n");
628     return 0;
629 }
630
631 // -----------------------------------------------------------------------------
632 int TNEFAttachmentFilename STD_ARGLIST {
633     Attachment *p;
634     p = &(TNEF->starting_attach);
635     while (p->next!=NULL) p=p->next;
636
637     p->Title.size = size;
638     p->Title.data = calloc(size, sizeof(BYTE));
639     memcpy(p->Title.data, data, size);
640
641     return 0;
642 }
643
644 // -----------------------------------------------------------------------------
645 int TNEFAttachmentSave STD_ARGLIST {
646     Attachment *p;
647     p = &(TNEF->starting_attach);
648     while (p->next!=NULL) p=p->next;
649
650     p->FileData.data = calloc(sizeof(unsigned char), size);
651     p->FileData.size = size;
652
653     memcpy(p->FileData.data, data, size);
654
655     return 0;
656 }
657
658 // -----------------------------------------------------------------------------
659 int TNEFPriority STD_ARGLIST {
660     DWORD value;
661
662     value = SwapDWord(data);
663     switch (value) {
664         case 3:
665             sprintf((TNEF->priority), "high");
666             break;
667         case 2:
668             sprintf((TNEF->priority), "normal");
669             break;
670         case 1: 
671             sprintf((TNEF->priority), "low");
672             break;
673         default: 
674             sprintf((TNEF->priority), "N/A");
675             break;
676     }
677     return 0;
678 }
679
680 // -----------------------------------------------------------------------------
681 int TNEFCheckForSignature(DWORD sig) {
682     DWORD signature = 0x223E9F78;
683
684     sig = SwapDWord((BYTE*)&sig);
685
686     if (signature == sig) {
687         return 0;
688     } else {
689         return YTNEF_NOT_TNEF_STREAM;
690     }
691 }
692
693 // -----------------------------------------------------------------------------
694 int TNEFGetKey(TNEFStruct *TNEF, WORD *key) {
695     if (TNEF->IO.ReadProc (&(TNEF->IO), sizeof(WORD),1, key) < 1) {
696         if (TNEF->Debug >= 1) 
697             printf("Error reading Key\n");
698         return YTNEF_ERROR_READING_DATA;
699     }
700     *key = SwapWord((BYTE*)key);
701
702     DEBUG1(TNEF->Debug, 2, "Key = %i", *key);
703     return 0;
704 }
705
706 // -----------------------------------------------------------------------------
707 int TNEFGetHeader(TNEFStruct *TNEF, DWORD *type, DWORD *size) {
708     BYTE component;
709
710     DEBUG(TNEF->Debug, 2, "About to read Component");
711     if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(BYTE),1, &component) < 1) {
712         return YTNEF_ERROR_READING_DATA;
713     }
714
715
716     DEBUG(TNEF->Debug, 2, "About to read type");
717     if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, type)  < 1) {
718         if (TNEF->Debug >= 1) 
719             printf("ERROR: Error reading type\n");
720         return YTNEF_ERROR_READING_DATA;
721     }
722     DEBUG1(TNEF->Debug, 2, "Type = %i", *type);
723
724
725     DEBUG(TNEF->Debug, 2, "About to read size");
726     if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, size) < 1) {
727         if (TNEF->Debug >= 1) 
728             printf("ERROR: Error reading size\n");
729         return YTNEF_ERROR_READING_DATA;
730     }
731
732
733     DEBUG1(TNEF->Debug, 2, "Size = %i", *size);
734
735     *type = SwapDWord((BYTE*)type);
736     *size = SwapDWord((BYTE*)size);
737
738     return 0;
739 }
740
741 // -----------------------------------------------------------------------------
742 int TNEFRawRead(TNEFStruct *TNEF, BYTE *data, DWORD size, WORD *checksum) {
743     WORD temp;
744     int i;
745
746     if (TNEF->IO.ReadProc(&TNEF->IO, sizeof(BYTE), size, data) < size) {
747         if (TNEF->Debug >= 1) 
748             printf("ERROR: Error reading data\n");
749         return YTNEF_ERROR_READING_DATA;
750     }
751
752
753     if (checksum != NULL) {
754         *checksum = 0;
755         for(i=0; i<size; i++) {
756             temp = data[i];
757             *checksum = (*checksum + temp);
758         }
759     }
760     return 0;
761 }
762
763 #define INITVARLENGTH(x) (x).data = NULL; (x).size = 0;
764 #define INITDTR(x) (x).wYear=0; (x).wMonth=0; (x).wDay=0; \
765                    (x).wHour=0; (x).wMinute=0; (x).wSecond=0; \
766                    (x).wDayOfWeek=0;
767 #define INITSTR(x) memset((x), 0, sizeof(x));
768 void TNEFInitMapi(MAPIProps *p)
769 {
770     p->count = 0;
771     p->properties = NULL;
772 }
773
774 void TNEFInitAttachment(Attachment *p)
775 {
776     INITDTR(p->Date);
777     INITVARLENGTH(p->Title);
778     INITVARLENGTH(p->MetaFile);
779     INITDTR(p->CreateDate);
780     INITDTR(p->ModifyDate);
781     INITVARLENGTH(p->TransportFilename);
782     INITVARLENGTH(p->FileData);
783     INITVARLENGTH(p->IconData);
784     memset(&(p->RenderData), 0, sizeof(renddata));
785     TNEFInitMapi(&(p->MAPI));
786     p->next = NULL;
787 }
788
789 void TNEFInitialize(TNEFStruct *TNEF)
790 {
791     INITSTR(TNEF->version);
792     INITVARLENGTH(TNEF->from);
793     INITVARLENGTH(TNEF->subject);
794     INITDTR(TNEF->dateSent);
795     INITDTR(TNEF->dateReceived);
796
797     INITSTR(TNEF->messageStatus);
798     INITSTR(TNEF->messageClass);
799     INITSTR(TNEF->messageID);
800     INITSTR(TNEF->parentID);
801     INITSTR(TNEF->conversationID);
802     INITVARLENGTH(TNEF->body);
803     INITSTR(TNEF->priority);
804     TNEFInitAttachment(&(TNEF->starting_attach));
805     INITDTR(TNEF->dateModified);
806     TNEFInitMapi(&(TNEF->MapiProperties));
807     INITVARLENGTH(TNEF->CodePage);
808     INITVARLENGTH(TNEF->OriginalMessageClass);
809     INITVARLENGTH(TNEF->Owner);
810     INITVARLENGTH(TNEF->SentFor);
811     INITVARLENGTH(TNEF->Delegate);
812     INITDTR(TNEF->DateStart);
813     INITDTR(TNEF->DateEnd);
814     INITVARLENGTH(TNEF->AidOwner);
815     TNEF->RequestRes=0;
816     TNEF->IO.data = NULL;
817     TNEF->IO.InitProc = NULL;
818     TNEF->IO.ReadProc = NULL;
819     TNEF->IO.CloseProc = NULL;
820 }
821 #undef INITVARLENGTH
822 #undef INITDTR
823 #undef INITSTR
824
825 #define FREEVARLENGTH(x) if ((x).size > 0) { \
826                             free((x).data); (x).size =0; }
827 void TNEFFree(TNEFStruct *TNEF) {
828     Attachment *p, *store;
829
830     FREEVARLENGTH(TNEF->from);
831     FREEVARLENGTH(TNEF->subject);
832     FREEVARLENGTH(TNEF->body);
833     FREEVARLENGTH(TNEF->CodePage);
834     FREEVARLENGTH(TNEF->OriginalMessageClass);
835     FREEVARLENGTH(TNEF->Owner);
836     FREEVARLENGTH(TNEF->SentFor);
837     FREEVARLENGTH(TNEF->Delegate);
838     FREEVARLENGTH(TNEF->AidOwner);
839     TNEFFreeMapiProps(&(TNEF->MapiProperties));
840
841     p = TNEF->starting_attach.next;
842     while (p != NULL) {
843         TNEFFreeAttachment(p);
844         store = p->next;
845         free(p);
846         p=store;
847     }
848 }
849
850 void TNEFFreeAttachment(Attachment *p)
851 {
852     FREEVARLENGTH(p->Title);
853     FREEVARLENGTH(p->MetaFile);
854     FREEVARLENGTH(p->TransportFilename);
855     FREEVARLENGTH(p->FileData);
856     FREEVARLENGTH(p->IconData);
857     TNEFFreeMapiProps(&(p->MAPI));
858 }
859
860 void TNEFFreeMapiProps(MAPIProps *p)
861 {
862     int i,j;
863     for(i=0; i<p->count; i++) {
864         for(j=0; j<p->properties[i].count; j++) {
865             FREEVARLENGTH(p->properties[i].data[j]);
866         }
867         free(p->properties[i].data);
868     }
869     free(p->properties);
870     p->count = 0;
871 }
872 #undef FREEVARLENGTH
873
874 // Procedures to handle File IO
875 int TNEFFile_Open (TNEFIOStruct *IO) {
876     TNEFFileInfo *finfo;
877     finfo = (TNEFFileInfo*)IO->data;
878
879     DEBUG1(finfo->Debug, 3, "Opening %s", finfo->filename);
880     if ((finfo->fptr = g_fopen(finfo->filename, "rb")) == NULL) {
881         return -1;
882     } else {
883         return 0;
884     }
885 }
886
887 int TNEFFile_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
888     TNEFFileInfo *finfo;
889     finfo = (TNEFFileInfo*)IO->data;
890
891     DEBUG2(finfo->Debug, 3, "Reading %i blocks of %i size", count, size);
892     if (finfo->fptr != NULL) {
893         return fread((BYTE*)dest, size, count, finfo->fptr);
894     } else {
895         return -1;
896     }
897 }
898
899 int TNEFFile_Close (TNEFIOStruct *IO) {
900     TNEFFileInfo *finfo;
901     finfo = (TNEFFileInfo*)IO->data;
902
903     DEBUG1(finfo->Debug, 3, "Closing file %s", finfo->filename);
904     if (finfo->fptr != NULL) {
905         fclose(finfo->fptr);
906         finfo->fptr = NULL;
907     }
908     return 0;
909 }
910
911 int TNEFParseFile(char *filename, TNEFStruct *TNEF) {
912     TNEFFileInfo finfo;
913
914     if (TNEF->Debug >= 1) 
915         printf("Attempting to parse %s...\n", filename);
916
917
918     finfo.filename = filename;
919     finfo.fptr = NULL;
920     finfo.Debug = TNEF->Debug;
921     TNEF->IO.data = (void*)&finfo;
922     TNEF->IO.InitProc = TNEFFile_Open;
923     TNEF->IO.ReadProc = TNEFFile_Read;
924     TNEF->IO.CloseProc = TNEFFile_Close;
925     return TNEFParse(TNEF);
926 }
927 //-------------------------------------------------------------
928 // Procedures to handle Memory IO
929 int TNEFMemory_Open (TNEFIOStruct *IO) {
930     TNEFMemInfo *minfo;
931     minfo = (TNEFMemInfo*)IO->data;
932
933     minfo->ptr = minfo->dataStart;
934     return 0;
935 }
936
937 int TNEFMemory_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
938     TNEFMemInfo *minfo;
939     int length;
940     long max;
941     minfo = (TNEFMemInfo*)IO->data;
942
943     length = count*size;
944     max = (minfo->dataStart + minfo->size) - (minfo->ptr);
945     if (length > max) {
946         return -1;
947     }
948
949     DEBUG1(minfo->Debug, 3, "Copying %i bytes", length);
950
951     memcpy(dest, minfo->ptr, length);
952     minfo->ptr+=length;
953     return count;
954 }
955
956 int TNEFMemory_Close (TNEFIOStruct *IO) {
957     // Do nothing, really...
958     return 0;
959 }
960
961 int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF) {
962     TNEFMemInfo minfo;
963
964     DEBUG(TNEF->Debug, 1, "Attempting to parse memory block...\n");
965
966     minfo.dataStart = memory;
967     minfo.ptr = memory;
968     minfo.size = size;
969     minfo.Debug = TNEF->Debug;
970     TNEF->IO.data = (void*)&minfo;
971     TNEF->IO.InitProc = TNEFMemory_Open;
972     TNEF->IO.ReadProc = TNEFMemory_Read;
973     TNEF->IO.CloseProc = TNEFMemory_Close;
974     return TNEFParse(TNEF);
975 }
976
977
978 int TNEFParse(TNEFStruct *TNEF) {
979     WORD key;
980     DWORD type;
981     DWORD size;
982     DWORD signature;
983     BYTE *data;
984     WORD checksum, header_checksum;
985     int i;
986
987     if (TNEF->IO.ReadProc == NULL) {
988         printf("ERROR: Setup incorrectly: No ReadProc\n");
989         return YTNEF_INCORRECT_SETUP;
990     }
991
992     if (TNEF->IO.InitProc != NULL) {
993         DEBUG(TNEF->Debug, 2, "About to initialize");
994         if (TNEF->IO.InitProc (&TNEF->IO) != 0) {
995             return YTNEF_CANNOT_INIT_DATA;
996         }
997         DEBUG(TNEF->Debug, 2, "Initialization finished");
998     }
999    
1000     DEBUG(TNEF->Debug, 2, "Reading Signature");
1001     if (TNEF->IO.ReadProc (&TNEF->IO, sizeof(DWORD), 1, &signature) < 1) {
1002         printf("ERROR: Error reading signature\n");
1003         if (TNEF->IO.CloseProc != NULL) {
1004             TNEF->IO.CloseProc (&TNEF->IO);
1005         }
1006         return YTNEF_ERROR_READING_DATA;
1007     }
1008
1009     DEBUG(TNEF->Debug, 2, "Checking Signature");
1010     if (TNEFCheckForSignature(signature) < 0) {
1011         printf("ERROR: Signature does not match. Not TNEF.\n");
1012         if (TNEF->IO.CloseProc != NULL) {
1013             TNEF->IO.CloseProc (&TNEF->IO);
1014         }
1015         return YTNEF_NOT_TNEF_STREAM;
1016     }
1017
1018     DEBUG(TNEF->Debug, 2, "Reading Key.");
1019
1020     if (TNEFGetKey(TNEF, &key) < 0) {
1021         printf("ERROR: Unable to retrieve key.\n");
1022         if (TNEF->IO.CloseProc != NULL) {
1023             TNEF->IO.CloseProc (&TNEF->IO);
1024         }
1025         return YTNEF_NO_KEY;
1026     }
1027
1028     DEBUG(TNEF->Debug, 2, "Starting Full Processing.");
1029
1030     while (TNEFGetHeader(TNEF, &type, &size) == 0) {
1031         DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size);
1032         if (size > 0) {
1033             data = calloc(size, sizeof(BYTE));
1034             if (TNEFRawRead(TNEF, data, size, &header_checksum)< 0) {
1035                 printf("ERROR: Unable to read data.\n");
1036                 if (TNEF->IO.CloseProc != NULL) {
1037                     TNEF->IO.CloseProc (&TNEF->IO);
1038                 }
1039                 free(data);
1040                 return YTNEF_ERROR_READING_DATA;
1041             }
1042             if (TNEFRawRead(TNEF, (BYTE *)&checksum, 2, NULL) < 0) {
1043                 printf("ERROR: Unable to read checksum.\n");
1044                 if (TNEF->IO.CloseProc != NULL) {
1045                     TNEF->IO.CloseProc (&TNEF->IO);
1046                 }
1047                 free(data);
1048                 return YTNEF_ERROR_READING_DATA;
1049             }
1050             checksum = SwapWord((BYTE*)&checksum);
1051             if (checksum != header_checksum) {
1052                 printf("ERROR: Checksum mismatch. Data corruption?:\n");
1053                 if (TNEF->IO.CloseProc != NULL) {
1054                     TNEF->IO.CloseProc (&TNEF->IO);
1055                 }
1056                 free(data);
1057                 return YTNEF_BAD_CHECKSUM;
1058             }
1059             for(i=0; i<(sizeof(TNEFList)/sizeof(TNEFHandler));i++) {
1060                 if (TNEFList[i].id == type) {
1061                     if (TNEFList[i].handler != NULL) {
1062                         if (TNEFList[i].handler(TNEF, i, data, size) < 0) {
1063                             free(data);
1064                             if (TNEF->IO.CloseProc != NULL) {
1065                                 TNEF->IO.CloseProc (&TNEF->IO);
1066                             }
1067                             return YTNEF_ERROR_IN_HANDLER;
1068                         }
1069                     } else {
1070                         DEBUG2(TNEF->Debug, 1, "No handler for %s: %i bytes",
1071                                     TNEFList[i].name, size);
1072                     }
1073                 }
1074             }
1075
1076             free(data);
1077         }
1078     }
1079
1080     if (TNEF->IO.CloseProc != NULL) {
1081         TNEF->IO.CloseProc (&TNEF->IO);
1082     }
1083     return 0;
1084
1085 }
1086
1087 // ----------------------------------------------------------------------------
1088
1089 variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID) 
1090 {
1091     int i;
1092     if (p != NULL) {
1093         for(i=0;i<p->count; i++) {
1094             if ((p->properties[i].id == ID) && (p->properties[i].custom == 1)) {
1095                 return (p->properties[i].data);
1096             }
1097         }
1098     }
1099     return MAPI_UNDEFINED;
1100 }
1101
1102 variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID)
1103 {
1104     int i;
1105     if (p != NULL) {
1106         for(i=0;i<p->count; i++) {
1107             if ((p->properties[i].id == ID) && (p->properties[i].custom == 0)) {
1108                 return (p->properties[i].data);
1109             }
1110         }
1111     }
1112     return MAPI_UNDEFINED;
1113 }
1114
1115 int MAPISysTimetoDTR(BYTE *data, dtr *thedate)
1116 {
1117     DDWORD ddword_tmp;
1118     int startingdate = 0;
1119     int tmp_date;
1120     int days_in_year = 365;
1121     unsigned int months[] = {31,28,31,30,31,30,31,31,30,31,30,31};
1122
1123     ddword_tmp = *((DDWORD*)data);
1124     ddword_tmp = ddword_tmp /10; // micro-s
1125     ddword_tmp /= 1000; // ms
1126     ddword_tmp /= 1000; // s
1127
1128     thedate->wSecond = (ddword_tmp % 60);
1129
1130     ddword_tmp /= 60; // seconds to minutes
1131     thedate->wMinute = (ddword_tmp % 60);
1132
1133     ddword_tmp /= 60; //minutes to hours
1134     thedate->wHour = (ddword_tmp % 24);
1135
1136     ddword_tmp /= 24; // Hours to days
1137
1138     // Now calculate the year based on # of days
1139     thedate->wYear = 1601;
1140     startingdate = 1; 
1141     while(ddword_tmp >= days_in_year) {
1142         ddword_tmp-=days_in_year;
1143         thedate->wYear++;
1144         days_in_year = 365;
1145         startingdate++;
1146         if ((thedate->wYear % 4) == 0) {
1147             if ((thedate->wYear % 100) == 0) {
1148                 // if the year is 1700,1800,1900, etc, then it is only 
1149                 // a leap year if exactly divisible by 400, not 4.
1150                 if ((thedate->wYear % 400) == 0) {
1151                     startingdate++;
1152                     days_in_year = 366;
1153                 }
1154             }  else {
1155                 startingdate++;
1156                 days_in_year = 366;
1157             }
1158         }
1159         startingdate %= 7;
1160     }
1161
1162     // the remaining number is the day # in this year
1163     // So now calculate the Month, & Day of month
1164     if ((thedate->wYear % 4) == 0) {
1165         // 29 days in february in a leap year
1166         months[1] = 29;
1167     }
1168
1169     tmp_date = (int)ddword_tmp;
1170     thedate->wDayOfWeek = (tmp_date + startingdate) % 7;
1171     thedate->wMonth = 0;
1172
1173     while (tmp_date > months[thedate->wMonth]) {
1174         tmp_date -= months[thedate->wMonth];
1175         thedate->wMonth++;
1176     }
1177     thedate->wMonth++;
1178     thedate->wDay = tmp_date+1;
1179     return 0;
1180 }
1181
1182 int IsCompressedRTF(variableLength *p) {
1183     unsigned int in;
1184     unsigned char *src;
1185     ULONG compressedSize, uncompressedSize, magic, crc32;
1186
1187     src = p->data;
1188     in = 0;
1189
1190     compressedSize = (ULONG)SwapDWord(src+in);
1191     in += 4;
1192     uncompressedSize = (ULONG)SwapDWord(src+in);
1193     in += 4;
1194     magic = SwapDWord(src+in);
1195     in += 4;
1196     crc32 = SwapDWord(src+in);
1197     in += 4;
1198
1199     if (magic == 0x414c454d) { 
1200         return 1;
1201     } else if (magic == 0x75465a4c) { 
1202         return 1;
1203     } else {
1204         return 0;
1205     }
1206 }
1207
1208 void MAPIPrint(MAPIProps *p)
1209 {
1210     int j, i,index, h;
1211     dtr thedate;
1212     MAPIProperty *mapi;
1213     variableLength *mapidata;
1214     variableLength vlTemp;
1215     int found;
1216
1217     for(j=0; j<p->count; j++) {
1218         mapi = &(p->properties[j]);
1219         printf("   #%i: Type: [", j);
1220         switch (PROP_TYPE(mapi->id)) {
1221             case PT_UNSPECIFIED:
1222                 printf("  NONE   "); break;
1223             case PT_NULL:
1224                 printf("  NULL   "); break;
1225             case PT_I2:
1226                 printf("   I2    "); break;
1227             case PT_LONG:
1228                 printf("  LONG   "); break;
1229             case PT_R4:
1230                 printf("   R4    "); break;
1231             case PT_DOUBLE:
1232                 printf(" DOUBLE  "); break;
1233             case PT_CURRENCY:
1234                 printf("CURRENCY "); break;
1235             case PT_APPTIME:
1236                 printf("APP TIME "); break;
1237             case PT_ERROR:
1238                 printf("  ERROR  "); break;
1239             case PT_BOOLEAN:
1240                 printf(" BOOLEAN "); break;
1241             case PT_OBJECT:
1242                 printf(" OBJECT  "); break;
1243             case PT_I8:
1244                 printf("   I8    "); break;
1245             case PT_STRING8:
1246                 printf(" STRING8 "); break;
1247             case PT_UNICODE:
1248                 printf(" UNICODE "); break;
1249             case PT_SYSTIME:
1250                 printf("SYS TIME "); break;
1251             case PT_CLSID:
1252                 printf("OLE GUID "); break;
1253             case PT_BINARY:
1254                 printf(" BINARY  "); break;
1255             default:
1256                 printf("<%x>", PROP_TYPE(mapi->id)); break;
1257         }
1258                 
1259         printf("]  Code: [");
1260         if (mapi->custom == 1) {
1261             printf("UD:x%04x", PROP_ID(mapi->id));
1262         } else {
1263             found = 0;
1264             for(index=0; index<sizeof(MPList)/sizeof(MAPIPropertyTagList); index++) {
1265                 if ((MPList[index].id == PROP_ID(mapi->id)) && (found == 0)) {
1266                     printf("%s", MPList[index].name);
1267                     found = 1;
1268                 }
1269             }
1270             if (found == 0) {
1271                 printf("0x%04x", PROP_ID(mapi->id));
1272             }
1273         }
1274         printf("]\n");
1275         if (mapi->namedproperty > 0) {
1276             for(i=0; i<mapi->namedproperty; i++) {
1277                 printf("    Name: %s\n", mapi->propnames[i].data);
1278             }
1279         }
1280         for (i=0;i<mapi->count;i++) {
1281             mapidata = &(mapi->data[i]);
1282             if (mapi->count > 1) {
1283                 printf("    [%i/%i] ", i, mapi->count);
1284             } else {
1285                 printf("    ");
1286             }
1287             printf("Size: %i", mapidata->size);
1288             switch (PROP_TYPE(mapi->id)) {
1289                 case PT_SYSTIME:
1290                     MAPISysTimetoDTR(mapidata->data, &thedate);
1291                     printf("    Value: ");
1292                     TNEFPrintDate(thedate);
1293                     printf("\n");
1294                     break;
1295                 case PT_LONG:
1296                     printf("    Value: %li\n", (long int) *(mapidata->data));
1297                     break;
1298                 case PT_I2:
1299                     printf("    Value: %hi\n", *(mapidata->data));
1300                     break;
1301                 case PT_BOOLEAN:
1302                     if (mapi->data->data[0]!=0) {
1303                         printf("    Value: True\n");
1304                     } else {
1305                         printf("    Value: False\n");
1306                     }
1307                     break;
1308                 case PT_OBJECT:
1309                     printf("\n");
1310                     break;
1311                 case PT_BINARY:
1312                     if(IsCompressedRTF(mapidata)==1) {
1313                         printf("    Detected Compressed RTF.");
1314                         printf("Decompressed text follows\n");
1315                         printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1316                         if((vlTemp.data = DecompressRTF(mapidata, &(vlTemp.size))) != NULL) {
1317                             printf("%s\n", vlTemp.data);
1318                             free(vlTemp.data);
1319                         }
1320                         printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1321                     } else {
1322                         printf("    Value: [");
1323                         for(h=0; h< mapidata->size; h++) {
1324                             if (isprint(mapidata->data[h])) 
1325                                 printf("%c", mapidata->data[h]);
1326                             else 
1327                                 printf(".");
1328
1329                         }
1330                         printf("]\n");
1331                     }
1332                     break;
1333                 case PT_STRING8:
1334                     printf("    Value: [%s]\n", mapidata->data);
1335                     if (strlen(mapidata->data) != mapidata->size-1) {
1336                         printf("Detected Hidden data: [");
1337                         for(h=0; h< mapidata->size; h++) {
1338                             if (isprint(mapidata->data[h])) 
1339                                 printf("%c", mapidata->data[h]);
1340                             else 
1341                                 printf(".");
1342
1343                         }
1344                         printf("]\n");
1345                     }
1346                     break;
1347                 default:
1348                     printf("    Value: [%s]\n", mapidata->data);
1349             }
1350         }
1351     }
1352 }
1353
1354 unsigned char *DecompressRTF(variableLength *p, int *size) {
1355     unsigned char *dst; // destination for uncompressed bytes
1356     unsigned char *src;
1357     unsigned int in;
1358     unsigned int out;
1359     variableLength comp_Prebuf;
1360     ULONG compressedSize, uncompressedSize, magic, crc32;
1361
1362     comp_Prebuf.size = strlen(RTF_PREBUF);
1363     comp_Prebuf.data = calloc(comp_Prebuf.size + 1, 1);
1364     strcpy(comp_Prebuf.data, RTF_PREBUF);
1365
1366     src = p->data;
1367     in = 0;
1368
1369     compressedSize = (ULONG)SwapDWord(src+in);
1370     in += 4;
1371     uncompressedSize = (ULONG)SwapDWord(src+in);
1372     in += 4;
1373     magic = SwapDWord(src+in);
1374     in += 4;
1375     crc32 = SwapDWord(src+in);
1376     in += 4;
1377
1378     // check size excluding the size field itself
1379     if (compressedSize != p->size - 4) {
1380         printf(" Size Mismatch: %i != %i\n", compressedSize, p->size-4);
1381         return NULL;
1382     }
1383
1384     // process the data
1385     if (magic == 0x414c454d) { 
1386         // magic number that identifies the stream as a uncompressed stream
1387         dst = calloc(uncompressedSize,1);
1388         memcpy(dst, src+4, uncompressedSize);
1389         return dst;
1390     } else if (magic == 0x75465a4c) { 
1391         // magic number that identifies the stream as a compressed stream
1392         int flagCount = 0;
1393         int flags = 0;
1394         dst = calloc(comp_Prebuf.size + uncompressedSize,1);
1395         memcpy(dst, comp_Prebuf.data, comp_Prebuf.size);
1396         out = comp_Prebuf.size;
1397         while (out < (comp_Prebuf.size+uncompressedSize)) {
1398             // each flag byte flags 8 literals/references, 1 per bit
1399             flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1;
1400             if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0 for literal
1401                 int offset = src[in++];
1402                 int length = src[in++];
1403                 int end;
1404                 offset = (offset << 4) | (length >> 4); // the offset relative to block start
1405                 length = (length & 0xF) + 2; // the number of bytes to copy
1406                 // the decompression buffer is supposed to wrap around back
1407                 // to the beginning when the end is reached. we save the
1408                 // need for such a buffer by pointing straight into the data
1409                 // buffer, and simulating this behaviour by modifying the
1410                 // pointers appropriately.
1411                 offset = (out / 4096) * 4096 + offset; 
1412                 if (offset >= out) // take from previous block
1413                         offset -= 4096;
1414                 // note: can't use System.arraycopy, because the referenced
1415                 // bytes can cross through the current out position.
1416                 end = offset + length;
1417                 while (offset < end)
1418                         dst[out++] = dst[offset++];
1419             } else { // literal
1420                 dst[out++] = src[in++];
1421             }
1422         }
1423         // copy it back without the prebuffered data
1424         src = dst;
1425         dst = calloc(uncompressedSize,1);
1426         memcpy(dst, src + comp_Prebuf.size, uncompressedSize);
1427         free(src);
1428         *size = uncompressedSize;
1429         return dst;
1430     } else { // unknown magic number
1431         printf("Unknown compression type (magic number %x)\n", magic );
1432         return NULL;
1433     }
1434 }