/* * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * Copyright (C) Randall Hand * */ #ifdef HAVE_CONFIG_H #include #endif /* We include gi18n-lib.h so that we have strings translated directly for this package */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_YTNEF_H #include #elif defined HAVE_LIBYTNEF_YTNEF_H #include #endif #include #include #include #include gint verbose = 0; gint saveRTF = 0; gint saveintermediate = 0; gboolean loaded = FALSE; void processTnef (TNEFStruct *tnef, const gchar *tmpdir); void saveVCalendar (TNEFStruct *tnef, const gchar *tmpdir); void saveVCard (TNEFStruct *tnef, const gchar *tmpdir); void saveVTask (TNEFStruct *tnef, const gchar *tmpdir); void org_gnome_format_tnef (gpointer ep, EMFormatHookTarget *t); /* Other Prototypes */ void fprintProperty (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]); void fprintUserProp (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]); void quotedfprint (FILE *fptr, variableLength *vl); void cstylefprint (FILE *fptr, variableLength *vl); void printRtf (FILE *fptr, variableLength *vl); void printRrule (FILE *fptr, gchar *recur_data, gint size, TNEFStruct *tnef); guchar getRruleCount (guchar a, guchar b); guchar getRruleMonthNum (guchar a, guchar b); gchar * getRruleDayname (guchar a); static gchar * sanitize_filename (const gchar *filename) { gchar * sanitized_name; sanitized_name = g_path_get_basename (filename); if (sanitized_name == NULL || !g_strcmp0 (sanitized_name, ".")) { g_free (sanitized_name); return NULL; } else { return g_strdelimit (sanitized_name, " ", '_'); } } void org_gnome_format_tnef (gpointer ep, EMFormatHookTarget *t) { gchar *tmpdir, *name; CamelStream *out; struct dirent *d; DIR *dir; CamelMultipart *mp; CamelMimePart *mainpart; CamelDataWrapper *content; gint len; TNEFStruct tnef; tmpdir = e_mkdtemp("tnef-attachment-XXXXXX"); if (tmpdir == NULL) return; name = g_build_filename(tmpdir, ".evo-attachment.tnef", NULL); out = camel_stream_fs_new_with_name (name, O_RDWR|O_CREAT, 0666, NULL); if (out == NULL) goto fail; content = camel_medium_get_content ((CamelMedium *) t->part); if (content == NULL) goto fail; if (camel_data_wrapper_decode_to_stream_sync (content, out, NULL, NULL) == -1 || camel_stream_close (out, NULL, NULL) == -1) { g_object_unref (out); goto fail; } g_object_unref (out); /* Extracting the winmail.dat */ TNEFInitialize (&tnef); tnef.Debug = verbose; if (TNEFParseFile (name, &tnef) == -1) { printf("ERROR processing file\n"); } processTnef (&tnef, tmpdir); TNEFFree (&tnef); /* Extraction done */ dir = opendir (tmpdir); if (dir == NULL) goto fail; mainpart = camel_mime_part_new (); mp = camel_multipart_new (); camel_data_wrapper_set_mime_type((CamelDataWrapper *)mp, "multipart/mixed"); camel_multipart_set_boundary (mp, NULL); camel_medium_set_content ((CamelMedium *) mainpart, (CamelDataWrapper *) mp); while ((d = readdir (dir))) { CamelMimePart *part; CamelDataWrapper *content; CamelStream *stream; gchar *path; const gchar *type; if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..") || !strcmp(d->d_name, ".evo-attachment.tnef")) continue; path = g_build_filename (tmpdir, d->d_name, NULL); stream = camel_stream_fs_new_with_name (path, O_RDONLY, 0, NULL); content = camel_data_wrapper_new (); camel_data_wrapper_construct_from_stream_sync ( content, stream, NULL, NULL); g_object_unref (stream); part = camel_mime_part_new (); camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BINARY); camel_medium_set_content ((CamelMedium *) part, content); g_object_unref (content); type = em_format_snoop_type (part); if (type) camel_data_wrapper_set_mime_type ((CamelDataWrapper *) part, type); camel_mime_part_set_filename (part, d->d_name); g_free (path); camel_multipart_add_part (mp, part); g_object_unref (part); } closedir (dir); len = t->format->part_id->len; g_string_append_printf(t->format->part_id, ".tnef"); if (camel_multipart_get_number (mp) > 0) /* FIXME Not passing a GCancellable here. */ em_format_part_as ( t->format, t->stream, mainpart, "multipart/mixed", NULL); else if (t->item->handler.old) /* FIXME Not passing a GCancellable here. */ t->item->handler.old->handler ( t->format, t->stream, t->part, t->item->handler.old, NULL, FALSE); g_string_truncate (t->format->part_id, len); g_object_unref (mp); g_object_unref (mainpart); goto ok; fail: if (t->item->handler.old) /* FIXME Not passing a GCancellable here. */ t->item->handler.old->handler ( t->format, t->stream, t->part, t->item->handler.old, NULL, FALSE); ok: g_free (name); g_free (tmpdir); } gint e_plugin_lib_enable (EPlugin *ep, gint enable); gint e_plugin_lib_enable (EPlugin *ep, gint enable) { if (loaded) return 0; loaded = TRUE; return 0; } void processTnef (TNEFStruct *tnef, const gchar *tmpdir) { variableLength *filename; variableLength *filedata; Attachment *p; gint RealAttachment; gint object; gchar *ifilename = NULL; gchar *absfilename, *file; gint count; gint foundCal=0; FILE *fptr; /* First see if this requires special processing. */ /* ie: it's a Contact Card, Task, or Meeting request (vCal/vCard) */ if (tnef->messageClass[0] != 0) { if (strcmp(tnef->messageClass, "IPM.Contact") == 0) { saveVCard (tnef, tmpdir); } if (strcmp(tnef->messageClass, "IPM.Task") == 0) { saveVTask (tnef, tmpdir); } if (strcmp(tnef->messageClass, "IPM.Appointment") == 0) { saveVCalendar (tnef, tmpdir); foundCal = 1; } } if ((filename = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8,0x24))) != MAPI_UNDEFINED) { if (strcmp(filename->data, "IPM.Appointment") == 0) { /* If it's "indicated" twice, we don't want to save 2 calendar entries. */ if (foundCal == 0) { saveVCalendar (tnef, tmpdir); } } } if (strcmp(tnef->messageClass, "IPM.Microsoft Mail.Note") == 0) { if ((saveRTF == 1) && (tnef->subject.size > 0)) { /* Description */ if ((filename=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_BINARY, PR_RTF_COMPRESSED))) != MAPI_UNDEFINED) { variableLength buf; if ((buf.data = (gchar *) DecompressRTF (filename, &buf.size)) != NULL) { file = sanitize_filename (tnef->subject.data); if (!file) return; absfilename = g_strconcat (file, ".rtf", NULL); ifilename = g_build_filename (tmpdir, file, NULL); g_free (absfilename); g_free (file); if ((fptr = fopen(ifilename, "wb"))==NULL) { printf("ERROR: Error writing file to disk!"); } else { fwrite (buf.data, sizeof (BYTE), buf.size, fptr); fclose (fptr); } free (buf.data); } } } } /* Now process each attachment */ p = tnef->starting_attach.next; count = 0; while (p != NULL) { count++; /* Make sure it has a size. */ if (p->FileData.size > 0) { object = 1; /* See if the contents are stored as "attached data" */ /* Inside the MAPI blocks. */ if ((filedata = MAPIFindProperty (&(p->MAPI), PROP_TAG (PT_OBJECT, PR_ATTACH_DATA_OBJ))) == MAPI_UNDEFINED) { if ((filedata = MAPIFindProperty (&(p->MAPI), PROP_TAG (PT_BINARY, PR_ATTACH_DATA_OBJ))) == MAPI_UNDEFINED) { /* Nope, standard TNEF stuff. */ filedata = &(p->FileData); object = 0; } } /* See if this is an embedded TNEF stream. */ RealAttachment = 1; if (object == 1) { /* This is an "embedded object", so skip the */ /* 16-byte identifier first. */ TNEFStruct emb_tnef; DWORD signature; memcpy (&signature, filedata->data+16, sizeof (DWORD)); if (TNEFCheckForSignature (signature) == 0) { /* Has a TNEF signature, so process it. */ TNEFInitialize (&emb_tnef); emb_tnef.Debug = tnef->Debug; if (TNEFParseMemory ((guchar *) filedata->data+16, filedata->size-16, &emb_tnef) != -1) { processTnef (&emb_tnef, tmpdir); RealAttachment = 0; } TNEFFree (&emb_tnef); } } else { TNEFStruct emb_tnef; DWORD signature; memcpy (&signature, filedata->data, sizeof (DWORD)); if (TNEFCheckForSignature (signature) == 0) { /* Has a TNEF signature, so process it. */ TNEFInitialize (&emb_tnef); emb_tnef.Debug = tnef->Debug; if (TNEFParseMemory ((guchar *) filedata->data, filedata->size, &emb_tnef) != -1) { processTnef (&emb_tnef, tmpdir); RealAttachment = 0; } TNEFFree (&emb_tnef); } } if ((RealAttachment == 1) || (saveintermediate == 1)) { gchar tmpname[20]; /* Ok, it's not an embedded stream, so now we */ /* process it. */ if ((filename = MAPIFindProperty (&(p->MAPI), PROP_TAG (PT_STRING8, PR_ATTACH_LONG_FILENAME))) == MAPI_UNDEFINED) { if ((filename = MAPIFindProperty (&(p->MAPI), PROP_TAG (PT_STRING8, PR_DISPLAY_NAME))) == MAPI_UNDEFINED) { filename = &(p->Title); } } if (filename->size == 1) { filename->size = 20; g_sprintf(tmpname, "file_%03i.dat", count); filename->data = tmpname; } absfilename = sanitize_filename (filename->data); if (!absfilename) return; ifilename = g_build_filename (tmpdir, absfilename, NULL); g_free (absfilename); if ((fptr = fopen(ifilename, "wb"))==NULL) { printf("ERROR: Error writing file to disk!"); } else { if (object == 1) { fwrite (filedata->data + 16, sizeof (BYTE), filedata->size - 16, fptr); } else { fwrite (filedata->data, sizeof (BYTE), filedata->size, fptr); } fclose (fptr); } } } /* if size>0 */ p=p->next; } /* while p!= null */ g_free (ifilename); } void saveVCard (TNEFStruct *tnef, const gchar *tmpdir) { gchar *ifilename; gchar *absfilename, *file=NULL; FILE *fptr; variableLength *vl; variableLength *pobox, *street, *city, *state, *zip, *country; dtr thedate; gint boolean; if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_DISPLAY_NAME))) == MAPI_UNDEFINED) { if ((vl=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_COMPANY_NAME))) == MAPI_UNDEFINED) { if (tnef->subject.size > 0) { file = sanitize_filename (tnef->subject.data); if (!file) return; absfilename = g_strconcat (file, ".vcard", NULL); } else absfilename = g_strdup ("unknown.vcard"); } else { file = sanitize_filename (vl->data); if (!file) return; absfilename = g_strconcat (file, ".vcard", NULL); } } else { file = sanitize_filename (vl->data); if (!file) return; absfilename = g_strconcat (file, ".vcard", NULL); } ifilename = g_build_filename (tmpdir, absfilename, NULL); g_free (file); g_free (absfilename); if ((fptr = fopen(ifilename, "wb"))==NULL) { printf("Error writing file to disk!"); } else { fprintf(fptr, "BEGIN:VCARD\n"); fprintf(fptr, "VERSION:2.1\n"); if (vl != MAPI_UNDEFINED) { fprintf(fptr, "FN:%s\n", vl->data); } fprintProperty(tnef, fptr, PT_STRING8, PR_NICKNAME, "NICKNAME:%s\n"); fprintUserProp(tnef, fptr, PT_STRING8, 0x8554, "MAILER:Microsoft Outlook %s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_SPOUSE_NAME, "X-EVOLUTION-SPOUSE:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_MANAGER_NAME, "X-EVOLUTION-MANAGER:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_ASSISTANT, "X-EVOLUTION-ASSISTANT:%s\n"); /* Organizational */ if ((vl=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_COMPANY_NAME))) != MAPI_UNDEFINED) { if (vl->size > 0) { if ((vl->size == 1) && (vl->data[0] == 0)) { } else { fprintf(fptr,"ORG:%s", vl->data); if ((vl=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_DEPARTMENT_NAME))) != MAPI_UNDEFINED) { fprintf(fptr,";%s", vl->data); } fprintf(fptr, "\n"); } } } fprintProperty(tnef, fptr, PT_STRING8, PR_OFFICE_LOCATION, "X-EVOLUTION-OFFICE:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_TITLE, "TITLE:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_PROFESSION, "ROLE:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_BODY, "NOTE:%s\n"); if (tnef->body.size > 0) { fprintf(fptr, "NOTE;QUOTED-PRINTABLE:"); quotedfprint (fptr, &(tnef->body)); fprintf(fptr,"\n"); } /* Business Address */ boolean = 0; if ((pobox = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_POST_OFFICE_BOX))) != MAPI_UNDEFINED) { boolean = 1; } if ((street = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_STREET_ADDRESS))) != MAPI_UNDEFINED) { boolean = 1; } if ((city = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_LOCALITY))) != MAPI_UNDEFINED) { boolean = 1; } if ((state = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) { boolean = 1; } if ((zip = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_POSTAL_CODE))) != MAPI_UNDEFINED) { boolean = 1; } if ((country = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_COUNTRY))) != MAPI_UNDEFINED) { boolean = 1; } if (boolean == 1) { fprintf(fptr, "ADR;QUOTED-PRINTABLE;WORK:"); if (pobox != MAPI_UNDEFINED) { quotedfprint (fptr, pobox); } fprintf(fptr, ";;"); if (street != MAPI_UNDEFINED) { quotedfprint (fptr, street); } fprintf(fptr, ";"); if (city != MAPI_UNDEFINED) { quotedfprint (fptr, city); } fprintf(fptr, ";"); if (state != MAPI_UNDEFINED) { quotedfprint (fptr, state); } fprintf(fptr, ";"); if (zip != MAPI_UNDEFINED) { quotedfprint (fptr, zip); } fprintf(fptr, ";"); if (country != MAPI_UNDEFINED) { quotedfprint (fptr, country); } fprintf(fptr,"\n"); if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x801b))) != MAPI_UNDEFINED) { fprintf(fptr, "LABEL;QUOTED-PRINTABLE;WORK:"); quotedfprint (fptr, vl); fprintf(fptr,"\n"); } } /* Home Address */ boolean = 0; if ((pobox = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_POST_OFFICE_BOX))) != MAPI_UNDEFINED) { boolean = 1; } if ((street = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_STREET))) != MAPI_UNDEFINED) { boolean = 1; } if ((city = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_CITY))) != MAPI_UNDEFINED) { boolean = 1; } if ((state = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) { boolean = 1; } if ((zip = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_POSTAL_CODE))) != MAPI_UNDEFINED) { boolean = 1; } if ((country = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_COUNTRY))) != MAPI_UNDEFINED) { boolean = 1; } if (boolean == 1) { fprintf(fptr, "ADR;QUOTED-PRINTABLE;HOME:"); if (pobox != MAPI_UNDEFINED) { quotedfprint (fptr, pobox); } fprintf(fptr, ";;"); if (street != MAPI_UNDEFINED) { quotedfprint (fptr, street); } fprintf(fptr, ";"); if (city != MAPI_UNDEFINED) { quotedfprint (fptr, city); } fprintf(fptr, ";"); if (state != MAPI_UNDEFINED) { quotedfprint (fptr, state); } fprintf(fptr, ";"); if (zip != MAPI_UNDEFINED) { quotedfprint (fptr, zip); } fprintf(fptr, ";"); if (country != MAPI_UNDEFINED) { quotedfprint (fptr, country); } fprintf(fptr,"\n"); if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x801a))) != MAPI_UNDEFINED) { fprintf(fptr, "LABEL;QUOTED-PRINTABLE;WORK:"); quotedfprint (fptr, vl); fprintf(fptr,"\n"); } } /* Other Address */ boolean = 0; if ((pobox = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_POST_OFFICE_BOX))) != MAPI_UNDEFINED) { boolean = 1; } if ((street = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_STREET))) != MAPI_UNDEFINED) { boolean = 1; } if ((city = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_CITY))) != MAPI_UNDEFINED) { boolean = 1; } if ((state = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) { boolean = 1; } if ((zip = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_POSTAL_CODE))) != MAPI_UNDEFINED) { boolean = 1; } if ((country = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_COUNTRY))) != MAPI_UNDEFINED) { boolean = 1; } if (boolean == 1) { fprintf(fptr, "ADR;QUOTED-PRINTABLE;OTHER:"); if (pobox != MAPI_UNDEFINED) { quotedfprint (fptr, pobox); } fprintf(fptr, ";;"); if (street != MAPI_UNDEFINED) { quotedfprint (fptr, street); } fprintf(fptr, ";"); if (city != MAPI_UNDEFINED) { quotedfprint (fptr, city); } fprintf(fptr, ";"); if (state != MAPI_UNDEFINED) { quotedfprint (fptr, state); } fprintf(fptr, ";"); if (zip != MAPI_UNDEFINED) { quotedfprint (fptr, zip); } fprintf(fptr, ";"); if (country != MAPI_UNDEFINED) { quotedfprint (fptr, country); } fprintf(fptr,"\n"); } fprintProperty(tnef, fptr, PT_STRING8, PR_CALLBACK_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-CALLBACK:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_PRIMARY_TELEPHONE_NUMBER, "TEL;PREF:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_MOBILE_TELEPHONE_NUMBER, "TEL;CELL:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_RADIO_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-RADIO:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_CAR_TELEPHONE_NUMBER, "TEL;CAR:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_OTHER_TELEPHONE_NUMBER, "TEL;VOICE:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_PAGER_TELEPHONE_NUMBER, "TEL;PAGER:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_TELEX_NUMBER, "TEL;X-EVOLUTION-TELEX:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_ISDN_NUMBER, "TEL;ISDN:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_HOME2_TELEPHONE_NUMBER, "TEL;HOME:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_TTYTDD_PHONE_NUMBER, "TEL;X-EVOLUTION-TTYTDD:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_HOME_TELEPHONE_NUMBER, "TEL;HOME;VOICE:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_ASSISTANT_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-ASSISTANT:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_COMPANY_MAIN_PHONE_NUMBER, "TEL;WORK:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_BUSINESS_TELEPHONE_NUMBER, "TEL;WORK:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_BUSINESS2_TELEPHONE_NUMBER, "TEL;WORK;VOICE:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_PRIMARY_FAX_NUMBER, "TEL;PREF;FAX:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_BUSINESS_FAX_NUMBER, "TEL;WORK;FAX:%s\n"); fprintProperty(tnef, fptr, PT_STRING8, PR_HOME_FAX_NUMBER, "TEL;HOME;FAX:%s\n"); /* Email addresses */ if ((vl=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8083))) == MAPI_UNDEFINED) { vl=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8084)); } if (vl != MAPI_UNDEFINED) { if (vl->size > 0) fprintf(fptr, "EMAIL:%s\n", vl->data); } if ((vl=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8093))) == MAPI_UNDEFINED) { vl=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8094)); } if (vl != MAPI_UNDEFINED) { if (vl->size > 0) fprintf(fptr, "EMAIL:%s\n", vl->data); } if ((vl=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x80a3))) == MAPI_UNDEFINED) { vl=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x80a4)); } if (vl != MAPI_UNDEFINED) { if (vl->size > 0) fprintf(fptr, "EMAIL:%s\n", vl->data); } fprintProperty(tnef, fptr, PT_STRING8, PR_BUSINESS_HOME_PAGE, "URL:%s\n"); fprintUserProp(tnef, fptr, PT_STRING8, 0x80d8, "FBURL:%s\n"); /* Birthday */ if ((vl=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, PR_BIRTHDAY))) != MAPI_UNDEFINED) { fprintf(fptr, "BDAY:"); MAPISysTimetoDTR ((guchar *) vl->data, &thedate); fprintf(fptr, "%i-%02i-%02i\n", thedate.wYear, thedate.wMonth, thedate.wDay); } /* Anniversary */ if ((vl=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, PR_WEDDING_ANNIVERSARY))) != MAPI_UNDEFINED) { fprintf(fptr, "X-EVOLUTION-ANNIVERSARY:"); MAPISysTimetoDTR ((guchar *) vl->data, &thedate); fprintf(fptr, "%i-%02i-%02i\n", thedate.wYear, thedate.wMonth, thedate.wDay); } fprintf(fptr, "END:VCARD\n"); fclose (fptr); } g_free (ifilename); } guchar getRruleCount (guchar a, guchar b) { return ((a << 8) | b); } guchar getRruleMonthNum (guchar a, guchar b) { switch (a) { case 0x00: switch (b) { case 0x00: /* Jan */ return (1); case 0xA3: /* May */ return (5); case 0xAE: /* Nov */ return (11); } break; case 0x60: switch (b) { case 0xAE: /* Feb */ return (2); case 0x51: /* Jun */ return (6); } break; case 0xE0: switch (b) { case 0x4B: /* Mar */ return (3); case 0x56: /* Sep */ return (9); } break; case 0x40: switch (b) { case 0xFA: /* Apr */ return (4); } break; case 0x20: if (b == 0xFA) { /* Jul */ return (7); } break; case 0x80: if (b == 0xA8) { /* Aug */ return (8); } break; case 0xA0: if (b == 0xFF) { /* Oct */ return (10); } break; case 0xC0: if (b == 0x56) { return (12); } } /* Error */ return (0); } gchar * getRruleDayname (guchar a) { static gchar daystring[25]; *daystring = 0; if (a & 0x01) { strcat(daystring, "SU,"); } if (a & 0x02) { strcat(daystring, "MO,"); } if (a & 0x04) { strcat(daystring, "TU,"); } if (a & 0x08) { strcat(daystring, "WE,"); } if (a & 0x10) { strcat(daystring, "TH,"); } if (a & 0x20) { strcat(daystring, "FR,"); } if (a & 0x40) { strcat(daystring, "SA,"); } if (strlen (daystring)) { daystring[strlen (daystring) - 1] = 0; } return (daystring); } void printRrule (FILE *fptr, gchar *recur_data, gint size, TNEFStruct *tnef) { variableLength *filename; if (size < 0x1F) { return; } fprintf(fptr, "RRULE:FREQ="); if (recur_data[0x04] == 0x0A) { fprintf(fptr, "DAILY"); if (recur_data[0x16] == 0x23 || recur_data[0x16] == 0x22 || recur_data[0x16] == 0x21) { if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_I2, 0x0011))) != MAPI_UNDEFINED) { fprintf(fptr, ";INTERVAL=%d", *(filename->data)); } if (recur_data[0x16] == 0x22 || recur_data[0x16] == 0x21) { fprintf(fptr, ";COUNT=%d", getRruleCount (recur_data[0x1B], recur_data[0x1A])); } } else if (recur_data[0x16] == 0x3E) { fprintf(fptr, ";BYDAY=MO,TU,WE,TH,FR"); if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) { fprintf(fptr, ";COUNT=%d", getRruleCount (recur_data[0x1F], recur_data[0x1E])); } } } else if (recur_data[0x04] == 0x0B) { fprintf(fptr, "WEEKLY;INTERVAL=%d;BYDAY=%s", recur_data[0x0E], getRruleDayname (recur_data[0x16])); if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) { fprintf(fptr, ";COUNT=%d", getRruleCount (recur_data[0x1F], recur_data[0x1E])); } } else if (recur_data[0x04] == 0x0C) { fprintf(fptr, "MONTHLY"); if (recur_data[0x06] == 0x02) { fprintf(fptr, ";INTERVAL=%d;BYMONTHDAY=%d", recur_data[0x0E], recur_data[0x16]); if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) { fprintf(fptr, ";COUNT=%d", getRruleCount(recur_data[0x1F], recur_data[0x1E])); } } else if (recur_data[0x06] == 0x03) { fprintf(fptr, ";BYDAY=%s;BYSETPOS=%d;INTERVAL=%d", getRruleDayname (recur_data[0x16]), recur_data[0x1A] == 0x05 ? -1 : recur_data[0x1A], recur_data[0x0E]); if (recur_data[0x1E] == 0x22 || recur_data[0x1E] == 0x21) { fprintf(fptr, ";COUNT=%d", getRruleCount(recur_data[0x23], recur_data[0x22])); } } } else if (recur_data[0x04] == 0x0D) { fprintf(fptr, "YEARLY;BYMONTH=%d", getRruleMonthNum (recur_data[0x0A], recur_data[0x0B])); if (recur_data[0x06] == 0x02) { fprintf(fptr, ";BYMONTHDAY=%d", recur_data[0x16]); } else if (recur_data[0x06] == 0x03) { fprintf(fptr, ";BYDAY=%s;BYSETPOS=%d", getRruleDayname (recur_data[0x16]), recur_data[0x1A] == 0x05 ? -1 : recur_data[0x1A]); } if (recur_data[0x1E] == 0x22 || recur_data[0x1E] == 0x21) { fprintf(fptr, ";COUNT=%d", getRruleCount(recur_data[0x23], recur_data[0x22])); } } fprintf(fptr, "\n"); } void saveVCalendar (TNEFStruct *tnef, const gchar *tmpdir) { gchar *ifilename; variableLength *filename; gchar *charptr, *charptr2; FILE *fptr; gint index; DWORD *dword_ptr; dtr thedate; ifilename = g_build_filename (tmpdir, "calendar.vcf", NULL); printf("%s\n", ifilename); if ((fptr = fopen(ifilename, "wb"))==NULL) { printf("Error writing file to disk!"); } else { fprintf(fptr, "BEGIN:VCALENDAR\n"); if (tnef->messageClass[0] != 0) { charptr2=tnef->messageClass; charptr=charptr2; while (*charptr != 0) { if (*charptr == '.') { charptr2 = charptr; } charptr++; } if (strcmp(charptr2, ".MtgCncl") == 0) { fprintf(fptr, "METHOD:CANCEL\n"); } else { fprintf(fptr, "METHOD:REQUEST\n"); } } else { fprintf(fptr, "METHOD:REQUEST\n"); } fprintf(fptr, "VERSION:2.0\n"); fprintf(fptr, "BEGIN:VEVENT\n"); /* UID After alot of comparisons, I'm reasonably sure this is totally wrong. But it's not really necessary. */ /* I think it only exists to connect future modification entries to this entry. so as long as it's incorrectly interpreted the same way every time, it should be ok :) */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_BINARY, 0x3))) == MAPI_UNDEFINED) { if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_BINARY, 0x23))) == MAPI_UNDEFINED) { filename = NULL; } } if (filename!=NULL) { fprintf(fptr, "UID:"); for (index=0;indexsize;index++) { fprintf(fptr,"%02X", (guchar)filename->data[index]); } fprintf(fptr,"\n"); } /* Sequence */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_LONG, 0x8201))) != MAPI_UNDEFINED) { dword_ptr = (DWORD*) filename->data; fprintf(fptr, "SEQUENCE:%i\n", (gint) *dword_ptr); } if ((filename=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_BINARY, PR_SENDER_SEARCH_KEY))) != MAPI_UNDEFINED) { charptr = filename->data; charptr2 = strstr(charptr, ":"); if (charptr2 == NULL) charptr2 = charptr; else charptr2++; fprintf(fptr, "ORGANIZER;CN=\"%s\":MAILTO:%s\n", charptr2, charptr2); } /* Required Attendees */ if ((filename = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x823b))) != MAPI_UNDEFINED) { /* We have a list of required participants, so write them out. */ if (filename->size > 1) { charptr = filename->data-1; while (charptr != NULL) { charptr++; charptr2 = strstr(charptr, ";"); if (charptr2 != NULL) { *charptr2 = 0; } while (*charptr == ' ') charptr++; fprintf(fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;"); fprintf(fptr, "ROLE=REQ-PARTICIPANT;RSVP=TRUE;"); fprintf(fptr, "CN=\"%s\":MAILTO:%s\n", charptr, charptr); charptr = charptr2; } } /* Optional attendees */ if ((filename = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x823c))) != MAPI_UNDEFINED) { /* The list of optional participants */ if (filename->size > 1) { charptr = filename->data-1; while (charptr != NULL) { charptr++; charptr2 = strstr(charptr, ";"); if (charptr2 != NULL) { *charptr2 = 0; } while (*charptr == ' ') charptr++; fprintf(fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;"); fprintf(fptr, "ROLE=OPT-PARTICIPANT;RSVP=TRUE;"); fprintf(fptr, "CN=\"%s\":MAILTO:%s\n", charptr, charptr); charptr = charptr2; } } } } else if ((filename = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8238))) != MAPI_UNDEFINED) { if (filename->size > 1) { charptr = filename->data-1; while (charptr != NULL) { charptr++; charptr2 = strstr(charptr, ";"); if (charptr2 != NULL) { *charptr2 = 0; } while (*charptr == ' ') charptr++; fprintf(fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;"); fprintf(fptr, "ROLE=REQ-PARTICIPANT;RSVP=TRUE;"); fprintf(fptr, "CN=\"%s\":MAILTO:%s\n", charptr, charptr); charptr = charptr2; } } } /* Summary */ filename = NULL; if ((filename=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_CONVERSATION_TOPIC))) != MAPI_UNDEFINED) { fprintf(fptr, "SUMMARY:"); cstylefprint (fptr, filename); fprintf(fptr, "\n"); } /* Description */ if ((filename=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_BINARY, PR_RTF_COMPRESSED))) != MAPI_UNDEFINED) { variableLength buf; if ((buf.data = (gchar *) DecompressRTF (filename, &buf.size)) != NULL) { fprintf(fptr, "DESCRIPTION:"); printRtf (fptr, &buf); free (buf.data); } } /* Location */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x0002))) == MAPI_UNDEFINED) { if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8208))) == MAPI_UNDEFINED) { filename = NULL; } } if (filename != NULL) { fprintf(fptr,"LOCATION: %s\n", filename->data); } /* Date Start */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, 0x820d))) == MAPI_UNDEFINED) { if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, 0x8516))) == MAPI_UNDEFINED) { filename=NULL; } } if (filename != NULL) { fprintf(fptr, "DTSTART:"); MAPISysTimetoDTR ((guchar *) filename->data, &thedate); fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n", thedate.wYear, thedate.wMonth, thedate.wDay, thedate.wHour, thedate.wMinute, thedate.wSecond); } /* Date End */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, 0x820e))) == MAPI_UNDEFINED) { if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, 0x8517))) == MAPI_UNDEFINED) { filename=NULL; } } if (filename != NULL) { fprintf(fptr, "DTEND:"); MAPISysTimetoDTR ((guchar *) filename->data, &thedate); fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n", thedate.wYear, thedate.wMonth, thedate.wDay, thedate.wHour, thedate.wMinute, thedate.wSecond); } /* Date Stamp */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, 0x8202))) != MAPI_UNDEFINED) { fprintf(fptr, "CREATED:"); MAPISysTimetoDTR ((guchar *) filename->data, &thedate); fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n", thedate.wYear, thedate.wMonth, thedate.wDay, thedate.wHour, thedate.wMinute, thedate.wSecond); } /* Class */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_BOOLEAN, 0x8506))) != MAPI_UNDEFINED) { dword_ptr = (DWORD*) filename->data; fprintf(fptr, "CLASS:" ); if (*dword_ptr == 1) { fprintf(fptr,"PRIVATE\n"); } else { fprintf(fptr,"PUBLIC\n"); } } /* Recurrence */ filename = NULL; if ((filename=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_BINARY, 0x8216))) != MAPI_UNDEFINED) { printRrule (fptr, filename->data, filename->size, tnef); } /* Wrap it up */ fprintf(fptr, "END:VEVENT\n"); fprintf(fptr, "END:VCALENDAR\n"); fclose (fptr); } g_free (ifilename); } void saveVTask (TNEFStruct *tnef, const gchar *tmpdir) { variableLength *vl; variableLength *filename; gint index; gchar *ifilename; gchar *absfilename, *file; gchar *charptr, *charptr2; dtr thedate; FILE *fptr; DWORD *dword_ptr; vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_CONVERSATION_TOPIC)); if (vl == MAPI_UNDEFINED) { return; } index = strlen (vl->data); while (vl->data[index] == ' ') vl->data[index--] = 0; file = sanitize_filename (vl->data); if (!file) return; absfilename = g_strconcat (file, ".vcf", NULL); ifilename = g_build_filename (tmpdir, absfilename, NULL); g_free (file); g_free (absfilename); printf("%s\n", ifilename); if ((fptr = fopen(ifilename, "wb"))==NULL) { printf("Error writing file to disk!"); } else { fprintf(fptr, "BEGIN:VCALENDAR\n"); fprintf(fptr, "VERSION:2.0\n"); fprintf(fptr, "METHOD:PUBLISH\n"); filename = NULL; fprintf(fptr, "BEGIN:VTODO\n"); if (tnef->messageID[0] != 0) { fprintf(fptr,"UID:%s\n", tnef->messageID); } filename = MAPIFindUserProp (&(tnef->MapiProperties), \ PROP_TAG (PT_STRING8, 0x8122)); if (filename != MAPI_UNDEFINED) { fprintf(fptr, "ORGANIZER:%s\n", filename->data); } if ((filename = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_DISPLAY_TO))) != MAPI_UNDEFINED) { filename = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x811f)); } if ((filename != MAPI_UNDEFINED) && (filename->size > 1)) { charptr = filename->data-1; while (charptr != NULL) { charptr++; charptr2 = strstr(charptr, ";"); if (charptr2 != NULL) { *charptr2 = 0; } while (*charptr == ' ') charptr++; fprintf(fptr, "ATTENDEE;CN=%s;ROLE=REQ-PARTICIPANT:%s\n", charptr, charptr); charptr = charptr2; } } if (tnef->subject.size > 0) { fprintf(fptr,"SUMMARY:"); cstylefprint (fptr,&(tnef->subject)); fprintf(fptr,"\n"); } if (tnef->body.size > 0) { fprintf(fptr,"DESCRIPTION:"); cstylefprint (fptr,&(tnef->body)); fprintf(fptr,"\n"); } filename = MAPIFindProperty (&(tnef->MapiProperties), \ PROP_TAG (PT_SYSTIME, PR_CREATION_TIME)); if (filename != MAPI_UNDEFINED) { fprintf(fptr, "DTSTAMP:"); MAPISysTimetoDTR ((guchar *) filename->data, &thedate); fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n", thedate.wYear, thedate.wMonth, thedate.wDay, thedate.wHour, thedate.wMinute, thedate.wSecond); } filename = MAPIFindUserProp (&(tnef->MapiProperties), \ PROP_TAG (PT_SYSTIME, 0x8517)); if (filename != MAPI_UNDEFINED) { fprintf(fptr, "DUE:"); MAPISysTimetoDTR ((guchar *) filename->data, &thedate); fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n", thedate.wYear, thedate.wMonth, thedate.wDay, thedate.wHour, thedate.wMinute, thedate.wSecond); } filename = MAPIFindProperty (&(tnef->MapiProperties), \ PROP_TAG (PT_SYSTIME, PR_LAST_MODIFICATION_TIME)); if (filename != MAPI_UNDEFINED) { fprintf(fptr, "LAST-MODIFIED:"); MAPISysTimetoDTR ((guchar *) filename->data, &thedate); fprintf(fptr,"%04i%02i%02iT%02i%02i%02iZ\n", thedate.wYear, thedate.wMonth, thedate.wDay, thedate.wHour, thedate.wMinute, thedate.wSecond); } /* Class */ filename = MAPIFindUserProp (&(tnef->MapiProperties), \ PROP_TAG (PT_BOOLEAN, 0x8506)); if (filename != MAPI_UNDEFINED) { dword_ptr = (DWORD*) filename->data; fprintf(fptr, "CLASS:" ); if (*dword_ptr == 1) { fprintf(fptr,"PRIVATE\n"); } else { fprintf(fptr,"PUBLIC\n"); } } fprintf(fptr, "END:VTODO\n"); fprintf(fptr, "END:VCALENDAR\n"); fclose (fptr); } g_free (ifilename); } void fprintProperty (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]) { variableLength *vl; if ((vl=MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (proptype, propid))) != MAPI_UNDEFINED) { if (vl->size > 0) { if ((vl->size == 1) && (vl->data[0] == 0)) { } else { fprintf (fptr, text, vl->data); } } } } void fprintUserProp (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]) { variableLength *vl; if ((vl=MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (proptype, propid))) != MAPI_UNDEFINED) { if (vl->size > 0) { if ((vl->size == 1) && (vl->data[0] == 0)) { } else { fprintf (fptr, text, vl->data); } } } } void quotedfprint (FILE *fptr, variableLength *vl) { gint index; for (index=0;indexsize-1; index++) { if (vl->data[index] == '\n') { fprintf(fptr, "=0A"); } else if (vl->data[index] == '\r') { } else { fprintf(fptr, "%c", vl->data[index]); } } } void cstylefprint (FILE *fptr, variableLength *vl) { gint index; for (index=0;indexsize-1; index++) { if (vl->data[index] == '\n') { fprintf(fptr, "\\n"); } else if (vl->data[index] == '\r') { /* Print nothing. */ } else if (vl->data[index] == ';') { fprintf(fptr, "\\;"); } else if (vl->data[index] == ',') { fprintf(fptr, "\\,"); } else if (vl->data[index] == '\\') { fprintf(fptr, "\\"); } else { fprintf(fptr, "%c", vl->data[index]); } } } void printRtf (FILE *fptr, variableLength *vl) { gint index; gchar *byte; gint brace_ct; gint key; key = 0; brace_ct = 0; for (index = 0, byte=vl->data; index < vl->size; index++, byte++) { if (*byte == '}') { brace_ct--; key = 0; continue; } if (*byte == '{') { brace_ct++; continue; } if (*byte == '\\') { key = 1; } if (isspace (*byte)) { key = 0; } if ((brace_ct == 1) && (key == 0)) { if (*byte == '\n') { fprintf(fptr, "\\n"); } else if (*byte == '\r') { /* Print nothing. */ } else if (*byte == ';') { fprintf(fptr, "\\;"); } else if (*byte == ',') { fprintf(fptr, "\\,"); } else if (*byte == '\\') { fprintf(fptr, "\\"); } else { fprintf(fptr, "%c", *byte); } } } fprintf(fptr, "\n"); }