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
6 * This file Copyright (C) 2002-2007 Randall Hand <yerase@yerot.com>
7 * Thanks to him for allowing redistribution of this code as GPLv3.
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.
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.
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.
26 #include "claws-features.h"
34 #include "tnef-errors.h"
41 #include <glib/gstdio.h>
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); \
53 #define DEBUG2(lvl, curlvl, msg, var1, var2) \
54 if ((lvl) >= (curlvl)) { \
55 printf("DEBUG(%i/%i):", curlvl, lvl); \
56 printf(msg, var1, var2); \
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); \
67 #define MIN(x,y) (((x)<(y))?(x):(y))
70 void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p);
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;
97 BYTE *TNEFFileContents=NULL;
98 DWORD TNEFFileContentsSize;
99 BYTE *TNEFFileIcon=NULL;
100 DWORD TNEFFileIconSize;
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} };
138 WORD SwapWord(BYTE *p)
141 #ifdef WORDS_BIGENDIAN
145 word_ptr = (WORD*)&(bytes[0]);
152 DWORD SwapDWord(BYTE *p)
155 #ifdef WORDS_BIGENDIAN
161 dword_ptr = (DWORD*)&(bytes[0]);
163 dword_ptr = (DWORD*)p;
168 DDWORD SwapDDWord(BYTE *p)
171 #ifdef WORDS_BIGENDIAN
181 ddword_ptr = (DDWORD*)&(bytes[0]);
183 ddword_ptr = (DDWORD*)p;
188 /* convert 16-bit unicode to UTF8 unicode */
189 char* to_utf8(int len, char* buf)
192 /* worst case length */
193 char *utf8 = malloc(3 * len/2 + 1);
195 for (i=0; i<len-1; i+=2) {
196 unsigned int c = SwapWord(buf+i);
198 utf8[j++] = 0x00 | ((c & 0x007f) >> 0);
200 else if (c < 0x07ff) {
201 utf8[j++] = 0xc0 | ((c & 0x07c0) >> 6);
202 utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
205 utf8[j++] = 0xe0 | ((c & 0xf000) >> 12);
206 utf8[j++] = 0x80 | ((c & 0x0fc0) >> 6);
207 utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
211 /* just in case the original was not null terminated */
218 // -----------------------------------------------------------------------------
219 int TNEFDefaultHandler STD_ARGLIST {
220 if (TNEF->Debug >= 1)
221 printf("%s: [%i] %s\n", TNEFList[id].name, size, data);
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);
233 // -----------------------------------------------------------------------------
234 int TNEFParentID STD_ARGLIST {
235 memcpy(TNEF->parentID, data, MIN(size,sizeof(TNEF->parentID)));
238 // -----------------------------------------------------------------------------
239 int TNEFMessageID STD_ARGLIST {
240 memcpy(TNEF->messageID, data, MIN(size,sizeof(TNEF->messageID)));
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);
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);
257 // -----------------------------------------------------------------------------
258 int TNEFMessageClass STD_ARGLIST {
259 memcpy(TNEF->messageClass, data, MIN(size,sizeof(TNEF->messageClass)));
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);
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);
277 // -----------------------------------------------------------------------------
278 int TNEFRendData STD_ARGLIST {
280 // Find the last attachment.
281 p = &(TNEF->starting_attach);
282 while (p->next!=NULL) p=p->next;
285 p->next = calloc(1,sizeof(Attachment));
288 TNEFInitAttachment(p);
290 memcpy(&(p->RenderData), data, sizeof(renddata));
294 // -----------------------------------------------------------------------------
295 int TNEFVersion STD_ARGLIST {
298 major = SwapWord(data+2);
299 minor = SwapWord(data);
301 sprintf(TNEF->version, "TNEF%i.%i", major, minor);
305 // -----------------------------------------------------------------------------
306 int TNEFIcon STD_ARGLIST {
308 // Find the last attachment.
309 p = &(TNEF->starting_attach);
310 while (p->next!=NULL) p=p->next;
312 p->IconData.size = size;
313 p->IconData.data = calloc(size, sizeof(BYTE));
314 memcpy(p->IconData.data, data, size);
318 // -----------------------------------------------------------------------------
319 int TNEFRecipTable STD_ARGLIST {
325 // printf("Recipient Table containing %u rows\n", count);
329 // -----------------------------------------------------------------------------
330 int TNEFAttachmentMAPI STD_ARGLIST {
332 // Find the last attachment.
334 p = &(TNEF->starting_attach);
335 while (p->next!=NULL) p=p->next;
336 TNEFFillMapi(TNEF, data, size, &(p->MAPI));
340 // -----------------------------------------------------------------------------
341 int TNEFMapiProperties STD_ARGLIST {
342 TNEFFillMapi(TNEF, data, size, &(TNEF->MapiProperties));
346 void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) {
361 p->count = SwapDWord(data);
363 p->properties = calloc(p->count, sizeof(MAPIProperty));
366 for(i=0; i<p->count; i++) {
368 mp->id = SwapDWord(d);
372 mp->namedproperty = 0;
374 if (PROP_ID(mp->id) >= 0x8000) {
376 memcpy(&(mp->guid[0]), d, 16);
379 length = SwapDWord(d);
382 mp->namedproperty = length;
383 mp->propnames = calloc(length, sizeof(variableLength));
386 mp->propnames[length-1].data = calloc(type, sizeof(BYTE));
387 mp->propnames[length-1].size = type;
389 for(j=0; j<(type>>1); j++) {
390 mp->propnames[length-1].data[j] = d[j*2];
392 d += type + ((type % 4) ? (4 - type%4) : 0);
399 mp->id = PROP_TAG(PROP_TYPE(mp->id), type);
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);
411 mp->data = calloc(mp->count, sizeof(variableLength));
416 vl = &(mp->data[count]);
419 switch (PROP_TYPE(mp->id)) {
424 // First number of objects (assume 1 for now)
426 vl->size = SwapDWord(d);
429 // now size of object
430 vl->size = SwapDWord(d);
434 if (PROP_TYPE(mp->id) == PT_UNICODE) {
435 vl->data = to_utf8(vl->size, d);
438 vl->data = calloc(vl->size, sizeof(BYTE));
439 memcpy(vl->data, d, vl->size);
442 // Make sure to read in a multiple of 4
444 d += num + ((num % 4) ? (4 - num%4) : 0);
448 // Read in 2 bytes, but proceed by 4 bytes
450 vl->data = calloc(vl->size, sizeof(WORD));
451 temp_word = SwapWord(d);
452 memcpy(vl->data, &temp_word, vl->size);
462 vl->data = calloc(vl->size, sizeof(BYTE));
463 temp_dword = SwapDWord(d);
464 memcpy(vl->data, &temp_dword, vl->size);
471 vl->data = calloc(vl->size, sizeof(BYTE));
472 temp_ddword = SwapDDWord(d);
473 memcpy(vl->data, &temp_ddword, vl->size);
477 if (count == (mp->count-1)) {
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));
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);
499 // -----------------------------------------------------------------------------
500 int TNEFSentFor STD_ARGLIST {
501 WORD name_length, addr_length;
506 while ((d-data)<size) {
507 name_length = SwapWord(d);
509 if (TNEF->Debug >= 1)
510 printf("Sent For : %s", d);
513 addr_length = SwapWord(d);
515 if (TNEF->Debug >= 1)
521 // -----------------------------------------------------------------------------
522 int TNEFDateHandler STD_ARGLIST {
525 WORD *tmp_src, *tmp_dst;
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);
539 case attAttachModifyDate:
540 while (p->next!=NULL) p=p->next;
541 Date = &(p->ModifyDate);
544 if (TNEF->Debug >= 1)
545 printf("MISSING CASE\n");
546 return YTNEF_UNKNOWN_PROPERTY;
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++);
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",
564 if (Date.wDayOfWeek < 7)
565 printf("%s ", days[Date.wDayOfWeek]);
567 if ((Date.wMonth < 13) && (Date.wMonth>0))
568 printf("%s ", months[Date.wMonth-1]);
570 printf("%hu, %hu ", Date.wDay, Date.wYear);
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);
579 printf("%hu:%02hu:%02hu am", Date.wHour,
580 Date.wMinute, Date.wSecond);
582 // -----------------------------------------------------------------------------
583 int TNEFHexBreakdown STD_ARGLIST {
585 if (TNEF->Debug == 0)
588 printf("%s: [%i bytes] \n", TNEFList[id].name, size);
590 for(i=0; i<size; i++) {
591 printf("%02x ", data[i]);
592 if ((i+1)%16 == 0) printf("\n");
598 // -----------------------------------------------------------------------------
599 int TNEFDetailedPrint STD_ARGLIST {
601 if (TNEF->Debug == 0)
604 printf("%s: [%i bytes] \n", TNEFList[id].name, size);
606 for(i=0; i<size; i++) {
607 printf("%c", data[i]);
613 // -----------------------------------------------------------------------------
614 int TNEFAttachmentFilename STD_ARGLIST {
616 p = &(TNEF->starting_attach);
617 while (p->next!=NULL) p=p->next;
619 p->Title.size = size;
620 p->Title.data = calloc(size, sizeof(BYTE));
621 memcpy(p->Title.data, data, size);
626 // -----------------------------------------------------------------------------
627 int TNEFAttachmentSave STD_ARGLIST {
629 p = &(TNEF->starting_attach);
630 while (p->next!=NULL) p=p->next;
632 p->FileData.data = calloc(sizeof(unsigned char), size);
633 p->FileData.size = size;
635 memcpy(p->FileData.data, data, size);
640 // -----------------------------------------------------------------------------
641 int TNEFPriority STD_ARGLIST {
644 value = SwapDWord(data);
647 sprintf((TNEF->priority), "high");
650 sprintf((TNEF->priority), "normal");
653 sprintf((TNEF->priority), "low");
656 sprintf((TNEF->priority), "N/A");
662 // -----------------------------------------------------------------------------
663 int TNEFCheckForSignature(DWORD sig) {
664 DWORD signature = 0x223E9F78;
666 sig = SwapDWord((BYTE*)&sig);
668 if (signature == sig) {
671 return YTNEF_NOT_TNEF_STREAM;
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;
682 *key = SwapWord((BYTE*)key);
684 DEBUG1(TNEF->Debug, 2, "Key = %i", *key);
688 // -----------------------------------------------------------------------------
689 int TNEFGetHeader(TNEFStruct *TNEF, DWORD *type, DWORD *size) {
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;
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;
704 DEBUG1(TNEF->Debug, 2, "Type = %i", *type);
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;
715 DEBUG1(TNEF->Debug, 2, "Size = %i", *size);
717 *type = SwapDWord((BYTE*)type);
718 *size = SwapDWord((BYTE*)size);
723 // -----------------------------------------------------------------------------
724 int TNEFRawRead(TNEFStruct *TNEF, BYTE *data, DWORD size, WORD *checksum) {
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;
735 if (checksum != NULL) {
737 for(i=0; i<size; i++) {
739 *checksum = (*checksum + temp);
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; \
749 #define INITSTR(x) memset((x), 0, sizeof(x));
750 void TNEFInitMapi(MAPIProps *p)
753 p->properties = NULL;
756 void TNEFInitAttachment(Attachment *p)
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));
771 void TNEFInitialize(TNEFStruct *TNEF)
773 INITSTR(TNEF->version);
774 INITVARLENGTH(TNEF->from);
775 INITVARLENGTH(TNEF->subject);
776 INITDTR(TNEF->dateSent);
777 INITDTR(TNEF->dateReceived);
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);
798 TNEF->IO.data = NULL;
799 TNEF->IO.InitProc = NULL;
800 TNEF->IO.ReadProc = NULL;
801 TNEF->IO.CloseProc = NULL;
807 #define FREEVARLENGTH(x) if ((x).size > 0) { \
808 free((x).data); (x).size =0; }
809 void TNEFFree(TNEFStruct *TNEF) {
810 Attachment *p, *store;
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));
823 p = TNEF->starting_attach.next;
825 TNEFFreeAttachment(p);
832 void TNEFFreeAttachment(Attachment *p)
834 FREEVARLENGTH(p->Title);
835 FREEVARLENGTH(p->MetaFile);
836 FREEVARLENGTH(p->TransportFilename);
837 FREEVARLENGTH(p->FileData);
838 FREEVARLENGTH(p->IconData);
839 TNEFFreeMapiProps(&(p->MAPI));
842 void TNEFFreeMapiProps(MAPIProps *p)
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]);
849 free(p->properties[i].data);
856 // Procedures to handle File IO
857 int TNEFFile_Open (TNEFIOStruct *IO) {
859 finfo = (TNEFFileInfo*)IO->data;
861 DEBUG1(finfo->Debug, 3, "Opening %s", finfo->filename);
862 if ((finfo->fptr = g_fopen(finfo->filename, "rb")) == NULL) {
869 int TNEFFile_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
871 finfo = (TNEFFileInfo*)IO->data;
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);
881 int TNEFFile_Close (TNEFIOStruct *IO) {
883 finfo = (TNEFFileInfo*)IO->data;
885 DEBUG1(finfo->Debug, 3, "Closing file %s", finfo->filename);
886 if (finfo->fptr != NULL) {
893 int TNEFParseFile(char *filename, TNEFStruct *TNEF) {
896 if (TNEF->Debug >= 1)
897 printf("Attempting to parse %s...\n", filename);
900 finfo.filename = filename;
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);
909 //-------------------------------------------------------------
910 // Procedures to handle Memory IO
911 int TNEFMemory_Open (TNEFIOStruct *IO) {
913 minfo = (TNEFMemInfo*)IO->data;
915 minfo->ptr = minfo->dataStart;
919 int TNEFMemory_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
923 minfo = (TNEFMemInfo*)IO->data;
926 max = (minfo->dataStart + minfo->size) - (minfo->ptr);
931 DEBUG1(minfo->Debug, 3, "Copying %i bytes", length);
933 memcpy(dest, minfo->ptr, length);
938 int TNEFMemory_Close (TNEFIOStruct *IO) {
939 // Do nothing, really...
943 int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF) {
946 DEBUG(TNEF->Debug, 1, "Attempting to parse memory block...\n");
948 minfo.dataStart = memory;
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);
960 int TNEFParse(TNEFStruct *TNEF) {
966 WORD checksum, header_checksum;
969 if (TNEF->IO.ReadProc == NULL) {
970 printf("ERROR: Setup incorrectly: No ReadProc\n");
971 return YTNEF_INCORRECT_SETUP;
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;
979 DEBUG(TNEF->Debug, 2, "Initialization finished");
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);
988 return YTNEF_ERROR_READING_DATA;
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);
997 return YTNEF_NOT_TNEF_STREAM;
1000 DEBUG(TNEF->Debug, 2, "Reading Key.");
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);
1007 return YTNEF_NO_KEY;
1010 DEBUG(TNEF->Debug, 2, "Starting Full Processing.");
1012 while (TNEFGetHeader(TNEF, &type, &size) == 0) {
1013 DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size);
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);
1022 return YTNEF_ERROR_READING_DATA;
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);
1030 return YTNEF_ERROR_READING_DATA;
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);
1039 return YTNEF_BAD_CHECKSUM;
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) {
1046 if (TNEF->IO.CloseProc != NULL) {
1047 TNEF->IO.CloseProc (&TNEF->IO);
1049 return YTNEF_ERROR_IN_HANDLER;
1052 DEBUG2(TNEF->Debug, 1, "No handler for %s: %i bytes",
1053 TNEFList[i].name, size);
1062 if (TNEF->IO.CloseProc != NULL) {
1063 TNEF->IO.CloseProc (&TNEF->IO);
1069 // ----------------------------------------------------------------------------
1071 variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID)
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);
1081 return MAPI_UNDEFINED;
1084 variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID)
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);
1094 return MAPI_UNDEFINED;
1097 int MAPISysTimetoDTR(BYTE *data, dtr *thedate)
1100 int startingdate = 0;
1102 int days_in_year = 365;
1103 unsigned int months[] = {31,28,31,30,31,30,31,31,30,31,30,31};
1105 ddword_tmp = *((DDWORD*)data);
1106 ddword_tmp = ddword_tmp /10; // micro-s
1107 ddword_tmp /= 1000; // ms
1108 ddword_tmp /= 1000; // s
1110 thedate->wSecond = (ddword_tmp % 60);
1112 ddword_tmp /= 60; // seconds to minutes
1113 thedate->wMinute = (ddword_tmp % 60);
1115 ddword_tmp /= 60; //minutes to hours
1116 thedate->wHour = (ddword_tmp % 24);
1118 ddword_tmp /= 24; // Hours to days
1120 // Now calculate the year based on # of days
1121 thedate->wYear = 1601;
1123 while(ddword_tmp >= days_in_year) {
1124 ddword_tmp-=days_in_year;
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) {
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
1151 tmp_date = (int)ddword_tmp;
1152 thedate->wDayOfWeek = (tmp_date + startingdate) % 7;
1153 thedate->wMonth = 0;
1155 while (tmp_date > months[thedate->wMonth]) {
1156 tmp_date -= months[thedate->wMonth];
1160 thedate->wDay = tmp_date+1;
1164 int IsCompressedRTF(variableLength *p) {
1168 ULONG compressedSize, uncompressedSize, magic, crc32;
1173 compressedSize = (ULONG)SwapDWord(src+in);
1175 uncompressedSize = (ULONG)SwapDWord(src+in);
1177 magic = SwapDWord(src+in);
1179 crc32 = SwapDWord(src+in);
1182 if (magic == 0x414c454d) {
1184 } else if (magic == 0x75465a4c) {
1190 unsigned char *src = p->data;
1191 ULONG magic = SwapDWord(src + 8);
1193 if (magic == 0x414c454d || magic == 0x75465a4c)
1199 void MAPIPrint(MAPIProps *p)
1204 variableLength *mapidata;
1205 variableLength vlTemp;
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;
1215 printf(" NULL "); break;
1217 printf(" I2 "); break;
1219 printf(" LONG "); break;
1221 printf(" R4 "); break;
1223 printf(" DOUBLE "); break;
1225 printf("CURRENCY "); break;
1227 printf("APP TIME "); break;
1229 printf(" ERROR "); break;
1231 printf(" BOOLEAN "); break;
1233 printf(" OBJECT "); break;
1235 printf(" I8 "); break;
1237 printf(" STRING8 "); break;
1239 printf(" UNICODE "); break;
1241 printf("SYS TIME "); break;
1243 printf("OLE GUID "); break;
1245 printf(" BINARY "); break;
1247 printf("<%x>", PROP_TYPE(mapi->id)); break;
1250 printf("] Code: [");
1251 if (mapi->custom == 1) {
1252 printf("UD:x%04x", PROP_ID(mapi->id));
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);
1262 printf("0x%04x", PROP_ID(mapi->id));
1266 if (mapi->namedproperty > 0) {
1267 for(i=0; i<mapi->namedproperty; i++) {
1268 printf(" Name: %s\n", mapi->propnames[i].data);
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);
1278 printf("Size: %i", mapidata->size);
1279 switch (PROP_TYPE(mapi->id)) {
1281 MAPISysTimetoDTR(mapidata->data, &thedate);
1283 TNEFPrintDate(thedate);
1287 printf(" Value: %li\n", (long int) *(mapidata->data));
1290 printf(" Value: %hi\n", *(mapidata->data));
1293 if (mapi->data->data[0]!=0) {
1294 printf(" Value: True\n");
1296 printf(" Value: False\n");
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);
1311 printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1313 printf(" Value: [");
1314 for(h=0; h< mapidata->size; h++) {
1315 if (isprint(mapidata->data[h]))
1316 printf("%c", mapidata->data[h]);
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]);
1339 printf(" Value: [%s]\n", mapidata->data);
1345 unsigned char *DecompressRTF(variableLength *p, int *size) {
1346 unsigned char *dst; // destination for uncompressed bytes
1350 variableLength comp_Prebuf;
1351 ULONG compressedSize, uncompressedSize, magic; // , crc32;
1353 comp_Prebuf.size = strlen(RTF_PREBUF);
1354 comp_Prebuf.data = calloc(comp_Prebuf.size + 1, 1);
1355 memcpy(comp_Prebuf.data, RTF_PREBUF, comp_Prebuf.size);
1360 compressedSize = (ULONG)SwapDWord(src+in);
1362 uncompressedSize = (ULONG)SwapDWord(src+in);
1364 magic = SwapDWord(src+in);
1366 // crc32 = SwapDWord(src+in);
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);
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);
1381 } else if (magic == 0x75465a4c) {
1382 // magic number that identifies the stream as a compressed stream
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++];
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
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++];
1411 dst[out++] = src[in++];
1414 // copy it back without the prebuffered data
1416 dst = calloc(uncompressedSize,1);
1417 memcpy(dst, src + comp_Prebuf.size, uncompressedSize);
1419 *size = uncompressedSize;
1421 } else { // unknown magic number
1422 printf("Unknown compression type (magic number %x)\n", magic );