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 vl->size = 16; /* Size of struct GUID */
449 vl->data = calloc(vl->size, sizeof(WORD));
450 memcpy(vl->data, &d, vl->size);
451 d += 16; /* Size of struct GUID */
455 // Read in 2 bytes, but proceed by 4 bytes
457 vl->data = calloc(vl->size, sizeof(WORD));
458 temp_word = SwapWord(d);
459 memcpy(vl->data, &temp_word, vl->size);
469 vl->data = calloc(vl->size, sizeof(BYTE));
470 temp_dword = SwapDWord(d);
471 memcpy(vl->data, &temp_dword, vl->size);
478 vl->data = calloc(vl->size, sizeof(BYTE));
479 temp_ddword = SwapDDWord(d);
480 memcpy(vl->data, &temp_ddword, vl->size);
484 fprintf(stderr, "%s: Fatal BUG: unknown MAPI ID type (%u), (%u)\n", __func__, PROP_TYPE(mp->id), mp->id);
486 if (count == (mp->count-1)) {
493 if ((d-data) < size) {
494 if (TNEF->Debug >= 1) {
495 printf("ERROR DURING MAPI READ\n");
496 printf("Read %ld bytes, Expected %u bytes\n", (d-data), size);
497 printf("%ld bytes missing\n", size - (d-data));
499 } else if ((d-data) > size){
500 if (TNEF->Debug >= 1) {
501 printf("ERROR DURING MAPI READ\n");
502 printf("Read %ld bytes, Expected %u bytes\n", (d-data), size);
503 printf("%ld bytes extra\n", (d-data)-size);
508 // -----------------------------------------------------------------------------
509 int TNEFSentFor STD_ARGLIST {
510 WORD name_length, addr_length;
515 while ((d-data)<size) {
516 name_length = SwapWord(d);
518 if (TNEF->Debug >= 1)
519 printf("Sent For : %s", d);
522 addr_length = SwapWord(d);
524 if (TNEF->Debug >= 1)
530 // -----------------------------------------------------------------------------
531 int TNEFDateHandler STD_ARGLIST {
534 WORD *tmp_src, *tmp_dst;
537 p = &(TNEF->starting_attach);
538 switch (TNEFList[id].id) {
539 case attDateSent: Date = &(TNEF->dateSent); break;
540 case attDateRecd: Date = &(TNEF->dateReceived); break;
541 case attDateModified: Date = &(TNEF->dateModified); break;
542 case attDateStart: Date = &(TNEF->DateStart); break;
543 case attDateEnd: Date = &(TNEF->DateEnd); break;
544 case attAttachCreateDate:
545 while (p->next!=NULL) p=p->next;
546 Date = &(p->CreateDate);
548 case attAttachModifyDate:
549 while (p->next!=NULL) p=p->next;
550 Date = &(p->ModifyDate);
553 if (TNEF->Debug >= 1)
554 printf("MISSING CASE\n");
555 return YTNEF_UNKNOWN_PROPERTY;
558 tmp_src = (WORD*)data;
559 tmp_dst = (WORD*)Date;
560 for(i=0;i<sizeof(dtr)/sizeof(WORD);i++) {
561 *tmp_dst++ = SwapWord((BYTE*)tmp_src++);
566 void TNEFPrintDate(dtr Date) {
567 char days[7][15] = {"Sunday", "Monday", "Tuesday",
568 "Wednesday", "Thursday", "Friday", "Saturday"};
569 char months[12][15] = {"January", "February", "March", "April", "May",
570 "June", "July", "August", "September", "October", "November",
573 if (Date.wDayOfWeek < 7)
574 printf("%s ", days[Date.wDayOfWeek]);
576 if ((Date.wMonth < 13) && (Date.wMonth>0))
577 printf("%s ", months[Date.wMonth-1]);
579 printf("%hu, %hu ", Date.wDay, Date.wYear);
582 printf("%hu:%02hu:%02hu pm", (Date.wHour-12),
583 Date.wMinute, Date.wSecond);
584 else if (Date.wHour == 12)
585 printf("%hu:%02hu:%02hu pm", (Date.wHour),
586 Date.wMinute, Date.wSecond);
588 printf("%hu:%02hu:%02hu am", Date.wHour,
589 Date.wMinute, Date.wSecond);
591 // -----------------------------------------------------------------------------
592 int TNEFHexBreakdown STD_ARGLIST {
594 if (TNEF->Debug == 0)
597 printf("%s: [%i bytes] \n", TNEFList[id].name, size);
599 for(i=0; i<size; i++) {
600 printf("%02x ", data[i]);
601 if ((i+1)%16 == 0) printf("\n");
607 // -----------------------------------------------------------------------------
608 int TNEFDetailedPrint STD_ARGLIST {
610 if (TNEF->Debug == 0)
613 printf("%s: [%i bytes] \n", TNEFList[id].name, size);
615 for(i=0; i<size; i++) {
616 printf("%c", data[i]);
622 // -----------------------------------------------------------------------------
623 int TNEFAttachmentFilename STD_ARGLIST {
625 p = &(TNEF->starting_attach);
626 while (p->next!=NULL) p=p->next;
628 p->Title.size = size;
629 p->Title.data = calloc(size, sizeof(BYTE));
630 memcpy(p->Title.data, data, size);
635 // -----------------------------------------------------------------------------
636 int TNEFAttachmentSave STD_ARGLIST {
638 p = &(TNEF->starting_attach);
639 while (p->next!=NULL) p=p->next;
641 p->FileData.data = calloc(sizeof(unsigned char), size);
642 p->FileData.size = size;
644 memcpy(p->FileData.data, data, size);
649 // -----------------------------------------------------------------------------
650 int TNEFPriority STD_ARGLIST {
653 value = SwapDWord(data);
656 sprintf((TNEF->priority), "high");
659 sprintf((TNEF->priority), "normal");
662 sprintf((TNEF->priority), "low");
665 sprintf((TNEF->priority), "N/A");
671 // -----------------------------------------------------------------------------
672 int TNEFCheckForSignature(DWORD sig) {
673 DWORD signature = 0x223E9F78;
675 sig = SwapDWord((BYTE*)&sig);
677 if (signature == sig) {
680 return YTNEF_NOT_TNEF_STREAM;
684 // -----------------------------------------------------------------------------
685 int TNEFGetKey(TNEFStruct *TNEF, WORD *key) {
686 if (TNEF->IO.ReadProc (&(TNEF->IO), sizeof(WORD),1, key) < 1) {
687 if (TNEF->Debug >= 1)
688 printf("Error reading Key\n");
689 return YTNEF_ERROR_READING_DATA;
691 *key = SwapWord((BYTE*)key);
693 DEBUG1(TNEF->Debug, 2, "Key = %i", *key);
697 // -----------------------------------------------------------------------------
698 int TNEFGetHeader(TNEFStruct *TNEF, DWORD *type, DWORD *size) {
701 DEBUG(TNEF->Debug, 2, "About to read Component");
702 if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(BYTE),1, &component) < 1) {
703 return YTNEF_ERROR_READING_DATA;
707 DEBUG(TNEF->Debug, 2, "About to read type");
708 if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, type) < 1) {
709 if (TNEF->Debug >= 1)
710 printf("ERROR: Error reading type\n");
711 return YTNEF_ERROR_READING_DATA;
713 DEBUG1(TNEF->Debug, 2, "Type = %i", *type);
716 DEBUG(TNEF->Debug, 2, "About to read size");
717 if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, size) < 1) {
718 if (TNEF->Debug >= 1)
719 printf("ERROR: Error reading size\n");
720 return YTNEF_ERROR_READING_DATA;
724 DEBUG1(TNEF->Debug, 2, "Size = %i", *size);
726 *type = SwapDWord((BYTE*)type);
727 *size = SwapDWord((BYTE*)size);
732 // -----------------------------------------------------------------------------
733 int TNEFRawRead(TNEFStruct *TNEF, BYTE *data, DWORD size, WORD *checksum) {
737 if (TNEF->IO.ReadProc(&TNEF->IO, sizeof(BYTE), size, data) < size) {
738 if (TNEF->Debug >= 1)
739 printf("ERROR: Error reading data\n");
740 return YTNEF_ERROR_READING_DATA;
744 if (checksum != NULL) {
746 for(i=0; i<size; i++) {
748 *checksum = (*checksum + temp);
754 #define INITVARLENGTH(x) (x).data = NULL; (x).size = 0;
755 #define INITDTR(x) (x).wYear=0; (x).wMonth=0; (x).wDay=0; \
756 (x).wHour=0; (x).wMinute=0; (x).wSecond=0; \
758 #define INITSTR(x) memset((x), 0, sizeof(x));
759 void TNEFInitMapi(MAPIProps *p)
762 p->properties = NULL;
765 void TNEFInitAttachment(Attachment *p)
768 INITVARLENGTH(p->Title);
769 INITVARLENGTH(p->MetaFile);
770 INITDTR(p->CreateDate);
771 INITDTR(p->ModifyDate);
772 INITVARLENGTH(p->TransportFilename);
773 INITVARLENGTH(p->FileData);
774 INITVARLENGTH(p->IconData);
775 memset(&(p->RenderData), 0, sizeof(renddata));
776 TNEFInitMapi(&(p->MAPI));
780 void TNEFInitialize(TNEFStruct *TNEF)
782 INITSTR(TNEF->version);
783 INITVARLENGTH(TNEF->from);
784 INITVARLENGTH(TNEF->subject);
785 INITDTR(TNEF->dateSent);
786 INITDTR(TNEF->dateReceived);
788 INITSTR(TNEF->messageStatus);
789 INITSTR(TNEF->messageClass);
790 INITSTR(TNEF->messageID);
791 INITSTR(TNEF->parentID);
792 INITSTR(TNEF->conversationID);
793 INITVARLENGTH(TNEF->body);
794 INITSTR(TNEF->priority);
795 TNEFInitAttachment(&(TNEF->starting_attach));
796 INITDTR(TNEF->dateModified);
797 TNEFInitMapi(&(TNEF->MapiProperties));
798 INITVARLENGTH(TNEF->CodePage);
799 INITVARLENGTH(TNEF->OriginalMessageClass);
800 INITVARLENGTH(TNEF->Owner);
801 INITVARLENGTH(TNEF->SentFor);
802 INITVARLENGTH(TNEF->Delegate);
803 INITDTR(TNEF->DateStart);
804 INITDTR(TNEF->DateEnd);
805 INITVARLENGTH(TNEF->AidOwner);
807 TNEF->IO.data = NULL;
808 TNEF->IO.InitProc = NULL;
809 TNEF->IO.ReadProc = NULL;
810 TNEF->IO.CloseProc = NULL;
816 #define FREEVARLENGTH(x) if ((x).size > 0) { \
817 free((x).data); (x).size =0; }
818 void TNEFFree(TNEFStruct *TNEF) {
819 Attachment *p, *store;
821 FREEVARLENGTH(TNEF->from);
822 FREEVARLENGTH(TNEF->subject);
823 FREEVARLENGTH(TNEF->body);
824 FREEVARLENGTH(TNEF->CodePage);
825 FREEVARLENGTH(TNEF->OriginalMessageClass);
826 FREEVARLENGTH(TNEF->Owner);
827 FREEVARLENGTH(TNEF->SentFor);
828 FREEVARLENGTH(TNEF->Delegate);
829 FREEVARLENGTH(TNEF->AidOwner);
830 TNEFFreeMapiProps(&(TNEF->MapiProperties));
832 p = TNEF->starting_attach.next;
834 TNEFFreeAttachment(p);
841 void TNEFFreeAttachment(Attachment *p)
843 FREEVARLENGTH(p->Title);
844 FREEVARLENGTH(p->MetaFile);
845 FREEVARLENGTH(p->TransportFilename);
846 FREEVARLENGTH(p->FileData);
847 FREEVARLENGTH(p->IconData);
848 TNEFFreeMapiProps(&(p->MAPI));
851 void TNEFFreeMapiProps(MAPIProps *p)
854 for(i=0; i<p->count; i++) {
855 for(j=0; j<p->properties[i].count; j++) {
856 FREEVARLENGTH(p->properties[i].data[j]);
858 free(p->properties[i].data);
865 // Procedures to handle File IO
866 int TNEFFile_Open (TNEFIOStruct *IO) {
868 finfo = (TNEFFileInfo*)IO->data;
870 DEBUG1(finfo->Debug, 3, "Opening %s", finfo->filename);
871 if ((finfo->fptr = g_fopen(finfo->filename, "rb")) == NULL) {
878 int TNEFFile_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
880 finfo = (TNEFFileInfo*)IO->data;
882 DEBUG2(finfo->Debug, 3, "Reading %i blocks of %i size", count, size);
883 if (finfo->fptr != NULL) {
884 return fread((BYTE*)dest, size, count, finfo->fptr);
890 int TNEFFile_Close (TNEFIOStruct *IO) {
892 finfo = (TNEFFileInfo*)IO->data;
894 DEBUG1(finfo->Debug, 3, "Closing file %s", finfo->filename);
895 if (finfo->fptr != NULL) {
902 int TNEFParseFile(char *filename, TNEFStruct *TNEF) {
905 if (TNEF->Debug >= 1)
906 printf("Attempting to parse %s...\n", filename);
909 finfo.filename = filename;
911 finfo.Debug = TNEF->Debug;
912 TNEF->IO.data = (void*)&finfo;
913 TNEF->IO.InitProc = TNEFFile_Open;
914 TNEF->IO.ReadProc = TNEFFile_Read;
915 TNEF->IO.CloseProc = TNEFFile_Close;
916 return TNEFParse(TNEF);
918 //-------------------------------------------------------------
919 // Procedures to handle Memory IO
920 int TNEFMemory_Open (TNEFIOStruct *IO) {
922 minfo = (TNEFMemInfo*)IO->data;
924 minfo->ptr = minfo->dataStart;
928 int TNEFMemory_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
932 minfo = (TNEFMemInfo*)IO->data;
935 max = (minfo->dataStart + minfo->size) - (minfo->ptr);
940 DEBUG1(minfo->Debug, 3, "Copying %i bytes", length);
942 memcpy(dest, minfo->ptr, length);
947 int TNEFMemory_Close (TNEFIOStruct *IO) {
948 // Do nothing, really...
952 int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF) {
955 DEBUG(TNEF->Debug, 1, "Attempting to parse memory block...\n");
957 minfo.dataStart = memory;
960 minfo.Debug = TNEF->Debug;
961 TNEF->IO.data = (void*)&minfo;
962 TNEF->IO.InitProc = TNEFMemory_Open;
963 TNEF->IO.ReadProc = TNEFMemory_Read;
964 TNEF->IO.CloseProc = TNEFMemory_Close;
965 return TNEFParse(TNEF);
969 int TNEFParse(TNEFStruct *TNEF) {
975 WORD checksum, header_checksum;
978 if (TNEF->IO.ReadProc == NULL) {
979 printf("ERROR: Setup incorrectly: No ReadProc\n");
980 return YTNEF_INCORRECT_SETUP;
983 if (TNEF->IO.InitProc != NULL) {
984 DEBUG(TNEF->Debug, 2, "About to initialize");
985 if (TNEF->IO.InitProc (&TNEF->IO) != 0) {
986 return YTNEF_CANNOT_INIT_DATA;
988 DEBUG(TNEF->Debug, 2, "Initialization finished");
991 DEBUG(TNEF->Debug, 2, "Reading Signature");
992 if (TNEF->IO.ReadProc (&TNEF->IO, sizeof(DWORD), 1, &signature) < 1) {
993 printf("ERROR: Error reading signature\n");
994 if (TNEF->IO.CloseProc != NULL) {
995 TNEF->IO.CloseProc (&TNEF->IO);
997 return YTNEF_ERROR_READING_DATA;
1000 DEBUG(TNEF->Debug, 2, "Checking Signature");
1001 if (TNEFCheckForSignature(signature) < 0) {
1002 printf("ERROR: Signature does not match. Not TNEF.\n");
1003 if (TNEF->IO.CloseProc != NULL) {
1004 TNEF->IO.CloseProc (&TNEF->IO);
1006 return YTNEF_NOT_TNEF_STREAM;
1009 DEBUG(TNEF->Debug, 2, "Reading Key.");
1011 if (TNEFGetKey(TNEF, &key) < 0) {
1012 printf("ERROR: Unable to retrieve key.\n");
1013 if (TNEF->IO.CloseProc != NULL) {
1014 TNEF->IO.CloseProc (&TNEF->IO);
1016 return YTNEF_NO_KEY;
1019 DEBUG(TNEF->Debug, 2, "Starting Full Processing.");
1021 while (TNEFGetHeader(TNEF, &type, &size) == 0) {
1022 DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size);
1024 data = calloc(size, sizeof(BYTE));
1025 if (TNEFRawRead(TNEF, data, size, &header_checksum)< 0) {
1026 printf("ERROR: Unable to read data.\n");
1027 if (TNEF->IO.CloseProc != NULL) {
1028 TNEF->IO.CloseProc (&TNEF->IO);
1031 return YTNEF_ERROR_READING_DATA;
1033 if (TNEFRawRead(TNEF, (BYTE *)&checksum, 2, NULL) < 0) {
1034 printf("ERROR: Unable to read checksum.\n");
1035 if (TNEF->IO.CloseProc != NULL) {
1036 TNEF->IO.CloseProc (&TNEF->IO);
1039 return YTNEF_ERROR_READING_DATA;
1041 checksum = SwapWord((BYTE*)&checksum);
1042 if (checksum != header_checksum) {
1043 printf("ERROR: Checksum mismatch. Data corruption?:\n");
1044 if (TNEF->IO.CloseProc != NULL) {
1045 TNEF->IO.CloseProc (&TNEF->IO);
1048 return YTNEF_BAD_CHECKSUM;
1050 for(i=0; i<(sizeof(TNEFList)/sizeof(TNEFHandler));i++) {
1051 if (TNEFList[i].id == type) {
1052 if (TNEFList[i].handler != NULL) {
1053 if (TNEFList[i].handler(TNEF, i, data, size) < 0) {
1055 if (TNEF->IO.CloseProc != NULL) {
1056 TNEF->IO.CloseProc (&TNEF->IO);
1058 return YTNEF_ERROR_IN_HANDLER;
1061 DEBUG2(TNEF->Debug, 1, "No handler for %s: %i bytes",
1062 TNEFList[i].name, size);
1071 if (TNEF->IO.CloseProc != NULL) {
1072 TNEF->IO.CloseProc (&TNEF->IO);
1078 // ----------------------------------------------------------------------------
1080 variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID)
1084 for(i=0;i<p->count; i++) {
1085 if ((p->properties[i].id == ID) && (p->properties[i].custom == 1)) {
1086 return (p->properties[i].data);
1090 return MAPI_UNDEFINED;
1093 variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID)
1097 for(i=0;i<p->count; i++) {
1098 if ((p->properties[i].id == ID) && (p->properties[i].custom == 0)) {
1099 return (p->properties[i].data);
1103 return MAPI_UNDEFINED;
1106 int MAPISysTimetoDTR(BYTE *data, dtr *thedate)
1109 int startingdate = 0;
1111 int days_in_year = 365;
1112 unsigned int months[] = {31,28,31,30,31,30,31,31,30,31,30,31};
1114 ddword_tmp = *((DDWORD*)data);
1115 ddword_tmp = ddword_tmp /10; // micro-s
1116 ddword_tmp /= 1000; // ms
1117 ddword_tmp /= 1000; // s
1119 thedate->wSecond = (ddword_tmp % 60);
1121 ddword_tmp /= 60; // seconds to minutes
1122 thedate->wMinute = (ddword_tmp % 60);
1124 ddword_tmp /= 60; //minutes to hours
1125 thedate->wHour = (ddword_tmp % 24);
1127 ddword_tmp /= 24; // Hours to days
1129 // Now calculate the year based on # of days
1130 thedate->wYear = 1601;
1132 while(ddword_tmp >= days_in_year) {
1133 ddword_tmp-=days_in_year;
1137 if ((thedate->wYear % 4) == 0) {
1138 if ((thedate->wYear % 100) == 0) {
1139 // if the year is 1700,1800,1900, etc, then it is only
1140 // a leap year if exactly divisible by 400, not 4.
1141 if ((thedate->wYear % 400) == 0) {
1153 // the remaining number is the day # in this year
1154 // So now calculate the Month, & Day of month
1155 if ((thedate->wYear % 4) == 0) {
1156 // 29 days in february in a leap year
1160 tmp_date = (int)ddword_tmp;
1161 thedate->wDayOfWeek = (tmp_date + startingdate) % 7;
1162 thedate->wMonth = 0;
1164 while (tmp_date > months[thedate->wMonth]) {
1165 tmp_date -= months[thedate->wMonth];
1169 thedate->wDay = tmp_date+1;
1173 int IsCompressedRTF(variableLength *p) {
1177 ULONG compressedSize, uncompressedSize, magic, crc32;
1182 compressedSize = (ULONG)SwapDWord(src+in);
1184 uncompressedSize = (ULONG)SwapDWord(src+in);
1186 magic = SwapDWord(src+in);
1188 crc32 = SwapDWord(src+in);
1191 if (magic == 0x414c454d) {
1193 } else if (magic == 0x75465a4c) {
1199 unsigned char *src = p->data;
1200 ULONG magic = SwapDWord(src + 8);
1202 if (magic == 0x414c454d || 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 memcpy(comp_Prebuf.data, RTF_PREBUF, comp_Prebuf.size);
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 );