-/*
- * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2008 Colin Leroy <colin@colino.net>
- * and the Claws Mail Team
- *
- * This file Copyright (C) 2002-2007 Randall Hand <yerase@yerot.com>
- * Thanks to him for allowing redistribution of this code as GPLv3.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#include "claws-features.h"
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include "ytnef.h"
-#include "tnef-errors.h"
-#include "mapi.h"
-#include "mapidefs.h"
-#include "mapitags.h"
-#include "config.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#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"
-#define DEBUG(lvl, curlvl, msg) \
- if ((lvl) >= (curlvl)) \
- printf("DEBUG(%i/%i): %s\n", curlvl, lvl, msg);
-#define DEBUG1(lvl, curlvl, msg, var1) \
- if ((lvl) >= (curlvl)) { \
- printf("DEBUG(%i/%i):", curlvl, lvl); \
- printf(msg, var1); \
- printf("\n"); \
- }
-#define DEBUG2(lvl, curlvl, msg, var1, var2) \
- if ((lvl) >= (curlvl)) { \
- printf("DEBUG(%i/%i):", curlvl, lvl); \
- printf(msg, var1, var2); \
- printf("\n"); \
- }
-#define DEBUG3(lvl, curlvl, msg, var1, var2, var3) \
- if ((lvl) >= (curlvl)) { \
- printf("DEBUG(%i/%i):", curlvl, lvl); \
- printf(msg, var1, var2,var3); \
- printf("\n"); \
- }
-
-#ifndef MIN
-#define MIN(x,y) (((x)<(y))?(x):(y))
-#endif
-
-void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p);
-void SetFlip(void);
-
-int TNEFDefaultHandler STD_ARGLIST;
-int TNEFAttachmentFilename STD_ARGLIST;
-int TNEFAttachmentSave STD_ARGLIST;
-int TNEFDetailedPrint STD_ARGLIST;
-int TNEFHexBreakdown STD_ARGLIST;
-int TNEFBody STD_ARGLIST;
-int TNEFRendData STD_ARGLIST;
-int TNEFDateHandler STD_ARGLIST;
-int TNEFPriority STD_ARGLIST;
-int TNEFVersion STD_ARGLIST;
-int TNEFMapiProperties STD_ARGLIST;
-int TNEFIcon STD_ARGLIST;
-int TNEFSubjectHandler STD_ARGLIST;
-int TNEFFromHandler STD_ARGLIST;
-int TNEFRecipTable STD_ARGLIST;
-int TNEFAttachmentMAPI STD_ARGLIST;
-int TNEFSentFor STD_ARGLIST;
-int TNEFMessageClass STD_ARGLIST;
-int TNEFMessageID STD_ARGLIST;
-int TNEFParentID STD_ARGLIST;
-int TNEFOriginalMsgClass STD_ARGLIST;
-int TNEFCodePage STD_ARGLIST;
-
-
-BYTE *TNEFFileContents=NULL;
-DWORD TNEFFileContentsSize;
-BYTE *TNEFFileIcon=NULL;
-DWORD TNEFFileIconSize;
-
-TNEFHandler TNEFList[] = {
- {attNull, "Null", TNEFDefaultHandler},
- {attFrom, "From", TNEFFromHandler},
- {attSubject, "Subject", TNEFSubjectHandler},
- {attDateSent, "Date Sent", TNEFDateHandler},
- {attDateRecd, "Date Received", TNEFDateHandler},
- {attMessageStatus, "Message Status", TNEFDefaultHandler},
- {attMessageClass, "Message Class", TNEFMessageClass},
- {attMessageID, "Message ID", TNEFMessageID},
- {attParentID, "Parent ID", TNEFParentID},
- {attConversationID, "Conversation ID", TNEFDefaultHandler},
- {attBody, "Body", TNEFBody},
- {attPriority, "Priority", TNEFPriority},
- {attAttachData, "Attach Data", TNEFAttachmentSave},
- {attAttachTitle, "Attach Title", TNEFAttachmentFilename},
- {attAttachMetaFile, "Attach Meta-File", TNEFIcon},
- {attAttachCreateDate, "Attachment Create Date", TNEFDateHandler},
- {attAttachModifyDate, "Attachment Modify Date", TNEFDateHandler},
- {attDateModified, "Date Modified", TNEFDateHandler},
- {attAttachTransportFilename, "Attachment Transport name", TNEFDefaultHandler},
- {attAttachRenddata, "Attachment Display info", TNEFRendData},
- {attMAPIProps, "MAPI Properties", TNEFMapiProperties},
- {attRecipTable, "Recip Table", TNEFRecipTable},
- {attAttachment, "Attachment", TNEFAttachmentMAPI},
- {attTnefVersion, "TNEF Version", TNEFVersion},
- {attOemCodepage, "OEM CodePage", TNEFCodePage},
- {attOriginalMessageClass, "Original Message Class", TNEFOriginalMsgClass},
- {attOwner, "Owner", TNEFDefaultHandler},
- {attSentFor, "Sent For", TNEFSentFor},
- {attDelegate, "Delegate", TNEFDefaultHandler},
- {attDateStart, "Date Start", TNEFDateHandler},
- {attDateEnd, "Date End", TNEFDateHandler},
- {attAidOwner, "Aid Owner", TNEFDefaultHandler},
- {attRequestRes, "Request Response", TNEFDefaultHandler} };
-
-
-WORD SwapWord(BYTE *p)
-{
- WORD *word_ptr;
-#ifdef WORDS_BIGENDIAN
- BYTE bytes[2];
- bytes[0] = p[1];
- bytes[1] = p[0];
- word_ptr = (WORD*)&(bytes[0]);
-#else
- word_ptr = (WORD*)p;
-#endif
- return *word_ptr;
-}
-
-DWORD SwapDWord(BYTE *p)
-{
- DWORD *dword_ptr;
-#ifdef WORDS_BIGENDIAN
- BYTE bytes[4];
- bytes[0] = p[3];
- bytes[1] = p[2];
- bytes[2] = p[1];
- bytes[3] = p[0];
- dword_ptr = (DWORD*)&(bytes[0]);
-#else
- dword_ptr = (DWORD*)p;
-#endif
- return *dword_ptr;
-}
-
-DDWORD SwapDDWord(BYTE *p)
-{
- DDWORD *ddword_ptr;
-#ifdef WORDS_BIGENDIAN
- BYTE bytes[8];
- bytes[0] = p[7];
- bytes[1] = p[6];
- bytes[2] = p[5];
- bytes[3] = p[4];
- bytes[4] = p[3];
- bytes[5] = p[2];
- bytes[6] = p[1];
- bytes[7] = p[0];
- ddword_ptr = (DDWORD*)&(bytes[0]);
-#else
- ddword_ptr = (DDWORD*)p;
-#endif
- return *ddword_ptr;
-}
-
-/* convert 16-bit unicode to UTF8 unicode */
-char* to_utf8(int len, char* buf)
-{
- int i, j = 0;
- /* worst case length */
- char *utf8 = malloc(3 * len/2 + 1);
-
- for (i=0; i<len-1; i+=2) {
- unsigned int c = SwapWord(buf+i);
- if (c <= 0x007f) {
- utf8[j++] = 0x00 | ((c & 0x007f) >> 0);
- }
- else if (c < 0x07ff) {
- utf8[j++] = 0xc0 | ((c & 0x07c0) >> 6);
- utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
- }
- else {
- utf8[j++] = 0xe0 | ((c & 0xf000) >> 12);
- utf8[j++] = 0x80 | ((c & 0x0fc0) >> 6);
- utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
- }
- }
-
- /* just in case the original was not null terminated */
- utf8[j++] = '\0';
-
- return utf8;
-}
-
-
-// -----------------------------------------------------------------------------
-int TNEFDefaultHandler STD_ARGLIST {
- if (TNEF->Debug >= 1)
- printf("%s: [%i] %s\n", TNEFList[id].name, size, data);
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFCodePage STD_ARGLIST {
- TNEF->CodePage.size = size;
- TNEF->CodePage.data = calloc(size, sizeof(BYTE));
- memcpy(TNEF->CodePage.data, data, size);
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFParentID STD_ARGLIST {
- memcpy(TNEF->parentID, data, MIN(size,sizeof(TNEF->parentID)));
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFMessageID STD_ARGLIST {
- memcpy(TNEF->messageID, data, MIN(size,sizeof(TNEF->messageID)));
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFBody STD_ARGLIST {
- TNEF->body.size = size;
- TNEF->body.data = calloc(size, sizeof(BYTE));
- memcpy(TNEF->body.data, data, size);
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFOriginalMsgClass STD_ARGLIST {
- TNEF->OriginalMessageClass.size = size;
- TNEF->OriginalMessageClass.data = calloc(size, sizeof(BYTE));
- memcpy(TNEF->OriginalMessageClass.data, data, size);
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFMessageClass STD_ARGLIST {
- memcpy(TNEF->messageClass, data, MIN(size,sizeof(TNEF->messageClass)));
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFFromHandler STD_ARGLIST {
- TNEF->from.data = calloc(size, sizeof(BYTE));
- TNEF->from.size = size;
- memcpy(TNEF->from.data, data,size);
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFSubjectHandler STD_ARGLIST {
- TNEF->subject.data = calloc(size, sizeof(BYTE));
- TNEF->subject.size = size;
- memcpy(TNEF->subject.data, data,size);
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFRendData STD_ARGLIST {
- Attachment *p;
- // Find the last attachment.
- p = &(TNEF->starting_attach);
- while (p->next!=NULL) p=p->next;
-
- // Add a new one
- p->next = calloc(1,sizeof(Attachment));
- p=p->next;
-
- TNEFInitAttachment(p);
-
- memcpy(&(p->RenderData), data, sizeof(renddata));
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFVersion STD_ARGLIST {
- WORD major;
- WORD minor;
- major = SwapWord(data+2);
- minor = SwapWord(data);
-
- sprintf(TNEF->version, "TNEF%i.%i", major, minor);
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFIcon STD_ARGLIST {
- Attachment *p;
- // Find the last attachment.
- p = &(TNEF->starting_attach);
- while (p->next!=NULL) p=p->next;
-
- p->IconData.size = size;
- p->IconData.data = calloc(size, sizeof(BYTE));
- memcpy(p->IconData.data, data, size);
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFRecipTable STD_ARGLIST {
- BYTE *d;
-
- d = data;
- SwapDWord(d);
- d += 4;
-// printf("Recipient Table containing %u rows\n", count);
-
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFAttachmentMAPI STD_ARGLIST {
- Attachment *p;
- // Find the last attachment.
- //
- p = &(TNEF->starting_attach);
- while (p->next!=NULL) p=p->next;
- TNEFFillMapi(TNEF, data, size, &(p->MAPI));
-
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFMapiProperties STD_ARGLIST {
- TNEFFillMapi(TNEF, data, size, &(TNEF->MapiProperties));
- return 0;
-}
-
-void TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) {
- int i,j;
- DWORD num;
- BYTE *d;
- MAPIProperty *mp;
- DWORD type;
- DWORD length;
- variableLength *vl;
-
- WORD temp_word;
- DWORD temp_dword;
- DDWORD temp_ddword;
- int count=-1;
-
- d = data;
- p->count = SwapDWord(data);
- d += 4;
- p->properties = calloc(p->count, sizeof(MAPIProperty));
- mp = p->properties;
-
- for(i=0; i<p->count; i++) {
- if (count == -1) {
- mp->id = SwapDWord(d);
- d+=4;
- mp->custom = 0;
- mp->count = 1;
- mp->namedproperty = 0;
- length = -1;
- if (PROP_ID(mp->id) >= 0x8000) {
- // Read the GUID
- memcpy(&(mp->guid[0]), d, 16);
- d+=16;
-
- length = SwapDWord(d);
- d+=sizeof(DWORD);
- if (length > 0) {
- mp->namedproperty = length;
- mp->propnames = calloc(length, sizeof(variableLength));
- while (length > 0) {
- type = SwapDWord(d);
- mp->propnames[length-1].data = calloc(type, sizeof(BYTE));
- mp->propnames[length-1].size = type;
- d+=4;
- for(j=0; j<(type>>1); j++) {
- mp->propnames[length-1].data[j] = d[j*2];
- }
- d += type + ((type % 4) ? (4 - type%4) : 0);
- length--;
- }
- } else {
- // READ the type
- type = SwapDWord(d);
- d+=sizeof(DWORD);
- mp->id = PROP_TAG(PROP_TYPE(mp->id), type);
- }
- mp->custom = 1;
- }
-
- //printf("Type id = %04x\n", PROP_TYPE(mp->id));
- if (PROP_TYPE(mp->id) & MV_FLAG) {
- mp->id = PROP_TAG(PROP_TYPE(mp->id) - MV_FLAG, PROP_ID(mp->id));
- mp->count = SwapDWord(d);
- d+=4;
- count = 0;
- }
- mp->data = calloc(mp->count, sizeof(variableLength));
- vl = mp->data;
- } else {
- i--;
- count++;
- vl = &(mp->data[count]);
- }
-
- switch (PROP_TYPE(mp->id)) {
- case PT_BINARY:
- case PT_OBJECT:
- case PT_STRING8:
- case PT_UNICODE:
- // First number of objects (assume 1 for now)
- if (count == -1) {
- vl->size = SwapDWord(d);
- d+=4;
- }
- // now size of object
- vl->size = SwapDWord(d);
- d+=4;
-
- // now actual object
- if (PROP_TYPE(mp->id) == PT_UNICODE) {
- vl->data = to_utf8(vl->size, d);
- }
- else {
- vl->data = calloc(vl->size, sizeof(BYTE));
- memcpy(vl->data, d, vl->size);
- }
-
- // Make sure to read in a multiple of 4
- num = vl->size;
- d += num + ((num % 4) ? (4 - num%4) : 0);
- break;
-
- case PT_CLSID:
- vl->size = 16; /* Size of struct GUID */
- vl->data = calloc(vl->size, sizeof(WORD));
- memcpy(vl->data, &d, vl->size);
- d += 16; /* Size of struct GUID */
- break;
-
- case PT_I2:
- // Read in 2 bytes, but proceed by 4 bytes
- vl->size = 2;
- vl->data = calloc(vl->size, sizeof(WORD));
- temp_word = SwapWord(d);
- memcpy(vl->data, &temp_word, vl->size);
- d += 4;
- break;
- case PT_BOOLEAN:
- case PT_LONG:
- case PT_R4:
- case PT_CURRENCY:
- case PT_APPTIME:
- case PT_ERROR:
- vl->size = 4;
- vl->data = calloc(vl->size, sizeof(BYTE));
- temp_dword = SwapDWord(d);
- memcpy(vl->data, &temp_dword, vl->size);
- d += 4;
- break;
- case PT_DOUBLE:
- case PT_I8:
- case PT_SYSTIME:
- vl->size = 8;
- vl->data = calloc(vl->size, sizeof(BYTE));
- temp_ddword = SwapDDWord(d);
- memcpy(vl->data, &temp_ddword, vl->size);
- d+=8;
- break;
- default:
- fprintf(stderr, "%s: Fatal BUG: unknown MAPI ID type (%u), (%u)\n", __func__, PROP_TYPE(mp->id), mp->id);
- }
- if (count == (mp->count-1)) {
- count = -1;
- }
- if (count == -1) {
- mp++;
- }
- }
- if ((d-data) < size) {
- if (TNEF->Debug >= 1) {
- printf("ERROR DURING MAPI READ\n");
- printf("Read %ld bytes, Expected %u bytes\n", (d-data), size);
- printf("%ld bytes missing\n", size - (d-data));
- }
- } else if ((d-data) > size){
- if (TNEF->Debug >= 1) {
- printf("ERROR DURING MAPI READ\n");
- printf("Read %ld bytes, Expected %u bytes\n", (d-data), size);
- printf("%ld bytes extra\n", (d-data)-size);
- }
- }
- return;
-}
-// -----------------------------------------------------------------------------
-int TNEFSentFor STD_ARGLIST {
- WORD name_length, addr_length;
- BYTE *d;
-
- d=data;
-
- while ((d-data)<size) {
- name_length = SwapWord(d);
- d+=sizeof(WORD);
- if (TNEF->Debug >= 1)
- printf("Sent For : %s", d);
- d+=name_length;
-
- addr_length = SwapWord(d);
- d+=sizeof(WORD);
- if (TNEF->Debug >= 1)
- printf("<%s>\n", d);
- d+=addr_length;
- }
- return 0;
-}
-// -----------------------------------------------------------------------------
-int TNEFDateHandler STD_ARGLIST {
- dtr *Date;
- Attachment *p;
- WORD *tmp_src, *tmp_dst;
- int i;
-
- p = &(TNEF->starting_attach);
- switch (TNEFList[id].id) {
- case attDateSent: Date = &(TNEF->dateSent); break;
- case attDateRecd: Date = &(TNEF->dateReceived); break;
- case attDateModified: Date = &(TNEF->dateModified); break;
- case attDateStart: Date = &(TNEF->DateStart); break;
- case attDateEnd: Date = &(TNEF->DateEnd); break;
- case attAttachCreateDate:
- while (p->next!=NULL) p=p->next;
- Date = &(p->CreateDate);
- break;
- case attAttachModifyDate:
- while (p->next!=NULL) p=p->next;
- Date = &(p->ModifyDate);
- break;
- default:
- if (TNEF->Debug >= 1)
- printf("MISSING CASE\n");
- return YTNEF_UNKNOWN_PROPERTY;
- }
-
- tmp_src = (WORD*)data;
- tmp_dst = (WORD*)Date;
- for(i=0;i<sizeof(dtr)/sizeof(WORD);i++) {
- *tmp_dst++ = SwapWord((BYTE*)tmp_src++);
- }
- return 0;
-}
-
-void TNEFPrintDate(dtr Date) {
- char days[7][15] = {"Sunday", "Monday", "Tuesday",
- "Wednesday", "Thursday", "Friday", "Saturday"};
- char months[12][15] = {"January", "February", "March", "April", "May",
- "June", "July", "August", "September", "October", "November",
- "December"};
-
- if (Date.wDayOfWeek < 7)
- printf("%s ", days[Date.wDayOfWeek]);
-
- if ((Date.wMonth < 13) && (Date.wMonth>0))
- printf("%s ", months[Date.wMonth-1]);
-
- printf("%hu, %hu ", Date.wDay, Date.wYear);
-
- if (Date.wHour>12)
- printf("%hu:%02hu:%02hu pm", (Date.wHour-12),
- Date.wMinute, Date.wSecond);
- else if (Date.wHour == 12)
- printf("%hu:%02hu:%02hu pm", (Date.wHour),
- Date.wMinute, Date.wSecond);
- else
- printf("%hu:%02hu:%02hu am", Date.wHour,
- Date.wMinute, Date.wSecond);
-}
-// -----------------------------------------------------------------------------
-int TNEFHexBreakdown STD_ARGLIST {
- int i;
- if (TNEF->Debug == 0)
- return 0;
-
- printf("%s: [%i bytes] \n", TNEFList[id].name, size);
-
- for(i=0; i<size; i++) {
- printf("%02x ", data[i]);
- if ((i+1)%16 == 0) printf("\n");
- }
- printf("\n");
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFDetailedPrint STD_ARGLIST {
- int i;
- if (TNEF->Debug == 0)
- return 0;
-
- printf("%s: [%i bytes] \n", TNEFList[id].name, size);
-
- for(i=0; i<size; i++) {
- printf("%c", data[i]);
- }
- printf("\n");
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFAttachmentFilename STD_ARGLIST {
- Attachment *p;
- p = &(TNEF->starting_attach);
- while (p->next!=NULL) p=p->next;
-
- p->Title.size = size;
- p->Title.data = calloc(size, sizeof(BYTE));
- memcpy(p->Title.data, data, size);
-
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFAttachmentSave STD_ARGLIST {
- Attachment *p;
- p = &(TNEF->starting_attach);
- while (p->next!=NULL) p=p->next;
-
- p->FileData.data = calloc(sizeof(unsigned char), size);
- p->FileData.size = size;
-
- memcpy(p->FileData.data, data, size);
-
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFPriority STD_ARGLIST {
- DWORD value;
-
- value = SwapDWord(data);
- switch (value) {
- case 3:
- sprintf((TNEF->priority), "high");
- break;
- case 2:
- sprintf((TNEF->priority), "normal");
- break;
- case 1:
- sprintf((TNEF->priority), "low");
- break;
- default:
- sprintf((TNEF->priority), "N/A");
- break;
- }
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFCheckForSignature(DWORD sig) {
- DWORD signature = 0x223E9F78;
-
- sig = SwapDWord((BYTE*)&sig);
-
- if (signature == sig) {
- return 0;
- } else {
- return YTNEF_NOT_TNEF_STREAM;
- }
-}
-
-// -----------------------------------------------------------------------------
-int TNEFGetKey(TNEFStruct *TNEF, WORD *key) {
- if (TNEF->IO.ReadProc (&(TNEF->IO), sizeof(WORD),1, key) < 1) {
- if (TNEF->Debug >= 1)
- printf("Error reading Key\n");
- return YTNEF_ERROR_READING_DATA;
- }
- *key = SwapWord((BYTE*)key);
-
- DEBUG1(TNEF->Debug, 2, "Key = %i", *key);
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFGetHeader(TNEFStruct *TNEF, DWORD *type, DWORD *size) {
- BYTE component;
-
- DEBUG(TNEF->Debug, 2, "About to read Component");
- if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(BYTE),1, &component) < 1) {
- return YTNEF_ERROR_READING_DATA;
- }
-
-
- DEBUG(TNEF->Debug, 2, "About to read type");
- if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, type) < 1) {
- if (TNEF->Debug >= 1)
- printf("ERROR: Error reading type\n");
- return YTNEF_ERROR_READING_DATA;
- }
- DEBUG1(TNEF->Debug, 2, "Type = %i", *type);
-
-
- DEBUG(TNEF->Debug, 2, "About to read size");
- if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, size) < 1) {
- if (TNEF->Debug >= 1)
- printf("ERROR: Error reading size\n");
- return YTNEF_ERROR_READING_DATA;
- }
-
-
- DEBUG1(TNEF->Debug, 2, "Size = %i", *size);
-
- *type = SwapDWord((BYTE*)type);
- *size = SwapDWord((BYTE*)size);
-
- return 0;
-}
-
-// -----------------------------------------------------------------------------
-int TNEFRawRead(TNEFStruct *TNEF, BYTE *data, DWORD size, WORD *checksum) {
- WORD temp;
- int i;
-
- if (TNEF->IO.ReadProc(&TNEF->IO, sizeof(BYTE), size, data) < size) {
- if (TNEF->Debug >= 1)
- printf("ERROR: Error reading data\n");
- return YTNEF_ERROR_READING_DATA;
- }
-
-
- if (checksum != NULL) {
- *checksum = 0;
- for(i=0; i<size; i++) {
- temp = data[i];
- *checksum = (*checksum + temp);
- }
- }
- return 0;
-}
-
-#define INITVARLENGTH(x) (x).data = NULL; (x).size = 0;
-#define INITDTR(x) (x).wYear=0; (x).wMonth=0; (x).wDay=0; \
- (x).wHour=0; (x).wMinute=0; (x).wSecond=0; \
- (x).wDayOfWeek=0;
-#define INITSTR(x) memset((x), 0, sizeof(x));
-void TNEFInitMapi(MAPIProps *p)
-{
- p->count = 0;
- p->properties = NULL;
-}
-
-void TNEFInitAttachment(Attachment *p)
-{
- INITDTR(p->Date);
- INITVARLENGTH(p->Title);
- INITVARLENGTH(p->MetaFile);
- INITDTR(p->CreateDate);
- INITDTR(p->ModifyDate);
- INITVARLENGTH(p->TransportFilename);
- INITVARLENGTH(p->FileData);
- INITVARLENGTH(p->IconData);
- memset(&(p->RenderData), 0, sizeof(renddata));
- TNEFInitMapi(&(p->MAPI));
- p->next = NULL;
-}
-
-void TNEFInitialize(TNEFStruct *TNEF)
-{
- INITSTR(TNEF->version);
- INITVARLENGTH(TNEF->from);
- INITVARLENGTH(TNEF->subject);
- INITDTR(TNEF->dateSent);
- INITDTR(TNEF->dateReceived);
-
- INITSTR(TNEF->messageStatus);
- INITSTR(TNEF->messageClass);
- INITSTR(TNEF->messageID);
- INITSTR(TNEF->parentID);
- INITSTR(TNEF->conversationID);
- INITVARLENGTH(TNEF->body);
- INITSTR(TNEF->priority);
- TNEFInitAttachment(&(TNEF->starting_attach));
- INITDTR(TNEF->dateModified);
- TNEFInitMapi(&(TNEF->MapiProperties));
- INITVARLENGTH(TNEF->CodePage);
- INITVARLENGTH(TNEF->OriginalMessageClass);
- INITVARLENGTH(TNEF->Owner);
- INITVARLENGTH(TNEF->SentFor);
- INITVARLENGTH(TNEF->Delegate);
- INITDTR(TNEF->DateStart);
- INITDTR(TNEF->DateEnd);
- INITVARLENGTH(TNEF->AidOwner);
- TNEF->RequestRes=0;
- TNEF->IO.data = NULL;
- TNEF->IO.InitProc = NULL;
- TNEF->IO.ReadProc = NULL;
- TNEF->IO.CloseProc = NULL;
-}
-#undef INITVARLENGTH
-#undef INITDTR
-#undef INITSTR
-
-#define FREEVARLENGTH(x) if ((x).size > 0) { \
- free((x).data); (x).size =0; }
-void TNEFFree(TNEFStruct *TNEF) {
- Attachment *p, *store;
-
- FREEVARLENGTH(TNEF->from);
- FREEVARLENGTH(TNEF->subject);
- FREEVARLENGTH(TNEF->body);
- FREEVARLENGTH(TNEF->CodePage);
- FREEVARLENGTH(TNEF->OriginalMessageClass);
- FREEVARLENGTH(TNEF->Owner);
- FREEVARLENGTH(TNEF->SentFor);
- FREEVARLENGTH(TNEF->Delegate);
- FREEVARLENGTH(TNEF->AidOwner);
- TNEFFreeMapiProps(&(TNEF->MapiProperties));
-
- p = TNEF->starting_attach.next;
- while (p != NULL) {
- TNEFFreeAttachment(p);
- store = p->next;
- free(p);
- p=store;
- }
-}
-
-void TNEFFreeAttachment(Attachment *p)
-{
- FREEVARLENGTH(p->Title);
- FREEVARLENGTH(p->MetaFile);
- FREEVARLENGTH(p->TransportFilename);
- FREEVARLENGTH(p->FileData);
- FREEVARLENGTH(p->IconData);
- TNEFFreeMapiProps(&(p->MAPI));
-}
-
-void TNEFFreeMapiProps(MAPIProps *p)
-{
- int i,j;
- for(i=0; i<p->count; i++) {
- for(j=0; j<p->properties[i].count; j++) {
- FREEVARLENGTH(p->properties[i].data[j]);
- }
- free(p->properties[i].data);
- }
- free(p->properties);
- p->count = 0;
-}
-#undef FREEVARLENGTH
-
-// Procedures to handle File IO
-int TNEFFile_Open (TNEFIOStruct *IO) {
- TNEFFileInfo *finfo;
- finfo = (TNEFFileInfo*)IO->data;
-
- DEBUG1(finfo->Debug, 3, "Opening %s", finfo->filename);
- if ((finfo->fptr = g_fopen(finfo->filename, "rb")) == NULL) {
- return -1;
- } else {
- return 0;
- }
-}
-
-int TNEFFile_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
- TNEFFileInfo *finfo;
- finfo = (TNEFFileInfo*)IO->data;
-
- DEBUG2(finfo->Debug, 3, "Reading %i blocks of %i size", count, size);
- if (finfo->fptr != NULL) {
- return fread((BYTE*)dest, size, count, finfo->fptr);
- } else {
- return -1;
- }
-}
-
-int TNEFFile_Close (TNEFIOStruct *IO) {
- TNEFFileInfo *finfo;
- finfo = (TNEFFileInfo*)IO->data;
-
- DEBUG1(finfo->Debug, 3, "Closing file %s", finfo->filename);
- if (finfo->fptr != NULL) {
- fclose(finfo->fptr);
- finfo->fptr = NULL;
- }
- return 0;
-}
-
-int TNEFParseFile(char *filename, TNEFStruct *TNEF) {
- TNEFFileInfo finfo;
-
- if (TNEF->Debug >= 1)
- printf("Attempting to parse %s...\n", filename);
-
-
- finfo.filename = filename;
- finfo.fptr = NULL;
- finfo.Debug = TNEF->Debug;
- TNEF->IO.data = (void*)&finfo;
- TNEF->IO.InitProc = TNEFFile_Open;
- TNEF->IO.ReadProc = TNEFFile_Read;
- TNEF->IO.CloseProc = TNEFFile_Close;
- return TNEFParse(TNEF);
-}
-//-------------------------------------------------------------
-// Procedures to handle Memory IO
-int TNEFMemory_Open (TNEFIOStruct *IO) {
- TNEFMemInfo *minfo;
- minfo = (TNEFMemInfo*)IO->data;
-
- minfo->ptr = minfo->dataStart;
- return 0;
-}
-
-int TNEFMemory_Read (TNEFIOStruct *IO, int size, int count, void *dest) {
- TNEFMemInfo *minfo;
- int length;
- long max;
- minfo = (TNEFMemInfo*)IO->data;
-
- length = count*size;
- max = (minfo->dataStart + minfo->size) - (minfo->ptr);
- if (length > max) {
- return -1;
- }
-
- DEBUG1(minfo->Debug, 3, "Copying %i bytes", length);
-
- memcpy(dest, minfo->ptr, length);
- minfo->ptr+=length;
- return count;
-}
-
-int TNEFMemory_Close (TNEFIOStruct *IO) {
- // Do nothing, really...
- return 0;
-}
-
-int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF) {
- TNEFMemInfo minfo;
-
- DEBUG(TNEF->Debug, 1, "Attempting to parse memory block...\n");
-
- minfo.dataStart = memory;
- minfo.ptr = memory;
- minfo.size = size;
- minfo.Debug = TNEF->Debug;
- TNEF->IO.data = (void*)&minfo;
- TNEF->IO.InitProc = TNEFMemory_Open;
- TNEF->IO.ReadProc = TNEFMemory_Read;
- TNEF->IO.CloseProc = TNEFMemory_Close;
- return TNEFParse(TNEF);
-}
-
-
-int TNEFParse(TNEFStruct *TNEF) {
- WORD key;
- DWORD type;
- DWORD size;
- DWORD signature;
- BYTE *data;
- WORD checksum, header_checksum;
- int i;
-
- if (TNEF->IO.ReadProc == NULL) {
- printf("ERROR: Setup incorrectly: No ReadProc\n");
- return YTNEF_INCORRECT_SETUP;
- }
-
- if (TNEF->IO.InitProc != NULL) {
- DEBUG(TNEF->Debug, 2, "About to initialize");
- if (TNEF->IO.InitProc (&TNEF->IO) != 0) {
- return YTNEF_CANNOT_INIT_DATA;
- }
- DEBUG(TNEF->Debug, 2, "Initialization finished");
- }
-
- DEBUG(TNEF->Debug, 2, "Reading Signature");
- if (TNEF->IO.ReadProc (&TNEF->IO, sizeof(DWORD), 1, &signature) < 1) {
- printf("ERROR: Error reading signature\n");
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- return YTNEF_ERROR_READING_DATA;
- }
-
- DEBUG(TNEF->Debug, 2, "Checking Signature");
- if (TNEFCheckForSignature(signature) < 0) {
- printf("ERROR: Signature does not match. Not TNEF.\n");
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- return YTNEF_NOT_TNEF_STREAM;
- }
-
- DEBUG(TNEF->Debug, 2, "Reading Key.");
-
- if (TNEFGetKey(TNEF, &key) < 0) {
- printf("ERROR: Unable to retrieve key.\n");
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- return YTNEF_NO_KEY;
- }
-
- DEBUG(TNEF->Debug, 2, "Starting Full Processing.");
-
- while (TNEFGetHeader(TNEF, &type, &size) == 0) {
- DEBUG2(TNEF->Debug, 2, "Header says type=%i, size=%i", type, size);
- if (size > 0) {
- data = calloc(size, sizeof(BYTE));
- if (TNEFRawRead(TNEF, data, size, &header_checksum)< 0) {
- printf("ERROR: Unable to read data.\n");
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- free(data);
- return YTNEF_ERROR_READING_DATA;
- }
- if (TNEFRawRead(TNEF, (BYTE *)&checksum, 2, NULL) < 0) {
- printf("ERROR: Unable to read checksum.\n");
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- free(data);
- return YTNEF_ERROR_READING_DATA;
- }
- checksum = SwapWord((BYTE*)&checksum);
- if (checksum != header_checksum) {
- printf("ERROR: Checksum mismatch. Data corruption?:\n");
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- free(data);
- return YTNEF_BAD_CHECKSUM;
- }
- for(i=0; i<(sizeof(TNEFList)/sizeof(TNEFHandler));i++) {
- if (TNEFList[i].id == type) {
- if (TNEFList[i].handler != NULL) {
- if (TNEFList[i].handler(TNEF, i, data, size) < 0) {
- free(data);
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- return YTNEF_ERROR_IN_HANDLER;
- }
- } else {
- DEBUG2(TNEF->Debug, 1, "No handler for %s: %i bytes",
- TNEFList[i].name, size);
- }
- }
- }
-
- free(data);
- }
- }
-
- if (TNEF->IO.CloseProc != NULL) {
- TNEF->IO.CloseProc (&TNEF->IO);
- }
- return 0;
-
-}
-
-// ----------------------------------------------------------------------------
-
-variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID)
-{
- int i;
- if (p != NULL) {
- for(i=0;i<p->count; i++) {
- if ((p->properties[i].id == ID) && (p->properties[i].custom == 1)) {
- return (p->properties[i].data);
- }
- }
- }
- return MAPI_UNDEFINED;
-}
-
-variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID)
-{
- int i;
- if (p != NULL) {
- for(i=0;i<p->count; i++) {
- if ((p->properties[i].id == ID) && (p->properties[i].custom == 0)) {
- return (p->properties[i].data);
- }
- }
- }
- return MAPI_UNDEFINED;
-}
-
-int MAPISysTimetoDTR(BYTE *data, dtr *thedate)
-{
- DDWORD ddword_tmp;
- int startingdate = 0;
- int tmp_date;
- int days_in_year = 365;
- unsigned int months[] = {31,28,31,30,31,30,31,31,30,31,30,31};
-
- ddword_tmp = *((DDWORD*)data);
- ddword_tmp = ddword_tmp /10; // micro-s
- ddword_tmp /= 1000; // ms
- ddword_tmp /= 1000; // s
-
- thedate->wSecond = (ddword_tmp % 60);
-
- ddword_tmp /= 60; // seconds to minutes
- thedate->wMinute = (ddword_tmp % 60);
-
- ddword_tmp /= 60; //minutes to hours
- thedate->wHour = (ddword_tmp % 24);
-
- ddword_tmp /= 24; // Hours to days
-
- // Now calculate the year based on # of days
- thedate->wYear = 1601;
- startingdate = 1;
- while(ddword_tmp >= days_in_year) {
- ddword_tmp-=days_in_year;
- thedate->wYear++;
- days_in_year = 365;
- startingdate++;
- if ((thedate->wYear % 4) == 0) {
- if ((thedate->wYear % 100) == 0) {
- // if the year is 1700,1800,1900, etc, then it is only
- // a leap year if exactly divisible by 400, not 4.
- if ((thedate->wYear % 400) == 0) {
- startingdate++;
- days_in_year = 366;
- }
- } else {
- startingdate++;
- days_in_year = 366;
- }
- }
- startingdate %= 7;
- }
-
- // the remaining number is the day # in this year
- // So now calculate the Month, & Day of month
- if ((thedate->wYear % 4) == 0) {
- // 29 days in february in a leap year
- months[1] = 29;
- }
-
- tmp_date = (int)ddword_tmp;
- thedate->wDayOfWeek = (tmp_date + startingdate) % 7;
- thedate->wMonth = 0;
-
- while (tmp_date > months[thedate->wMonth]) {
- tmp_date -= months[thedate->wMonth];
- thedate->wMonth++;
- }
- thedate->wMonth++;
- thedate->wDay = tmp_date+1;
- return 0;
-}
-
-int IsCompressedRTF(variableLength *p) {
-/*
- unsigned int in;
- unsigned char *src;
- ULONG compressedSize, uncompressedSize, magic, crc32;
-
- src = p->data;
- in = 0;
-
- compressedSize = (ULONG)SwapDWord(src+in);
- in += 4;
- uncompressedSize = (ULONG)SwapDWord(src+in);
- in += 4;
- magic = SwapDWord(src+in);
- in += 4;
- crc32 = SwapDWord(src+in);
- in += 4;
-
- if (magic == 0x414c454d) {
- return 1;
- } else if (magic == 0x75465a4c) {
- return 1;
- } else {
- return 0;
- }
-*/
- unsigned char *src = p->data;
- ULONG magic = SwapDWord(src + 8);
-
- if (magic == 0x414c454d || magic == 0x75465a4c)
- return 1;
-
- return 0;
-}
-
-void MAPIPrint(MAPIProps *p)
-{
- int j, i,index, h;
- dtr thedate;
- MAPIProperty *mapi;
- variableLength *mapidata;
- variableLength vlTemp;
- int found;
-
- for(j=0; j<p->count; j++) {
- mapi = &(p->properties[j]);
- printf(" #%i: Type: [", j);
- switch (PROP_TYPE(mapi->id)) {
- case PT_UNSPECIFIED:
- printf(" NONE "); break;
- case PT_NULL:
- printf(" NULL "); break;
- case PT_I2:
- printf(" I2 "); break;
- case PT_LONG:
- printf(" LONG "); break;
- case PT_R4:
- printf(" R4 "); break;
- case PT_DOUBLE:
- printf(" DOUBLE "); break;
- case PT_CURRENCY:
- printf("CURRENCY "); break;
- case PT_APPTIME:
- printf("APP TIME "); break;
- case PT_ERROR:
- printf(" ERROR "); break;
- case PT_BOOLEAN:
- printf(" BOOLEAN "); break;
- case PT_OBJECT:
- printf(" OBJECT "); break;
- case PT_I8:
- printf(" I8 "); break;
- case PT_STRING8:
- printf(" STRING8 "); break;
- case PT_UNICODE:
- printf(" UNICODE "); break;
- case PT_SYSTIME:
- printf("SYS TIME "); break;
- case PT_CLSID:
- printf("OLE GUID "); break;
- case PT_BINARY:
- printf(" BINARY "); break;
- default:
- printf("<%x>", PROP_TYPE(mapi->id)); break;
- }
-
- printf("] Code: [");
- if (mapi->custom == 1) {
- printf("UD:x%04x", PROP_ID(mapi->id));
- } else {
- found = 0;
- for(index=0; index<sizeof(MPList)/sizeof(MAPIPropertyTagList); index++) {
- if ((MPList[index].id == PROP_ID(mapi->id)) && (found == 0)) {
- printf("%s", MPList[index].name);
- found = 1;
- }
- }
- if (found == 0) {
- printf("0x%04x", PROP_ID(mapi->id));
- }
- }
- printf("]\n");
- if (mapi->namedproperty > 0) {
- for(i=0; i<mapi->namedproperty; i++) {
- printf(" Name: %s\n", mapi->propnames[i].data);
- }
- }
- for (i=0;i<mapi->count;i++) {
- mapidata = &(mapi->data[i]);
- if (mapi->count > 1) {
- printf(" [%i/%i] ", i, mapi->count);
- } else {
- printf(" ");
- }
- printf("Size: %i", mapidata->size);
- switch (PROP_TYPE(mapi->id)) {
- case PT_SYSTIME:
- MAPISysTimetoDTR(mapidata->data, &thedate);
- printf(" Value: ");
- TNEFPrintDate(thedate);
- printf("\n");
- break;
- case PT_LONG:
- printf(" Value: %li\n", (long int) *(mapidata->data));
- break;
- case PT_I2:
- printf(" Value: %hi\n", *(mapidata->data));
- break;
- case PT_BOOLEAN:
- if (mapi->data->data[0]!=0) {
- printf(" Value: True\n");
- } else {
- printf(" Value: False\n");
- }
- break;
- case PT_OBJECT:
- printf("\n");
- break;
- case PT_BINARY:
- if(IsCompressedRTF(mapidata)==1) {
- printf(" Detected Compressed RTF.");
- printf("Decompressed text follows\n");
- printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
- if((vlTemp.data = DecompressRTF(mapidata, &(vlTemp.size))) != NULL) {
- printf("%s\n", vlTemp.data);
- free(vlTemp.data);
- }
- printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
- } else {
- printf(" Value: [");
- for(h=0; h< mapidata->size; h++) {
- if (isprint(mapidata->data[h]))
- printf("%c", mapidata->data[h]);
- else
- printf(".");
-
- }
- printf("]\n");
- }
- break;
- case PT_STRING8:
- printf(" Value: [%s]\n", mapidata->data);
- if (strlen(mapidata->data) != mapidata->size-1) {
- printf("Detected Hidden data: [");
- for(h=0; h< mapidata->size; h++) {
- if (isprint(mapidata->data[h]))
- printf("%c", mapidata->data[h]);
- else
- printf(".");
-
- }
- printf("]\n");
- }
- break;
- default:
- printf(" Value: [%s]\n", mapidata->data);
- }
- }
- }
-}
-
-unsigned char *DecompressRTF(variableLength *p, int *size) {
- unsigned char *dst; // destination for uncompressed bytes
- unsigned char *src;
- unsigned int in;
- unsigned int out;
- variableLength comp_Prebuf;
- ULONG compressedSize, uncompressedSize, magic; // , crc32;
-
- comp_Prebuf.size = strlen(RTF_PREBUF);
- comp_Prebuf.data = calloc(comp_Prebuf.size + 1, 1);
- memcpy(comp_Prebuf.data, RTF_PREBUF, comp_Prebuf.size);
-
- src = p->data;
- in = 0;
-
- compressedSize = (ULONG)SwapDWord(src+in);
- in += 4;
- uncompressedSize = (ULONG)SwapDWord(src+in);
- in += 4;
- magic = SwapDWord(src+in);
- in += 4;
- // crc32 = SwapDWord(src+in);
- in += 4;
-
- // check size excluding the size field itself
- if (compressedSize != p->size - 4) {
- printf(" Size Mismatch: %i != %i\n", compressedSize, p->size-4);
- return NULL;
- }
-
- // process the data
- if (magic == 0x414c454d) {
- // magic number that identifies the stream as a uncompressed stream
- dst = calloc(uncompressedSize,1);
- memcpy(dst, src+4, uncompressedSize);
- return dst;
- } else if (magic == 0x75465a4c) {
- // magic number that identifies the stream as a compressed stream
- int flagCount = 0;
- int flags = 0;
- dst = calloc(comp_Prebuf.size + uncompressedSize,1);
- memcpy(dst, comp_Prebuf.data, comp_Prebuf.size);
- out = comp_Prebuf.size;
- while (out < (comp_Prebuf.size+uncompressedSize)) {
- // each flag byte flags 8 literals/references, 1 per bit
- flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1;
- if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0 for literal
- int offset = src[in++];
- int length = src[in++];
- int end;
- offset = (offset << 4) | (length >> 4); // the offset relative to block start
- length = (length & 0xF) + 2; // the number of bytes to copy
- // the decompression buffer is supposed to wrap around back
- // to the beginning when the end is reached. we save the
- // need for such a buffer by pointing straight into the data
- // buffer, and simulating this behaviour by modifying the
- // pointers appropriately.
- offset = (out / 4096) * 4096 + offset;
- if (offset >= out) // take from previous block
- offset -= 4096;
- // note: can't use System.arraycopy, because the referenced
- // bytes can cross through the current out position.
- end = offset + length;
- while (offset < end)
- dst[out++] = dst[offset++];
- } else { // literal
- dst[out++] = src[in++];
- }
- }
- // copy it back without the prebuffered data
- src = dst;
- dst = calloc(uncompressedSize,1);
- memcpy(dst, src + comp_Prebuf.size, uncompressedSize);
- free(src);
- *size = uncompressedSize;
- return dst;
- } else { // unknown magic number
- printf("Unknown compression type (magic number %x)\n", magic );
- return NULL;
- }
-}