Clean ytnef.c warnings
[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     
376     d = data;
377     p->count = SwapDWord(data);
378     d += 4;
379     p->properties = calloc(p->count, sizeof(MAPIProperty));
380     mp = p->properties;
381
382     for(i=0; i<p->count; i++) {
383         if (count == -1) {
384             mp->id = SwapDWord(d);
385             d+=4;
386             mp->custom = 0;
387             mp->count = 1;
388             mp->namedproperty = 0;
389             length = -1;
390             if (PROP_ID(mp->id) >= 0x8000) {
391                 // Read the GUID
392                 memcpy(&(mp->guid[0]), d, 16);
393                 d+=16;
394     
395                 length = SwapDWord(d);
396                 d+=sizeof(DWORD);
397                 if (length > 0) {
398                     mp->namedproperty = length;
399                     mp->propnames = calloc(length, sizeof(variableLength));
400                     while (length > 0) {
401                         type = SwapDWord(d);
402                         mp->propnames[length-1].data = calloc(type, sizeof(BYTE));
403                         mp->propnames[length-1].size = type;
404                         d+=4;
405                         for(j=0; j<(type>>1); j++) {
406                             mp->propnames[length-1].data[j] = d[j*2];
407                         }
408                         d += type + ((type % 4) ? (4 - type%4) : 0);
409                         length--;
410                     }
411                 } else {
412                     // READ the type
413                     type = SwapDWord(d);
414                     d+=sizeof(DWORD);
415                     mp->id = PROP_TAG(PROP_TYPE(mp->id), type);
416                 }
417                 mp->custom = 1;
418             }
419             
420             //printf("Type id = %04x\n", PROP_TYPE(mp->id));
421             if (PROP_TYPE(mp->id) & MV_FLAG) {
422                 mp->id = PROP_TAG(PROP_TYPE(mp->id) - MV_FLAG, PROP_ID(mp->id));
423                 mp->count = SwapDWord(d);
424                 d+=4;
425                 count = 0;
426             }
427             mp->data = calloc(mp->count, sizeof(variableLength));
428             vl = mp->data;
429         } else {
430             i--;
431             count++;
432             vl = &(mp->data[count]);
433         }
434
435         switch (PROP_TYPE(mp->id)) {
436             case PT_BINARY:
437             case PT_OBJECT:
438             case PT_STRING8:
439             case PT_UNICODE:
440                 // First number of objects (assume 1 for now)
441                 if (count == -1) {
442                     vl->size = SwapDWord(d);
443                     d+=4;
444                 }
445                 // now size of object
446                 vl->size = SwapDWord(d);
447                 d+=4;
448
449                 // now actual object
450                 if (PROP_TYPE(mp->id) == PT_UNICODE) {
451                     vl->data = to_utf8(vl->size, d);
452                 }
453                 else {
454                     vl->data = calloc(vl->size, sizeof(BYTE));
455                     memcpy(vl->data, d, vl->size);
456                 }
457
458                 // Make sure to read in a multiple of 4
459                 num = vl->size;
460                 d += num + ((num % 4) ? (4 - num%4) : 0);
461                 break;
462
463             case PT_I2:
464                 // Read in 2 bytes, but proceed by 4 bytes
465                 vl->size = 2;
466                 vl->data = calloc(vl->size, sizeof(WORD));
467                 temp_word = SwapWord(d);
468                 memcpy(vl->data, &temp_word, vl->size);
469                 d += 4;
470                 break;
471             case PT_BOOLEAN:
472             case PT_LONG:
473             case PT_R4:
474             case PT_CURRENCY:
475             case PT_APPTIME:
476             case PT_ERROR:
477                 vl->size = 4;
478                 vl->data = calloc(vl->size, sizeof(BYTE));
479                 temp_dword = SwapDWord(d);
480                 memcpy(vl->data, &temp_dword, vl->size);
481                 d += 4;
482                 break;
483             case PT_DOUBLE:
484             case PT_I8:
485             case PT_SYSTIME:
486                 vl->size = 8;
487                 vl->data = calloc(vl->size, sizeof(BYTE));
488                 temp_ddword = SwapDDWord(d);
489                 memcpy(vl->data, &temp_ddword, vl->size);
490                 d+=8;
491                 break;
492         }
493         if (count == (mp->count-1)) {
494             count = -1;
495         }
496         if (count == -1) {
497             mp++;
498         }
499     }
500     if ((d-data) < size) {
501         if (TNEF->Debug >= 1)  {
502             printf("ERROR DURING MAPI READ\n");
503             printf("Read %ld bytes, Expected %u bytes\n", (d-data), size);
504             printf("%ld bytes missing\n", size - (d-data));
505         }
506     } else if ((d-data) > size){
507         if (TNEF->Debug >= 1)  {
508             printf("ERROR DURING MAPI READ\n");
509             printf("Read %ld bytes, Expected %u bytes\n", (d-data), size);
510             printf("%ld bytes extra\n", (d-data)-size);
511         }
512     }
513     return;
514 }
515 // -----------------------------------------------------------------------------
516 int TNEFSentFor STD_ARGLIST {
517     WORD name_length, addr_length;
518     BYTE *d;
519
520     d=data;
521
522     while ((d-data)<size) {
523         name_length = SwapWord(d);
524         d+=sizeof(WORD);
525         if (TNEF->Debug >= 1) 
526             printf("Sent For : %s", d);
527         d+=name_length;
528
529         addr_length = SwapWord(d);
530         d+=sizeof(WORD);
531         if (TNEF->Debug >= 1) 
532             printf("<%s>\n", d);
533         d+=addr_length;
534     }
535     return 0;
536 }
537 // -----------------------------------------------------------------------------
538 int TNEFDateHandler STD_ARGLIST {
539     dtr *Date;
540     Attachment *p;
541     WORD *tmp_src, *tmp_dst;
542     int i;
543
544     p = &(TNEF->starting_attach);
545     switch (TNEFList[id].id) {
546         case attDateSent: Date = &(TNEF->dateSent); break;
547         case attDateRecd: Date = &(TNEF->dateReceived); break;
548         case attDateModified: Date = &(TNEF->dateModified); break;
549         case attDateStart: Date = &(TNEF->DateStart); break;
550         case attDateEnd:  Date = &(TNEF->DateEnd); break;
551         case attAttachCreateDate:
552             while (p->next!=NULL) p=p->next;
553             Date = &(p->CreateDate);
554             break;
555         case attAttachModifyDate:
556             while (p->next!=NULL) p=p->next;
557             Date = &(p->ModifyDate);
558             break;
559         default:
560             if (TNEF->Debug >= 1)
561                 printf("MISSING CASE\n");
562             return YTNEF_UNKNOWN_PROPERTY;
563     }
564
565     tmp_src = (WORD*)data;
566     tmp_dst = (WORD*)Date;
567     for(i=0;i<sizeof(dtr)/sizeof(WORD);i++) {
568         *tmp_dst++ = SwapWord((BYTE*)tmp_src++);
569     }
570     return 0;
571 }
572
573 void TNEFPrintDate(dtr Date) {
574     char days[7][15] = {"Sunday", "Monday", "Tuesday", 
575             "Wednesday", "Thursday", "Friday", "Saturday"};
576     char months[12][15] = {"January", "February", "March", "April", "May",
577             "June", "July", "August", "September", "October", "November",
578             "December"};
579
580     if (Date.wDayOfWeek < 7) 
581         printf("%s ", days[Date.wDayOfWeek]);
582     
583     if ((Date.wMonth < 13) && (Date.wMonth>0)) 
584         printf("%s ", months[Date.wMonth-1]);
585
586     printf("%hu, %hu ", Date.wDay, Date.wYear);
587
588     if (Date.wHour>12) 
589         printf("%hu:%02hu:%02hu pm", (Date.wHour-12), 
590                 Date.wMinute, Date.wSecond);
591     else if (Date.wHour == 12) 
592         printf("%hu:%02hu:%02hu pm", (Date.wHour), 
593                 Date.wMinute, Date.wSecond);
594     else
595         printf("%hu:%02hu:%02hu am", Date.wHour, 
596                 Date.wMinute, Date.wSecond);
597 }
598 // -----------------------------------------------------------------------------
599 int TNEFHexBreakdown STD_ARGLIST {
600     int i;
601     if (TNEF->Debug == 0) 
602         return 0;
603
604     printf("%s: [%i bytes] \n", TNEFList[id].name, size);
605
606     for(i=0; i<size; i++) {
607         printf("%02x ", data[i]);
608         if ((i+1)%16 == 0) printf("\n");
609     }
610     printf("\n");
611     return 0;
612 }
613     
614 // -----------------------------------------------------------------------------
615 int TNEFDetailedPrint STD_ARGLIST {
616     int i;
617     if (TNEF->Debug == 0) 
618         return 0;
619
620     printf("%s: [%i bytes] \n", TNEFList[id].name, size);
621
622     for(i=0; i<size; i++) {
623         printf("%c", data[i]);
624     }
625     printf("\n");
626     return 0;
627 }
628
629 // -----------------------------------------------------------------------------
630 int TNEFAttachmentFilename STD_ARGLIST {
631     Attachment *p;
632     p = &(TNEF->starting_attach);
633     while (p->next!=NULL) p=p->next;
634
635     p->Title.size = size;
636     p->Title.data = calloc(size, sizeof(BYTE));
637     memcpy(p->Title.data, data, size);
638
639     return 0;
640 }
641
642 // -----------------------------------------------------------------------------
643 int TNEFAttachmentSave STD_ARGLIST {
644     Attachment *p;
645     p = &(TNEF->starting_attach);
646     while (p->next!=NULL) p=p->next;
647
648     p->FileData.data = calloc(sizeof(unsigned char), size);
649     p->FileData.size = size;
650
651     memcpy(p->FileData.data, data, size);
652
653     return 0;
654 }
655
656 // -----------------------------------------------------------------------------
657 int TNEFPriority STD_ARGLIST {
658     DWORD value;
659
660     value = SwapDWord(data);
661     switch (value) {
662         case 3:
663             sprintf((TNEF->priority), "high");
664             break;
665         case 2:
666             sprintf((TNEF->priority), "normal");
667             break;
668         case 1: 
669             sprintf((TNEF->priority), "low");
670             break;
671         default: 
672             sprintf((TNEF->priority), "N/A");
673             break;
674     }
675     return 0;
676 }
677
678 // -----------------------------------------------------------------------------
679 int TNEFCheckForSignature(DWORD sig) {
680     DWORD signature = 0x223E9F78;
681
682     sig = SwapDWord((BYTE*)&sig);
683
684     if (signature == sig) {
685         return 0;
686     } else {
687         return YTNEF_NOT_TNEF_STREAM;
688     }
689 }
690
691 // -----------------------------------------------------------------------------
692 int TNEFGetKey(TNEFStruct *TNEF, WORD *key) {
693     if (TNEF->IO.ReadProc (&(TNEF->IO), sizeof(WORD),1, key) < 1) {
694         if (TNEF->Debug >= 1) 
695             printf("Error reading Key\n");
696         return YTNEF_ERROR_READING_DATA;
697     }
698     *key = SwapWord((BYTE*)key);
699
700     DEBUG1(TNEF->Debug, 2, "Key = %i", *key);
701     return 0;
702 }
703
704 // -----------------------------------------------------------------------------
705 int TNEFGetHeader(TNEFStruct *TNEF, DWORD *type, DWORD *size) {
706     BYTE component;
707
708     DEBUG(TNEF->Debug, 2, "About to read Component");
709     if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(BYTE),1, &component) < 1) {
710         return YTNEF_ERROR_READING_DATA;
711     }
712
713
714     DEBUG(TNEF->Debug, 2, "About to read type");
715     if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, type)  < 1) {
716         if (TNEF->Debug >= 1) 
717             printf("ERROR: Error reading type\n");
718         return YTNEF_ERROR_READING_DATA;
719     }
720     DEBUG1(TNEF->Debug, 2, "Type = %i", *type);
721
722
723     DEBUG(TNEF->Debug, 2, "About to read size");
724     if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, size) < 1) {
725         if (TNEF->Debug >= 1) 
726             printf("ERROR: Error reading size\n");
727         return YTNEF_ERROR_READING_DATA;
728     }
729
730
731     DEBUG1(TNEF->Debug, 2, "Size = %i", *size);
732
733     *type = SwapDWord((BYTE*)type);
734     *size = SwapDWord((BYTE*)size);
735
736     return 0;
737 }
738
739 // -----------------------------------------------------------------------------
740 int TNEFRawRead(TNEFStruct *TNEF, BYTE *data, DWORD size, WORD *checksum) {
741     WORD temp;
742     int i;
743
744     if (TNEF->IO.ReadProc(&TNEF->IO, sizeof(BYTE), size, data) < size) {
745         if (TNEF->Debug >= 1) 
746             printf("ERROR: Error reading data\n");
747         return YTNEF_ERROR_READING_DATA;
748     }
749
750
751     if (checksum != NULL) {
752         *checksum = 0;
753         for(i=0; i<size; i++) {
754             temp = data[i];
755             *checksum = (*checksum + temp);
756         }
757     }
758     return 0;
759 }
760
761 #define INITVARLENGTH(x) (x).data = NULL; (x).size = 0;
762 #define INITDTR(x) (x).wYear=0; (x).wMonth=0; (x).wDay=0; \
763                    (x).wHour=0; (x).wMinute=0; (x).wSecond=0; \
764                    (x).wDayOfWeek=0;
765 #define INITSTR(x) memset((x), 0, sizeof(x));
766 void TNEFInitMapi(MAPIProps *p)
767 {
768     p->count = 0;
769     p->properties = NULL;
770 }
771
772 void TNEFInitAttachment(Attachment *p)
773 {
774     INITDTR(p->Date);
775     INITVARLENGTH(p->Title);
776     INITVARLENGTH(p->MetaFile);
777     INITDTR(p->CreateDate);
778     INITDTR(p->ModifyDate);
779     INITVARLENGTH(p->TransportFilename);
780     INITVARLENGTH(p->FileData);
781     INITVARLENGTH(p->IconData);
782     memset(&(p->RenderData), 0, sizeof(renddata));
783     TNEFInitMapi(&(p->MAPI));
784     p->next = NULL;
785 }
786
787 void TNEFInitialize(TNEFStruct *TNEF)
788 {
789     INITSTR(TNEF->version);
790     INITVARLENGTH(TNEF->from);
791     INITVARLENGTH(TNEF->subject);
792     INITDTR(TNEF->dateSent);
793     INITDTR(TNEF->dateReceived);
794
795     INITSTR(TNEF->messageStatus);
796     INITSTR(TNEF->messageClass);
797     INITSTR(TNEF->messageID);
798     INITSTR(TNEF->parentID);
799     INITSTR(TNEF->conversationID);
800     INITVARLENGTH(TNEF->body);
801     INITSTR(TNEF->priority);
802     TNEFInitAttachment(&(TNEF->starting_attach));
803     INITDTR(TNEF->dateModified);
804     TNEFInitMapi(&(TNEF->MapiProperties));
805     INITVARLENGTH(TNEF->CodePage);
806     INITVARLENGTH(TNEF->OriginalMessageClass);
807     INITVARLENGTH(TNEF->Owner);
808     INITVARLENGTH(TNEF->SentFor);
809     INITVARLENGTH(TNEF->Delegate);
810     INITDTR(TNEF->DateStart);
811     INITDTR(TNEF->DateEnd);
812     INITVARLENGTH(TNEF->AidOwner);
813     TNEF->RequestRes=0;
814     TNEF->IO.data = NULL;
815     TNEF->IO.InitProc = NULL;
816     TNEF->IO.ReadProc = NULL;
817     TNEF->IO.CloseProc = NULL;
818 }
819 #undef INITVARLENGTH
820 #undef INITDTR
821 #undef INITSTR
822
823 #define FREEVARLENGTH(x) if ((x).size > 0) { \
824                             free((x).data); (x).size =0; }
825 void TNEFFree(TNEFStruct *TNEF) {
826     Attachment *p, *store;
827
828     FREEVARLENGTH(TNEF->from);
829     FREEVARLENGTH(TNEF->subject);
830     FREEVARLENGTH(TNEF->body);
831     FREEVARLENGTH(TNEF->CodePage);
832     FREEVARLENGTH(TNEF->OriginalMessageClass);
833     FREEVARLENGTH(TNEF->Owner);
834     FREEVARLENGTH(TNEF->SentFor);
835     FREEVARLENGTH(TNEF->Delegate);
836     FREEVARLENGTH(TNEF->AidOwner);
837     TNEFFreeMapiProps(&(TNEF->MapiProperties));
838
839     p = TNEF->starting_attach.next;
840     while (p != NULL) {
841         TNEFFreeAttachment(p);
842         store = p->next;
843         free(p);
844         p=store;
845     }
846 }
847
848 void TNEFFreeAttachment(Attachment *p)
849 {
850     FREEVARLENGTH(p->Title);
851     FREEVARLENGTH(p->MetaFile);
852     FREEVARLENGTH(p->TransportFilename);
853     FREEVARLENGTH(p->FileData);
854     FREEVARLENGTH(p->IconData);
855     TNEFFreeMapiProps(&(p->MAPI));
856 }
857
858 void TNEFFreeMapiProps(MAPIProps *p)
859 {
860     int i,j;
861     for(i=0; i<p->count; i++) {
862         for(j=0; j<p->properties[i].count; j++) {
863             FREEVARLENGTH(p->properties[i].data[j]);
864         }
865         free(p->properties[i].data);
866     }
867     free(p->properties);
868     p->count = 0;
869 }
870 #undef FREEVARLENGTH
871
872 // Procedures to handle File IO
873 int TNEFFile_Open (TNEFIOStruct *IO) {
874     TNEFFileInfo *finfo;
875     finfo = (TNEFFileInfo*)IO->data;
876
877     DEBUG1(finfo->Debug, 3, "Opening %s", finfo->filename);
878     if ((finfo->fptr = g_fopen(finfo->filename, "rb")) == NULL) {
879         return -1;
880     } else {
881         return 0;
882     }
883 }
884
885 int TNEFFile_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
886     TNEFFileInfo *finfo;
887     finfo = (TNEFFileInfo*)IO->data;
888
889     DEBUG2(finfo->Debug, 3, "Reading %i blocks of %i size", count, size);
890     if (finfo->fptr != NULL) {
891         return fread((BYTE*)dest, size, count, finfo->fptr);
892     } else {
893         return -1;
894     }
895 }
896
897 int TNEFFile_Close (TNEFIOStruct *IO) {
898     TNEFFileInfo *finfo;
899     finfo = (TNEFFileInfo*)IO->data;
900
901     DEBUG1(finfo->Debug, 3, "Closing file %s", finfo->filename);
902     if (finfo->fptr != NULL) {
903         fclose(finfo->fptr);
904         finfo->fptr = NULL;
905     }
906     return 0;
907 }
908
909 int TNEFParseFile(char *filename, TNEFStruct *TNEF) {
910     TNEFFileInfo finfo;
911
912     if (TNEF->Debug >= 1) 
913         printf("Attempting to parse %s...\n", filename);
914
915
916     finfo.filename = filename;
917     finfo.fptr = NULL;
918     finfo.Debug = TNEF->Debug;
919     TNEF->IO.data = (void*)&finfo;
920     TNEF->IO.InitProc = TNEFFile_Open;
921     TNEF->IO.ReadProc = TNEFFile_Read;
922     TNEF->IO.CloseProc = TNEFFile_Close;
923     return TNEFParse(TNEF);
924 }
925 //-------------------------------------------------------------
926 // Procedures to handle Memory IO
927 int TNEFMemory_Open (TNEFIOStruct *IO) {
928     TNEFMemInfo *minfo;
929     minfo = (TNEFMemInfo*)IO->data;
930
931     minfo->ptr = minfo->dataStart;
932     return 0;
933 }
934
935 int TNEFMemory_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
936     TNEFMemInfo *minfo;
937     int length;
938     long max;
939     minfo = (TNEFMemInfo*)IO->data;
940
941     length = count*size;
942     max = (minfo->dataStart + minfo->size) - (minfo->ptr);
943     if (length > max) {
944         return -1;
945     }
946
947     DEBUG1(minfo->Debug, 3, "Copying %i bytes", length);
948
949     memcpy(dest, minfo->ptr, length);
950     minfo->ptr+=length;
951     return count;
952 }
953
954 int TNEFMemory_Close (TNEFIOStruct *IO) {
955     // Do nothing, really...
956     return 0;
957 }
958
959 int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF) {
960     TNEFMemInfo minfo;
961
962     DEBUG(TNEF->Debug, 1, "Attempting to parse memory block...\n");
963
964     minfo.dataStart = memory;
965     minfo.ptr = memory;
966     minfo.size = size;
967     minfo.Debug = TNEF->Debug;
968     TNEF->IO.data = (void*)&minfo;
969     TNEF->IO.InitProc = TNEFMemory_Open;
970     TNEF->IO.ReadProc = TNEFMemory_Read;
971     TNEF->IO.CloseProc = TNEFMemory_Close;
972     return TNEFParse(TNEF);
973 }
974
975
976 int TNEFParse(TNEFStruct *TNEF) {
977     WORD key;
978     DWORD type;
979     DWORD size;
980     DWORD signature;
981     BYTE *data;
982     WORD checksum, header_checksum;
983     int i;
984
985     if (TNEF->IO.ReadProc == NULL) {
986         printf("ERROR: Setup incorrectly: No ReadProc\n");
987         return YTNEF_INCORRECT_SETUP;
988     }
989
990     if (TNEF->IO.InitProc != NULL) {
991         DEBUG(TNEF->Debug, 2, "About to initialize");
992         if (TNEF->IO.InitProc (&TNEF->IO) != 0) {
993             return YTNEF_CANNOT_INIT_DATA;
994         }
995         DEBUG(TNEF->Debug, 2, "Initialization finished");
996     }
997    
998     DEBUG(TNEF->Debug, 2, "Reading Signature");
999     if (TNEF->IO.ReadProc (&TNEF->IO, sizeof(DWORD), 1, &signature) < 1) {
1000         printf("ERROR: Error reading signature\n");
1001         if (TNEF->IO.CloseProc != NULL) {
1002             TNEF->IO.CloseProc (&TNEF->IO);
1003         }
1004         return YTNEF_ERROR_READING_DATA;
1005     }
1006
1007     DEBUG(TNEF->Debug, 2, "Checking Signature");
1008     if (TNEFCheckForSignature(signature) < 0) {
1009         printf("ERROR: Signature does not match. Not TNEF.\n");
1010         if (TNEF->IO.CloseProc != NULL) {
1011             TNEF->IO.CloseProc (&TNEF->IO);
1012         }
1013         return YTNEF_NOT_TNEF_STREAM;
1014     }
1015
1016     DEBUG(TNEF->Debug, 2, "Reading Key.");
1017
1018     if (TNEFGetKey(TNEF, &key) < 0) {
1019         printf("ERROR: Unable to retrieve key.\n");
1020         if (TNEF->IO.CloseProc != NULL) {
1021             TNEF->IO.CloseProc (&TNEF->IO);
1022         }
1023         return YTNEF_NO_KEY;
1024     }
1025
1026     DEBUG(TNEF->Debug, 2, "Starting Full Processing.");
1027
1028     while (TNEFGetHeader(TNEF, &type, &size) == 0) {
1029         DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size);
1030         if (size > 0) {
1031             data = calloc(size, sizeof(BYTE));
1032             if (TNEFRawRead(TNEF, data, size, &header_checksum)< 0) {
1033                 printf("ERROR: Unable to read data.\n");
1034                 if (TNEF->IO.CloseProc != NULL) {
1035                     TNEF->IO.CloseProc (&TNEF->IO);
1036                 }
1037                 free(data);
1038                 return YTNEF_ERROR_READING_DATA;
1039             }
1040             if (TNEFRawRead(TNEF, (BYTE *)&checksum, 2, NULL) < 0) {
1041                 printf("ERROR: Unable to read checksum.\n");
1042                 if (TNEF->IO.CloseProc != NULL) {
1043                     TNEF->IO.CloseProc (&TNEF->IO);
1044                 }
1045                 free(data);
1046                 return YTNEF_ERROR_READING_DATA;
1047             }
1048             checksum = SwapWord((BYTE*)&checksum);
1049             if (checksum != header_checksum) {
1050                 printf("ERROR: Checksum mismatch. Data corruption?:\n");
1051                 if (TNEF->IO.CloseProc != NULL) {
1052                     TNEF->IO.CloseProc (&TNEF->IO);
1053                 }
1054                 free(data);
1055                 return YTNEF_BAD_CHECKSUM;
1056             }
1057             for(i=0; i<(sizeof(TNEFList)/sizeof(TNEFHandler));i++) {
1058                 if (TNEFList[i].id == type) {
1059                     if (TNEFList[i].handler != NULL) {
1060                         if (TNEFList[i].handler(TNEF, i, data, size) < 0) {
1061                             free(data);
1062                             if (TNEF->IO.CloseProc != NULL) {
1063                                 TNEF->IO.CloseProc (&TNEF->IO);
1064                             }
1065                             return YTNEF_ERROR_IN_HANDLER;
1066                         }
1067                     } else {
1068                         DEBUG2(TNEF->Debug, 1, "No handler for %s: %i bytes",
1069                                     TNEFList[i].name, size);
1070                     }
1071                 }
1072             }
1073
1074             free(data);
1075         }
1076     }
1077
1078     if (TNEF->IO.CloseProc != NULL) {
1079         TNEF->IO.CloseProc (&TNEF->IO);
1080     }
1081     return 0;
1082
1083 }
1084
1085 // ----------------------------------------------------------------------------
1086
1087 variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID) 
1088 {
1089     int i;
1090     if (p != NULL) {
1091         for(i=0;i<p->count; i++) {
1092             if ((p->properties[i].id == ID) && (p->properties[i].custom == 1)) {
1093                 return (p->properties[i].data);
1094             }
1095         }
1096     }
1097     return MAPI_UNDEFINED;
1098 }
1099
1100 variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID)
1101 {
1102     int i;
1103     if (p != NULL) {
1104         for(i=0;i<p->count; i++) {
1105             if ((p->properties[i].id == ID) && (p->properties[i].custom == 0)) {
1106                 return (p->properties[i].data);
1107             }
1108         }
1109     }
1110     return MAPI_UNDEFINED;
1111 }
1112
1113 int MAPISysTimetoDTR(BYTE *data, dtr *thedate)
1114 {
1115     DDWORD ddword_tmp;
1116     int startingdate = 0;
1117     int tmp_date;
1118     int days_in_year = 365;
1119     unsigned int months[] = {31,28,31,30,31,30,31,31,30,31,30,31};
1120
1121     ddword_tmp = *((DDWORD*)data);
1122     ddword_tmp = ddword_tmp /10; // micro-s
1123     ddword_tmp /= 1000; // ms
1124     ddword_tmp /= 1000; // s
1125
1126     thedate->wSecond = (ddword_tmp % 60);
1127
1128     ddword_tmp /= 60; // seconds to minutes
1129     thedate->wMinute = (ddword_tmp % 60);
1130
1131     ddword_tmp /= 60; //minutes to hours
1132     thedate->wHour = (ddword_tmp % 24);
1133
1134     ddword_tmp /= 24; // Hours to days
1135
1136     // Now calculate the year based on # of days
1137     thedate->wYear = 1601;
1138     startingdate = 1; 
1139     while(ddword_tmp >= days_in_year) {
1140         ddword_tmp-=days_in_year;
1141         thedate->wYear++;
1142         days_in_year = 365;
1143         startingdate++;
1144         if ((thedate->wYear % 4) == 0) {
1145             if ((thedate->wYear % 100) == 0) {
1146                 // if the year is 1700,1800,1900, etc, then it is only 
1147                 // a leap year if exactly divisible by 400, not 4.
1148                 if ((thedate->wYear % 400) == 0) {
1149                     startingdate++;
1150                     days_in_year = 366;
1151                 }
1152             }  else {
1153                 startingdate++;
1154                 days_in_year = 366;
1155             }
1156         }
1157         startingdate %= 7;
1158     }
1159
1160     // the remaining number is the day # in this year
1161     // So now calculate the Month, & Day of month
1162     if ((thedate->wYear % 4) == 0) {
1163         // 29 days in february in a leap year
1164         months[1] = 29;
1165     }
1166
1167     tmp_date = (int)ddword_tmp;
1168     thedate->wDayOfWeek = (tmp_date + startingdate) % 7;
1169     thedate->wMonth = 0;
1170
1171     while (tmp_date > months[thedate->wMonth]) {
1172         tmp_date -= months[thedate->wMonth];
1173         thedate->wMonth++;
1174     }
1175     thedate->wMonth++;
1176     thedate->wDay = tmp_date+1;
1177     return 0;
1178 }
1179
1180 int IsCompressedRTF(variableLength *p) {
1181 /*
1182     unsigned int in;
1183     unsigned char *src;
1184     ULONG compressedSize, uncompressedSize, magic, crc32;
1185
1186     src = p->data;
1187     in = 0;
1188
1189     compressedSize = (ULONG)SwapDWord(src+in);
1190     in += 4;
1191     uncompressedSize = (ULONG)SwapDWord(src+in);
1192     in += 4;
1193     magic = SwapDWord(src+in);
1194     in += 4;
1195     crc32 = SwapDWord(src+in);
1196     in += 4;
1197
1198     if (magic == 0x414c454d) { 
1199         return 1;
1200     } else if (magic == 0x75465a4c) { 
1201         return 1;
1202     } else {
1203         return 0;
1204     }
1205 */
1206     unsigned char *src = p->data;
1207     ULONG magic = SwapDWord(src + 8);
1208
1209     if (magic == 0x414c454d || magic == 0x75465a4c)
1210         return 1;
1211
1212     return 0;
1213 }
1214
1215 void MAPIPrint(MAPIProps *p)
1216 {
1217     int j, i,index, h;
1218     dtr thedate;
1219     MAPIProperty *mapi;
1220     variableLength *mapidata;
1221     variableLength vlTemp;
1222     int found;
1223
1224     for(j=0; j<p->count; j++) {
1225         mapi = &(p->properties[j]);
1226         printf("   #%i: Type: [", j);
1227         switch (PROP_TYPE(mapi->id)) {
1228             case PT_UNSPECIFIED:
1229                 printf("  NONE   "); break;
1230             case PT_NULL:
1231                 printf("  NULL   "); break;
1232             case PT_I2:
1233                 printf("   I2    "); break;
1234             case PT_LONG:
1235                 printf("  LONG   "); break;
1236             case PT_R4:
1237                 printf("   R4    "); break;
1238             case PT_DOUBLE:
1239                 printf(" DOUBLE  "); break;
1240             case PT_CURRENCY:
1241                 printf("CURRENCY "); break;
1242             case PT_APPTIME:
1243                 printf("APP TIME "); break;
1244             case PT_ERROR:
1245                 printf("  ERROR  "); break;
1246             case PT_BOOLEAN:
1247                 printf(" BOOLEAN "); break;
1248             case PT_OBJECT:
1249                 printf(" OBJECT  "); break;
1250             case PT_I8:
1251                 printf("   I8    "); break;
1252             case PT_STRING8:
1253                 printf(" STRING8 "); break;
1254             case PT_UNICODE:
1255                 printf(" UNICODE "); break;
1256             case PT_SYSTIME:
1257                 printf("SYS TIME "); break;
1258             case PT_CLSID:
1259                 printf("OLE GUID "); break;
1260             case PT_BINARY:
1261                 printf(" BINARY  "); break;
1262             default:
1263                 printf("<%x>", PROP_TYPE(mapi->id)); break;
1264         }
1265                 
1266         printf("]  Code: [");
1267         if (mapi->custom == 1) {
1268             printf("UD:x%04x", PROP_ID(mapi->id));
1269         } else {
1270             found = 0;
1271             for(index=0; index<sizeof(MPList)/sizeof(MAPIPropertyTagList); index++) {
1272                 if ((MPList[index].id == PROP_ID(mapi->id)) && (found == 0)) {
1273                     printf("%s", MPList[index].name);
1274                     found = 1;
1275                 }
1276             }
1277             if (found == 0) {
1278                 printf("0x%04x", PROP_ID(mapi->id));
1279             }
1280         }
1281         printf("]\n");
1282         if (mapi->namedproperty > 0) {
1283             for(i=0; i<mapi->namedproperty; i++) {
1284                 printf("    Name: %s\n", mapi->propnames[i].data);
1285             }
1286         }
1287         for (i=0;i<mapi->count;i++) {
1288             mapidata = &(mapi->data[i]);
1289             if (mapi->count > 1) {
1290                 printf("    [%i/%i] ", i, mapi->count);
1291             } else {
1292                 printf("    ");
1293             }
1294             printf("Size: %i", mapidata->size);
1295             switch (PROP_TYPE(mapi->id)) {
1296                 case PT_SYSTIME:
1297                     MAPISysTimetoDTR(mapidata->data, &thedate);
1298                     printf("    Value: ");
1299                     TNEFPrintDate(thedate);
1300                     printf("\n");
1301                     break;
1302                 case PT_LONG:
1303                     printf("    Value: %li\n", (long int) *(mapidata->data));
1304                     break;
1305                 case PT_I2:
1306                     printf("    Value: %hi\n", *(mapidata->data));
1307                     break;
1308                 case PT_BOOLEAN:
1309                     if (mapi->data->data[0]!=0) {
1310                         printf("    Value: True\n");
1311                     } else {
1312                         printf("    Value: False\n");
1313                     }
1314                     break;
1315                 case PT_OBJECT:
1316                     printf("\n");
1317                     break;
1318                 case PT_BINARY:
1319                     if(IsCompressedRTF(mapidata)==1) {
1320                         printf("    Detected Compressed RTF.");
1321                         printf("Decompressed text follows\n");
1322                         printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1323                         if((vlTemp.data = DecompressRTF(mapidata, &(vlTemp.size))) != NULL) {
1324                             printf("%s\n", vlTemp.data);
1325                             free(vlTemp.data);
1326                         }
1327                         printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1328                     } else {
1329                         printf("    Value: [");
1330                         for(h=0; h< mapidata->size; h++) {
1331                             if (isprint(mapidata->data[h])) 
1332                                 printf("%c", mapidata->data[h]);
1333                             else 
1334                                 printf(".");
1335
1336                         }
1337                         printf("]\n");
1338                     }
1339                     break;
1340                 case PT_STRING8:
1341                     printf("    Value: [%s]\n", mapidata->data);
1342                     if (strlen(mapidata->data) != mapidata->size-1) {
1343                         printf("Detected Hidden data: [");
1344                         for(h=0; h< mapidata->size; h++) {
1345                             if (isprint(mapidata->data[h])) 
1346                                 printf("%c", mapidata->data[h]);
1347                             else 
1348                                 printf(".");
1349
1350                         }
1351                         printf("]\n");
1352                     }
1353                     break;
1354                 default:
1355                     printf("    Value: [%s]\n", mapidata->data);
1356             }
1357         }
1358     }
1359 }
1360
1361 unsigned char *DecompressRTF(variableLength *p, int *size) {
1362     unsigned char *dst; // destination for uncompressed bytes
1363     unsigned char *src;
1364     unsigned int in;
1365     unsigned int out;
1366     variableLength comp_Prebuf;
1367     ULONG compressedSize, uncompressedSize, magic; // , crc32;
1368
1369     comp_Prebuf.size = strlen(RTF_PREBUF);
1370     comp_Prebuf.data = calloc(comp_Prebuf.size + 1, 1);
1371     strcpy(comp_Prebuf.data, RTF_PREBUF);
1372
1373     src = p->data;
1374     in = 0;
1375
1376     compressedSize = (ULONG)SwapDWord(src+in);
1377     in += 4;
1378     uncompressedSize = (ULONG)SwapDWord(src+in);
1379     in += 4;
1380     magic = SwapDWord(src+in);
1381     in += 4;
1382     // crc32 = SwapDWord(src+in);
1383     in += 4;
1384
1385     // check size excluding the size field itself
1386     if (compressedSize != p->size - 4) {
1387         printf(" Size Mismatch: %i != %i\n", compressedSize, p->size-4);
1388         return NULL;
1389     }
1390
1391     // process the data
1392     if (magic == 0x414c454d) { 
1393         // magic number that identifies the stream as a uncompressed stream
1394         dst = calloc(uncompressedSize,1);
1395         memcpy(dst, src+4, uncompressedSize);
1396         return dst;
1397     } else if (magic == 0x75465a4c) { 
1398         // magic number that identifies the stream as a compressed stream
1399         int flagCount = 0;
1400         int flags = 0;
1401         dst = calloc(comp_Prebuf.size + uncompressedSize,1);
1402         memcpy(dst, comp_Prebuf.data, comp_Prebuf.size);
1403         out = comp_Prebuf.size;
1404         while (out < (comp_Prebuf.size+uncompressedSize)) {
1405             // each flag byte flags 8 literals/references, 1 per bit
1406             flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1;
1407             if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0 for literal
1408                 int offset = src[in++];
1409                 int length = src[in++];
1410                 int end;
1411                 offset = (offset << 4) | (length >> 4); // the offset relative to block start
1412                 length = (length & 0xF) + 2; // the number of bytes to copy
1413                 // the decompression buffer is supposed to wrap around back
1414                 // to the beginning when the end is reached. we save the
1415                 // need for such a buffer by pointing straight into the data
1416                 // buffer, and simulating this behaviour by modifying the
1417                 // pointers appropriately.
1418                 offset = (out / 4096) * 4096 + offset; 
1419                 if (offset >= out) // take from previous block
1420                         offset -= 4096;
1421                 // note: can't use System.arraycopy, because the referenced
1422                 // bytes can cross through the current out position.
1423                 end = offset + length;
1424                 while (offset < end)
1425                         dst[out++] = dst[offset++];
1426             } else { // literal
1427                 dst[out++] = src[in++];
1428             }
1429         }
1430         // copy it back without the prebuffered data
1431         src = dst;
1432         dst = calloc(uncompressedSize,1);
1433         memcpy(dst, src + comp_Prebuf.size, uncompressedSize);
1434         free(src);
1435         *size = uncompressedSize;
1436         return dst;
1437     } else { // unknown magic number
1438         printf("Unknown compression type (magic number %x)\n", magic );
1439         return NULL;
1440     }
1441 }