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
strcpy(comp_Prebuf.data, RTF_PREBUF);
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 );