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