talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit 260386baa47e01160d2458a8c1af626260c45eda
parent 0880b6433517052e9bd405947e62003392811590
Author: Colin Leroy <colin@colino.net>
Date:   Wed, 20 Feb 2013 08:45:59 +0000

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

Diffstat:
MChangeLog | 28++++++++++++++++++++++++++++
MPATCHSETS | 1+
Mconfigure.ac | 37+++++++++++++++++++++++++++++++++++--
Msrc/plugins/Makefile.am | 14++++++++++++--
Asrc/plugins/spam_report/.cvsignore | 7+++++++
Asrc/plugins/spam_report/Makefile.am | 31+++++++++++++++++++++++++++++++
Dsrc/plugins/spam_report/placeholder.txt | 1-
Asrc/plugins/spam_report/spam_report.c | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/spam_report/spam_report_prefs.c | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/spam_report/spam_report_prefs.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/.cvsignore | 7+++++++
Asrc/plugins/tnef_parse/Makefile.am | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/claws.def | 17+++++++++++++++++
Asrc/plugins/tnef_parse/mapi.h | 29+++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/mapidefs.h | 433+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/mapitags.h | 432+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/plugins/tnef_parse/placeholder.txt | 1-
Asrc/plugins/tnef_parse/plugin.def | 10++++++++++
Asrc/plugins/tnef_parse/tnef-errors.h | 16++++++++++++++++
Asrc/plugins/tnef_parse/tnef-types.h | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/tnef_dump.c | 947+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/tnef_dump.h | 28++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/tnef_parse.c | 435+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/version.rc | 36++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/ytnef.c | 1434+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/tnef_parse/ytnef.h | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
26 files changed, 4951 insertions(+), 6 deletions(-)

diff --git 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 diff --git a/PATCHSETS b/PATCHSETS @@ -4580,3 +4580,4 @@ ( 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 diff --git a/configure.ac b/configure.ac @@ -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 diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am @@ -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 @@ -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 @@ -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 @@ -1 +0,0 @@ -Placeholder diff --git a/src/plugins/spam_report/spam_report.c b/src/plugins/spam_report/spam_report.c @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -1 +0,0 @@ -Placeholder diff --git a/src/plugins/tnef_parse/plugin.def b/src/plugins/tnef_parse/plugin.def @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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