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 {
327 count = SwapDWord(d);
329 // printf("Recipient Table containing %u rows\n", count);
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);
338 for(current_prop=0; current_prop<propcount; current_prop++) {
345 // -----------------------------------------------------------------------------
346 int TNEFAttachmentMAPI STD_ARGLIST {
348 // Find the last attachment.
350 p = &(TNEF->starting_attach);
351 while (p->next!=NULL) p=p->next;
352 TNEFFillMapi(TNEF, data, size, &(p->MAPI));
356 // -----------------------------------------------------------------------------
357 int TNEFMapiProperties STD_ARGLIST {
358 TNEFFillMapi(TNEF, data, size, &(TNEF->MapiProperties));
362 void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) {
378 p->count = SwapDWord(data);
380 p->properties = calloc(p->count, sizeof(MAPIProperty));
383 for(i=0; i<p->count; i++) {
385 mp->id = SwapDWord(d);
389 mp->namedproperty = 0;
391 if (PROP_ID(mp->id) >= 0x8000) {
393 memcpy(&(mp->guid[0]), d, 16);
396 length = SwapDWord(d);
399 mp->namedproperty = length;
400 mp->propnames = calloc(length, sizeof(variableLength));
403 mp->propnames[length-1].data = calloc(type, sizeof(BYTE));
404 mp->propnames[length-1].size = type;
406 for(j=0; j<(type>>1); j++) {
407 mp->propnames[length-1].data[j] = d[j*2];
409 d += type + ((type % 4) ? (4 - type%4) : 0);
416 mp->id = PROP_TAG(PROP_TYPE(mp->id), type);
421 //printf("Type id = %04x\n", PROP_TYPE(mp->id));
422 if (PROP_TYPE(mp->id) & MV_FLAG) {
423 mp->id = PROP_TAG(PROP_TYPE(mp->id) - MV_FLAG, PROP_ID(mp->id));
424 mp->count = SwapDWord(d);
428 mp->data = calloc(mp->count, sizeof(variableLength));
433 vl = &(mp->data[count]);
436 switch (PROP_TYPE(mp->id)) {
441 // First number of objects (assume 1 for now)
443 vl->size = SwapDWord(d);
446 // now size of object
447 vl->size = SwapDWord(d);
451 if (PROP_TYPE(mp->id) == PT_UNICODE) {
452 vl->data = to_utf8(vl->size, d);
455 vl->data = calloc(vl->size, sizeof(BYTE));
456 memcpy(vl->data, d, vl->size);
459 // Make sure to read in a multiple of 4
461 offset = ((num % 4) ? (4 - num%4) : 0);
462 d += num + ((num % 4) ? (4 - num%4) : 0);
466 // Read in 2 bytes, but proceed by 4 bytes
468 vl->data = calloc(vl->size, sizeof(WORD));
469 temp_word = SwapWord(d);
470 memcpy(vl->data, &temp_word, vl->size);
480 vl->data = calloc(vl->size, sizeof(BYTE));
481 temp_dword = SwapDWord(d);
482 memcpy(vl->data, &temp_dword, vl->size);
489 vl->data = calloc(vl->size, sizeof(BYTE));
490 temp_ddword = SwapDDWord(d);
491 memcpy(vl->data, &temp_ddword, vl->size);
495 if (count == (mp->count-1)) {
502 if ((d-data) < size) {
503 if (TNEF->Debug >= 1) {
504 printf("ERROR DURING MAPI READ\n");
505 printf("Read %i bytes, Expected %i bytes\n", (d-data), size);
506 printf("%i bytes missing\n", size - (d-data));
508 } else if ((d-data) > size){
509 if (TNEF->Debug >= 1) {
510 printf("ERROR DURING MAPI READ\n");
511 printf("Read %i bytes, Expected %i bytes\n", (d-data), size);
512 printf("%i bytes extra\n", (d-data)-size);
517 // -----------------------------------------------------------------------------
518 int TNEFSentFor STD_ARGLIST {
519 WORD name_length, addr_length;
524 while ((d-data)<size) {
525 name_length = SwapWord(d);
527 if (TNEF->Debug >= 1)
528 printf("Sent For : %s", d);
531 addr_length = SwapWord(d);
533 if (TNEF->Debug >= 1)
539 // -----------------------------------------------------------------------------
540 int TNEFDateHandler STD_ARGLIST {
543 WORD *tmp_src, *tmp_dst;
546 p = &(TNEF->starting_attach);
547 switch (TNEFList[id].id) {
548 case attDateSent: Date = &(TNEF->dateSent); break;
549 case attDateRecd: Date = &(TNEF->dateReceived); break;
550 case attDateModified: Date = &(TNEF->dateModified); break;
551 case attDateStart: Date = &(TNEF->DateStart); break;
552 case attDateEnd: Date = &(TNEF->DateEnd); break;
553 case attAttachCreateDate:
554 while (p->next!=NULL) p=p->next;
555 Date = &(p->CreateDate);
557 case attAttachModifyDate:
558 while (p->next!=NULL) p=p->next;
559 Date = &(p->ModifyDate);
562 if (TNEF->Debug >= 1)
563 printf("MISSING CASE\n");
564 return YTNEF_UNKNOWN_PROPERTY;
567 tmp_src = (WORD*)data;
568 tmp_dst = (WORD*)Date;
569 for(i=0;i<sizeof(dtr)/sizeof(WORD);i++) {
570 *tmp_dst++ = SwapWord((BYTE*)tmp_src++);
575 void TNEFPrintDate(dtr Date) {
576 char days[7][15] = {"Sunday", "Monday", "Tuesday",
577 "Wednesday", "Thursday", "Friday", "Saturday"};
578 char months[12][15] = {"January", "February", "March", "April", "May",
579 "June", "July", "August", "September", "October", "November",
582 if (Date.wDayOfWeek < 7)
583 printf("%s ", days[Date.wDayOfWeek]);
585 if ((Date.wMonth < 13) && (Date.wMonth>0))
586 printf("%s ", months[Date.wMonth-1]);
588 printf("%hu, %hu ", Date.wDay, Date.wYear);
591 printf("%hu:%02hu:%02hu pm", (Date.wHour-12),
592 Date.wMinute, Date.wSecond);
593 else if (Date.wHour == 12)
594 printf("%hu:%02hu:%02hu pm", (Date.wHour),
595 Date.wMinute, Date.wSecond);
597 printf("%hu:%02hu:%02hu am", Date.wHour,
598 Date.wMinute, Date.wSecond);
600 // -----------------------------------------------------------------------------
601 int TNEFHexBreakdown STD_ARGLIST {
603 if (TNEF->Debug == 0)
606 printf("%s: [%i bytes] \n", TNEFList[id].name, size);
608 for(i=0; i<size; i++) {
609 printf("%02x ", data[i]);
610 if ((i+1)%16 == 0) printf("\n");
616 // -----------------------------------------------------------------------------
617 int TNEFDetailedPrint STD_ARGLIST {
619 if (TNEF->Debug == 0)
622 printf("%s: [%i bytes] \n", TNEFList[id].name, size);
624 for(i=0; i<size; i++) {
625 printf("%c", data[i]);
631 // -----------------------------------------------------------------------------
632 int TNEFAttachmentFilename STD_ARGLIST {
634 p = &(TNEF->starting_attach);
635 while (p->next!=NULL) p=p->next;
637 p->Title.size = size;
638 p->Title.data = calloc(size, sizeof(BYTE));
639 memcpy(p->Title.data, data, size);
644 // -----------------------------------------------------------------------------
645 int TNEFAttachmentSave STD_ARGLIST {
647 p = &(TNEF->starting_attach);
648 while (p->next!=NULL) p=p->next;
650 p->FileData.data = calloc(sizeof(unsigned char), size);
651 p->FileData.size = size;
653 memcpy(p->FileData.data, data, size);
658 // -----------------------------------------------------------------------------
659 int TNEFPriority STD_ARGLIST {
662 value = SwapDWord(data);
665 sprintf((TNEF->priority), "high");
668 sprintf((TNEF->priority), "normal");
671 sprintf((TNEF->priority), "low");
674 sprintf((TNEF->priority), "N/A");
680 // -----------------------------------------------------------------------------
681 int TNEFCheckForSignature(DWORD sig) {
682 DWORD signature = 0x223E9F78;
684 sig = SwapDWord((BYTE*)&sig);
686 if (signature == sig) {
689 return YTNEF_NOT_TNEF_STREAM;
693 // -----------------------------------------------------------------------------
694 int TNEFGetKey(TNEFStruct *TNEF, WORD *key) {
695 if (TNEF->IO.ReadProc (&(TNEF->IO), sizeof(WORD),1, key) < 1) {
696 if (TNEF->Debug >= 1)
697 printf("Error reading Key\n");
698 return YTNEF_ERROR_READING_DATA;
700 *key = SwapWord((BYTE*)key);
702 DEBUG1(TNEF->Debug, 2, "Key = %i", *key);
706 // -----------------------------------------------------------------------------
707 int TNEFGetHeader(TNEFStruct *TNEF, DWORD *type, DWORD *size) {
710 DEBUG(TNEF->Debug, 2, "About to read Component");
711 if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(BYTE),1, &component) < 1) {
712 return YTNEF_ERROR_READING_DATA;
716 DEBUG(TNEF->Debug, 2, "About to read type");
717 if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, type) < 1) {
718 if (TNEF->Debug >= 1)
719 printf("ERROR: Error reading type\n");
720 return YTNEF_ERROR_READING_DATA;
722 DEBUG1(TNEF->Debug, 2, "Type = %i", *type);
725 DEBUG(TNEF->Debug, 2, "About to read size");
726 if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, size) < 1) {
727 if (TNEF->Debug >= 1)
728 printf("ERROR: Error reading size\n");
729 return YTNEF_ERROR_READING_DATA;
733 DEBUG1(TNEF->Debug, 2, "Size = %i", *size);
735 *type = SwapDWord((BYTE*)type);
736 *size = SwapDWord((BYTE*)size);
741 // -----------------------------------------------------------------------------
742 int TNEFRawRead(TNEFStruct *TNEF, BYTE *data, DWORD size, WORD *checksum) {
746 if (TNEF->IO.ReadProc(&TNEF->IO, sizeof(BYTE), size, data) < size) {
747 if (TNEF->Debug >= 1)
748 printf("ERROR: Error reading data\n");
749 return YTNEF_ERROR_READING_DATA;
753 if (checksum != NULL) {
755 for(i=0; i<size; i++) {
757 *checksum = (*checksum + temp);
763 #define INITVARLENGTH(x) (x).data = NULL; (x).size = 0;
764 #define INITDTR(x) (x).wYear=0; (x).wMonth=0; (x).wDay=0; \
765 (x).wHour=0; (x).wMinute=0; (x).wSecond=0; \
767 #define INITSTR(x) memset((x), 0, sizeof(x));
768 void TNEFInitMapi(MAPIProps *p)
771 p->properties = NULL;
774 void TNEFInitAttachment(Attachment *p)
777 INITVARLENGTH(p->Title);
778 INITVARLENGTH(p->MetaFile);
779 INITDTR(p->CreateDate);
780 INITDTR(p->ModifyDate);
781 INITVARLENGTH(p->TransportFilename);
782 INITVARLENGTH(p->FileData);
783 INITVARLENGTH(p->IconData);
784 memset(&(p->RenderData), 0, sizeof(renddata));
785 TNEFInitMapi(&(p->MAPI));
789 void TNEFInitialize(TNEFStruct *TNEF)
791 INITSTR(TNEF->version);
792 INITVARLENGTH(TNEF->from);
793 INITVARLENGTH(TNEF->subject);
794 INITDTR(TNEF->dateSent);
795 INITDTR(TNEF->dateReceived);
797 INITSTR(TNEF->messageStatus);
798 INITSTR(TNEF->messageClass);
799 INITSTR(TNEF->messageID);
800 INITSTR(TNEF->parentID);
801 INITSTR(TNEF->conversationID);
802 INITVARLENGTH(TNEF->body);
803 INITSTR(TNEF->priority);
804 TNEFInitAttachment(&(TNEF->starting_attach));
805 INITDTR(TNEF->dateModified);
806 TNEFInitMapi(&(TNEF->MapiProperties));
807 INITVARLENGTH(TNEF->CodePage);
808 INITVARLENGTH(TNEF->OriginalMessageClass);
809 INITVARLENGTH(TNEF->Owner);
810 INITVARLENGTH(TNEF->SentFor);
811 INITVARLENGTH(TNEF->Delegate);
812 INITDTR(TNEF->DateStart);
813 INITDTR(TNEF->DateEnd);
814 INITVARLENGTH(TNEF->AidOwner);
816 TNEF->IO.data = NULL;
817 TNEF->IO.InitProc = NULL;
818 TNEF->IO.ReadProc = NULL;
819 TNEF->IO.CloseProc = NULL;
825 #define FREEVARLENGTH(x) if ((x).size > 0) { \
826 free((x).data); (x).size =0; }
827 void TNEFFree(TNEFStruct *TNEF) {
828 Attachment *p, *store;
830 FREEVARLENGTH(TNEF->from);
831 FREEVARLENGTH(TNEF->subject);
832 FREEVARLENGTH(TNEF->body);
833 FREEVARLENGTH(TNEF->CodePage);
834 FREEVARLENGTH(TNEF->OriginalMessageClass);
835 FREEVARLENGTH(TNEF->Owner);
836 FREEVARLENGTH(TNEF->SentFor);
837 FREEVARLENGTH(TNEF->Delegate);
838 FREEVARLENGTH(TNEF->AidOwner);
839 TNEFFreeMapiProps(&(TNEF->MapiProperties));
841 p = TNEF->starting_attach.next;
843 TNEFFreeAttachment(p);
850 void TNEFFreeAttachment(Attachment *p)
852 FREEVARLENGTH(p->Title);
853 FREEVARLENGTH(p->MetaFile);
854 FREEVARLENGTH(p->TransportFilename);
855 FREEVARLENGTH(p->FileData);
856 FREEVARLENGTH(p->IconData);
857 TNEFFreeMapiProps(&(p->MAPI));
860 void TNEFFreeMapiProps(MAPIProps *p)
863 for(i=0; i<p->count; i++) {
864 for(j=0; j<p->properties[i].count; j++) {
865 FREEVARLENGTH(p->properties[i].data[j]);
867 free(p->properties[i].data);
874 // Procedures to handle File IO
875 int TNEFFile_Open (TNEFIOStruct *IO) {
877 finfo = (TNEFFileInfo*)IO->data;
879 DEBUG1(finfo->Debug, 3, "Opening %s", finfo->filename);
880 if ((finfo->fptr = g_fopen(finfo->filename, "rb")) == NULL) {
887 int TNEFFile_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
889 finfo = (TNEFFileInfo*)IO->data;
891 DEBUG2(finfo->Debug, 3, "Reading %i blocks of %i size", count, size);
892 if (finfo->fptr != NULL) {
893 return fread((BYTE*)dest, size, count, finfo->fptr);
899 int TNEFFile_Close (TNEFIOStruct *IO) {
901 finfo = (TNEFFileInfo*)IO->data;
903 DEBUG1(finfo->Debug, 3, "Closing file %s", finfo->filename);
904 if (finfo->fptr != NULL) {
911 int TNEFParseFile(char *filename, TNEFStruct *TNEF) {
914 if (TNEF->Debug >= 1)
915 printf("Attempting to parse %s...\n", filename);
918 finfo.filename = filename;
920 finfo.Debug = TNEF->Debug;
921 TNEF->IO.data = (void*)&finfo;
922 TNEF->IO.InitProc = TNEFFile_Open;
923 TNEF->IO.ReadProc = TNEFFile_Read;
924 TNEF->IO.CloseProc = TNEFFile_Close;
925 return TNEFParse(TNEF);
927 //-------------------------------------------------------------
928 // Procedures to handle Memory IO
929 int TNEFMemory_Open (TNEFIOStruct *IO) {
931 minfo = (TNEFMemInfo*)IO->data;
933 minfo->ptr = minfo->dataStart;
937 int TNEFMemory_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
941 minfo = (TNEFMemInfo*)IO->data;
944 max = (minfo->dataStart + minfo->size) - (minfo->ptr);
949 DEBUG1(minfo->Debug, 3, "Copying %i bytes", length);
951 memcpy(dest, minfo->ptr, length);
956 int TNEFMemory_Close (TNEFIOStruct *IO) {
957 // Do nothing, really...
961 int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF) {
964 DEBUG(TNEF->Debug, 1, "Attempting to parse memory block...\n");
966 minfo.dataStart = memory;
969 minfo.Debug = TNEF->Debug;
970 TNEF->IO.data = (void*)&minfo;
971 TNEF->IO.InitProc = TNEFMemory_Open;
972 TNEF->IO.ReadProc = TNEFMemory_Read;
973 TNEF->IO.CloseProc = TNEFMemory_Close;
974 return TNEFParse(TNEF);
978 int TNEFParse(TNEFStruct *TNEF) {
984 WORD checksum, header_checksum;
987 if (TNEF->IO.ReadProc == NULL) {
988 printf("ERROR: Setup incorrectly: No ReadProc\n");
989 return YTNEF_INCORRECT_SETUP;
992 if (TNEF->IO.InitProc != NULL) {
993 DEBUG(TNEF->Debug, 2, "About to initialize");
994 if (TNEF->IO.InitProc (&TNEF->IO) != 0) {
995 return YTNEF_CANNOT_INIT_DATA;
997 DEBUG(TNEF->Debug, 2, "Initialization finished");
1000 DEBUG(TNEF->Debug, 2, "Reading Signature");
1001 if (TNEF->IO.ReadProc (&TNEF->IO, sizeof(DWORD), 1, &signature) < 1) {
1002 printf("ERROR: Error reading signature\n");
1003 if (TNEF->IO.CloseProc != NULL) {
1004 TNEF->IO.CloseProc (&TNEF->IO);
1006 return YTNEF_ERROR_READING_DATA;
1009 DEBUG(TNEF->Debug, 2, "Checking Signature");
1010 if (TNEFCheckForSignature(signature) < 0) {
1011 printf("ERROR: Signature does not match. Not TNEF.\n");
1012 if (TNEF->IO.CloseProc != NULL) {
1013 TNEF->IO.CloseProc (&TNEF->IO);
1015 return YTNEF_NOT_TNEF_STREAM;
1018 DEBUG(TNEF->Debug, 2, "Reading Key.");
1020 if (TNEFGetKey(TNEF, &key) < 0) {
1021 printf("ERROR: Unable to retrieve key.\n");
1022 if (TNEF->IO.CloseProc != NULL) {
1023 TNEF->IO.CloseProc (&TNEF->IO);
1025 return YTNEF_NO_KEY;
1028 DEBUG(TNEF->Debug, 2, "Starting Full Processing.");
1030 while (TNEFGetHeader(TNEF, &type, &size) == 0) {
1031 DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size);
1033 data = calloc(size, sizeof(BYTE));
1034 if (TNEFRawRead(TNEF, data, size, &header_checksum)< 0) {
1035 printf("ERROR: Unable to read data.\n");
1036 if (TNEF->IO.CloseProc != NULL) {
1037 TNEF->IO.CloseProc (&TNEF->IO);
1040 return YTNEF_ERROR_READING_DATA;
1042 if (TNEFRawRead(TNEF, (BYTE *)&checksum, 2, NULL) < 0) {
1043 printf("ERROR: Unable to read checksum.\n");
1044 if (TNEF->IO.CloseProc != NULL) {
1045 TNEF->IO.CloseProc (&TNEF->IO);
1048 return YTNEF_ERROR_READING_DATA;
1050 checksum = SwapWord((BYTE*)&checksum);
1051 if (checksum != header_checksum) {
1052 printf("ERROR: Checksum mismatch. Data corruption?:\n");
1053 if (TNEF->IO.CloseProc != NULL) {
1054 TNEF->IO.CloseProc (&TNEF->IO);
1057 return YTNEF_BAD_CHECKSUM;
1059 for(i=0; i<(sizeof(TNEFList)/sizeof(TNEFHandler));i++) {
1060 if (TNEFList[i].id == type) {
1061 if (TNEFList[i].handler != NULL) {
1062 if (TNEFList[i].handler(TNEF, i, data, size) < 0) {
1064 if (TNEF->IO.CloseProc != NULL) {
1065 TNEF->IO.CloseProc (&TNEF->IO);
1067 return YTNEF_ERROR_IN_HANDLER;
1070 DEBUG2(TNEF->Debug, 1, "No handler for %s: %i bytes",
1071 TNEFList[i].name, size);
1080 if (TNEF->IO.CloseProc != NULL) {
1081 TNEF->IO.CloseProc (&TNEF->IO);
1087 // ----------------------------------------------------------------------------
1089 variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID)
1093 for(i=0;i<p->count; i++) {
1094 if ((p->properties[i].id == ID) && (p->properties[i].custom == 1)) {
1095 return (p->properties[i].data);
1099 return MAPI_UNDEFINED;
1102 variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID)
1106 for(i=0;i<p->count; i++) {
1107 if ((p->properties[i].id == ID) && (p->properties[i].custom == 0)) {
1108 return (p->properties[i].data);
1112 return MAPI_UNDEFINED;
1115 int MAPISysTimetoDTR(BYTE *data, dtr *thedate)
1118 int startingdate = 0;
1120 int days_in_year = 365;
1121 unsigned int months[] = {31,28,31,30,31,30,31,31,30,31,30,31};
1123 ddword_tmp = *((DDWORD*)data);
1124 ddword_tmp = ddword_tmp /10; // micro-s
1125 ddword_tmp /= 1000; // ms
1126 ddword_tmp /= 1000; // s
1128 thedate->wSecond = (ddword_tmp % 60);
1130 ddword_tmp /= 60; // seconds to minutes
1131 thedate->wMinute = (ddword_tmp % 60);
1133 ddword_tmp /= 60; //minutes to hours
1134 thedate->wHour = (ddword_tmp % 24);
1136 ddword_tmp /= 24; // Hours to days
1138 // Now calculate the year based on # of days
1139 thedate->wYear = 1601;
1141 while(ddword_tmp >= days_in_year) {
1142 ddword_tmp-=days_in_year;
1146 if ((thedate->wYear % 4) == 0) {
1147 if ((thedate->wYear % 100) == 0) {
1148 // if the year is 1700,1800,1900, etc, then it is only
1149 // a leap year if exactly divisible by 400, not 4.
1150 if ((thedate->wYear % 400) == 0) {
1162 // the remaining number is the day # in this year
1163 // So now calculate the Month, & Day of month
1164 if ((thedate->wYear % 4) == 0) {
1165 // 29 days in february in a leap year
1169 tmp_date = (int)ddword_tmp;
1170 thedate->wDayOfWeek = (tmp_date + startingdate) % 7;
1171 thedate->wMonth = 0;
1173 while (tmp_date > months[thedate->wMonth]) {
1174 tmp_date -= months[thedate->wMonth];
1178 thedate->wDay = tmp_date+1;
1182 int IsCompressedRTF(variableLength *p) {
1185 ULONG compressedSize, uncompressedSize, magic, crc32;
1190 compressedSize = (ULONG)SwapDWord(src+in);
1192 uncompressedSize = (ULONG)SwapDWord(src+in);
1194 magic = SwapDWord(src+in);
1196 crc32 = SwapDWord(src+in);
1199 if (magic == 0x414c454d) {
1201 } else if (magic == 0x75465a4c) {
1208 void MAPIPrint(MAPIProps *p)
1213 variableLength *mapidata;
1214 variableLength vlTemp;
1217 for(j=0; j<p->count; j++) {
1218 mapi = &(p->properties[j]);
1219 printf(" #%i: Type: [", j);
1220 switch (PROP_TYPE(mapi->id)) {
1221 case PT_UNSPECIFIED:
1222 printf(" NONE "); break;
1224 printf(" NULL "); break;
1226 printf(" I2 "); break;
1228 printf(" LONG "); break;
1230 printf(" R4 "); break;
1232 printf(" DOUBLE "); break;
1234 printf("CURRENCY "); break;
1236 printf("APP TIME "); break;
1238 printf(" ERROR "); break;
1240 printf(" BOOLEAN "); break;
1242 printf(" OBJECT "); break;
1244 printf(" I8 "); break;
1246 printf(" STRING8 "); break;
1248 printf(" UNICODE "); break;
1250 printf("SYS TIME "); break;
1252 printf("OLE GUID "); break;
1254 printf(" BINARY "); break;
1256 printf("<%x>", PROP_TYPE(mapi->id)); break;
1259 printf("] Code: [");
1260 if (mapi->custom == 1) {
1261 printf("UD:x%04x", PROP_ID(mapi->id));
1264 for(index=0; index<sizeof(MPList)/sizeof(MAPIPropertyTagList); index++) {
1265 if ((MPList[index].id == PROP_ID(mapi->id)) && (found == 0)) {
1266 printf("%s", MPList[index].name);
1271 printf("0x%04x", PROP_ID(mapi->id));
1275 if (mapi->namedproperty > 0) {
1276 for(i=0; i<mapi->namedproperty; i++) {
1277 printf(" Name: %s\n", mapi->propnames[i].data);
1280 for (i=0;i<mapi->count;i++) {
1281 mapidata = &(mapi->data[i]);
1282 if (mapi->count > 1) {
1283 printf(" [%i/%i] ", i, mapi->count);
1287 printf("Size: %i", mapidata->size);
1288 switch (PROP_TYPE(mapi->id)) {
1290 MAPISysTimetoDTR(mapidata->data, &thedate);
1292 TNEFPrintDate(thedate);
1296 printf(" Value: %li\n", (long int) *(mapidata->data));
1299 printf(" Value: %hi\n", *(mapidata->data));
1302 if (mapi->data->data[0]!=0) {
1303 printf(" Value: True\n");
1305 printf(" Value: False\n");
1312 if(IsCompressedRTF(mapidata)==1) {
1313 printf(" Detected Compressed RTF.");
1314 printf("Decompressed text follows\n");
1315 printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1316 if((vlTemp.data = DecompressRTF(mapidata, &(vlTemp.size))) != NULL) {
1317 printf("%s\n", vlTemp.data);
1320 printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1322 printf(" Value: [");
1323 for(h=0; h< mapidata->size; h++) {
1324 if (isprint(mapidata->data[h]))
1325 printf("%c", mapidata->data[h]);
1334 printf(" Value: [%s]\n", mapidata->data);
1335 if (strlen(mapidata->data) != mapidata->size-1) {
1336 printf("Detected Hidden data: [");
1337 for(h=0; h< mapidata->size; h++) {
1338 if (isprint(mapidata->data[h]))
1339 printf("%c", mapidata->data[h]);
1348 printf(" Value: [%s]\n", mapidata->data);
1354 unsigned char *DecompressRTF(variableLength *p, int *size) {
1355 unsigned char *dst; // destination for uncompressed bytes
1359 variableLength comp_Prebuf;
1360 ULONG compressedSize, uncompressedSize, magic, crc32;
1362 comp_Prebuf.size = strlen(RTF_PREBUF);
1363 comp_Prebuf.data = calloc(comp_Prebuf.size + 1, 1);
1364 strcpy(comp_Prebuf.data, RTF_PREBUF);
1369 compressedSize = (ULONG)SwapDWord(src+in);
1371 uncompressedSize = (ULONG)SwapDWord(src+in);
1373 magic = SwapDWord(src+in);
1375 crc32 = SwapDWord(src+in);
1378 // check size excluding the size field itself
1379 if (compressedSize != p->size - 4) {
1380 printf(" Size Mismatch: %i != %i\n", compressedSize, p->size-4);
1385 if (magic == 0x414c454d) {
1386 // magic number that identifies the stream as a uncompressed stream
1387 dst = calloc(uncompressedSize,1);
1388 memcpy(dst, src+4, uncompressedSize);
1390 } else if (magic == 0x75465a4c) {
1391 // magic number that identifies the stream as a compressed stream
1394 dst = calloc(comp_Prebuf.size + uncompressedSize,1);
1395 memcpy(dst, comp_Prebuf.data, comp_Prebuf.size);
1396 out = comp_Prebuf.size;
1397 while (out < (comp_Prebuf.size+uncompressedSize)) {
1398 // each flag byte flags 8 literals/references, 1 per bit
1399 flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1;
1400 if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0 for literal
1401 int offset = src[in++];
1402 int length = src[in++];
1404 offset = (offset << 4) | (length >> 4); // the offset relative to block start
1405 length = (length & 0xF) + 2; // the number of bytes to copy
1406 // the decompression buffer is supposed to wrap around back
1407 // to the beginning when the end is reached. we save the
1408 // need for such a buffer by pointing straight into the data
1409 // buffer, and simulating this behaviour by modifying the
1410 // pointers appropriately.
1411 offset = (out / 4096) * 4096 + offset;
1412 if (offset >= out) // take from previous block
1414 // note: can't use System.arraycopy, because the referenced
1415 // bytes can cross through the current out position.
1416 end = offset + length;
1417 while (offset < end)
1418 dst[out++] = dst[offset++];
1420 dst[out++] = src[in++];
1423 // copy it back without the prebuffered data
1425 dst = calloc(uncompressedSize,1);
1426 memcpy(dst, src + comp_Prebuf.size, uncompressedSize);
1428 *size = uncompressedSize;
1430 } else { // unknown magic number
1431 printf("Unknown compression type (magic number %x)\n", magic );