2013-02-20 [colin] 3.9.0cvs83
authorColin Leroy <colin@colino.net>
Wed, 20 Feb 2013 08:45:59 +0000 (08:45 +0000)
committerColin Leroy <colin@colino.net>
Wed, 20 Feb 2013 08:45:59 +0000 (08:45 +0000)
* configure.ac
* src/plugins/Makefile.am
* src/plugins/spam_report/.cvsignore
* src/plugins/spam_report/Makefile.am
* src/plugins/spam_report/placeholder.txt
* src/plugins/spam_report/spam_report.c
* src/plugins/spam_report/spam_report_prefs.c
* src/plugins/spam_report/spam_report_prefs.h
* src/plugins/tnef_parse/.cvsignore
* src/plugins/tnef_parse/Makefile.am
* src/plugins/tnef_parse/claws.def
* src/plugins/tnef_parse/mapi.h
* src/plugins/tnef_parse/mapidefs.h
* src/plugins/tnef_parse/mapitags.h
* src/plugins/tnef_parse/placeholder.txt
* src/plugins/tnef_parse/plugin.def
* src/plugins/tnef_parse/tnef-errors.h
* src/plugins/tnef_parse/tnef-types.h
* src/plugins/tnef_parse/tnef_dump.c
* src/plugins/tnef_parse/tnef_dump.h
* src/plugins/tnef_parse/tnef_parse.c
* src/plugins/tnef_parse/version.rc
* src/plugins/tnef_parse/ytnef.c
* src/plugins/tnef_parse/ytnef.h
Add tnef_parse and spam_report

26 files changed:
ChangeLog
PATCHSETS
configure.ac
src/plugins/Makefile.am
src/plugins/spam_report/.cvsignore [new file with mode: 0644]
src/plugins/spam_report/Makefile.am [new file with mode: 0644]
src/plugins/spam_report/placeholder.txt [deleted file]
src/plugins/spam_report/spam_report.c [new file with mode: 0644]
src/plugins/spam_report/spam_report_prefs.c [new file with mode: 0644]
src/plugins/spam_report/spam_report_prefs.h [new file with mode: 0644]
src/plugins/tnef_parse/.cvsignore [new file with mode: 0644]
src/plugins/tnef_parse/Makefile.am [new file with mode: 0644]
src/plugins/tnef_parse/claws.def [new file with mode: 0644]
src/plugins/tnef_parse/mapi.h [new file with mode: 0644]
src/plugins/tnef_parse/mapidefs.h [new file with mode: 0644]
src/plugins/tnef_parse/mapitags.h [new file with mode: 0644]
src/plugins/tnef_parse/placeholder.txt [deleted file]
src/plugins/tnef_parse/plugin.def [new file with mode: 0644]
src/plugins/tnef_parse/tnef-errors.h [new file with mode: 0644]
src/plugins/tnef_parse/tnef-types.h [new file with mode: 0644]
src/plugins/tnef_parse/tnef_dump.c [new file with mode: 0644]
src/plugins/tnef_parse/tnef_dump.h [new file with mode: 0644]
src/plugins/tnef_parse/tnef_parse.c [new file with mode: 0644]
src/plugins/tnef_parse/version.rc [new file with mode: 0644]
src/plugins/tnef_parse/ytnef.c [new file with mode: 0644]
src/plugins/tnef_parse/ytnef.h [new file with mode: 0644]

index c0762261ebfa0697be840fa24dd0eebae23297e8..9d9733ab9ad55a56ebe5d8cdc6750cac3ef3687c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2013-02-20 [colin]     3.9.0cvs83
+
+       * configure.ac
+       * src/plugins/Makefile.am
+       * src/plugins/spam_report/.cvsignore
+       * src/plugins/spam_report/Makefile.am
+       * src/plugins/spam_report/placeholder.txt
+       * src/plugins/spam_report/spam_report.c
+       * src/plugins/spam_report/spam_report_prefs.c
+       * src/plugins/spam_report/spam_report_prefs.h
+       * src/plugins/tnef_parse/.cvsignore
+       * src/plugins/tnef_parse/Makefile.am
+       * src/plugins/tnef_parse/claws.def
+       * src/plugins/tnef_parse/mapi.h
+       * src/plugins/tnef_parse/mapidefs.h
+       * src/plugins/tnef_parse/mapitags.h
+       * src/plugins/tnef_parse/placeholder.txt
+       * src/plugins/tnef_parse/plugin.def
+       * src/plugins/tnef_parse/tnef-errors.h
+       * src/plugins/tnef_parse/tnef-types.h
+       * src/plugins/tnef_parse/tnef_dump.c
+       * src/plugins/tnef_parse/tnef_dump.h
+       * src/plugins/tnef_parse/tnef_parse.c
+       * src/plugins/tnef_parse/version.rc
+       * src/plugins/tnef_parse/ytnef.c
+       * src/plugins/tnef_parse/ytnef.h
+               Add tnef_parse and spam_report
+
 2013-02-20 [colin]     3.9.0cvs82
 
        * src/plugins/bogofilter/Makefile.am
index 6f49fc07e607f6d7faa6c9c3a5a253d4a3e0f2fe..7df696ed82fef16798ef3fc18b65153041544783 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/notification/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/pdf_viewer/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/python/Makefile.am;  ) > 3.9.0cvs80.patchset
 ( cvs diff -u -r 1.654.2.4657 -r 1.654.2.4658 configure.ac;  ) > 3.9.0cvs81.patchset
 ( cvs diff -u -r 1.1.2.7 -r 1.1.2.8 src/plugins/bogofilter/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/clamd/Makefile.am;  cvs diff -u -r 1.3.2.4 -r 1.3.2.5 src/plugins/demo/Makefile.am;  cvs diff -u -r 1.4.2.9 -r 1.4.2.10 src/plugins/dillo_viewer/Makefile.am;  cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/fancy/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/fetchinfo/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/gdata/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/mailmbox/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/newmail/Makefile.am;  cvs diff -u -r 1.1.2.3 -r 1.1.2.4 src/plugins/notification/Makefile.am;  cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/pdf_viewer/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/perl/Makefile.am;  cvs diff -u -r 1.1.2.2 -r 1.1.2.3 src/plugins/python/Makefile.am;  cvs diff -u -r 1.5.2.10 -r 1.5.2.11 src/plugins/spamassassin/Makefile.am;  cvs diff -u -r 1.4.2.14 -r 1.4.2.15 src/plugins/trayicon/Makefile.am;  cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/plugins/vcalendar/libical/libical/Makefile.am;  ) > 3.9.0cvs82.patchset
+( cvs diff -u -r 1.654.2.4659 -r 1.654.2.4660 configure.ac;  cvs diff -u -r 1.8.2.14 -r 1.8.2.15 src/plugins/Makefile.am;  diff -u /dev/null src/plugins/spam_report/.cvsignore;  diff -u /dev/null src/plugins/spam_report/Makefile.am;  cvs diff -u -r -1.1.2.1 -r -1.1.2.2 src/plugins/spam_report/placeholder.txt;  diff -u /dev/null src/plugins/spam_report/spam_report.c;  diff -u /dev/null src/plugins/spam_report/spam_report_prefs.c;  diff -u /dev/null src/plugins/spam_report/spam_report_prefs.h;  diff -u /dev/null src/plugins/tnef_parse/.cvsignore;  diff -u /dev/null src/plugins/tnef_parse/Makefile.am;  diff -u /dev/null src/plugins/tnef_parse/claws.def;  diff -u /dev/null src/plugins/tnef_parse/mapi.h;  diff -u /dev/null src/plugins/tnef_parse/mapidefs.h;  diff -u /dev/null src/plugins/tnef_parse/mapitags.h;  cvs diff -u -r -1.1.2.1 -r -1.1.2.2 src/plugins/tnef_parse/placeholder.txt;  diff -u /dev/null src/plugins/tnef_parse/plugin.def;  diff -u /dev/null src/plugins/tnef_parse/tnef-errors.h;  diff -u /dev/null src/plugins/tnef_parse/tnef-types.h;  diff -u /dev/null src/plugins/tnef_parse/tnef_dump.c;  diff -u /dev/null src/plugins/tnef_parse/tnef_dump.h;  diff -u /dev/null src/plugins/tnef_parse/tnef_parse.c;  diff -u /dev/null src/plugins/tnef_parse/version.rc;  diff -u /dev/null src/plugins/tnef_parse/ytnef.c;  diff -u /dev/null src/plugins/tnef_parse/ytnef.h;  ) > 3.9.0cvs83.patchset
index c96e27b3c38d6ab9eaf566e1cba10ab42448cfcc..0ea7defca193e573bc59c93c70dae62c6942518b 100644 (file)
@@ -12,7 +12,7 @@ MINOR_VERSION=9
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=82
+EXTRA_VERSION=83
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
@@ -853,7 +853,7 @@ dnl *************************
 PLUGINS=""
 
 dnl Find curl-config, used by fancy, vcalendar
-PKG_CHECK_MODULES(CURL, libcurl)
+PKG_CHECK_MODULES(CURL, libcurl, [have_curl=yes], [have_curl=no])
 AC_SUBST(CURL_LIBS)
 AC_SUBST(CURL_CFLAGS)
 
@@ -1334,6 +1334,7 @@ else
        AC_MSG_RESULT(no)
 fi
 AM_CONDITIONAL(BUILD_SMIME_PLUGIN, test x"$ac_cv_enable_smime_plugin" = xyes)
+
 dnl --- SpamAssassin ---
 AC_MSG_CHECKING([whether to build SpamAssassin plugin])
 AC_ARG_ENABLE(spamassassin-plugin,
@@ -1349,6 +1350,36 @@ else
 fi
 AM_CONDITIONAL(BUILD_SPAMASSASSIN_PLUGIN, test x"$ac_cv_enable_spamassassin_plugin" = xyes)
 
+dnl --- spam_report ---
+AC_MSG_CHECKING([whether to build spam_report plugin])
+AC_ARG_ENABLE(spam_report-plugin,
+       [  --disable-spam_report-plugin      do not build spam_report plugin],
+       [ac_cv_enable_spam_report_plugin=$enableval], [ac_cv_enable_spam_report_plugin=yes])
+if test x"$ac_cv_enable_spam_report_plugin" = xyes; then
+       if test x"$have_curl" = xyes; then
+               AC_MSG_RESULT(yes)
+               PLUGINS="spam_report $PLUGINS"
+       else
+               AC_MSG_ERROR(spam_report needs libcurl)
+       fi
+else
+       AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL(BUILD_SPAM_REPORT_PLUGIN, test x"$ac_cv_enable_spam_report_plugin" = xyes)
+
+dnl --- tnef_parse ---
+AC_MSG_CHECKING([whether to build tnef_parse plugin])
+AC_ARG_ENABLE(tnef_parse-plugin,
+       [  --disable-tnef_parse-plugin      do not build tnef_parse plugin],
+       [ac_cv_enable_tnef_parse_plugin=$enableval], [ac_cv_enable_tnef_parse_plugin=yes])
+if test x"$ac_cv_enable_tnef_parse_plugin" = xyes; then
+       AC_MSG_RESULT(yes)
+       PLUGINS="tnef_parse $PLUGINS"
+else
+       AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL(BUILD_TNEF_PARSE_PLUGIN, test x"$ac_cv_enable_tnef_parse_plugin" = xyes)
+
 dnl --- Trayicon ---
 AC_MSG_CHECKING([whether to build Trayicon plugin])
 AC_ARG_ENABLE(trayicon-plugin,
@@ -1484,6 +1515,8 @@ src/plugins/pgpinline/Makefile
 src/plugins/rssyl/Makefile
 src/plugins/smime/Makefile
 src/plugins/spamassassin/Makefile
+src/plugins/spam_report/Makefile
+src/plugins/tnef_parse/Makefile
 src/plugins/trayicon/Makefile
 src/plugins/vcalendar/Makefile
 src/plugins/vcalendar/libical/Makefile
index 73850f2d541bfaa9b97ba05a13d51718848a3dd2..9929474c8fd11cb4487fb8deb159b17904a1d11e 100644 (file)
@@ -92,7 +92,15 @@ rssyl_dir = rssyl
 endif
 
 if BUILD_SPAMASSASSIN_PLUGIN
-spamassasssin_dir = spamassassin
+spamassassin_dir = spamassassin
+endif
+
+if BUILD_SPAM_REPORT_PLUGIN
+spam_report_dir = spam_report
+endif
+
+if BUILD_TNEF_PARSE_PLUGIN
+tnef_parse_dir = tnef_parse
 endif
 
 if BUILD_TRAYICON_PLUGIN
@@ -127,7 +135,9 @@ SUBDIRS = \
        $(pgpmime_dir) \
        $(pgpinline_dir) \
        $(rssyl_dir) \
-       $(spamassasssin_dir) \
        $(smime_dir) \
+       $(spamassassin_dir) \
+       $(spam_report_dir) \
+       $(tnef_parse_dir) \
        $(trayicon_dir) \
        $(vcalendar_dir)
diff --git a/src/plugins/spam_report/.cvsignore b/src/plugins/spam_report/.cvsignore
new file mode 100644 (file)
index 0000000..10140b2
--- /dev/null
@@ -0,0 +1,7 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.la
+*.lo
+*.o
diff --git a/src/plugins/spam_report/Makefile.am b/src/plugins/spam_report/Makefile.am
new file mode 100644 (file)
index 0000000..9d6a720
--- /dev/null
@@ -0,0 +1,31 @@
+plugindir = $(pkglibdir)/plugins
+
+plugin_LTLIBRARIES = spamreport.la
+
+spamreport_la_SOURCES = \
+         spam_report.c \
+        spam_report_prefs.c \
+        spam_report_prefs.h \
+        gettext.h
+
+spamreport_la_LDFLAGS = \
+       -avoid-version -module \
+       $(GTK_LIBS)
+
+spamreport_la_LIBADD = \
+       $(CURL_LIBS) \
+       $(GTK_LIBS)
+
+INCLUDES = \
+       -I$(top_srcdir)/src \
+       -I$(top_srcdir)/src/common \
+       -I$(top_builddir)/src/common \
+       -I$(top_srcdir)/src/gtk
+
+AM_CPPFLAGS = \
+       -Wall \
+       $(CLAWS_MAIL_CFLAGS) \
+       $(GLIB_CFLAGS) \
+       $(CURL_CFLAGS) \
+       $(GTK_CFLAGS) \
+       -DLOCALEDIR=\""$(localedir)"\"
diff --git a/src/plugins/spam_report/placeholder.txt b/src/plugins/spam_report/placeholder.txt
deleted file mode 100644 (file)
index 3b94f91..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Placeholder
diff --git a/src/plugins/spam_report/spam_report.c b/src/plugins/spam_report/spam_report.c
new file mode 100644 (file)
index 0000000..593a7c5
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net>
+ * and the Claws Mail Team
+ *
+ * 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 <unistd.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include "common/claws.h"
+#include "common/version.h"
+#include "main.h"
+#include "plugin.h"
+#include "prefs_common.h"
+#include "utils.h"
+#include "spam_report_prefs.h"
+#include "statusbar.h"
+#include "procmsg.h"
+#include "log.h"
+#include "inc.h"
+#include "plugin.h"
+#include "menu.h"
+#include "defs.h"
+#include "base64.h"
+#include "procheader.h"
+
+#ifdef USE_PTHREAD
+#include <pthread.h>
+#endif
+
+#include <curl/curl.h>
+#include <curl/curlver.h>
+
+struct CurlReadWrite {
+        char *data;
+        size_t size;
+};
+
+static gboolean check_debian_listid(MsgInfo *msginfo);
+
+/* this interface struct is probably not enough for the various available 
+ * reporting places/methods. It'll be extended as necessary. */
+
+ReportInterface spam_interfaces[] = {
+       { "Signal-Spam.fr", INTF_HTTP_AUTH, "https://www.signal-spam.fr/api/signaler",
+               "message=%claws_mail_body_b64%", NULL},
+       { "Spamcop.net", INTF_MAIL, NULL, NULL, NULL},
+       { "Debian Lists", INTF_HTTP_GET, 
+               "http://lists.debian.org/cgi-bin/nominate-for-review.pl?Quiet=on&msgid=%claws_mail_msgid%",
+               NULL, check_debian_listid},
+       { NULL, INTF_NULL, NULL, NULL, NULL}
+};
+
+/* From RSSyl. This should be factorized to the core... */
+static gchar *spamreport_strreplace(gchar *source, gchar *pattern,
+               gchar *replacement)
+{
+       gchar *new, *w_new, *c;
+       guint count = 0, final_length;
+       size_t len_pattern, len_replacement;
+
+       if( source == NULL || pattern == NULL ) {
+               debug_print("source or pattern is NULL!!!\n");
+               return NULL;
+       }
+
+       if( !g_utf8_validate(source, -1, NULL) ) {
+               debug_print("source is not an UTF-8 encoded text\n");
+               return NULL;
+       }
+
+       if( !g_utf8_validate(pattern, -1, NULL) ) {
+               debug_print("pattern is not an UTF-8 encoded text\n");
+               return NULL;
+       }
+
+       len_pattern = strlen(pattern);
+       len_replacement = replacement ? strlen(replacement) : 0;
+
+       c = source;
+       while( ( c = g_strstr_len(c, strlen(c), pattern) ) ) {
+               count++;
+               c += len_pattern;
+       }
+
+       final_length = strlen(source)
+               - ( count * len_pattern )
+               + ( count * len_replacement );
+
+       new = malloc(final_length + 1);
+       w_new = new;
+       memset(new, '\0', final_length + 1);
+
+       c = source;
+
+       while( *c != '\0' ) {
+               if( !memcmp(c, pattern, len_pattern) ) {
+                       gboolean break_after_rep = FALSE;
+                       size_t i;
+                       if (*(c + len_pattern) == '\0')
+                               break_after_rep = TRUE;
+                       for (i = 0; i < len_replacement; i++) {
+                               *w_new = replacement[i];
+                               w_new++;
+                       }
+                       if (break_after_rep)
+                               break;
+                       c = c + len_pattern;
+               } else {
+                       *w_new = *c;
+                       w_new++;
+                       c++;
+               }
+       }
+       return new;
+}
+
+static gboolean check_debian_listid(MsgInfo *msginfo)
+{
+       gchar buf[1024];
+       if (!procheader_get_header_from_msginfo(msginfo, buf, sizeof(buf), "List-Id:")) {
+               if (strstr(buf, "lists.debian.org")) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+static void spamreport_http_response_log(gchar *url, long response)
+{
+       switch (response) {
+       case 400: /* Bad Request */
+               log_error(LOG_PROTOCOL, "%s: Bad Request\n", url);
+               break;
+       case 401: /* Not Authorized */
+               log_error(LOG_PROTOCOL, "%s: Wrong login or password\n", url);
+               break;
+       case 404: /* Not Authorized */
+               log_error(LOG_PROTOCOL, "%s: Not found\n", url);
+               break;
+       }
+}
+
+static void *myrealloc(void *pointer, size_t size) {
+        /*
+         * There might be a realloc() out there that doesn't like reallocing
+         * NULL pointers, so we take care of it here.
+         */
+        if (pointer) {
+                return realloc(pointer, size);
+        } else {
+                return malloc(size);
+        }
+}
+
+static size_t curl_writefunction_cb(void *pointer, size_t size, size_t nmemb, void *data) {
+        size_t realsize = size * nmemb;
+        struct CurlReadWrite *mem = (struct CurlReadWrite *)data;
+
+        mem->data = myrealloc(mem->data, mem->size + realsize + 1);
+        if (mem->data) {
+                memcpy(&(mem->data[mem->size]), pointer, realsize);
+                mem->size += realsize;
+                mem->data[mem->size] = 0;
+        }
+        return realsize;
+}
+
+static void report_spam(gint id, ReportInterface *intf, MsgInfo *msginfo, gchar *contents)
+{
+       gchar *reqbody = NULL, *tmp = NULL, *auth = NULL, *b64 = NULL, *geturl = NULL;
+       size_t len_contents;
+       CURL *curl;
+       CURLcode res;
+       long response;
+       struct CurlReadWrite chunk;
+
+       chunk.data = NULL;
+       chunk.size = 0;
+       
+       if (spamreport_prefs.enabled[id] == FALSE) {
+               debug_print("not reporting via %s (disabled)\n", intf->name);
+               return;
+       }
+       if (intf->should_report != NULL && (intf->should_report)(msginfo) == FALSE) {
+               debug_print("not reporting via %s (unsuitable)\n", intf->name);
+               return;
+       }
+
+       debug_print("reporting via %s\n", intf->name);
+       tmp = spamreport_strreplace(intf->body, "%claws_mail_body%", contents);
+       len_contents = strlen(contents);
+       b64 = g_malloc0(B64LEN(len_contents) + 1);
+       base64_encode(b64, contents, len_contents);
+       reqbody = spamreport_strreplace(tmp, "%claws_mail_body_b64%", b64);
+       geturl = spamreport_strreplace(intf->url, "%claws_mail_msgid%", msginfo->msgid);
+       g_free(b64);
+       g_free(tmp);
+       
+       switch(intf->type) {
+       case INTF_HTTP_AUTH:
+               if (spamreport_prefs.user[id] && *(spamreport_prefs.user[id])) {
+                       auth = g_strdup_printf("%s:%s", spamreport_prefs.user[id], spamreport_prefs.pass[id]);
+
+                       curl = curl_easy_init();
+                       curl_easy_setopt(curl, CURLOPT_URL, intf->url);
+                       curl_easy_setopt(curl, CURLOPT_POSTFIELDS, reqbody);
+                       curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
+                       curl_easy_setopt(curl, CURLOPT_TIMEOUT, prefs_common_get_prefs()->io_timeout_secs);
+                       curl_easy_setopt(curl, CURLOPT_USERAGENT,
+                               SPAM_REPORT_USERAGENT "(" PLUGINS_URI ")");
+                       res = curl_easy_perform(curl);
+                       curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+                       curl_easy_cleanup(curl);
+                       spamreport_http_response_log(intf->url, response);
+                       g_free(auth);
+               }
+               break;
+       case INTF_MAIL:
+               if (spamreport_prefs.user[id] && *(spamreport_prefs.user[id])) {
+                       Compose *compose = compose_forward(NULL, msginfo, TRUE, NULL, TRUE, TRUE);
+                       compose->use_signing = FALSE;
+                       compose_entry_append(compose, spamreport_prefs.user[id], COMPOSE_TO, PREF_NONE);
+                       compose_send(compose);
+               }
+               break;
+       case INTF_HTTP_GET:
+               curl = curl_easy_init();
+               curl_easy_setopt(curl, CURLOPT_URL, geturl);
+               curl_easy_setopt(curl, CURLOPT_USERAGENT,
+                               SPAM_REPORT_USERAGENT "(" PLUGINS_URI ")");
+               curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writefunction_cb);
+               curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+               res = curl_easy_perform(curl);
+               curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+               curl_easy_cleanup(curl);
+               spamreport_http_response_log(geturl, response);
+               /* On success the page should return "OK: nominated <msgid>" */
+               if (chunk.size < 13 || strstr(chunk.data, "OK: nominated") == NULL) {
+                       if (chunk.size > 0) {
+                               log_error(LOG_PROTOCOL, "%s: response was %s\n", geturl, chunk.data);
+                       }
+                       else {
+                               log_error(LOG_PROTOCOL, "%s: response was empty\n", geturl);
+                       }
+               }
+               break;
+       default:
+               g_warning("Unknown method\n");
+       }
+       g_free(reqbody);
+       g_free(geturl);
+}
+
+static void report_spam_cb_ui(GtkAction *action, gpointer data)
+{
+       MainWindow *mainwin = mainwindow_get_mainwindow();
+       SummaryView *summaryview = mainwin->summaryview;
+       GSList *msglist = summary_get_selected_msg_list(summaryview);
+       GSList *cur;
+       gint curnum=0, total=0;
+       if (summary_is_locked(summaryview) || !msglist) {
+               if (msglist)
+                       g_slist_free(msglist);
+               return;
+       }
+       main_window_cursor_wait(summaryview->mainwin);
+       gtk_cmclist_freeze(GTK_CMCLIST(summaryview->ctree));
+       folder_item_update_freeze();
+       inc_lock();
+
+       STATUSBAR_PUSH(mainwin, _("Reporting spam..."));
+       total = g_slist_length(msglist);
+
+       for (cur = msglist; cur; cur = cur->next) {
+               MsgInfo *msginfo = (MsgInfo *)cur->data;
+               gchar *file = procmsg_get_message_file(msginfo);
+               gchar *contents = NULL;
+               int i = 0;
+               if (!file)
+                       continue;
+               debug_print("reporting message %d (%s)\n", msginfo->msgnum, file);
+               statusbar_progress_all(curnum, total, 1);
+               GTK_EVENTS_FLUSH();
+               curnum++;
+
+               contents = file_read_to_str(file);
+               
+               for (i = 0; i < INTF_LAST; i++)
+                       report_spam(i, &(spam_interfaces[i]), msginfo, contents);
+               
+               g_free(contents);
+               g_free(file);
+       }
+
+       statusbar_progress_all(0,0,0);
+       STATUSBAR_POP(mainwin);
+       inc_unlock();
+       folder_item_update_thaw();
+       gtk_cmclist_thaw(GTK_CMCLIST(summaryview->ctree));
+       main_window_cursor_normal(summaryview->mainwin);
+       g_slist_free(msglist);
+}
+
+static GtkActionEntry spamreport_main_menu[] = {{
+       "Message/ReportSpam",
+       NULL, N_("Report spam online..."), NULL, NULL, G_CALLBACK(report_spam_cb_ui)
+}};
+
+static guint context_menu_id = 0;
+static guint main_menu_id = 0;
+
+gint plugin_init(gchar **error)
+{
+       MainWindow *mainwin = mainwindow_get_mainwindow();
+
+       if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,7,3,13),
+                               VERSION_NUMERIC, _("SpamReport"), error))
+               return -1;
+
+       spamreport_prefs_init();
+#ifdef HAVE_LIBCURL
+       curl_global_init(CURL_GLOBAL_DEFAULT);
+#endif
+
+       gtk_action_group_add_actions(mainwin->action_group, spamreport_main_menu,
+                       1, (gpointer)mainwin);
+       MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menu/Message", "ReportSpam", 
+                         "Message/ReportSpam", GTK_UI_MANAGER_MENUITEM,
+                         main_menu_id)
+       MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "ReportSpam", 
+                         "Message/ReportSpam", GTK_UI_MANAGER_MENUITEM,
+                         context_menu_id)
+       return 0;
+}
+
+gboolean plugin_done(void)
+{
+       MainWindow *mainwin = mainwindow_get_mainwindow();
+       SummaryView *summaryview = NULL;
+
+       if (mainwin == NULL)
+               return TRUE;
+
+       summaryview = mainwin->summaryview;
+       MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/ReportSpam", main_menu_id);
+       main_menu_id = 0;
+
+       MENUITEM_REMUI_MANAGER(mainwin->ui_manager,mainwin->action_group, "Message/ReportSpam", context_menu_id);
+       context_menu_id = 0;
+#ifdef HAVE_LIBCURL
+       spamreport_prefs_done();
+#endif
+       return TRUE;
+}
+
+const gchar *plugin_name(void)
+{
+       return _("SpamReport");
+}
+
+const gchar *plugin_desc(void)
+{
+       return _("This plugin reports spam to various places.\n"
+                "Currently the following sites or methods are supported:\n\n"
+                " * spam-signal.fr\n"
+                 " * spamcop.net\n"
+                " * lists.debian.org nomination system");
+}
+
+const gchar *plugin_type(void)
+{
+       return "GTK2";
+}
+
+const gchar *plugin_licence(void)
+{
+       return "GPL3+";
+}
+
+const gchar *plugin_version(void)
+{
+       return VERSION;
+}
+
+struct PluginFeature *plugin_provides(void)
+{
+       static struct PluginFeature features[] = 
+               { {PLUGIN_UTILITY, N_("Spam reporting")},
+                 {PLUGIN_NOTHING, NULL}};
+       return features;
+}
diff --git a/src/plugins/spam_report/spam_report_prefs.c b/src/plugins/spam_report/spam_report_prefs.c
new file mode 100644 (file)
index 0000000..f0c7604
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net>
+ * and the Claws Mail Team
+ *
+ * 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 "defs.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gtkutils.h"
+#include "prefs.h"
+#include "prefs_gtk.h"
+#include "prefswindow.h"
+#include "alertpanel.h"
+#include "utils.h"
+
+#include "spam_report_prefs.h"
+
+#define PREFS_BLOCK_NAME "SpamReport"
+
+SpamReportPrefs spamreport_prefs;
+void spamreport_clear_cache(void);
+
+typedef struct _SpamReportPage SpamReportPage;
+
+struct _SpamReportPage {
+        PrefsPage page;
+        GtkWidget *frame[INTF_LAST];
+       GtkWidget *enabled_chkbtn[INTF_LAST];
+       GtkWidget *user_entry[INTF_LAST];
+       GtkWidget *pass_entry[INTF_LAST];
+};
+
+static PrefParam param[] = {
+        {"signalspam_enabled", "FALSE", &spamreport_prefs.enabled[INTF_SIGNALSPAM], P_BOOL, NULL, NULL, NULL},
+        {"signalspam_user", "", &spamreport_prefs.user[INTF_SIGNALSPAM], P_STRING, NULL, NULL, NULL},
+        {"signalspam_pass", "", &spamreport_prefs.pass[INTF_SIGNALSPAM], P_PASSWORD, NULL, NULL, NULL},
+       {"spamcop_enabled",    "FALSE", &spamreport_prefs.enabled[INTF_SPAMCOP], P_BOOL, NULL, NULL, NULL},
+       {"spamcop_user",    "", &spamreport_prefs.user[INTF_SPAMCOP], P_STRING, NULL, NULL, NULL},
+       {"debianspam_enabled", "FALSE", &spamreport_prefs.enabled[INTF_DEBIANSPAM], P_BOOL, NULL, NULL, NULL},
+       {0,0,0,0,0,0,0}
+};
+
+static SpamReportPage spamreport_prefs_page;
+
+static void create_spamreport_prefs_page       (PrefsPage *page,
+                                        GtkWindow *window,
+                                        gpointer   data);
+static void destroy_spamreport_prefs_page      (PrefsPage *page);
+static void save_spamreport_prefs              (PrefsPage *page);
+
+void spamreport_prefs_init(void)
+{
+       static gchar *path[3];
+       gchar *rcpath;
+
+       path[0] = _("Plugins");
+       path[1] = _("SpamReport");
+       path[2] = NULL;
+
+        prefs_set_default(param);
+       rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
+        prefs_read_config(param, PREFS_BLOCK_NAME, rcpath, NULL);
+       g_free(rcpath);
+        
+        spamreport_prefs_page.page.path = path;
+        spamreport_prefs_page.page.create_widget = create_spamreport_prefs_page;
+        spamreport_prefs_page.page.destroy_widget = destroy_spamreport_prefs_page;
+        spamreport_prefs_page.page.save_page = save_spamreport_prefs;
+       spamreport_prefs_page.page.weight = 30.0;
+        
+        prefs_gtk_register_page((PrefsPage *) &spamreport_prefs_page);
+}
+
+void spamreport_prefs_done(void)
+{
+        prefs_gtk_unregister_page((PrefsPage *) &spamreport_prefs_page);
+}
+
+static void create_spamreport_prefs_page(PrefsPage *page,
+                                   GtkWindow *window,
+                                    gpointer data)
+{
+        SpamReportPage *prefs_page = (SpamReportPage *) page;
+
+        GtkWidget *vbox, *table;
+       GtkWidget *tmp;
+       int i = 0;
+       
+        vbox = gtk_vbox_new(FALSE, VSPACING_NARROW);
+        gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
+       gtk_widget_show(vbox);
+       
+       for (i = 0; i < INTF_LAST; i++) {
+               prefs_page->frame[i] = gtk_frame_new(spam_interfaces[i].name);
+               gtk_box_pack_start(GTK_BOX(vbox), prefs_page->frame[i], FALSE, FALSE, 6);
+
+               prefs_page->user_entry[i] = gtk_entry_new();
+               prefs_page->pass_entry[i] = gtk_entry_new();
+               prefs_page->enabled_chkbtn[i] = gtk_check_button_new_with_label(_("Enabled"));
+
+               gtk_entry_set_visibility(GTK_ENTRY(prefs_page->pass_entry[i]), FALSE);
+
+               gtk_entry_set_text(GTK_ENTRY(prefs_page->user_entry[i]),
+                       spamreport_prefs.user[i] ? spamreport_prefs.user[i]:"");
+               gtk_entry_set_text(GTK_ENTRY(prefs_page->pass_entry[i]),
+                       spamreport_prefs.pass[i] ? spamreport_prefs.pass[i]:"");
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(prefs_page->enabled_chkbtn[i]),
+                       spamreport_prefs.enabled[i]);
+
+               table = gtk_table_new(3, 2, FALSE);
+               gtk_container_set_border_width(GTK_CONTAINER(table), 8);
+               gtk_table_set_row_spacings(GTK_TABLE(table), 4);
+               gtk_table_set_col_spacings(GTK_TABLE(table), 8);
+       
+               gtk_container_add(GTK_CONTAINER(prefs_page->frame[i]), table);
+               gtk_widget_show(prefs_page->frame[i]);
+               gtk_widget_show(table);
+
+               gtk_table_attach(GTK_TABLE(table), prefs_page->enabled_chkbtn[i], 0, 2, 0, 1,
+                               GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 
+                               0, 0);
+               gtk_widget_show(prefs_page->enabled_chkbtn[i]);
+
+               switch(spam_interfaces[i].type) {
+               case INTF_MAIL:
+                       tmp = gtk_label_new(_("Forward to:"));
+                       break;
+               default:
+                       tmp = gtk_label_new(_("Username:"));
+               }
+               gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 1, 2,
+                               0, 0, 
+                               0, 0);
+               gtk_table_attach(GTK_TABLE(table), prefs_page->user_entry[i], 1, 2, 1, 2,
+                               GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 
+                               0, 0);
+               if (spam_interfaces[i].type != INTF_HTTP_GET) {
+                       gtk_widget_show(tmp);
+                       gtk_widget_show(prefs_page->user_entry[i]);
+               }
+
+               tmp = gtk_label_new(_("Password:"));
+               gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 2, 3,
+                               0, 0, 
+                               0, 0);
+               gtk_table_attach(GTK_TABLE(table), prefs_page->pass_entry[i], 1, 2, 2, 3,
+                               GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 
+                               0, 0);
+               if (spam_interfaces[i].type != INTF_MAIL && spam_interfaces[i].type != INTF_HTTP_GET) {
+                       gtk_widget_show(tmp);
+                       gtk_widget_show(prefs_page->pass_entry[i]);
+               }
+       }
+        prefs_page->page.widget = vbox;
+}
+
+static void destroy_spamreport_prefs_page(PrefsPage *page)
+{
+       /* Do nothing! */
+}
+
+static void save_spamreport_prefs(PrefsPage *page)
+{
+        SpamReportPage *prefs_page = (SpamReportPage *) page;
+        PrefFile *pref_file;
+        gchar *rc_file_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                          COMMON_RC, NULL);
+        int i = 0;
+       
+       for (i = 0; i < INTF_LAST; i++) {
+
+               g_free(spamreport_prefs.user[i]);
+               g_free(spamreport_prefs.pass[i]);
+
+               spamreport_prefs.enabled[i] = gtk_toggle_button_get_active(
+                       GTK_TOGGLE_BUTTON(prefs_page->enabled_chkbtn[i]));
+               spamreport_prefs.user[i] = gtk_editable_get_chars(
+                       GTK_EDITABLE(prefs_page->user_entry[i]), 0, -1);
+               spamreport_prefs.pass[i] = gtk_editable_get_chars(
+                       GTK_EDITABLE(prefs_page->pass_entry[i]), 0, -1);
+       }
+
+        pref_file = prefs_write_open(rc_file_path);
+        g_free(rc_file_path);
+        
+        if (!(pref_file) ||
+           (prefs_set_block_label(pref_file, PREFS_BLOCK_NAME) < 0))
+          return;
+        
+        if (prefs_write_param(param, pref_file->fp) < 0) {
+          g_warning("failed to write SpamReport Plugin configuration\n");
+          prefs_file_close_revert(pref_file);
+          return;
+        }
+        if (fprintf(pref_file->fp, "\n") < 0) {
+               FILE_OP_ERROR(rc_file_path, "fprintf");
+               prefs_file_close_revert(pref_file);
+       } else
+               prefs_file_close(pref_file);
+}
diff --git a/src/plugins/spam_report/spam_report_prefs.h b/src/plugins/spam_report/spam_report_prefs.h
new file mode 100644 (file)
index 0000000..08027f4
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net>
+ * and the Claws Mail Team
+ *
+ * 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.
+ */
+
+#ifndef SPAMREPORTPREFS_H
+#define SPAMREPORTPREFS_H
+
+#include <glib.h>
+
+#include "procmsg.h"
+
+#define SPAM_REPORT_USERAGENT "Claws Mail SpamReport plugin "
+
+typedef struct _SpamReportPrefs        SpamReportPrefs;
+
+typedef enum {
+       INTF_SIGNALSPAM,
+       INTF_SPAMCOP,
+       INTF_DEBIANSPAM,
+       INTF_LAST
+} InterfaceId;
+
+typedef enum {
+       INTF_HTTP,
+       INTF_HTTP_AUTH,
+       INTF_MAIL,
+       INTF_HTTP_GET,
+       INTF_NULL
+} InterfaceType;
+
+typedef struct _ReportInterface {
+       gchar *name;
+       InterfaceType type;
+       gchar *url;
+       gchar *body;
+       gboolean (*should_report)(MsgInfo *info);
+} ReportInterface;
+
+extern ReportInterface spam_interfaces[];
+
+struct _SpamReportPrefs
+{
+       gboolean enabled[INTF_LAST];
+       gchar *user[INTF_LAST];
+       gchar *pass[INTF_LAST];
+};
+
+extern SpamReportPrefs spamreport_prefs;
+
+void spamreport_prefs_init(void);
+void spamreport_prefs_done(void);
+
+#endif
diff --git a/src/plugins/tnef_parse/.cvsignore b/src/plugins/tnef_parse/.cvsignore
new file mode 100644 (file)
index 0000000..10140b2
--- /dev/null
@@ -0,0 +1,7 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.la
+*.lo
+*.o
diff --git a/src/plugins/tnef_parse/Makefile.am b/src/plugins/tnef_parse/Makefile.am
new file mode 100644 (file)
index 0000000..a4d1336
--- /dev/null
@@ -0,0 +1,85 @@
+EXTRA_DIST = claws.def plugin.def version.rc
+
+if OS_WIN32
+
+LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RC) \
+     `echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \
+     sed -e 's/-I/--include-dir /g;s/-D/--define /g'`
+
+%.lo : %.rc
+       $(LTRCCOMPILE) -i $< -o $@
+
+plugin_res = version.lo
+plugin_res_ldflag = -Wl,.libs/version.o
+
+export_symbols = -export-symbols $(srcdir)/plugin.def
+
+plugin_deps = libclaws.a $(plugin_res) plugin.def
+
+libclaws.a: claws.def
+       $(DLLTOOL) --output-lib $@ --def $<
+
+plugin_ldadd = -L. -lclaws
+
+else
+plugin_res =
+plugin_res_ldflag =
+export_symbols =
+plugin_deps =
+plugin_ldadd =
+endif
+
+if PLATFORM_WIN32
+no_undefined = -no-undefined
+else
+no_undefined =
+endif
+
+if CYGWIN
+cygwin_export_lib = -L$(top_builddir)/src -lclaws-mail
+else
+cygwin_export_lib = 
+endif
+
+plugindir = $(pkglibdir)/plugins
+
+plugin_LTLIBRARIES = tnef_parse.la
+
+tnef_parse_la_SOURCES = \
+         tnef_parse.c \
+         tnef_dump.c \
+         tnef_dump.h \
+        ytnef.c \
+        gettext.h
+
+tnef_parse_la_LDFLAGS = \
+       $(plugin_res_ldflag) $(no_undefined) $(export_symbols) \
+       -avoid-version -module \
+       $(GTK_LIBS)
+
+tnef_parse_la_DEPENDENCIES = $(plugin_deps)
+
+tnef_parse_la_LIBADD = $(plugin_ldadd) $(cygwin_export_lib) \
+       $(GTK_LIBS)
+
+noinst_HEADERS = \
+       mapidefs.h \
+       mapi.h \
+       mapitags.h \
+       tnef_dump.h \
+       tnef-errors.h \
+       tnef-types.h \
+       ytnef.h
+
+INCLUDES = \
+       -I$(top_srcdir)/src \
+       -I$(top_srcdir)/src/common \
+       -I$(top_builddir)/src/common \
+       -I$(top_srcdir)/src/gtk
+
+AM_CPPFLAGS = \
+       -Wall \
+       $(CLAWS_MAIL_CFLAGS) \
+       $(GLIB_CFLAGS) \
+       $(GTK_CFLAGS) \
+       -DLOCALEDIR=\""$(localedir)"\"
diff --git a/src/plugins/tnef_parse/claws.def b/src/plugins/tnef_parse/claws.def
new file mode 100644 (file)
index 0000000..28eadc1
--- /dev/null
@@ -0,0 +1,17 @@
+LIBRARY CLAWS-MAIL.EXE
+EXPORTS
+get_locale_dir
+check_plugin_version
+claws_unlink
+debug_get_mode
+debug_print_real
+debug_srcname
+get_mime_tmp_dir
+get_tmpfile_in_dir
+procmime_decode_content
+procmime_get_media_type
+procmime_get_mime_type
+procmime_mimeinfo_free_all
+procmime_mimeinfo_new
+procmime_mimeparser_register
+procmime_mimeparser_unregister
diff --git a/src/plugins/tnef_parse/mapi.h b/src/plugins/tnef_parse/mapi.h
new file mode 100644 (file)
index 0000000..856e2bb
--- /dev/null
@@ -0,0 +1,29 @@
+#define MV_FLAG         0x1000          /* Multi-value flag */
+
+#define PT_UNSPECIFIED  ((ULONG)  0)    /* (Reserved for interface use) type doesn't matter to caller */
+#define PT_NULL         ((ULONG)  1)    /* NULL property value */
+#define PT_I2           ((ULONG)  2)    /* Signed 16-bit value */
+#define PT_LONG         ((ULONG)  3)    /* Signed 32-bit value */
+#define PT_R4           ((ULONG)  4)    /* 4-byte floating point */
+#define PT_DOUBLE       ((ULONG)  5)    /* Floating point double */
+#define PT_CURRENCY     ((ULONG)  6)    /* Signed 64-bit int (decimal w/    4 digits right of decimal pt) */
+#define PT_APPTIME      ((ULONG)  7)    /* Application time */
+#define PT_ERROR        ((ULONG) 10)    /* 32-bit error value */
+#define PT_BOOLEAN      ((ULONG) 11)    /* 16-bit boolean (non-zero true) */
+#define PT_OBJECT       ((ULONG) 13)    /* Embedded object in a property */
+#define PT_I8           ((ULONG) 20)    /* 8-byte signed integer */
+#define PT_STRING8      ((ULONG) 30)    /* Null terminated 8-bit character string */
+#define PT_UNICODE      ((ULONG) 31)    /* Null terminated Unicode string */
+#define PT_SYSTIME      ((ULONG) 64)    /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */
+#define PT_CLSID        ((ULONG) 72)    /* OLE GUID */
+#define PT_BINARY       ((ULONG) 258)   /* Uninterpreted (counted byte array) */
+
+#define PROP_TYPE_MASK          ((ULONG)0x0000FFFF) /* Mask for Property type */
+#define PROP_TYPE(ulPropTag)    (((ULONG)(ulPropTag))&PROP_TYPE_MASK)
+#define PROP_ID(ulPropTag)      (((ULONG)(ulPropTag))>>16)
+#define PROP_TAG(ulPropType,ulPropID)   ((((ULONG)(ulPropID))<<16)|((ULONG)(ulPropType)))
+#define PROP_ID_NULL            0
+#define PROP_ID_INVALID         0xFFFF
+#define PR_NULL                 PROP_TAG( PT_NULL, PROP_ID_NULL)
+
+#define MAPI_UNDEFINED ((variableLength*)-1)
diff --git a/src/plugins/tnef_parse/mapidefs.h b/src/plugins/tnef_parse/mapidefs.h
new file mode 100644 (file)
index 0000000..8feb907
--- /dev/null
@@ -0,0 +1,433 @@
+#ifndef MAPIDEFS_H
+#define MAPIDEFS_H
+
+#define PR_ACKNOWLEDGEMENT_MODE                     0x0001
+#define PR_ALTERNATE_RECIPIENT_ALLOWED              0x0002
+#define PR_AUTHORIZING_USERS                        0x0003
+#define PR_AUTO_FORWARD_COMMENT                     0x0004
+#define PR_AUTO_FORWARDED                           0x0005
+#define PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID     0x0006
+#define PR_CONTENT_CORRELATOR                       0x0007
+#define PR_CONTENT_IDENTIFIER                       0x0008
+#define PR_CONTENT_LENGTH                           0x0009
+#define PR_CONTENT_RETURN_REQUESTED                 0x000A
+#define PR_CONVERSATION_KEY                         0x000B
+#define PR_CONVERSION_EITS                          0x000C
+#define PR_CONVERSION_WITH_LOSS_PROHIBITED          0x000D
+#define PR_CONVERTED_EITS                           0x000E
+#define PR_DEFERRED_DELIVERY_TIME                   0x000F
+#define PR_DELIVER_TIME                             0x0010
+#define PR_DISCARD_REASON                           0x0011
+#define PR_DISCLOSURE_OF_RECIPIENTS                 0x0012
+#define PR_DL_EXPANSION_HISTORY                     0x0013
+#define PR_DL_EXPANSION_PROHIBITED                  0x0014
+#define PR_EXPIRY_TIME                              0x0015
+#define PR_IMPLICIT_CONVERSION_PROHIBITED           0x0016
+#define PR_IMPORTANCE                               0x0017
+#define PR_IPM_ID                                   0x0018
+#define PR_LATEST_DELIVERY_TIME                     0x0019
+#define PR_MESSAGE_CLASS                            0x001A
+#define PR_MESSAGE_DELIVERY_ID                      0x001B
+#define PR_MESSAGE_SECURITY_LABEL                   0x001E
+#define PR_OBSOLETED_IPMS                           0x001F
+#define PR_ORIGINALLY_INTENDED_RECIPIENT_NAME       0x0020
+#define PR_ORIGINAL_EITS                            0x0021
+#define PR_ORIGINATOR_CERTIFICATE                   0x0022
+#define PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED     0x0023
+#define PR_ORIGINATOR_RETURN_ADDRESS                0x0024
+#define PR_PARENT_KEY                               0x0025
+#define PR_PRIORITY                                 0x0026
+#define PR_ORIGIN_CHECK                             0x0027
+#define PR_PROOF_OF_SUBMISSION_REQUESTED            0x0028
+#define PR_READ_RECEIPT_REQUESTED                   0x0029
+#define PR_RECEIPT_TIME                             0x002A
+#define PR_RECIPIENT_REASSIGNMENT_PROHIBITED        0x002B
+#define PR_REDIRECTION_HISTORY                      0x002C
+#define PR_RELATED_IPMS                             0x002D
+#define PR_ORIGINAL_SENSITIVITY                     0x002E
+#define PR_LANGUAGES                                0x002F
+#define PR_REPLY_TIME                               0x0030
+#define PR_REPORT_TAG                               0x0031
+#define PR_REPORT_TIME                              0x0032
+#define PR_RETURNED_IPM                             0x0033
+#define PR_SECURITY                                 0x0034
+#define PR_INCOMPLETE_COPY                          0x0035
+#define PR_SENSITIVITY                              0x0036
+#define PR_SUBJECT                                  0x0037
+#define PR_SUBJECT_IPM                              0x0038
+#define PR_CLIENT_SUBMIT_TIME                       0x0039
+#define PR_REPORT_NAME                              0x003A
+#define PR_SENT_REPRESENTING_SEARCH_KEY             0x003B
+#define PR_X400_CONTENT_TYPE                        0x003C
+#define PR_SUBJECT_PREFIX                           0x003D
+#define PR_NON_RECEIPT_REASON                       0x003E
+#define PR_RECEIVED_BY_ENTRYID                      0x003F
+#define PR_RECEIVED_BY_NAME                         0x0040
+#define PR_SENT_REPRESENTING_ENTRYID                0x0041
+#define PR_SENT_REPRESENTING_NAME                   0x0042
+#define PR_RCVD_REPRESENTING_ENTRYID                0x0043
+#define PR_RCVD_REPRESENTING_NAME                   0x0044
+#define PR_REPORT_ENTRYID                           0x0045
+#define PR_READ_RECEIPT_ENTRYID                     0x0046
+#define PR_MESSAGE_SUBMISSION_ID                    0x0047
+#define PR_PROVIDER_SUBMIT_TIME                     0x0048
+#define PR_ORIGINAL_SUBJECT                         0x0049
+#define PR_DISC_VAL                                 0x004A
+#define PR_ORIG_MESSAGE_CLASS                       0x004B
+#define PR_ORIGINAL_AUTHOR_ENTRYID                  0x004C
+#define PR_ORIGINAL_AUTHOR_NAME                     0x004D
+#define PR_ORIGINAL_SUBMIT_TIME                     0x004E
+#define PR_REPLY_RECIPIENT_ENTRIES                  0x004F
+#define PR_REPLY_RECIPIENT_NAMES                    0x0050
+#define PR_RECEIVED_BY_SEARCH_KEY                   0x0051
+#define PR_RCVD_REPRESENTING_SEARCH_KEY             0x0052
+#define PR_READ_RECEIPT_SEARCH_KEY                  0x0053
+#define PR_REPORT_SEARCH_KEY                        0x0054
+#define PR_ORIGINAL_DELIVERY_TIME                   0x0055
+#define PR_ORIGINAL_AUTHOR_SEARCH_KEY               0x0056
+#define PR_MESSAGE_TO_ME                            0x0057
+#define PR_MESSAGE_CC_ME                            0x0058
+#define PR_MESSAGE_RECIP_ME                         0x0059
+#define PR_ORIGINAL_SENDER_NAME                     0x005A
+#define PR_ORIGINAL_SENDER_ENTRYID                  0x005B
+#define PR_ORIGINAL_SENDER_SEARCH_KEY               0x005C
+#define PR_ORIGINAL_SENT_REPRESENTING_NAME          0x005D
+#define PR_ORIGINAL_SENT_REPRESENTING_ENTRYID       0x005E
+#define PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY    0x005F
+#define PR_START_DATE                               0x0060
+#define PR_END_DATE                                 0x0061
+#define PR_OWNER_APPT_ID                            0x0062
+#define PR_RESPONSE_REQUESTED                       0x0063
+#define PR_SENT_REPRESENTING_ADDRTYPE               0x0064
+#define PR_SENT_REPRESENTING_EMAIL_ADDRESS          0x0065
+#define PR_ORIGINAL_SENDER_ADDRTYPE                 0x0066
+#define PR_ORIGINAL_SENDER_EMAIL_ADDRESS            0x0067
+#define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE      0x0068
+#define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS 0x0069
+#define PR_CONVERSATION_TOPIC                       0x0070
+#define PR_CONVERSATION_INDEX                       0x0071
+#define PR_ORIGINAL_DISPLAY_BCC                     0x0072
+#define PR_ORIGINAL_DISPLAY_CC                      0x0073
+#define PR_ORIGINAL_DISPLAY_TO                      0x0074
+#define PR_RECEIVED_BY_ADDRTYPE                     0x0075
+#define PR_RECEIVED_BY_EMAIL_ADDRESS                0x0076
+#define PR_RCVD_REPRESENTING_ADDRTYPE               0x0077
+#define PR_RCVD_REPRESENTING_EMAIL_ADDRESS          0x0078
+#define PR_ORIGINAL_AUTHOR_ADDRTYPE                 0x0079
+#define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS            0x007A
+#define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE       0x007B
+#define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS  0x007C
+#define PR_TRANSPORT_MESSAGE_HEADERS                0x007D
+#define PR_DELEGATION                               0x007E
+#define PR_TNEF_CORRELATION_KEY                     0x007F
+#define PR_BODY                                     0x1000
+#define PR_REPORT_TEXT                              0x1001
+#define PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY      0x1002
+#define PR_REPORTING_DL_NAME                        0x1003
+#define PR_REPORTING_MTA_CERTIFICATE                0x1004
+#define PR_RTF_SYNC_BODY_CRC                        0x1006
+#define PR_RTF_SYNC_BODY_COUNT                      0x1007
+#define PR_RTF_SYNC_BODY_TAG                        0x1008
+#define PR_RTF_COMPRESSED                           0x1009
+#define PR_RTF_SYNC_PREFIX_COUNT                    0x1010
+#define PR_RTF_SYNC_TRAILING_COUNT                  0x1011
+#define PR_ORIGINALLY_INTENDED_RECIP_ENTRYID        0x1012
+#define PR_CONTENT_INTEGRITY_CHECK                  0x0C00
+#define PR_EXPLICIT_CONVERSION                      0x0C01
+#define PR_IPM_RETURN_REQUESTED                     0x0C02
+#define PR_MESSAGE_TOKEN                            0x0C03
+#define PR_NDR_REASON_CODE                          0x0C04
+#define PR_NDR_DIAG_CODE                            0x0C05
+#define PR_NON_RECEIPT_NOTIFICATION_REQUESTED       0x0C06
+#define PR_DELIVERY_POINT                           0x0C07
+
+#define PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED 0x0C08
+#define PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT 0x0C09
+#define PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY    0x0C0A
+#define PR_PHYSICAL_DELIVERY_MODE                   0x0C0B
+#define PR_PHYSICAL_DELIVERY_REPORT_REQUEST         0x0C0C
+#define PR_PHYSICAL_FORWARDING_ADDRESS              0x0C0D
+#define PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED    0x0C0E
+#define PR_PHYSICAL_FORWARDING_PROHIBITED           0x0C0F
+#define PR_PHYSICAL_RENDITION_ATTRIBUTES            0x0C10
+#define PR_PROOF_OF_DELIVERY                        0x0C11
+#define PR_PROOF_OF_DELIVERY_REQUESTED              0x0C12
+#define PR_RECIPIENT_CERTIFICATE                    0x0C13
+#define PR_RECIPIENT_NUMBER_FOR_ADVICE              0x0C14
+#define PR_RECIPIENT_TYPE                           0x0C15
+#define PR_REGISTERED_MAIL_TYPE                     0x0C16
+#define PR_REPLY_REQUESTED                          0x0C17
+#define PR_REQUESTED_DELIVERY_METHOD                0x0C18
+#define PR_SENDER_ENTRYID                           0x0C19
+#define PR_SENDER_NAME                              0x0C1A
+#define PR_SUPPLEMENTARY_INFO                       0x0C1B
+#define PR_TYPE_OF_MTS_USER                         0x0C1C
+#define PR_SENDER_SEARCH_KEY                        0x0C1D
+#define PR_SENDER_ADDRTYPE                          0x0C1E
+#define PR_SENDER_EMAIL_ADDRESS                     0x0C1F
+#define PR_CURRENT_VERSION                          0x0E00
+#define PR_DELETE_AFTER_SUBMIT                      0x0E01
+#define PR_DISPLAY_BCC                              0x0E02
+#define PR_DISPLAY_CC                               0x0E03
+#define PR_DISPLAY_TO                               0x0E04
+#define PR_PARENT_DISPLAY                           0x0E05
+#define PR_MESSAGE_DELIVERY_TIME                    0x0E06
+#define PR_MESSAGE_FLAGS                            0x0E07
+#define PR_MESSAGE_SIZE                             0x0E08
+#define PR_PARENT_ENTRYID                           0x0E09
+#define PR_SENTMAIL_ENTRYID                         0x0E0A
+#define PR_CORRELATE                                0x0E0C
+#define PR_CORRELATE_MTSID                          0x0E0D
+#define PR_DISCRETE_VALUES                          0x0E0E
+#define PR_RESPONSIBILITY                           0x0E0F
+#define PR_SPOOLER_STATUS                           0x0E10
+#define PR_TRANSPORT_STATUS                         0x0E11
+#define PR_MESSAGE_RECIPIENTS                       0x0E12
+#define PR_MESSAGE_ATTACHMENTS                      0x0E13
+#define PR_SUBMIT_FLAGS                             0x0E14
+#define PR_RECIPIENT_STATUS                         0x0E15
+#define PR_TRANSPORT_KEY                            0x0E16
+#define PR_MSG_STATUS                               0x0E17
+#define PR_MESSAGE_DOWNLOAD_TIME                    0x0E18
+#define PR_CREATION_VERSION                         0x0E19
+#define PR_MODIFY_VERSION                           0x0E1A
+#define PR_HASATTACH                                0x0E1B
+#define PR_BODY_CRC                                 0x0E1C
+#define PR_NORMALIZED_SUBJECT                       0x0E1D
+#define PR_RTF_IN_SYNC                              0x0E1F
+#define PR_ATTACH_SIZE                              0x0E20
+#define PR_ATTACH_NUM                               0x0E21
+#define PR_PREPROCESS                               0x0E22
+#define PR_ORIGINATING_MTA_CERTIFICATE              0x0E25
+#define PR_PROOF_OF_SUBMISSION                      0x0E26
+#define PR_ENTRYID                                  0x0FFF
+#define PR_OBJECT_TYPE                              0x0FFE
+#define PR_ICON                                     0x0FFD
+#define PR_MINI_ICON                                0x0FFC
+#define PR_STORE_ENTRYID                            0x0FFB
+#define PR_STORE_RECORD_KEY                         0x0FFA
+#define PR_RECORD_KEY                               0x0FF9
+#define PR_MAPPING_SIGNATURE                        0x0FF8
+#define PR_ACCESS_LEVEL                             0x0FF7
+#define PR_INSTANCE_KEY                             0x0FF6
+#define PR_ROW_TYPE                                 0x0FF5
+#define PR_ACCESS                                   0x0FF4
+#define PR_ROWID                                    0x3000
+#define PR_DISPLAY_NAME                             0x3001
+#define PR_ADDRTYPE                                 0x3002
+#define PR_EMAIL_ADDRESS                            0x3003
+#define PR_COMMENT                                  0x3004
+#define PR_DEPTH                                    0x3005
+#define PR_PROVIDER_DISPLAY                         0x3006
+#define PR_CREATION_TIME                            0x3007
+#define PR_LAST_MODIFICATION_TIME                   0x3008
+#define PR_RESOURCE_FLAGS                           0x3009
+#define PR_PROVIDER_DLL_NAME                        0x300A
+#define PR_SEARCH_KEY                               0x300B
+#define PR_PROVIDER_UID                             0x300C
+#define PR_PROVIDER_ORDINAL                         0x300D
+#define PR_FORM_VERSION                             0x3301
+#define PR_FORM_CLSID                               0x3302
+#define PR_FORM_CONTACT_NAME                        0x3303
+#define PR_FORM_CATEGORY                            0x3304
+#define PR_FORM_CATEGORY_SUB                        0x3305
+#define PR_FORM_HOST_MAP                            0x3306
+#define PR_FORM_HIDDEN                              0x3307
+#define PR_FORM_DESIGNER_NAME                       0x3308
+#define PR_FORM_DESIGNER_GUID                       0x3309
+#define PR_FORM_MESSAGE_BEHAVIOR                    0x330A
+#define PR_DEFAULT_STORE                            0x3400
+#define PR_STORE_SUPPORT_MASK                       0x340D
+#define PR_STORE_STATE                              0x340E
+#define PR_IPM_SUBTREE_SEARCH_KEY                   0x3410
+#define PR_IPM_OUTBOX_SEARCH_KEY                    0x3411
+#define PR_IPM_WASTEBASKET_SEARCH_KEY               0x3412
+#define PR_IPM_SENTMAIL_SEARCH_KEY                  0x3413
+#define PR_MDB_PROVIDER                             0x3414
+#define PR_RECEIVE_FOLDER_SETTINGS                  0x3415
+#define PR_VALID_FOLDER_MASK                        0x35DF
+#define PR_IPM_SUBTREE_ENTRYID                      0x35E0
+#define PR_IPM_OUTBOX_ENTRYID                       0x35E2
+#define PR_IPM_WASTEBASKET_ENTRYID                  0x35E3
+#define PR_IPM_SENTMAIL_ENTRYID                     0x35E4
+#define PR_VIEWS_ENTRYID                            0x35E5
+#define PR_COMMON_VIEWS_ENTRYID                     0x35E6
+#define PR_FINDER_ENTRYID                           0x35E7
+#define PR_CONTAINER_FLAGS                          0x3600
+#define PR_FOLDER_TYPE                              0x3601
+#define PR_CONTENT_COUNT                            0x3602
+#define PR_CONTENT_UNREAD                           0x3603
+#define PR_CREATE_TEMPLATES                         0x3604
+#define PR_DETAILS_TABLE                            0x3605
+#define PR_SEARCH                                   0x3607
+#define PR_SELECTABLE                               0x3609
+#define PR_SUBFOLDERS                               0x360A
+#define PR_STATUS                                   0x360B
+#define PR_ANR                                      0x360C
+#define PR_CONTENTS_SORT_ORDER                      0x360D
+#define PR_CONTAINER_HIERARCHY                      0x360E
+#define PR_CONTAINER_CONTENTS                       0x360F
+#define PR_FOLDER_ASSOCIATED_CONTENTS               0x3610
+#define PR_DEF_CREATE_DL                            0x3611
+#define PR_DEF_CREATE_MAILUSER                      0x3612
+#define PR_CONTAINER_CLASS                          0x3613
+#define PR_CONTAINER_MODIFY_VERSION                 0x3614
+#define PR_AB_PROVIDER_ID                           0x3615
+#define PR_DEFAULT_VIEW_ENTRYID                     0x3616
+#define PR_ASSOC_CONTENT_COUNT                      0x3617
+#define PR_ATTACHMENT_X400_PARAMETERS               0x3700
+#define PR_ATTACH_DATA_OBJ                          0x3701
+#define PR_ATTACH_ENCODING                          0x3702
+#define PR_ATTACH_EXTENSION                         0x3703
+#define PR_ATTACH_FILENAME                          0x3704
+#define PR_ATTACH_METHOD                            0x3705
+#define PR_ATTACH_LONG_FILENAME                     0x3707
+#define PR_ATTACH_PATHNAME                          0x3708
+#define PR_ATTACH_RENDERING                         0x3709
+#define PR_ATTACH_TAG                               0x370A
+#define PR_RENDERING_POSITION                       0x370B
+#define PR_ATTACH_TRANSPORT_NAME                    0x370C
+#define PR_ATTACH_LONG_PATHNAME                     0x370D
+#define PR_ATTACH_MIME_TAG                          0x370E
+#define PR_ATTACH_ADDITIONAL_INFO                   0x370F
+#define PR_DISPLAY_TYPE                             0x3900
+#define PR_TEMPLATEID                               0x3902
+#define PR_PRIMARY_CAPABILITY                       0x3904
+#define PR_7BIT_DISPLAY_NAME                        0x39FF
+#define PR_ACCOUNT                                  0x3A00
+#define PR_ALTERNATE_RECIPIENT                      0x3A01
+#define PR_CALLBACK_TELEPHONE_NUMBER                0x3A02
+#define PR_CONVERSION_PROHIBITED                    0x3A03
+#define PR_DISCLOSE_RECIPIENTS                      0x3A04
+#define PR_GENERATION                               0x3A05
+#define PR_GIVEN_NAME                               0x3A06
+#define PR_GOVERNMENT_ID_NUMBER                     0x3A07
+#define PR_BUSINESS_TELEPHONE_NUMBER                0x3A08
+#define PR_HOME_TELEPHONE_NUMBER                    0x3A09
+#define PR_INITIALS                                 0x3A0A
+#define PR_KEYWORD                                  0x3A0B
+#define PR_LANGUAGE                                 0x3A0C
+#define PR_LOCATION                                 0x3A0D
+#define PR_MAIL_PERMISSION                          0x3A0E
+#define PR_MHS_COMMON_NAME                          0x3A0F
+#define PR_ORGANIZATIONAL_ID_NUMBER                 0x3A10
+#define PR_SURNAME                                  0x3A11
+#define PR_ORIGINAL_ENTRYID                         0x3A12
+#define PR_ORIGINAL_DISPLAY_NAME                    0x3A13
+#define PR_ORIGINAL_SEARCH_KEY                      0x3A14
+#define PR_POSTAL_ADDRESS                           0x3A15
+#define PR_COMPANY_NAME                             0x3A16
+#define PR_TITLE                                    0x3A17
+#define PR_DEPARTMENT_NAME                          0x3A18
+#define PR_OFFICE_LOCATION                          0x3A19
+#define PR_PRIMARY_TELEPHONE_NUMBER                 0x3A1A
+#define PR_BUSINESS2_TELEPHONE_NUMBER               0x3A1B
+#define PR_MOBILE_TELEPHONE_NUMBER                  0x3A1C
+#define PR_RADIO_TELEPHONE_NUMBER                   0x3A1D
+#define PR_CAR_TELEPHONE_NUMBER                     0x3A1E
+#define PR_OTHER_TELEPHONE_NUMBER                   0x3A1F
+#define PR_TRANSMITABLE_DISPLAY_NAME                0x3A20
+#define PR_PAGER_TELEPHONE_NUMBER                   0x3A21
+#define PR_USER_CERTIFICATE                         0x3A22
+#define PR_PRIMARY_FAX_NUMBER                       0x3A23
+#define PR_BUSINESS_FAX_NUMBER                      0x3A24
+#define PR_HOME_FAX_NUMBER                          0x3A25
+#define PR_COUNTRY                                  0x3A26
+#define PR_LOCALITY                                 0x3A27
+#define PR_STATE_OR_PROVINCE                        0x3A28
+#define PR_STREET_ADDRESS                           0x3A29
+#define PR_POSTAL_CODE                              0x3A2A
+#define PR_POST_OFFICE_BOX                          0x3A2B
+#define PR_TELEX_NUMBER                             0x3A2C
+#define PR_ISDN_NUMBER                              0x3A2D
+#define PR_ASSISTANT_TELEPHONE_NUMBER               0x3A2E
+#define PR_HOME2_TELEPHONE_NUMBER                   0x3A2F
+#define PR_ASSISTANT                                0x3A30
+#define PR_SEND_RICH_INFO                           0x3A40
+#define PR_WEDDING_ANNIVERSARY                      0x3A41
+#define PR_BIRTHDAY                                 0x3A42
+#define PR_HOBBIES                                  0x3A43
+#define PR_MIDDLE_NAME                              0x3A44
+#define PR_DISPLAY_NAME_PREFIX                      0x3A45
+#define PR_PROFESSION                               0x3A46
+#define PR_PREFERRED_BY_NAME                        0x3A47
+#define PR_SPOUSE_NAME                              0x3A48
+#define PR_COMPUTER_NETWORK_NAME                    0x3A49
+#define PR_CUSTOMER_ID                              0x3A4A
+#define PR_TTYTDD_PHONE_NUMBER                      0x3A4B
+#define PR_FTP_SITE                                 0x3A4C
+#define PR_GENDER                                   0x3A4D
+#define PR_MANAGER_NAME                             0x3A4E
+#define PR_NICKNAME                                 0x3A4F
+#define PR_PERSONAL_HOME_PAGE                       0x3A50
+#define PR_BUSINESS_HOME_PAGE                       0x3A51
+#define PR_CONTACT_VERSION                          0x3A52
+#define PR_CONTACT_ENTRYIDS                         0x3A53
+#define PR_CONTACT_ADDRTYPES                        0x3A54
+#define PR_CONTACT_DEFAULT_ADDRESS_INDEX            0x3A55
+#define PR_CONTACT_EMAIL_ADDRESSES                  0x3A56
+#define PR_COMPANY_MAIN_PHONE_NUMBER                0x3A57
+#define PR_CHILDRENS_NAMES                          0x3A58
+#define PR_HOME_ADDRESS_CITY                        0x3A59
+#define PR_HOME_ADDRESS_COUNTRY                     0x3A5A
+#define PR_HOME_ADDRESS_POSTAL_CODE                 0x3A5B
+#define PR_HOME_ADDRESS_STATE_OR_PROVINCE           0x3A5C
+#define PR_HOME_ADDRESS_STREET                      0x3A5D
+#define PR_HOME_ADDRESS_POST_OFFICE_BOX             0x3A5E
+#define PR_OTHER_ADDRESS_CITY                       0x3A5F
+#define PR_OTHER_ADDRESS_COUNTRY                    0x3A60
+#define PR_OTHER_ADDRESS_POSTAL_CODE                0x3A61
+#define PR_OTHER_ADDRESS_STATE_OR_PROVINCE          0x3A62
+#define PR_OTHER_ADDRESS_STREET                     0x3A63
+#define PR_OTHER_ADDRESS_POST_OFFICE_BOX            0x3A64
+#define PR_STORE_PROVIDERS                          0x3D00
+#define PR_AB_PROVIDERS                             0x3D01
+#define PR_TRANSPORT_PROVIDERS                      0x3D02
+#define PR_DEFAULT_PROFILE                          0x3D04
+#define PR_AB_SEARCH_PATH                           0x3D05
+#define PR_AB_DEFAULT_DIR                           0x3D06
+#define PR_AB_DEFAULT_PAB                           0x3D07
+#define PR_FILTERING_HOOKS                          0x3D08
+#define PR_SERVICE_NAME                             0x3D09
+#define PR_SERVICE_DLL_NAME                         0x3D0A
+#define PR_SERVICE_ENTRY_NAME                       0x3D0B
+#define PR_SERVICE_UID                              0x3D0C
+#define PR_SERVICE_EXTRA_UIDS                       0x3D0D
+#define PR_SERVICES                                 0x3D0E
+#define PR_SERVICE_SUPPORT_FILES                    0x3D0F
+#define PR_SERVICE_DELETE_FILES                     0x3D10
+#define PR_AB_SEARCH_PATH_UPDATE                    0x3D11
+#define PR_PROFILE_NAME                             0x3D12
+#define PR_IDENTITY_DISPLAY                         0x3E00
+#define PR_IDENTITY_ENTRYID                         0x3E01
+#define PR_RESOURCE_METHODS                         0x3E02
+#define PR_RESOURCE_TYPE                            0x3E03
+#define PR_STATUS_CODE                              0x3E04
+#define PR_IDENTITY_SEARCH_KEY                      0x3E05
+#define PR_OWN_STORE_ENTRYID                        0x3E06
+#define PR_RESOURCE_PATH                            0x3E07
+#define PR_STATUS_STRING                            0x3E08
+#define PR_X400_DEFERRED_DELIVERY_CANCEL            0x3E09
+#define PR_HEADER_FOLDER_ENTRYID                    0x3E0A
+#define PR_REMOTE_PROGRESS                          0x3E0B
+#define PR_REMOTE_PROGRESS_TEXT                     0x3E0C
+#define PR_REMOTE_VALIDATE_OK                       0x3E0D
+#define PR_CONTROL_FLAGS                            0x3F00
+#define PR_CONTROL_STRUCTURE                        0x3F01
+#define PR_CONTROL_TYPE                             0x3F02
+#define PR_DELTAX                                   0x3F03
+#define PR_DELTAY                                   0x3F04
+#define PR_XPOS                                     0x3F05
+#define PR_YPOS                                     0x3F06
+#define PR_CONTROL_ID                               0x3F07
+#define PR_INITIAL_DETAILS_PANE                     0x3F08
+
+/*
+ * Secure property id range
+ */
+
+#define PROP_ID_SECURE_MIN                          0x67F0
+#define PROP_ID_SECURE_MAX                          0x67FF
+
+
+#endif  /* MAPIDEFS_H */
diff --git a/src/plugins/tnef_parse/mapitags.h b/src/plugins/tnef_parse/mapitags.h
new file mode 100644 (file)
index 0000000..dbefc71
--- /dev/null
@@ -0,0 +1,432 @@
+#ifndef MAPITAGS_H
+#define MAPITAGS_H
+
+#define MAPIMACRO(x) {x, #x}
+typedef struct {
+    unsigned int id;
+    char name[128];
+} MAPIPropertyTagList;
+
+
+MAPIPropertyTagList MPList[] = {
+        MAPIMACRO(PR_ACKNOWLEDGEMENT_MODE                     ),
+        MAPIMACRO(PR_ALTERNATE_RECIPIENT_ALLOWED              ),
+        MAPIMACRO(PR_AUTHORIZING_USERS                        ),
+        MAPIMACRO(PR_AUTO_FORWARD_COMMENT                     ),
+        MAPIMACRO(PR_AUTO_FORWARDED                           ),
+        MAPIMACRO(PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID     ),
+        MAPIMACRO(PR_CONTENT_CORRELATOR                       ),
+        MAPIMACRO(PR_CONTENT_IDENTIFIER                       ),
+        MAPIMACRO(PR_CONTENT_LENGTH                           ),
+        MAPIMACRO(PR_CONTENT_RETURN_REQUESTED                 ),
+        MAPIMACRO(PR_CONVERSATION_KEY                         ),
+        MAPIMACRO(PR_CONVERSION_EITS                          ),
+        MAPIMACRO(PR_CONVERSION_WITH_LOSS_PROHIBITED          ),
+        MAPIMACRO(PR_CONVERTED_EITS                           ),
+        MAPIMACRO(PR_DEFERRED_DELIVERY_TIME                   ),
+        MAPIMACRO(PR_DELIVER_TIME                             ),
+        MAPIMACRO(PR_DISCARD_REASON                           ),
+        MAPIMACRO(PR_DISCLOSURE_OF_RECIPIENTS                 ),
+        MAPIMACRO(PR_DL_EXPANSION_HISTORY                     ),
+        MAPIMACRO(PR_DL_EXPANSION_PROHIBITED                  ),
+        MAPIMACRO(PR_EXPIRY_TIME                              ),
+        MAPIMACRO(PR_IMPLICIT_CONVERSION_PROHIBITED           ),
+        MAPIMACRO(PR_IMPORTANCE                               ),
+        MAPIMACRO(PR_IPM_ID                                   ),
+        MAPIMACRO(PR_LATEST_DELIVERY_TIME                     ),
+        MAPIMACRO(PR_MESSAGE_CLASS                            ),
+        MAPIMACRO(PR_MESSAGE_DELIVERY_ID                      ),
+        MAPIMACRO(PR_MESSAGE_SECURITY_LABEL                   ),
+        MAPIMACRO(PR_OBSOLETED_IPMS                           ),
+        MAPIMACRO(PR_ORIGINALLY_INTENDED_RECIPIENT_NAME       ),
+        MAPIMACRO(PR_ORIGINAL_EITS                            ),
+        MAPIMACRO(PR_ORIGINATOR_CERTIFICATE                   ),
+        MAPIMACRO(PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED     ),
+        MAPIMACRO(PR_ORIGINATOR_RETURN_ADDRESS                ),
+        MAPIMACRO(PR_PARENT_KEY                               ),
+        MAPIMACRO(PR_PRIORITY                                 ),
+        MAPIMACRO(PR_ORIGIN_CHECK                             ),
+        MAPIMACRO(PR_PROOF_OF_SUBMISSION_REQUESTED            ),
+        MAPIMACRO(PR_READ_RECEIPT_REQUESTED                   ),
+        MAPIMACRO(PR_RECEIPT_TIME                             ),
+        MAPIMACRO(PR_RECIPIENT_REASSIGNMENT_PROHIBITED        ),
+        MAPIMACRO(PR_REDIRECTION_HISTORY                      ),
+        MAPIMACRO(PR_RELATED_IPMS                             ),
+        MAPIMACRO(PR_ORIGINAL_SENSITIVITY                     ),
+        MAPIMACRO(PR_LANGUAGES                                ),
+        MAPIMACRO(PR_REPLY_TIME                               ),
+        MAPIMACRO(PR_REPORT_TAG                               ),
+        MAPIMACRO(PR_REPORT_TIME                              ),
+        MAPIMACRO(PR_RETURNED_IPM                             ),
+        MAPIMACRO(PR_SECURITY                                 ),
+        MAPIMACRO(PR_INCOMPLETE_COPY                          ),
+        MAPIMACRO(PR_SENSITIVITY                              ),
+        MAPIMACRO(PR_SUBJECT                                  ),
+        MAPIMACRO(PR_SUBJECT_IPM                              ),
+        MAPIMACRO(PR_CLIENT_SUBMIT_TIME                       ),
+        MAPIMACRO(PR_REPORT_NAME                              ),
+        MAPIMACRO(PR_SENT_REPRESENTING_SEARCH_KEY             ),
+        MAPIMACRO(PR_X400_CONTENT_TYPE                        ),
+        MAPIMACRO(PR_SUBJECT_PREFIX                           ),
+        MAPIMACRO(PR_NON_RECEIPT_REASON                       ),
+        MAPIMACRO(PR_RECEIVED_BY_ENTRYID                      ),
+        MAPIMACRO(PR_RECEIVED_BY_NAME                         ),
+        MAPIMACRO(PR_SENT_REPRESENTING_ENTRYID                ),
+        MAPIMACRO(PR_SENT_REPRESENTING_NAME                   ),
+        MAPIMACRO(PR_RCVD_REPRESENTING_ENTRYID                ),
+        MAPIMACRO(PR_RCVD_REPRESENTING_NAME                   ),
+        MAPIMACRO(PR_REPORT_ENTRYID                           ),
+        MAPIMACRO(PR_READ_RECEIPT_ENTRYID                     ),
+        MAPIMACRO(PR_MESSAGE_SUBMISSION_ID                    ),
+        MAPIMACRO(PR_PROVIDER_SUBMIT_TIME                     ),
+        MAPIMACRO(PR_ORIGINAL_SUBJECT                         ),
+        MAPIMACRO(PR_DISC_VAL                                 ),
+        MAPIMACRO(PR_ORIG_MESSAGE_CLASS                       ),
+        MAPIMACRO(PR_ORIGINAL_AUTHOR_ENTRYID                  ),
+        MAPIMACRO(PR_ORIGINAL_AUTHOR_NAME                     ),
+        MAPIMACRO(PR_ORIGINAL_SUBMIT_TIME                     ),
+        MAPIMACRO(PR_REPLY_RECIPIENT_ENTRIES                  ),
+        MAPIMACRO(PR_REPLY_RECIPIENT_NAMES                    ),
+        MAPIMACRO(PR_RECEIVED_BY_SEARCH_KEY                   ),
+        MAPIMACRO(PR_RCVD_REPRESENTING_SEARCH_KEY             ),
+        MAPIMACRO(PR_READ_RECEIPT_SEARCH_KEY                  ),
+        MAPIMACRO(PR_REPORT_SEARCH_KEY                        ),
+        MAPIMACRO(PR_ORIGINAL_DELIVERY_TIME                   ),
+        MAPIMACRO(PR_ORIGINAL_AUTHOR_SEARCH_KEY               ),
+        MAPIMACRO(PR_MESSAGE_TO_ME                            ),
+        MAPIMACRO(PR_MESSAGE_CC_ME                            ),
+        MAPIMACRO(PR_MESSAGE_RECIP_ME                         ),
+        MAPIMACRO(PR_ORIGINAL_SENDER_NAME                     ),
+        MAPIMACRO(PR_ORIGINAL_SENDER_ENTRYID                  ),
+        MAPIMACRO(PR_ORIGINAL_SENDER_SEARCH_KEY               ),
+        MAPIMACRO(PR_ORIGINAL_SENT_REPRESENTING_NAME          ),
+        MAPIMACRO(PR_ORIGINAL_SENT_REPRESENTING_ENTRYID       ),
+        MAPIMACRO(PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY    ),
+        MAPIMACRO(PR_START_DATE                               ),
+        MAPIMACRO(PR_END_DATE                                 ),
+        MAPIMACRO(PR_OWNER_APPT_ID                            ),
+        MAPIMACRO(PR_RESPONSE_REQUESTED                       ),
+        MAPIMACRO(PR_SENT_REPRESENTING_ADDRTYPE               ),
+        MAPIMACRO(PR_SENT_REPRESENTING_EMAIL_ADDRESS          ),
+        MAPIMACRO(PR_ORIGINAL_SENDER_ADDRTYPE                 ),
+        MAPIMACRO(PR_ORIGINAL_SENDER_EMAIL_ADDRESS            ),
+        MAPIMACRO(PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE      ),
+        MAPIMACRO(PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS ),
+        MAPIMACRO(PR_CONVERSATION_TOPIC                       ),
+        MAPIMACRO(PR_CONVERSATION_INDEX                       ),
+        MAPIMACRO(PR_ORIGINAL_DISPLAY_BCC                     ),
+        MAPIMACRO(PR_ORIGINAL_DISPLAY_CC                      ),
+        MAPIMACRO(PR_ORIGINAL_DISPLAY_TO                      ),
+        MAPIMACRO(PR_RECEIVED_BY_ADDRTYPE                     ),
+        MAPIMACRO(PR_RECEIVED_BY_EMAIL_ADDRESS                ),
+        MAPIMACRO(PR_RCVD_REPRESENTING_ADDRTYPE               ),
+        MAPIMACRO(PR_RCVD_REPRESENTING_EMAIL_ADDRESS          ),
+        MAPIMACRO(PR_ORIGINAL_AUTHOR_ADDRTYPE                 ),
+        MAPIMACRO(PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS            ),
+        MAPIMACRO(PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE       ),
+        MAPIMACRO(PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS  ),
+        MAPIMACRO(PR_TRANSPORT_MESSAGE_HEADERS                ),
+        MAPIMACRO(PR_DELEGATION                               ),
+        MAPIMACRO(PR_TNEF_CORRELATION_KEY                     ),
+        MAPIMACRO(PR_BODY                                     ),
+        MAPIMACRO(PR_REPORT_TEXT                              ),
+        MAPIMACRO(PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY      ),
+        MAPIMACRO(PR_REPORTING_DL_NAME                        ),
+        MAPIMACRO(PR_REPORTING_MTA_CERTIFICATE                ),
+        MAPIMACRO(PR_RTF_SYNC_BODY_CRC                        ),
+        MAPIMACRO(PR_RTF_SYNC_BODY_COUNT                      ),
+        MAPIMACRO(PR_RTF_SYNC_BODY_TAG                        ),
+        MAPIMACRO(PR_RTF_COMPRESSED                           ),
+        MAPIMACRO(PR_RTF_SYNC_PREFIX_COUNT                    ),
+        MAPIMACRO(PR_RTF_SYNC_TRAILING_COUNT                  ),
+        MAPIMACRO(PR_ORIGINALLY_INTENDED_RECIP_ENTRYID        ),
+        MAPIMACRO(PR_CONTENT_INTEGRITY_CHECK                  ),
+        MAPIMACRO(PR_EXPLICIT_CONVERSION                      ),
+        MAPIMACRO(PR_IPM_RETURN_REQUESTED                     ),
+        MAPIMACRO(PR_MESSAGE_TOKEN                            ),
+        MAPIMACRO(PR_NDR_REASON_CODE                          ),
+        MAPIMACRO(PR_NDR_DIAG_CODE                            ),
+        MAPIMACRO(PR_NON_RECEIPT_NOTIFICATION_REQUESTED       ),
+        MAPIMACRO(PR_DELIVERY_POINT                           ),
+        MAPIMACRO(PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED ),
+        MAPIMACRO(PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT ),
+        MAPIMACRO(PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY    ),
+        MAPIMACRO(PR_PHYSICAL_DELIVERY_MODE                   ),
+        MAPIMACRO(PR_PHYSICAL_DELIVERY_REPORT_REQUEST         ),
+        MAPIMACRO(PR_PHYSICAL_FORWARDING_ADDRESS              ),
+        MAPIMACRO(PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED    ),
+        MAPIMACRO(PR_PHYSICAL_FORWARDING_PROHIBITED           ),
+        MAPIMACRO(PR_PHYSICAL_RENDITION_ATTRIBUTES            ),
+        MAPIMACRO(PR_PROOF_OF_DELIVERY                        ),
+        MAPIMACRO(PR_PROOF_OF_DELIVERY_REQUESTED              ),
+        MAPIMACRO(PR_RECIPIENT_CERTIFICATE                    ),
+        MAPIMACRO(PR_RECIPIENT_NUMBER_FOR_ADVICE              ),
+        MAPIMACRO(PR_RECIPIENT_TYPE                           ),
+        MAPIMACRO(PR_REGISTERED_MAIL_TYPE                     ),
+        MAPIMACRO(PR_REPLY_REQUESTED                          ),
+        MAPIMACRO(PR_REQUESTED_DELIVERY_METHOD                ),
+        MAPIMACRO(PR_SENDER_ENTRYID                           ),
+        MAPIMACRO(PR_SENDER_NAME                              ),
+        MAPIMACRO(PR_SUPPLEMENTARY_INFO                       ),
+        MAPIMACRO(PR_TYPE_OF_MTS_USER                         ),
+        MAPIMACRO(PR_SENDER_SEARCH_KEY                        ),
+        MAPIMACRO(PR_SENDER_ADDRTYPE                          ),
+        MAPIMACRO(PR_SENDER_EMAIL_ADDRESS                     ),
+        MAPIMACRO(PR_CURRENT_VERSION                          ),
+        MAPIMACRO(PR_DELETE_AFTER_SUBMIT                      ),
+        MAPIMACRO(PR_DISPLAY_BCC                              ),
+        MAPIMACRO(PR_DISPLAY_CC                               ),
+        MAPIMACRO(PR_DISPLAY_TO                               ),
+        MAPIMACRO(PR_PARENT_DISPLAY                           ),
+        MAPIMACRO(PR_MESSAGE_DELIVERY_TIME                    ),
+        MAPIMACRO(PR_MESSAGE_FLAGS                            ),
+        MAPIMACRO(PR_MESSAGE_SIZE                             ),
+        MAPIMACRO(PR_PARENT_ENTRYID                           ),
+        MAPIMACRO(PR_SENTMAIL_ENTRYID                         ),
+        MAPIMACRO(PR_CORRELATE                                ),
+        MAPIMACRO(PR_CORRELATE_MTSID                          ),
+        MAPIMACRO(PR_DISCRETE_VALUES                          ),
+        MAPIMACRO(PR_RESPONSIBILITY                           ),
+        MAPIMACRO(PR_SPOOLER_STATUS                           ),
+        MAPIMACRO(PR_TRANSPORT_STATUS                         ),
+        MAPIMACRO(PR_MESSAGE_RECIPIENTS                       ),
+        MAPIMACRO(PR_MESSAGE_ATTACHMENTS                      ),
+        MAPIMACRO(PR_SUBMIT_FLAGS                             ),
+        MAPIMACRO(PR_RECIPIENT_STATUS                         ),
+        MAPIMACRO(PR_TRANSPORT_KEY                            ),
+        MAPIMACRO(PR_MSG_STATUS                               ),
+        MAPIMACRO(PR_MESSAGE_DOWNLOAD_TIME                    ),
+        MAPIMACRO(PR_CREATION_VERSION                         ),
+        MAPIMACRO(PR_MODIFY_VERSION                           ),
+        MAPIMACRO(PR_HASATTACH                                ),
+        MAPIMACRO(PR_BODY_CRC                                 ),
+        MAPIMACRO(PR_NORMALIZED_SUBJECT                       ),
+        MAPIMACRO(PR_RTF_IN_SYNC                              ),
+        MAPIMACRO(PR_ATTACH_SIZE                              ),
+        MAPIMACRO(PR_ATTACH_NUM                               ),
+        MAPIMACRO(PR_PREPROCESS                               ),
+        MAPIMACRO(PR_ORIGINATING_MTA_CERTIFICATE              ),
+        MAPIMACRO(PR_PROOF_OF_SUBMISSION                      ),
+        MAPIMACRO(PR_ENTRYID                                  ),
+        MAPIMACRO(PR_OBJECT_TYPE                              ),
+        MAPIMACRO(PR_ICON                                     ),
+        MAPIMACRO(PR_MINI_ICON                                ),
+        MAPIMACRO(PR_STORE_ENTRYID                            ),
+        MAPIMACRO(PR_STORE_RECORD_KEY                         ),
+        MAPIMACRO(PR_RECORD_KEY                               ),
+        MAPIMACRO(PR_MAPPING_SIGNATURE                        ),
+        MAPIMACRO(PR_ACCESS_LEVEL                             ),
+        MAPIMACRO(PR_INSTANCE_KEY                             ),
+        MAPIMACRO(PR_ROW_TYPE                                 ),
+        MAPIMACRO(PR_ACCESS                                   ),
+        MAPIMACRO(PR_ROWID                                    ),
+        MAPIMACRO(PR_DISPLAY_NAME                             ),
+        MAPIMACRO(PR_ADDRTYPE                                 ),
+        MAPIMACRO(PR_EMAIL_ADDRESS                            ),
+        MAPIMACRO(PR_COMMENT                                  ),
+        MAPIMACRO(PR_DEPTH                                    ),
+        MAPIMACRO(PR_PROVIDER_DISPLAY                         ),
+        MAPIMACRO(PR_CREATION_TIME                            ),
+        MAPIMACRO(PR_LAST_MODIFICATION_TIME                   ),
+        MAPIMACRO(PR_RESOURCE_FLAGS                           ),
+        MAPIMACRO(PR_PROVIDER_DLL_NAME                        ),
+        MAPIMACRO(PR_SEARCH_KEY                               ),
+        MAPIMACRO(PR_PROVIDER_UID                             ),
+        MAPIMACRO(PR_PROVIDER_ORDINAL                         ),
+        MAPIMACRO(PR_FORM_VERSION                             ),
+        MAPIMACRO(PR_FORM_CLSID                               ),
+        MAPIMACRO(PR_FORM_CONTACT_NAME                        ),
+        MAPIMACRO(PR_FORM_CATEGORY                            ),
+        MAPIMACRO(PR_FORM_CATEGORY_SUB                        ),
+        MAPIMACRO(PR_FORM_HOST_MAP                            ),
+        MAPIMACRO(PR_FORM_HIDDEN                              ),
+        MAPIMACRO(PR_FORM_DESIGNER_NAME                       ),
+        MAPIMACRO(PR_FORM_DESIGNER_GUID                       ),
+        MAPIMACRO(PR_FORM_MESSAGE_BEHAVIOR                    ),
+        MAPIMACRO(PR_DEFAULT_STORE                            ),
+        MAPIMACRO(PR_STORE_SUPPORT_MASK                       ),
+        MAPIMACRO(PR_STORE_STATE                              ),
+        MAPIMACRO(PR_IPM_SUBTREE_SEARCH_KEY                   ),
+        MAPIMACRO(PR_IPM_OUTBOX_SEARCH_KEY                    ),
+        MAPIMACRO(PR_IPM_WASTEBASKET_SEARCH_KEY               ),
+        MAPIMACRO(PR_IPM_SENTMAIL_SEARCH_KEY                  ),
+        MAPIMACRO(PR_MDB_PROVIDER                             ),
+        MAPIMACRO(PR_RECEIVE_FOLDER_SETTINGS                  ),
+        MAPIMACRO(PR_VALID_FOLDER_MASK                        ),
+        MAPIMACRO(PR_IPM_SUBTREE_ENTRYID                      ),
+        MAPIMACRO(PR_IPM_OUTBOX_ENTRYID                       ),
+        MAPIMACRO(PR_IPM_WASTEBASKET_ENTRYID                  ),
+        MAPIMACRO(PR_IPM_SENTMAIL_ENTRYID                     ),
+        MAPIMACRO(PR_VIEWS_ENTRYID                            ),
+        MAPIMACRO(PR_COMMON_VIEWS_ENTRYID                     ),
+        MAPIMACRO(PR_FINDER_ENTRYID                           ),
+        MAPIMACRO(PR_CONTAINER_FLAGS                          ),
+        MAPIMACRO(PR_FOLDER_TYPE                              ),
+        MAPIMACRO(PR_CONTENT_COUNT                            ),
+        MAPIMACRO(PR_CONTENT_UNREAD                           ),
+        MAPIMACRO(PR_CREATE_TEMPLATES                         ),
+        MAPIMACRO(PR_DETAILS_TABLE                            ),
+        MAPIMACRO(PR_SEARCH                                   ),
+        MAPIMACRO(PR_SELECTABLE                               ),
+        MAPIMACRO(PR_SUBFOLDERS                               ),
+        MAPIMACRO(PR_STATUS                                   ),
+        MAPIMACRO(PR_ANR                                      ),
+        MAPIMACRO(PR_CONTENTS_SORT_ORDER                      ),
+        MAPIMACRO(PR_CONTAINER_HIERARCHY                      ),
+        MAPIMACRO(PR_CONTAINER_CONTENTS                       ),
+        MAPIMACRO(PR_FOLDER_ASSOCIATED_CONTENTS               ),
+        MAPIMACRO(PR_DEF_CREATE_DL                            ),
+        MAPIMACRO(PR_DEF_CREATE_MAILUSER                      ),
+        MAPIMACRO(PR_CONTAINER_CLASS                          ),
+        MAPIMACRO(PR_CONTAINER_MODIFY_VERSION                 ),
+        MAPIMACRO(PR_AB_PROVIDER_ID                           ),
+        MAPIMACRO(PR_DEFAULT_VIEW_ENTRYID                     ),
+        MAPIMACRO(PR_ASSOC_CONTENT_COUNT                      ),
+        MAPIMACRO(PR_ATTACHMENT_X400_PARAMETERS               ),
+        MAPIMACRO(PR_ATTACH_DATA_OBJ                          ),
+        MAPIMACRO(PR_ATTACH_ENCODING                          ),
+        MAPIMACRO(PR_ATTACH_EXTENSION                         ),
+        MAPIMACRO(PR_ATTACH_FILENAME                          ),
+        MAPIMACRO(PR_ATTACH_METHOD                            ),
+        MAPIMACRO(PR_ATTACH_LONG_FILENAME                     ),
+        MAPIMACRO(PR_ATTACH_PATHNAME                          ),
+        MAPIMACRO(PR_ATTACH_RENDERING                         ),
+        MAPIMACRO(PR_ATTACH_TAG                               ),
+        MAPIMACRO(PR_RENDERING_POSITION                       ),
+        MAPIMACRO(PR_ATTACH_TRANSPORT_NAME                    ),
+        MAPIMACRO(PR_ATTACH_LONG_PATHNAME                     ),
+        MAPIMACRO(PR_ATTACH_MIME_TAG                          ),
+        MAPIMACRO(PR_ATTACH_ADDITIONAL_INFO                   ),
+        MAPIMACRO(PR_DISPLAY_TYPE                             ),
+        MAPIMACRO(PR_TEMPLATEID                               ),
+        MAPIMACRO(PR_PRIMARY_CAPABILITY                       ),
+        MAPIMACRO(PR_7BIT_DISPLAY_NAME                        ),
+        MAPIMACRO(PR_ACCOUNT                                  ),
+        MAPIMACRO(PR_ALTERNATE_RECIPIENT                      ),
+        MAPIMACRO(PR_CALLBACK_TELEPHONE_NUMBER                ),
+        MAPIMACRO(PR_CONVERSION_PROHIBITED                    ),
+        MAPIMACRO(PR_DISCLOSE_RECIPIENTS                      ),
+        MAPIMACRO(PR_GENERATION                               ),
+        MAPIMACRO(PR_GIVEN_NAME                               ),
+        MAPIMACRO(PR_GOVERNMENT_ID_NUMBER                     ),
+        MAPIMACRO(PR_BUSINESS_TELEPHONE_NUMBER                ),
+        MAPIMACRO(PR_HOME_TELEPHONE_NUMBER                    ),
+        MAPIMACRO(PR_INITIALS                                 ),
+        MAPIMACRO(PR_KEYWORD                                  ),
+        MAPIMACRO(PR_LANGUAGE                                 ),
+        MAPIMACRO(PR_LOCATION                                 ),
+        MAPIMACRO(PR_MAIL_PERMISSION                          ),
+        MAPIMACRO(PR_MHS_COMMON_NAME                          ),
+        MAPIMACRO(PR_ORGANIZATIONAL_ID_NUMBER                 ),
+        MAPIMACRO(PR_SURNAME                                  ),
+        MAPIMACRO(PR_ORIGINAL_ENTRYID                         ),
+        MAPIMACRO(PR_ORIGINAL_DISPLAY_NAME                    ),
+        MAPIMACRO(PR_ORIGINAL_SEARCH_KEY                      ),
+        MAPIMACRO(PR_POSTAL_ADDRESS                           ),
+        MAPIMACRO(PR_COMPANY_NAME                             ),
+        MAPIMACRO(PR_TITLE                                    ),
+        MAPIMACRO(PR_DEPARTMENT_NAME                          ),
+        MAPIMACRO(PR_OFFICE_LOCATION                          ),
+        MAPIMACRO(PR_PRIMARY_TELEPHONE_NUMBER                 ),
+        MAPIMACRO(PR_BUSINESS2_TELEPHONE_NUMBER               ),
+        MAPIMACRO(PR_MOBILE_TELEPHONE_NUMBER                  ),
+        MAPIMACRO(PR_RADIO_TELEPHONE_NUMBER                   ),
+        MAPIMACRO(PR_CAR_TELEPHONE_NUMBER                     ),
+        MAPIMACRO(PR_OTHER_TELEPHONE_NUMBER                   ),
+        MAPIMACRO(PR_TRANSMITABLE_DISPLAY_NAME                ),
+        MAPIMACRO(PR_PAGER_TELEPHONE_NUMBER                   ),
+        MAPIMACRO(PR_USER_CERTIFICATE                         ),
+        MAPIMACRO(PR_PRIMARY_FAX_NUMBER                       ),
+        MAPIMACRO(PR_BUSINESS_FAX_NUMBER                      ),
+        MAPIMACRO(PR_HOME_FAX_NUMBER                          ),
+        MAPIMACRO(PR_COUNTRY                                  ),
+        MAPIMACRO(PR_LOCALITY                                 ),
+        MAPIMACRO(PR_STATE_OR_PROVINCE                        ),
+        MAPIMACRO(PR_STREET_ADDRESS                           ),
+        MAPIMACRO(PR_POSTAL_CODE                              ),
+        MAPIMACRO(PR_POST_OFFICE_BOX                          ),
+        MAPIMACRO(PR_TELEX_NUMBER                             ),
+        MAPIMACRO(PR_ISDN_NUMBER                              ),
+        MAPIMACRO(PR_ASSISTANT_TELEPHONE_NUMBER               ),
+        MAPIMACRO(PR_HOME2_TELEPHONE_NUMBER                   ),
+        MAPIMACRO(PR_ASSISTANT                                ),
+        MAPIMACRO(PR_SEND_RICH_INFO                           ),
+        MAPIMACRO(PR_WEDDING_ANNIVERSARY                      ),
+        MAPIMACRO(PR_BIRTHDAY                                 ),
+        MAPIMACRO(PR_HOBBIES                                  ),
+        MAPIMACRO(PR_MIDDLE_NAME                              ),
+        MAPIMACRO(PR_DISPLAY_NAME_PREFIX                      ),
+        MAPIMACRO(PR_PROFESSION                               ),
+        MAPIMACRO(PR_PREFERRED_BY_NAME                        ),
+        MAPIMACRO(PR_SPOUSE_NAME                              ),
+        MAPIMACRO(PR_COMPUTER_NETWORK_NAME                    ),
+        MAPIMACRO(PR_CUSTOMER_ID                              ),
+        MAPIMACRO(PR_TTYTDD_PHONE_NUMBER                      ),
+        MAPIMACRO(PR_FTP_SITE                                 ),
+        MAPIMACRO(PR_GENDER                                   ),
+        MAPIMACRO(PR_MANAGER_NAME                             ),
+        MAPIMACRO(PR_NICKNAME                                 ),
+        MAPIMACRO(PR_PERSONAL_HOME_PAGE                       ),
+        MAPIMACRO(PR_BUSINESS_HOME_PAGE                       ),
+        MAPIMACRO(PR_CONTACT_VERSION                          ),
+        MAPIMACRO(PR_CONTACT_ENTRYIDS                         ),
+        MAPIMACRO(PR_CONTACT_ADDRTYPES                        ),
+        MAPIMACRO(PR_CONTACT_DEFAULT_ADDRESS_INDEX            ),
+        MAPIMACRO(PR_CONTACT_EMAIL_ADDRESSES                  ),
+        MAPIMACRO(PR_COMPANY_MAIN_PHONE_NUMBER                ),
+        MAPIMACRO(PR_CHILDRENS_NAMES                          ),
+        MAPIMACRO(PR_HOME_ADDRESS_CITY                        ),
+        MAPIMACRO(PR_HOME_ADDRESS_COUNTRY                     ),
+        MAPIMACRO(PR_HOME_ADDRESS_POSTAL_CODE                 ),
+        MAPIMACRO(PR_HOME_ADDRESS_STATE_OR_PROVINCE           ),
+        MAPIMACRO(PR_HOME_ADDRESS_STREET                      ),
+        MAPIMACRO(PR_HOME_ADDRESS_POST_OFFICE_BOX             ),
+        MAPIMACRO(PR_OTHER_ADDRESS_CITY                       ),
+        MAPIMACRO(PR_OTHER_ADDRESS_COUNTRY                    ),
+        MAPIMACRO(PR_OTHER_ADDRESS_POSTAL_CODE                ),
+        MAPIMACRO(PR_OTHER_ADDRESS_STATE_OR_PROVINCE          ),
+        MAPIMACRO(PR_OTHER_ADDRESS_STREET                     ),
+        MAPIMACRO(PR_OTHER_ADDRESS_POST_OFFICE_BOX            ),
+        MAPIMACRO(PR_STORE_PROVIDERS                          ),
+        MAPIMACRO(PR_AB_PROVIDERS                             ),
+        MAPIMACRO(PR_TRANSPORT_PROVIDERS                      ),
+        MAPIMACRO(PR_DEFAULT_PROFILE                          ),
+        MAPIMACRO(PR_AB_SEARCH_PATH                           ),
+        MAPIMACRO(PR_AB_DEFAULT_DIR                           ),
+        MAPIMACRO(PR_AB_DEFAULT_PAB                           ),
+        MAPIMACRO(PR_FILTERING_HOOKS                          ),
+        MAPIMACRO(PR_SERVICE_NAME                             ),
+        MAPIMACRO(PR_SERVICE_DLL_NAME                         ),
+        MAPIMACRO(PR_SERVICE_ENTRY_NAME                       ),
+        MAPIMACRO(PR_SERVICE_UID                              ),
+        MAPIMACRO(PR_SERVICE_EXTRA_UIDS                       ),
+        MAPIMACRO(PR_SERVICES                                 ),
+        MAPIMACRO(PR_SERVICE_SUPPORT_FILES                    ),
+        MAPIMACRO(PR_SERVICE_DELETE_FILES                     ),
+        MAPIMACRO(PR_AB_SEARCH_PATH_UPDATE                    ),
+        MAPIMACRO(PR_PROFILE_NAME                             ),
+        MAPIMACRO(PR_IDENTITY_DISPLAY                         ),
+        MAPIMACRO(PR_IDENTITY_ENTRYID                         ),
+        MAPIMACRO(PR_RESOURCE_METHODS                         ),
+        MAPIMACRO(PR_RESOURCE_TYPE                            ),
+        MAPIMACRO(PR_STATUS_CODE                              ),
+        MAPIMACRO(PR_IDENTITY_SEARCH_KEY                      ),
+        MAPIMACRO(PR_OWN_STORE_ENTRYID                        ),
+        MAPIMACRO(PR_RESOURCE_PATH                            ),
+        MAPIMACRO(PR_STATUS_STRING                            ),
+        MAPIMACRO(PR_X400_DEFERRED_DELIVERY_CANCEL            ),
+        MAPIMACRO(PR_HEADER_FOLDER_ENTRYID                    ),
+        MAPIMACRO(PR_REMOTE_PROGRESS                          ),
+        MAPIMACRO(PR_REMOTE_PROGRESS_TEXT                     ),
+        MAPIMACRO(PR_REMOTE_VALIDATE_OK                       ),
+        MAPIMACRO(PR_CONTROL_FLAGS                            ),
+        MAPIMACRO(PR_CONTROL_STRUCTURE                        ),
+        MAPIMACRO(PR_CONTROL_TYPE                             ),
+        MAPIMACRO(PR_DELTAX                                   ),
+        MAPIMACRO(PR_DELTAY                                   ),
+        MAPIMACRO(PR_XPOS                                     ),
+        MAPIMACRO(PR_YPOS                                     ),
+        MAPIMACRO(PR_CONTROL_ID                               ),
+        MAPIMACRO(PR_INITIAL_DETAILS_PANE                     )};
+
+#endif  /* MAPITAGS_H */
diff --git a/src/plugins/tnef_parse/placeholder.txt b/src/plugins/tnef_parse/placeholder.txt
deleted file mode 100644 (file)
index 3b94f91..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Placeholder
diff --git a/src/plugins/tnef_parse/plugin.def b/src/plugins/tnef_parse/plugin.def
new file mode 100644 (file)
index 0000000..8916a5d
--- /dev/null
@@ -0,0 +1,10 @@
+EXPORTS
+        plugin_desc
+        plugin_done
+        plugin_init
+        plugin_licence
+        plugin_name
+        plugin_type
+       plugin_provides
+        plugin_version
+
diff --git a/src/plugins/tnef_parse/tnef-errors.h b/src/plugins/tnef_parse/tnef-errors.h
new file mode 100644 (file)
index 0000000..f9ef4eb
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _TNEF_ERRORS_
+#define _TNEF_ERRORS_
+
+
+#define YTNEF_CANNOT_INIT_DATA -1
+#define YTNEF_NOT_TNEF_STREAM  -2
+#define YTNEF_ERROR_READING_DATA -3
+#define YTNEF_NO_KEY -4
+#define YTNEF_BAD_CHECKSUM -5
+#define YTNEF_ERROR_IN_HANDLER -6
+#define YTNEF_UNKNOWN_PROPERTY -7
+#define YTNEF_INCORRECT_SETUP -8
+
+
+#endif
+
diff --git a/src/plugins/tnef_parse/tnef-types.h b/src/plugins/tnef_parse/tnef-types.h
new file mode 100644 (file)
index 0000000..57ba6c4
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef _TNEF_TYPES_H_
+#define _TNEF_TYPES_H_
+
+#define BYTE unsigned char
+#define WORD unsigned short int
+#define DWORD unsigned int
+#define ULONG unsigned int
+#define DDWORD unsigned long long
+typedef struct
+{
+    WORD    atyp;
+    ULONG   ulPosition;
+    WORD    dxWidth;
+    WORD    dyHeight;
+    DWORD   dwFlags;
+} renddata;
+
+/* ----------------------------------- */
+/* TNEF Down-level Date/Time Structure */
+/* ----------------------------------- */
+
+typedef struct 
+{
+    WORD    wYear;
+    WORD    wMonth;
+    WORD    wDay;
+    WORD    wHour;
+    WORD    wMinute;
+    WORD    wSecond;
+    WORD    wDayOfWeek;
+} dtr;
+
+typedef struct
+{
+    char *data;
+    int size;
+} variableLength;
+
+typedef struct {
+    DWORD custom;
+    BYTE guid[16];
+    DWORD id;
+    ULONG count;
+    int namedproperty;
+    variableLength *propnames;
+    variableLength *data;
+} MAPIProperty;
+
+typedef struct MAPIProps {
+    DWORD count;
+    MAPIProperty *properties;
+} MAPIProps;
+
+typedef struct Attachment
+{
+    dtr Date;
+    variableLength Title;
+    variableLength MetaFile;
+    dtr CreateDate;
+    dtr ModifyDate;
+    variableLength TransportFilename;
+    renddata RenderData;
+    MAPIProps MAPI;
+    struct Attachment *next;
+    variableLength FileData;
+    variableLength IconData;
+} Attachment;
+
+typedef struct _TNEFIOStruct
+{
+    int (*InitProc) (struct _TNEFIOStruct *IO);
+    int (*ReadProc) (struct _TNEFIOStruct *IO, int size, int count, void *dest);
+    int (*CloseProc) (struct _TNEFIOStruct *IO);
+    void *data;
+} TNEFIOStruct;
+
+typedef struct 
+{
+    char *filename;
+    FILE *fptr;
+    int Debug;
+} TNEFFileInfo;
+
+typedef struct 
+{
+    BYTE *dataStart;
+    BYTE *ptr;
+    long size;
+    int Debug;
+} TNEFMemInfo;
+
+typedef struct 
+{
+    char version[10];
+    variableLength from;
+    variableLength subject;
+    dtr dateSent;
+    dtr dateReceived;
+    char messageStatus[10];
+    char messageClass[50];
+    char messageID[50];
+    char parentID[50];
+    char conversationID[50];
+    variableLength body;
+    char priority[10];
+    Attachment starting_attach;
+    dtr dateModified;
+    MAPIProps MapiProperties;
+    variableLength CodePage;
+    variableLength OriginalMessageClass;
+    variableLength Owner;
+    variableLength SentFor;
+    variableLength Delegate;
+    dtr DateStart;
+    dtr DateEnd;
+    variableLength AidOwner;
+    int RequestRes;
+    int Debug;
+    TNEFIOStruct IO;
+} TNEFStruct;
+
+#endif
diff --git a/src/plugins/tnef_parse/tnef_dump.c b/src/plugins/tnef_parse/tnef_dump.c
new file mode 100644 (file)
index 0000000..f3d1d61
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2007 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 <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include "common/claws.h"
+#include "common/version.h"
+#include "main.h"
+#include "plugin.h"
+#include "procmime.h"
+#include "utils.h"
+
+#include <tnef-types.h>
+#include <ytnef.h>
+#include <mapi.h>
+#include <mapidefs.h>
+
+#include "tnef_dump.h"
+
+#define PRODID "PRODID:-//The Gauntlet//" PACKAGE " TNEF Parser " VERSION "//EN\n"
+
+static unsigned char GetRruleCount(unsigned char a, unsigned char b) {
+    return ((a << 8) | b);
+}
+
+static unsigned char GetRruleMonthNum(unsigned char a, unsigned char 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);
+}
+
+static char * GetRruleDayname(unsigned char a) {
+    static char 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);
+}
+
+static void PrintRrule(FILE *fptr, char *recur_data, int 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");
+}
+
+static void fprintProperty(TNEFStruct TNEF, FILE *FPTR, DWORD PROPTYPE, DWORD PROPID, char 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);
+            }
+       }
+    }
+}
+
+static void fprintUserProp(TNEFStruct TNEF, FILE *FPTR, DWORD PROPTYPE, DWORD PROPID, char 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);
+            }
+       }
+    }
+}
+
+static void quotedfprint(FILE *FPTR, variableLength *VL) {
+    int index;
+
+    for (index=0;index<VL->size-1; index++) {
+        if (VL->data[index] == '\n') {
+            fprintf(FPTR, "=0A");
+        } else if (VL->data[index] == '\r') {
+        } else {
+            fprintf(FPTR, "%c", VL->data[index]);
+        }
+    }
+}
+
+static void Cstylefprint(FILE *FPTR, variableLength *VL) {
+    int index;
+
+    for (index=0;index<VL->size-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]);
+        }
+    }
+}
+
+static void PrintRTF(FILE *fptr, variableLength *VL) {
+    int index;
+    char *byte;
+    int brace_ct;
+    int 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");
+}
+
+gboolean SaveVCalendar(FILE *fptr, TNEFStruct TNEF) {
+    variableLength *filename;
+    char *charptr, *charptr2;
+    int index;
+    DDWORD *ddword_ptr;
+    DDWORD ddword_val;
+    dtr thedate;
+
+        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, PRODID);
+        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;index<filename->size;index++) {
+                fprintf(fptr,"%02X", (unsigned char)filename->data[index]);
+            }
+            fprintf(fptr,"\n");
+        }
+
+        // Sequence
+        filename = NULL;
+        if ((filename=MAPIFindUserProp(&(TNEF.MapiProperties),
+                        PROP_TAG(PT_LONG, 0x8201))) != MAPI_UNDEFINED) {
+            ddword_ptr = (DDWORD*)filename->data;
+            fprintf(fptr, "SEQUENCE:%i\n", (int) *ddword_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;
+                charptr2=strstr(charptr+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;
+                    charptr2=strstr(charptr+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;
+                charptr2=strstr(charptr+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 = 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(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(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(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) {
+            ddword_ptr = (DDWORD*)filename->data;
+            ddword_val = SwapDDWord((BYTE*)ddword_ptr);
+            fprintf(fptr, "CLASS:" );
+            if (*ddword_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");
+       return TRUE;
+}
+
+       
+
+gboolean SaveVTask(FILE *fptr, TNEFStruct TNEF) {
+    variableLength *filename;
+    char *charptr, *charptr2;
+    dtr thedate;
+    DDWORD *ddword_ptr;
+    DDWORD ddword_val;
+
+        fprintf(fptr, "BEGIN:VCALENDAR\n");
+        fprintf(fptr, PRODID);
+        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;
+            charptr2=strstr(charptr+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(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(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(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) {
+            ddword_ptr = (DDWORD*)filename->data;
+            ddword_val = SwapDDWord((BYTE*)ddword_ptr);
+            fprintf(fptr, "CLASS:" );
+            if (*ddword_ptr == 1) {
+                fprintf(fptr,"PRIVATE\n");
+            } else {
+                fprintf(fptr,"PUBLIC\n");
+            }
+        }
+        fprintf(fptr, "END:VTODO\n");
+        fprintf(fptr, "END:VCALENDAR\n");
+        fclose(fptr);
+        return TRUE;
+}
+
+gboolean SaveVCard(FILE *fptr, TNEFStruct TNEF) {
+    variableLength *vl;
+    variableLength *pobox, *street, *city, *state, *zip, *country;
+    dtr thedate;
+    int boolean;
+
+    if ((vl = MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_DISPLAY_NAME))) == MAPI_UNDEFINED) {
+        vl=MAPIFindProperty(&(TNEF.MapiProperties), PROP_TAG(PT_STRING8, PR_COMPANY_NAME));
+    }
+
+        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(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(vl->data, &thedate);
+            fprintf(fptr, "%i-%02i-%02i\n", thedate.wYear, thedate.wMonth, thedate.wDay);
+        }
+        fprintf(fptr, "END:VCARD\n");
+       return TRUE;
+}
diff --git a/src/plugins/tnef_parse/tnef_dump.h b/src/plugins/tnef_parse/tnef_dump.h
new file mode 100644 (file)
index 0000000..72890bb
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net>
+ * and the Claws Mail Team
+ *
+ * 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.
+ */
+
+#ifndef __TNEF_DUMP__
+#define __TNEF_DUMP__
+
+gboolean SaveVCalendar(FILE *fptr, TNEFStruct TNEF);
+gboolean SaveVCard(FILE *fptr, TNEFStruct TNEF);
+gboolean SaveVTask(FILE *fptr, TNEFStruct TNEF);
+
+#endif
diff --git a/src/plugins/tnef_parse/tnef_parse.c b/src/plugins/tnef_parse/tnef_parse.c
new file mode 100644 (file)
index 0000000..163bd36
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2007 Colin Leroy <colin@colino.net>
+ * and the Claws Mail Team
+ *
+ * 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 <unistd.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include "common/claws.h"
+#include "common/version.h"
+#include "main.h"
+#include "plugin.h"
+#include "procmime.h"
+#include "utils.h"
+
+#include <tnef-types.h>
+#include <ytnef.h>
+#include <mapi.h>
+#include <mapidefs.h>
+
+#include "tnef_dump.h"
+
+static MimeParser *tnef_parser = NULL;
+
+static MimeInfo *tnef_broken_mimeinfo(const gchar *reason)
+{
+       MimeInfo *sub_info = NULL;
+       gchar *tmpfilename = NULL;
+       FILE *fp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmpfilename);
+       struct stat statbuf;
+
+       if (!fp) {
+               g_free(tmpfilename);
+               return NULL;
+       }
+       sub_info = procmime_mimeinfo_new();
+       sub_info->content = MIMECONTENT_FILE;
+       sub_info->data.filename = tmpfilename;
+       sub_info->type = MIMETYPE_TEXT;
+       sub_info->subtype = g_strdup("plain");
+       
+       fprintf(fp, _("\n"
+                       "Claws Mail TNEF parser:\n\n"
+                       "%s\n"), reason?reason:_("Unknown error"));
+       
+       fclose(fp);
+       g_stat(tmpfilename, &statbuf);
+       sub_info->tmp = TRUE;
+       sub_info->length = statbuf.st_size;
+       sub_info->encoding_type = ENC_BINARY;
+       
+       return sub_info;
+
+}
+
+static MimeInfo *tnef_dump_file(const gchar *filename, char *data, size_t size)
+{
+       MimeInfo *sub_info = NULL;
+       gchar *tmpfilename = NULL;
+       FILE *fp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmpfilename);
+       struct stat statbuf;
+       gchar *content_type = NULL;
+       if (!fp) {
+               g_free(tmpfilename);
+               return NULL;
+       }
+       sub_info = procmime_mimeinfo_new();
+       sub_info->content = MIMECONTENT_FILE;
+       sub_info->data.filename = tmpfilename;
+       sub_info->type = MIMETYPE_APPLICATION;
+       sub_info->subtype = g_strdup("octet-stream");
+       
+       if (filename) {
+               g_hash_table_insert(sub_info->typeparameters,
+                                   g_strdup("filename"),
+                                   g_strdup(filename));
+       
+               content_type = procmime_get_mime_type(filename);
+               if (content_type && strchr(content_type, '/')) {
+                       g_free(sub_info->subtype);
+                       sub_info->subtype = g_strdup(strchr(content_type, '/')+1);
+                       *(strchr(content_type, '/')) = '\0';
+                       sub_info->type = procmime_get_media_type(content_type);
+                       g_free(content_type);
+               }
+       } 
+
+       if (fwrite(data, 1, size, fp) < size) {
+               FILE_OP_ERROR(tmpfilename, "fwrite");
+               fclose(fp);
+               claws_unlink(tmpfilename);
+               procmime_mimeinfo_free_all(sub_info);
+               return tnef_broken_mimeinfo(_("Failed to write the part data."));
+       }
+       fclose(fp);
+       g_stat(tmpfilename, &statbuf);
+       sub_info->tmp = TRUE;
+       sub_info->length = statbuf.st_size;
+       sub_info->encoding_type = ENC_BINARY;
+       
+       return sub_info;
+}
+
+MimeInfo *tnef_parse_vcal(TNEFStruct tnef)
+{
+       MimeInfo *sub_info = NULL;
+       gchar *tmpfilename = NULL;
+       FILE *fp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmpfilename);
+       struct stat statbuf;
+       gboolean result = FALSE;
+       if (!fp) {
+               g_free(tmpfilename);
+               return NULL;
+       }
+       sub_info = procmime_mimeinfo_new();
+       sub_info->content = MIMECONTENT_FILE;
+       sub_info->data.filename = tmpfilename;
+       sub_info->type = MIMETYPE_TEXT;
+       sub_info->subtype = g_strdup("calendar");
+       g_hash_table_insert(sub_info->typeparameters,
+                           g_strdup("filename"),
+                           g_strdup("calendar.ics"));
+       
+       result = SaveVCalendar(fp, tnef);
+       
+       fclose(fp);
+       g_stat(tmpfilename, &statbuf);
+       sub_info->tmp = TRUE;
+       sub_info->length = statbuf.st_size;
+       sub_info->encoding_type = ENC_BINARY;
+       
+       if (!result) {
+               claws_unlink(tmpfilename);
+               procmime_mimeinfo_free_all(sub_info);
+               return tnef_broken_mimeinfo(_("Failed to parse VCalendar data."));
+       }
+       return sub_info;
+}
+
+MimeInfo *tnef_parse_vtask(TNEFStruct tnef)
+{
+       MimeInfo *sub_info = NULL;
+       gchar *tmpfilename = NULL;
+       FILE *fp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmpfilename);
+       struct stat statbuf;
+       gboolean result = FALSE;
+       if (!fp) {
+               g_free(tmpfilename);
+               return NULL;
+       }
+       sub_info = procmime_mimeinfo_new();
+       sub_info->content = MIMECONTENT_FILE;
+       sub_info->data.filename = tmpfilename;
+       sub_info->type = MIMETYPE_TEXT;
+       sub_info->subtype = g_strdup("calendar");
+       g_hash_table_insert(sub_info->typeparameters,
+                           g_strdup("filename"),
+                           g_strdup("task.ics"));
+       
+       result = SaveVTask(fp, tnef);
+       
+       fclose(fp);
+       g_stat(tmpfilename, &statbuf);
+       sub_info->tmp = TRUE;
+       sub_info->length = statbuf.st_size;
+       sub_info->encoding_type = ENC_BINARY;
+       
+       if (!result) {
+               claws_unlink(tmpfilename);
+               procmime_mimeinfo_free_all(sub_info);
+               return tnef_broken_mimeinfo(_("Failed to parse VTask data."));
+       }
+       return sub_info;
+}
+
+MimeInfo *tnef_parse_rtf(TNEFStruct tnef, variableLength *tmp_var)
+{
+       variableLength buf;
+       MimeInfo *info = NULL;
+       buf.data = DecompressRTF(tmp_var, &(buf.size));
+       if (buf.data) {
+               info = tnef_dump_file("message.rtf", buf.data, buf.size);
+               free(buf.data);
+               return info;
+       } else {
+               return NULL;
+       }
+}
+
+MimeInfo *tnef_parse_vcard(TNEFStruct tnef)
+{
+       MimeInfo *sub_info = NULL;
+       gchar *tmpfilename = NULL;
+       FILE *fp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmpfilename);
+       struct stat statbuf;
+       gboolean result = FALSE;
+       if (!fp) {
+               g_free(tmpfilename);
+               return NULL;
+       }
+       sub_info = procmime_mimeinfo_new();
+       sub_info->content = MIMECONTENT_FILE;
+       sub_info->data.filename = tmpfilename;
+       sub_info->type = MIMETYPE_TEXT;
+       sub_info->subtype = g_strdup("x-vcard");
+       g_hash_table_insert(sub_info->typeparameters,
+                           g_strdup("filename"),
+                           g_strdup("contact.vcf"));
+       
+       result = SaveVCard(fp, tnef);
+       
+       fclose(fp);
+       g_stat(tmpfilename, &statbuf);
+       sub_info->tmp = TRUE;
+       sub_info->length = statbuf.st_size;
+       sub_info->encoding_type = ENC_BINARY;
+       
+       if (!result) {
+               claws_unlink(tmpfilename);
+               procmime_mimeinfo_free_all(sub_info);
+               return tnef_broken_mimeinfo(_("Failed to parse VCard data."));
+       }
+       return sub_info;
+}
+
+static gboolean tnef_parse (MimeParser *parser, MimeInfo *mimeinfo)
+{
+       TNEFStruct tnef;
+       MimeInfo *sub_info = NULL;
+       variableLength *tmp_var;
+       Attachment *att;
+       int parse_result = 0;
+       gboolean cal_done = FALSE;
+
+       if (!procmime_decode_content(mimeinfo)) {
+               debug_print("error decoding\n");
+               return FALSE;
+       }
+       debug_print("Tnef parser parsing part (%d).\n", mimeinfo->length);
+       if (mimeinfo->content == MIMECONTENT_FILE)
+               debug_print("content: %s\n", mimeinfo->data.filename);
+       else 
+               debug_print("contents in memory (len %zd)\n", 
+                       strlen(mimeinfo->data.mem));
+                       
+       TNEFInitialize(&tnef);
+
+       if (!debug_get_mode())
+               tnef.Debug = 0;
+
+       if (mimeinfo->content == MIMECONTENT_MEM)
+               parse_result = TNEFParseMemory(mimeinfo->data.mem, mimeinfo->length, &tnef);
+       else
+               parse_result = TNEFParseFile(mimeinfo->data.filename, &tnef);
+       
+       mimeinfo->type = MIMETYPE_MULTIPART;
+       mimeinfo->subtype = g_strdup("mixed");
+       g_hash_table_insert(mimeinfo->typeparameters,
+                           g_strdup("description"),
+                           g_strdup("Parsed from MS-TNEF"));
+
+       if (parse_result != 0) {
+               g_warning("Failed to parse TNEF data.");
+               TNEFFree(&tnef);
+               return FALSE;
+       }
+       
+       sub_info = NULL;
+       if (tnef.messageClass != NULL && tnef.messageClass[0] != '\0') {
+               if (strcmp(tnef.messageClass, "IPM.Contact") == 0)
+                       sub_info = tnef_parse_vcard(tnef);
+               else if (strcmp(tnef.messageClass, "IPM.Task") == 0)
+                       sub_info = tnef_parse_vtask(tnef);
+               else if (strcmp(tnef.messageClass, "IPM.Appointment") == 0) {
+                       sub_info = tnef_parse_vcal(tnef);
+                       cal_done = TRUE;
+               }
+       }
+
+       if (sub_info)
+               g_node_append(mimeinfo->node, sub_info->node);
+       sub_info = NULL;
+
+       if (tnef.MapiProperties.count > 0) {
+               tmp_var = MAPIFindProperty (&(tnef.MapiProperties), PROP_TAG(PT_BINARY,PR_RTF_COMPRESSED));
+               if (tmp_var != MAPI_UNDEFINED) {
+                       sub_info = tnef_parse_rtf(tnef, tmp_var);
+               }
+       }
+
+       if (sub_info)
+               g_node_append(mimeinfo->node, sub_info->node);
+       sub_info = NULL;
+
+       tmp_var = MAPIFindUserProp(&(tnef.MapiProperties), PROP_TAG(PT_STRING8,0x24));
+       if (tmp_var != MAPI_UNDEFINED) {
+               if (!cal_done && strcmp(tmp_var->data, "IPM.Appointment") == 0) {
+                       sub_info = tnef_parse_vcal(tnef);
+               }
+       }
+       
+       if (sub_info)
+               g_node_append(mimeinfo->node, sub_info->node);
+       sub_info = NULL;
+
+       att = tnef.starting_attach.next;
+       while (att) {
+               gchar *filename = NULL;
+               gboolean is_object = TRUE;
+               DWORD signature;
+
+               tmp_var = MAPIFindProperty(&(att->MAPI), PROP_TAG(30,0x3707));
+               if (tmp_var == MAPI_UNDEFINED)
+                       tmp_var = MAPIFindProperty(&(att->MAPI), PROP_TAG(30,0x3001));
+               if (tmp_var == MAPI_UNDEFINED)
+                       tmp_var = &(att->Title);
+
+               if (tmp_var->data)
+                       filename = g_strdup(tmp_var->data);
+               
+               tmp_var = MAPIFindProperty(&(att->MAPI), PROP_TAG(PT_OBJECT, PR_ATTACH_DATA_OBJ));
+               if (tmp_var == MAPI_UNDEFINED)
+                       tmp_var = MAPIFindProperty(&(att->MAPI), PROP_TAG(PT_BINARY, PR_ATTACH_DATA_OBJ));
+               if (tmp_var == MAPI_UNDEFINED) {
+                       tmp_var = &(att->FileData);
+                       is_object = FALSE;
+               }
+               
+               sub_info = tnef_dump_file(filename, 
+                       tmp_var->data + (is_object ? 16:0), 
+                       tmp_var->size - (is_object ? 16:0));
+               
+               if (sub_info)
+                       g_node_append(mimeinfo->node, sub_info->node);
+       
+               memcpy(&signature, tmp_var->data+(is_object ? 16:0), sizeof(DWORD));
+
+               if (TNEFCheckForSignature(signature) == 0) {
+                       debug_print("that's TNEF stuff, process it\n");
+                       tnef_parse(parser, sub_info);
+               }
+
+               sub_info = NULL;
+               
+               att = att->next;
+
+               g_free(filename);
+       }
+       
+       TNEFFree(&tnef);
+       return TRUE;
+}
+
+gint plugin_init(gchar **error)
+{
+       if (!check_plugin_version(MAKE_NUMERIC_VERSION(2,9,2,72),
+                               VERSION_NUMERIC, _("TNEF Parser"), error))
+               return -1;
+
+       tnef_parser = g_new0(MimeParser, 1);
+       tnef_parser->type = MIMETYPE_APPLICATION;
+       tnef_parser->sub_type = "ms-tnef";
+       tnef_parser->parse = tnef_parse;
+       
+       procmime_mimeparser_register(tnef_parser);
+
+       return 0;
+}
+
+gboolean plugin_done(void)
+{
+       procmime_mimeparser_unregister(tnef_parser);
+       g_free(tnef_parser);
+       tnef_parser = NULL;
+
+       return TRUE;
+}
+
+const gchar *plugin_name(void)
+{
+       return _("TNEF Parser");
+}
+
+const gchar *plugin_desc(void)
+{
+       return _("This Claws Mail plugin allows you to read application/ms-tnef attachments.\n\n"
+                "The plugin uses the Ytnef library, which is copyright 2002-2007 by "
+                "Randall Hand <yerase@yerot.com>");
+}
+
+const gchar *plugin_type(void)
+{
+       return "GTK2";
+}
+
+const gchar *plugin_licence(void)
+{
+       return "GPL3+";
+}
+
+const gchar *plugin_version(void)
+{
+       return VERSION;
+}
+
+struct PluginFeature *plugin_provides(void)
+{
+       static struct PluginFeature features[] = 
+               { {PLUGIN_MIMEPARSER, "application/ms-tnef"},
+                 {PLUGIN_NOTHING, NULL}};
+       return features;
+}
diff --git a/src/plugins/tnef_parse/version.rc b/src/plugins/tnef_parse/version.rc
new file mode 100644 (file)
index 0000000..db9c0d4
--- /dev/null
@@ -0,0 +1,36 @@
+1 VERSIONINFO
+ FILEVERSION 0, 0, 0, 0
+ PRODUCTVERSION 0, 0, 0, 0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "000004b0"
+        BEGIN
+            VALUE "FileDescription", "TNEF Parser Plugin\0"
+            VALUE "FileVersion", "0.0.0.0\0"
+            VALUE "ProductVersion", "0.0.0.0 Win32\0"
+            VALUE "LegalCopyright", "GPL / Â© 1999-2008 Hiroyuki Yamamoto & The Claws Mail Team\0"
+            VALUE "CompanyName", "GNU / Free Software Foundation\0"
+            VALUE "ProductName", "Claws Mail\0"
+//            VALUE "Comments", "\0"
+//            VALUE "InternalName", "\0"
+//            VALUE "LegalTrademarks", "\0"
+//            VALUE "OriginalFilename", "\0"
+//            VALUE "PrivateBuild", "\0"
+//            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0, 1200
+    END
+END
diff --git a/src/plugins/tnef_parse/ytnef.c b/src/plugins/tnef_parse/ytnef.c
new file mode 100644 (file)
index 0000000..a30a0af
--- /dev/null
@@ -0,0 +1,1434 @@
+/*
+ * 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 {
+    DWORD count;
+    BYTE *d;
+    int current_row;
+    int propcount;
+    int current_prop;
+
+    d = data;
+    count = SwapDWord(d);
+    d += 4;
+//    printf("Recipient Table containing %u rows\n", count);
+
+    return 0;
+
+    for(current_row=0; current_row<count; current_row++) {
+       propcount = SwapDWord(d);
+        if (TNEF->Debug >= 1) 
+            printf("> Row %i contains %i properties\n", current_row, propcount);
+        d+=4;
+        for(current_prop=0; current_prop<propcount; current_prop++) {
+
+
+        }
+    }
+    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;
+    int offset;
+    
+    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;
+                offset = ((num % 4) ? (4 - num%4) : 0);
+                d += num + ((num % 4) ? (4 - num%4) : 0);
+                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;
+        }
+        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 %i bytes, Expected %i bytes\n", (d-data), size);
+            printf("%i bytes missing\n", size - (d-data));
+        }
+    } else if ((d-data) > size){
+        if (TNEF->Debug >= 1)  {
+            printf("ERROR DURING MAPI READ\n");
+            printf("Read %i bytes, Expected %i bytes\n", (d-data), size);
+            printf("%i 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;
+    }
+}
+
+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);
+    strcpy(comp_Prebuf.data, RTF_PREBUF);
+
+    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;
+    }
+}
diff --git a/src/plugins/tnef_parse/ytnef.h b/src/plugins/tnef_parse/ytnef.h
new file mode 100644 (file)
index 0000000..7018634
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef _TNEF_PROCS_H_
+#define _TNEF_PROCS_H_
+
+#include "tnef-types.h"
+#include "mapi.h"
+#include "mapidefs.h"
+#define STD_ARGLIST (TNEFStruct *TNEF, int id, unsigned char *data, int size)
+DWORD SwapDWord(BYTE *p);
+WORD SwapWord(BYTE *p);
+
+
+void TNEFInitMapi(MAPIProps *p);
+void TNEFInitAttachment(Attachment *p);
+void TNEFInitialize(TNEFStruct *TNEF);
+void TNEFFree(TNEFStruct *TNEF);
+void TNEFFreeAttachment(Attachment *p);
+void TNEFFreeMapiProps(MAPIProps *p);
+int TNEFCheckForSignature(DWORD sig);
+int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF);
+int TNEFParseFile(char *filename, TNEFStruct *TNEF);
+int TNEFParse(TNEFStruct *TNEF);
+variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID);
+variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID);
+int MAPISysTimetoDTR(BYTE *data, dtr *thedate);
+void MAPIPrint(MAPIProps *p);
+char* to_utf8(int len, char* buf);
+WORD SwapWord(BYTE *p);
+DWORD SwapDWord(BYTE *p);
+DDWORD SwapDDWord(BYTE *p);
+variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID);
+variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID);
+unsigned char * DecompressRTF(variableLength *p, int *size);
+
+/* ------------------------------------- */ 
+/* TNEF Down-level Attributes/Properties */
+/* ------------------------------------- */
+
+#define atpTriples      ((WORD) 0x0000)
+#define atpString       ((WORD) 0x0001)
+#define atpText         ((WORD) 0x0002)
+#define atpDate         ((WORD) 0x0003)
+#define atpShort        ((WORD) 0x0004)
+#define atpLong         ((WORD) 0x0005)
+#define atpByte         ((WORD) 0x0006)
+#define atpWord         ((WORD) 0x0007)
+#define atpDword        ((WORD) 0x0008)
+#define atpMax          ((WORD) 0x0009)
+
+#define LVL_MESSAGE     ((BYTE) 0x01)
+#define LVL_ATTACHMENT  ((BYTE) 0x02)
+
+#define ATT_ID(_att)                ((WORD) ((_att) & 0x0000FFFF))
+#define ATT_TYPE(_att)              ((WORD) (((_att) >> 16) & 0x0000FFFF))
+#define ATT(_atp, _id)              ((((DWORD) (_atp)) << 16) | ((WORD) (_id)))
+
+#define attNull                     ATT( 0,             0x0000)
+#define attFrom                     ATT( atpTriples,    0x8000) /* PR_ORIGINATOR_RETURN_ADDRESS */
+#define attSubject                  ATT( atpString,     0x8004) /* PR_SUBJECT */
+#define attDateSent                 ATT( atpDate,       0x8005) /* PR_CLIENT_SUBMIT_TIME */
+#define attDateRecd                 ATT( atpDate,       0x8006) /* PR_MESSAGE_DELIVERY_TIME */
+#define attMessageStatus            ATT( atpByte,       0x8007) /* PR_MESSAGE_FLAGS */
+#define attMessageClass             ATT( atpWord,       0x8008) /* PR_MESSAGE_CLASS */
+#define attMessageID                ATT( atpString,     0x8009) /* PR_MESSAGE_ID */
+#define attParentID                 ATT( atpString,     0x800A) /* PR_PARENT_ID */
+#define attConversationID           ATT( atpString,     0x800B) /* PR_CONVERSATION_ID */
+#define attBody                     ATT( atpText,       0x800C) /* PR_BODY */
+#define attPriority                 ATT( atpShort,      0x800D) /* PR_IMPORTANCE */
+#define attAttachData               ATT( atpByte,       0x800F) /* PR_ATTACH_DATA_xxx */
+#define attAttachTitle              ATT( atpString,     0x8010) /* PR_ATTACH_FILENAME */
+#define attAttachMetaFile           ATT( atpByte,       0x8011) /* PR_ATTACH_RENDERING */
+#define attAttachCreateDate         ATT( atpDate,       0x8012) /* PR_CREATION_TIME */
+#define attAttachModifyDate         ATT( atpDate,       0x8013) /* PR_LAST_MODIFICATION_TIME */
+#define attDateModified             ATT( atpDate,       0x8020) /* PR_LAST_MODIFICATION_TIME */
+#define attAttachTransportFilename  ATT( atpByte,       0x9001) /* PR_ATTACH_TRANSPORT_NAME */
+#define attAttachRenddata           ATT( atpByte,       0x9002)
+#define attMAPIProps                ATT( atpByte,       0x9003)
+#define attRecipTable               ATT( atpByte,       0x9004) /* PR_MESSAGE_RECIPIENTS */
+#define attAttachment               ATT( atpByte,       0x9005)
+#define attTnefVersion              ATT( atpDword,      0x9006)
+#define attOemCodepage              ATT( atpByte,       0x9007)
+#define attOriginalMessageClass     ATT( atpWord,       0x0006) /* PR_ORIG_MESSAGE_CLASS */
+
+#define attOwner                    ATT( atpByte,       0x0000) /* PR_RCVD_REPRESENTING_xxx  or
+                                                                                                                                      PR_SENT_REPRESENTING_xxx */
+#define attSentFor                  ATT( atpByte,       0x0001) /* PR_SENT_REPRESENTING_xxx */
+#define attDelegate                 ATT( atpByte,       0x0002) /* PR_RCVD_REPRESENTING_xxx */
+#define attDateStart                ATT( atpDate,       0x0006) /* PR_DATE_START */
+#define attDateEnd                  ATT( atpDate,       0x0007) /* PR_DATE_END */
+#define attAidOwner                 ATT( atpLong,       0x0008) /* PR_OWNER_APPT_ID */
+#define attRequestRes               ATT( atpShort,      0x0009) /* PR_RESPONSE_REQUESTED */
+
+typedef struct {
+    DWORD id;
+    char name[40];
+    int (*handler) STD_ARGLIST;
+} TNEFHandler;
+
+
+#endif