diff --git a/src/mimemaker.cpp b/src/mimemaker.cpp index cfc2abb..18bc271 100644 --- a/src/mimemaker.cpp +++ b/src/mimemaker.cpp @@ -1,2224 +1,2303 @@ /* mimemaker.c - Construct MIME message out of a MAPI * Copyright (C) 2007, 2008 g10 Code GmbH * Copyright (C) 2015 Intevation GmbH * * This file is part of GpgOL. * * GpgOL is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * GpgOL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #define COBJMACROS #include #include #include "mymapi.h" #include "mymapitags.h" #include "common.h" #include "engine.h" #include "mapihelp.h" #include "mimemaker.h" #include "oomhelp.h" #include "gpgolstr.h" #include "mail.h" static const unsigned char oid_mimetag[] = {0x2A, 0x86, 0x48, 0x86, 0xf7, 0x14, 0x03, 0x0a, 0x04}; /* The base-64 list used for base64 encoding. */ static unsigned char bintoasc[64+1] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"); /* Object used to collect data in a memory buffer. */ struct databuf_s { size_t len; /* Used length. */ size_t size; /* Allocated length of BUF. */ char *buf; /* Malloced buffer. */ }; /*** local prototypes ***/ static int write_multistring (sink_t sink, const char *text1, ...) GPGOL_GCC_A_SENTINEL(0); /* Standard write method used with a sink_t object. */ int sink_std_write (sink_t sink, const void *data, size_t datalen) { HRESULT hr; LPSTREAM stream = static_cast(sink->cb_data); if (!stream) { log_error ("%s:%s: sink not setup for writing", SRCNAME, __func__); return -1; } if (!data) return 0; /* Flush - nothing to do here. */ hr = stream->Write(data, datalen, NULL); if (hr) { log_error ("%s:%s: Write failed: hr=%#lx", SRCNAME, __func__, hr); return -1; } return 0; } /* Write method used with a sink_t that contains a file object. */ int sink_file_write (sink_t sink, const void *data, size_t datalen) { HANDLE hFile = sink->cb_data; DWORD written = 0; if (!hFile || hFile == INVALID_HANDLE_VALUE) { log_error ("%s:%s: sink not setup for writing", SRCNAME, __func__); return -1; } if (!data) return 0; /* Flush - nothing to do here. */ if (!WriteFile (hFile, data, datalen, &written, NULL)) { log_error ("%s:%s: Write failed: ", SRCNAME, __func__); return -1; } return 0; } /* Make sure that PROTOCOL is usable or return a suitable protocol. On error PROTOCOL_UNKNOWN is returned. */ static protocol_t check_protocol (protocol_t protocol) { switch (protocol) { case PROTOCOL_UNKNOWN: return PROTOCOL_UNKNOWN; case PROTOCOL_OPENPGP: case PROTOCOL_SMIME: return protocol; } log_error ("%s:%s: BUG", SRCNAME, __func__); return PROTOCOL_UNKNOWN; } /* Create a new MAPI attchment for MESSAGE which will be used to prepare the MIME message. On sucess the stream to write the data to is stored at STREAM and the attachment object itself is returned. The caller needs to call SaveChanges. Returns NULL on failure in which case STREAM will be set to NULL. */ static LPATTACH create_mapi_attachment (LPMESSAGE message, sink_t sink) { HRESULT hr; ULONG pos; SPropValue prop; LPATTACH att = NULL; LPUNKNOWN punk; sink->cb_data = NULL; sink->writefnc = NULL; hr = message->CreateAttach(NULL, 0, &pos, &att); if (hr) { log_error ("%s:%s: can't create attachment: hr=%#lx\n", SRCNAME, __func__, hr); return NULL; } prop.ulPropTag = PR_ATTACH_METHOD; prop.Value.ul = ATTACH_BY_VALUE; hr = HrSetOneProp ((LPMAPIPROP)att, &prop); if (hr) { log_error ("%s:%s: can't set attach method: hr=%#lx\n", SRCNAME, __func__, hr); goto failure; } /* Mark that attachment so that we know why it has been created. */ if (get_gpgolattachtype_tag (message, &prop.ulPropTag) ) goto failure; prop.Value.l = ATTACHTYPE_MOSSTEMPL; hr = HrSetOneProp ((LPMAPIPROP)att, &prop); if (hr) { log_error ("%s:%s: can't set %s property: hr=%#lx\n", SRCNAME, __func__, "GpgOL Attach Type", hr); goto failure; } /* We better insert a short filename. */ prop.ulPropTag = PR_ATTACH_FILENAME_A; prop.Value.lpszA = strdup (MIMEATTACHFILENAME); hr = HrSetOneProp ((LPMAPIPROP)att, &prop); xfree (prop.Value.lpszA); if (hr) { log_error ("%s:%s: can't set attach filename: hr=%#lx\n", SRCNAME, __func__, hr); goto failure; } /* Even for encrypted messages we need to set the MAPI property to multipart/signed. This seems to be a part of the trigger which leads OL to process such a message in a special way. */ prop.ulPropTag = PR_ATTACH_TAG; prop.Value.bin.cb = sizeof oid_mimetag; prop.Value.bin.lpb = (LPBYTE)oid_mimetag; hr = HrSetOneProp ((LPMAPIPROP)att, &prop); if (!hr) { prop.ulPropTag = PR_ATTACH_MIME_TAG_A; prop.Value.lpszA = strdup("multipart/signed"); hr = HrSetOneProp ((LPMAPIPROP)att, &prop); xfree (prop.Value.lpszA); } if (hr) { log_error ("%s:%s: can't set attach mime tag: hr=%#lx\n", SRCNAME, __func__, hr); goto failure; } punk = NULL; hr = att->OpenProperty(PR_ATTACH_DATA_BIN, &IID_IStream, 0, (MAPI_CREATE|MAPI_MODIFY), &punk); if (FAILED (hr)) { log_error ("%s:%s: can't create output stream: hr=%#lx\n", SRCNAME, __func__, hr); goto failure; } sink->cb_data = (LPSTREAM)punk; sink->writefnc = sink_std_write; return att; failure: gpgol_release (att); return NULL; } /* Write data to a sink_t. */ int write_buffer (sink_t sink, const void *data, size_t datalen) { if (!sink || !sink->writefnc) { log_error ("%s:%s: sink not properly setup", SRCNAME, __func__); return -1; } return sink->writefnc (sink, data, datalen); } /* Same as above but used for passing as callback function. This fucntion does not return an error code but the number of bytes written. */ int write_buffer_for_cb (void *opaque, const void *data, size_t datalen) { sink_t sink = (sink_t) opaque; sink->enc_counter += datalen; return write_buffer (sink, data, datalen) ? -1 : datalen; } /* Write the string TEXT to the IStream STREAM. Returns 0 on sucsess, prints an error message and returns -1 on error. */ static int write_string (sink_t sink, const char *text) { return write_buffer (sink, text, strlen (text)); } /* Write the string TEXT1 and all folloing arguments of type (const char*) to the SINK. The list of argumens needs to be terminated with a NULL. Returns 0 on sucsess, prints an error message and returns -1 on error. */ static int write_multistring (sink_t sink, const char *text1, ...) { va_list arg_ptr; int rc; const char *s; va_start (arg_ptr, text1); s = text1; do rc = write_string (sink, s); while (!rc && (s=va_arg (arg_ptr, const char *))); va_end (arg_ptr); return rc; } /* Helper to write a boundary to the output sink. The leading LF will be written as well. */ static int write_boundary (sink_t sink, const char *boundary, int lastone) { int rc = write_string (sink, "\r\n--"); if (!rc) rc = write_string (sink, boundary); if (!rc) rc = write_string (sink, lastone? "--\r\n":"\r\n"); return rc; } /* Write DATALEN bytes of DATA to SINK in base64 encoding. This creates a complete Base64 chunk including the trailing fillers. */ static int write_b64 (sink_t sink, const void *data, size_t datalen) { int rc; const unsigned char *p; unsigned char inbuf[4]; int idx, quads; char outbuf[2048]; size_t outlen; log_debug (" writing base64 of length %d\n", (int)datalen); idx = quads = 0; outlen = 0; for (p = (const unsigned char*)data; datalen; p++, datalen--) { inbuf[idx++] = *p; if (idx > 2) { /* We need space for a quad and a possible CR,LF. */ if (outlen+4+2 >= sizeof outbuf) { if ((rc = write_buffer (sink, outbuf, outlen))) return rc; outlen = 0; } outbuf[outlen++] = bintoasc[(*inbuf>>2)&077]; outbuf[outlen++] = bintoasc[(((*inbuf<<4)&060) |((inbuf[1] >> 4)&017))&077]; outbuf[outlen++] = bintoasc[(((inbuf[1]<<2)&074) |((inbuf[2]>>6)&03))&077]; outbuf[outlen++] = bintoasc[inbuf[2]&077]; idx = 0; if (++quads >= (64/4)) { quads = 0; outbuf[outlen++] = '\r'; outbuf[outlen++] = '\n'; } } } /* We need space for a quad and a final CR,LF. */ if (outlen+4+2 >= sizeof outbuf) { if ((rc = write_buffer (sink, outbuf, outlen))) return rc; outlen = 0; } if (idx) { outbuf[outlen++] = bintoasc[(*inbuf>>2)&077]; if (idx == 1) { outbuf[outlen++] = bintoasc[((*inbuf<<4)&060)&077]; outbuf[outlen++] = '='; outbuf[outlen++] = '='; } else { outbuf[outlen++] = bintoasc[(((*inbuf<<4)&060) |((inbuf[1]>>4)&017))&077]; outbuf[outlen++] = bintoasc[((inbuf[1]<<2)&074)&077]; outbuf[outlen++] = '='; } ++quads; } if (quads) { outbuf[outlen++] = '\r'; outbuf[outlen++] = '\n'; } if (outlen) { if ((rc = write_buffer (sink, outbuf, outlen))) return rc; } return 0; } /* Write DATALEN bytes of DATA to SINK in quoted-prinable encoding. */ static int write_qp (sink_t sink, const void *data, size_t datalen) { int rc; const unsigned char *p; char outbuf[80]; /* We only need 76 octect + 2 for the lineend. */ int outidx; /* Check whether the current character is followed by a line ending. Note that the end of the etxt also counts as a lineending */ #define nextlf_p() ((datalen > 2 && p[1] == '\r' && p[2] == '\n') \ || (datalen > 1 && p[1] == '\n') \ || datalen == 1 ) /* Macro to insert a soft line break if needed. */ # define do_softlf(n) \ do { \ if (outidx + (n) > 76 \ || (outidx + (n) == 76 && !nextlf_p())) \ { \ outbuf[outidx++] = '='; \ outbuf[outidx++] = '\r'; \ outbuf[outidx++] = '\n'; \ if ((rc = write_buffer (sink, outbuf, outidx))) \ return rc; \ outidx = 0; \ } \ } while (0) log_debug (" writing qp of length %d\n", (int)datalen); outidx = 0; for (p = (const unsigned char*) data; datalen; p++, datalen--) { if ((datalen > 1 && *p == '\r' && p[1] == '\n') || *p == '\n') { /* Line break. */ outbuf[outidx++] = '\r'; outbuf[outidx++] = '\n'; if ((rc = write_buffer (sink, outbuf, outidx))) return rc; outidx = 0; if (*p == '\r') { p++; datalen--; } } else if (*p == '\t' || *p == ' ') { /* Check whether tab or space is followed by a line break which forbids verbatim encoding. If we are already at the end of the buffer we take that as a line end too. */ if (nextlf_p()) { do_softlf (3); outbuf[outidx++] = '='; outbuf[outidx++] = tohex ((*p>>4)&15); outbuf[outidx++] = tohex (*p&15); } else { do_softlf (1); outbuf[outidx++] = *p; } } else if (!outidx && *p == '.' && nextlf_p () ) { /* We better protect a line with just a single dot. */ outbuf[outidx++] = '='; outbuf[outidx++] = tohex ((*p>>4)&15); outbuf[outidx++] = tohex (*p&15); } else if (!outidx && datalen >= 5 && !memcmp (p, "From ", 5)) { /* Protect the 'F' so that MTAs won't prefix the "From " with an '>' */ outbuf[outidx++] = '='; outbuf[outidx++] = tohex ((*p>>4)&15); outbuf[outidx++] = tohex (*p&15); } else if (*p >= '!' && *p <= '~' && *p != '=') { do_softlf (1); outbuf[outidx++] = *p; } else { do_softlf (3); outbuf[outidx++] = '='; outbuf[outidx++] = tohex ((*p>>4)&15); outbuf[outidx++] = tohex (*p&15); } } if (outidx) { outbuf[outidx++] = '\r'; outbuf[outidx++] = '\n'; if ((rc = write_buffer (sink, outbuf, outidx))) return rc; } # undef do_softlf # undef nextlf_p return 0; } /* Write DATALEN bytes of DATA to SINK in plain ascii encoding. */ static int write_plain (sink_t sink, const void *data, size_t datalen) { int rc; const unsigned char *p; char outbuf[100]; int outidx; log_debug (" writing ascii of length %d\n", (int)datalen); outidx = 0; for (p = (const unsigned char*) data; datalen; p++, datalen--) { if ((datalen > 1 && *p == '\r' && p[1] == '\n') || *p == '\n') { outbuf[outidx++] = '\r'; outbuf[outidx++] = '\n'; if ((rc = write_buffer (sink, outbuf, outidx))) return rc; outidx = 0; if (*p == '\r') { p++; datalen--; } } else if (!outidx && *p == '.' && ( (datalen > 2 && p[1] == '\r' && p[2] == '\n') || (datalen > 1 && p[1] == '\n') || datalen == 1)) { /* Better protect a line with just a single dot. We do this by adding a space. */ outbuf[outidx++] = *p; outbuf[outidx++] = ' '; } else if (outidx > 80) { /* We should never be called for too long lines - QP should have been used. */ log_error ("%s:%s: BUG: line longer than exepcted", SRCNAME, __func__); return -1; } else outbuf[outidx++] = *p; } if (outidx) { outbuf[outidx++] = '\r'; outbuf[outidx++] = '\n'; if ((rc = write_buffer (sink, outbuf, outidx))) return rc; } return 0; } /* Infer the conent type from the FILENAME. The return value is a static string there won't be an error return. In case Bae 64 encoding is required for the type true will be stored at FORCE_B64; however, this is only a shortcut and if that is not set, the caller should infer the encoding by other means. */ static const char * infer_content_type (const char * /*data*/, size_t /*datalen*/, const char *filename, int is_mapibody, int *force_b64) { static struct { char b64; const char *suffix; const char *ct; } suffix_table[] = { { 1, "3gp", "video/3gpp" }, { 1, "abw", "application/x-abiword" }, { 1, "ai", "application/postscript" }, { 1, "au", "audio/basic" }, { 1, "bin", "application/octet-stream" }, { 1, "class", "application/java-vm" }, { 1, "cpt", "application/mac-compactpro" }, { 0, "css", "text/css" }, { 0, "csv", "text/comma-separated-values" }, { 1, "deb", "application/x-debian-package" }, { 1, "dl", "video/dl" }, { 1, "doc", "application/msword" }, { 1, "dv", "video/dv" }, { 1, "dvi", "application/x-dvi" }, { 1, "eml", "message/rfc822" }, { 1, "eps", "application/postscript" }, { 1, "fig", "application/x-xfig" }, { 1, "flac", "application/x-flac" }, { 1, "fli", "video/fli" }, { 1, "gif", "image/gif" }, { 1, "gl", "video/gl" }, { 1, "gnumeric", "application/x-gnumeric" }, { 1, "hqx", "application/mac-binhex40" }, { 1, "hta", "application/hta" }, { 0, "htm", "text/html" }, { 0, "html", "text/html" }, { 0, "ics", "text/calendar" }, { 1, "jar", "application/java-archive" }, { 1, "jpeg", "image/jpeg" }, { 1, "jpg", "image/jpeg" }, { 1, "js", "application/x-javascript" }, { 1, "latex", "application/x-latex" }, { 1, "lha", "application/x-lha" }, { 1, "lzh", "application/x-lzh" }, { 1, "lzx", "application/x-lzx" }, { 1, "m3u", "audio/mpegurl" }, { 1, "m4a", "audio/mpeg" }, { 1, "mdb", "application/msaccess" }, { 1, "midi", "audio/midi" }, { 1, "mov", "video/quicktime" }, { 1, "mp2", "audio/mpeg" }, { 1, "mp3", "audio/mpeg" }, { 1, "mp4", "video/mp4" }, { 1, "mpeg", "video/mpeg" }, { 1, "mpega", "audio/mpeg" }, { 1, "mpg", "video/mpeg" }, { 1, "mpga", "audio/mpeg" }, { 1, "msi", "application/x-msi" }, { 1, "mxu", "video/vnd.mpegurl" }, { 1, "nb", "application/mathematica" }, { 1, "oda", "application/oda" }, { 1, "odb", "application/vnd.oasis.opendocument.database" }, { 1, "odc", "application/vnd.oasis.opendocument.chart" }, { 1, "odf", "application/vnd.oasis.opendocument.formula" }, { 1, "odg", "application/vnd.oasis.opendocument.graphics" }, { 1, "odi", "application/vnd.oasis.opendocument.image" }, { 1, "odm", "application/vnd.oasis.opendocument.text-master" }, { 1, "odp", "application/vnd.oasis.opendocument.presentation" }, { 1, "ods", "application/vnd.oasis.opendocument.spreadsheet" }, { 1, "odt", "application/vnd.oasis.opendocument.text" }, { 1, "ogg", "application/ogg" }, { 1, "otg", "application/vnd.oasis.opendocument.graphics-template" }, { 1, "oth", "application/vnd.oasis.opendocument.text-web" }, { 1, "otp", "application/vnd.oasis.opendocument.presentation-template"}, { 1, "ots", "application/vnd.oasis.opendocument.spreadsheet-template"}, { 1, "ott", "application/vnd.oasis.opendocument.text-template" }, { 1, "pdf", "application/pdf" }, { 1, "png", "image/png" }, { 1, "pps", "application/vnd.ms-powerpoint" }, { 1, "ppt", "application/vnd.ms-powerpoint" }, { 1, "prf", "application/pics-rules" }, { 1, "ps", "application/postscript" }, { 1, "qt", "video/quicktime" }, { 1, "rar", "application/rar" }, { 1, "rdf", "application/rdf+xml" }, { 1, "rpm", "application/x-redhat-package-manager" }, { 0, "rss", "application/rss+xml" }, { 1, "ser", "application/java-serialized-object" }, { 0, "sh", "application/x-sh" }, { 0, "shtml", "text/html" }, { 1, "sid", "audio/prs.sid" }, { 0, "smil", "application/smil" }, { 1, "snd", "audio/basic" }, { 0, "svg", "image/svg+xml" }, { 1, "tar", "application/x-tar" }, { 0, "texi", "application/x-texinfo" }, { 0, "texinfo", "application/x-texinfo" }, { 1, "tif", "image/tiff" }, { 1, "tiff", "image/tiff" }, { 1, "torrent", "application/x-bittorrent" }, { 1, "tsp", "application/dsptype" }, { 0, "vrml", "model/vrml" }, { 1, "vsd", "application/vnd.visio" }, { 1, "wp5", "application/wordperfect5.1" }, { 1, "wpd", "application/wordperfect" }, { 0, "xhtml", "application/xhtml+xml" }, { 1, "xlb", "application/vnd.ms-excel" }, { 1, "xls", "application/vnd.ms-excel" }, { 1, "xlt", "application/vnd.ms-excel" }, { 0, "xml", "application/xml" }, { 0, "xsl", "application/xml" }, { 0, "xul", "application/vnd.mozilla.xul+xml" }, { 1, "zip", "application/zip" }, { 0, NULL, NULL } }; int i; std::string suffix; *force_b64 = 0; if (filename) suffix = strrchr (filename, '.'); if (!suffix.empty()) { suffix.erase(0, 1); std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower); for (i=0; suffix_table[i].suffix; i++) { if (!strcmp (suffix_table[i].suffix, suffix.c_str())) { if (suffix_table[i].b64) *force_b64 = 1; return suffix_table[i].ct; } } } /* Not found via filename, look at the content. */ if (is_mapibody == 1) { return "text/plain"; } else if (is_mapibody == 2) { return "text/html"; } return "application/octet-stream"; } /* Figure out the best encoding to be used for the part. Return values are 0: Plain ASCII. 1: Quoted Printable 2: Base64 */ static int infer_content_encoding (const void *data, size_t datalen) { const unsigned char *p; int need_qp; size_t len, maxlen, highbin, lowbin, ntotal; ntotal = datalen; len = maxlen = lowbin = highbin = 0; need_qp = 0; for (p = (const unsigned char*) data; datalen; p++, datalen--) { len++; if ((*p & 0x80)) highbin++; else if ((datalen > 1 && *p == '\r' && p[1] == '\n') || *p == '\n') { len--; if (len > maxlen) maxlen = len; len = 0; } else if (*p == '\r') { /* CR not followed by a linefeed. */ lowbin++; } else if (*p == '\t' || *p == ' ' || *p == '\f') ; else if (*p < ' ' || *p == 127) lowbin++; else if (len == 1 && datalen > 2 && *p == '-' && p[1] == '-' && p[2] == ' ' && ( (datalen > 4 && p[3] == '\r' && p[4] == '\n') || (datalen > 3 && p[3] == '\n') || datalen == 3)) { /* This is a "-- \r\n" line, thus it indicates the usual signature line delimiter. We need to protect the trailing space. */ need_qp = 1; } else if (len == 1 && datalen > 5 && !memcmp (p, "--=-=", 5)) { /* This look pretty much like a our own boundary. We better protect it by forcing QP encoding. */ need_qp = 1; } else if (len == 1 && datalen >= 5 && !memcmp (p, "From ", 5)) { /* The usual From hack is required so that MTAs do not prefix it with an '>'. */ need_qp = 1; } } if (len > maxlen) maxlen = len; if (maxlen <= 76 && !lowbin && !highbin && !need_qp) return 0; /* Plain ASCII is sufficient. */ /* Somewhere in the Outlook documentation 20% is mentioned as discriminating value for Base64. Though our counting won't be identical we use that value to behave closely to it. */ if (ntotal && ((float)(lowbin+highbin))/ntotal < 0.20) return 1; /* Use quoted printable. */ return 2; /* Use base64. */ } /* Convert an utf8 input string to RFC2047 base64 encoding which is the subset of RFC2047 outlook likes. Return value needs to be freed. */ static char * utf8_to_rfc2047b (const char *input) { char *ret, *encoded; int inferred_encoding = 0; if (!input) { return NULL; } inferred_encoding = infer_content_encoding (input, strlen (input)); if (!inferred_encoding) { return xstrdup (input); } log_debug ("%s:%s: Encoding attachment filename. With: %s ", SRCNAME, __func__, inferred_encoding == 2 ? "Base64" : "QP"); if (inferred_encoding == 2) { encoded = b64_encode (input, strlen (input)); if (gpgrt_asprintf (&ret, "=?utf-8?B?%s?=", encoded) == -1) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); xfree (encoded); return NULL; } } else { /* There is a Bug here. If you encode 4 Byte UTF-8 outlook can't handle it itself. And sends out a message with ?? inserted in that place. This triggers an invalid signature. */ encoded = qp_encode (input, strlen (input), NULL); if (gpgrt_asprintf (&ret, "=?utf-8?Q?%s?=", encoded) == -1) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); xfree (encoded); return NULL; } } xfree (encoded); return ret; } /* Write a MIME part to SINK. First the BOUNDARY is written (unless it is NULL) then the DATA is analyzed and appropriate headers are written. If FILENAME is given it will be added to the part's header. IS_MAPIBODY should be passed as true if the data has been retrieved from the body property. */ static int write_part (sink_t sink, const char *data, size_t datalen, - const char *boundary, const char *filename, int is_mapibody) + const char *boundary, const char *filename, int is_mapibody, + const char *content_id = NULL) { int rc; const char *ct; int use_b64, use_qp, is_text; char *encoded_filename; if (filename) { /* If there is a filename strip the directory part. Take care that there might be slashes or backslashes. */ const char *s1 = strrchr (filename, '/'); const char *s2 = strrchr (filename, '\\'); if (!s1) s1 = s2; else if (s1 && s2 && s2 > s1) s1 = s2; if (s1) filename = s1; if (*filename && filename[1] == ':') filename += 2; if (!*filename) filename = NULL; } log_debug ("Writing part of length %d%s filename=`%s'\n", (int)datalen, is_mapibody? " (body)":"", filename?filename:"[none]"); ct = infer_content_type (data, datalen, filename, is_mapibody, &use_b64); use_qp = 0; if (!use_b64) { switch (infer_content_encoding (data, datalen)) { case 0: break; case 1: use_qp = 1; break; default: use_b64 = 1; break; } } is_text = !strncmp (ct, "text/", 5); if (boundary) if ((rc = write_boundary (sink, boundary, 0))) return rc; if ((rc=write_multistring (sink, "Content-Type: ", ct, (is_text || filename? ";\r\n" :"\r\n"), NULL))) return rc; /* OL inserts a charset parameter in many cases, so we do it right away for all text parts. We can assume us-ascii if no special encoding is required. */ if (is_text) if ((rc=write_multistring (sink, "\tcharset=\"", (!use_qp && !use_b64? "us-ascii" : "utf-8"), filename ? "\";\r\n" : "\"\r\n", NULL))) return rc; encoded_filename = utf8_to_rfc2047b (filename); if (encoded_filename) if ((rc=write_multistring (sink, "\tname=\"", encoded_filename, "\"\r\n", NULL))) return rc; /* Note that we need to output even 7bit because OL inserts that anyway. */ if ((rc = write_multistring (sink, "Content-Transfer-Encoding: ", (use_b64? "base64\r\n": use_qp? "quoted-printable\r\n":"7bit\r\n"), NULL))) return rc; - if (encoded_filename) + if (content_id) + { + if ((rc=write_multistring (sink, + "Content-ID: <", content_id, ">\r\n", + NULL))) + return rc; + } + else if (encoded_filename) if ((rc=write_multistring (sink, "Content-Disposition: attachment;\r\n" "\tfilename=\"", encoded_filename, "\"\r\n", NULL))) return rc; xfree(encoded_filename); /* Write delimiter. */ if ((rc = write_string (sink, "\r\n"))) return rc; /* Write the content. */ if (use_b64) rc = write_b64 (sink, data, datalen); else if (use_qp) rc = write_qp (sink, data, datalen); else rc = write_plain (sink, data, datalen); return rc; } /* Return the number of attachments in TABLE to be put into the MIME message. */ static int count_usable_attachments (mapi_attach_item_t *table) { int idx, count = 0; if (table) for (idx=0; !table[idx].end_of_table; idx++) if (table[idx].attach_type == ATTACHTYPE_UNKNOWN && table[idx].method == ATTACH_BY_VALUE) count++; return count; } /* Write out all attachments from TABLE separated by BOUNDARY to SINK. - This function needs to be syncronized with count_usable_attachments. */ + This function needs to be syncronized with count_usable_attachments. + If only_related is 1 only include attachments for multipart/related they + are excluded otherwise. */ static int write_attachments (sink_t sink, LPMESSAGE message, mapi_attach_item_t *table, - const char *boundary) + const char *boundary, int only_related) { int idx, rc; char *buffer; size_t buflen; if (table) for (idx=0; !table[idx].end_of_table; idx++) if (table[idx].attach_type == ATTACHTYPE_UNKNOWN && table[idx].method == ATTACH_BY_VALUE) { + if (only_related && !table[idx].content_id) + { + continue; + } + else if (!only_related && table[idx].content_id) + { + continue; + } buffer = mapi_get_attach (message, 0, table+idx, &buflen); if (!buffer) log_debug ("Attachment at index %d not found\n", idx); else log_debug ("Attachment at index %d: length=%d\n", idx, (int)buflen); if (!buffer) return -1; rc = write_part (sink, buffer, buflen, boundary, - table[idx].filename, 0); + table[idx].filename, 0, table[idx].content_id); if (rc) { log_error ("Write part returned err: %i", rc); } xfree (buffer); } return 0; } +/* Returns 1 if all attachments are related. 2 if there is a + related and a mixed attachment. 0 if there are no other parts*/ +static int +is_related (Mail *mail, mapi_attach_item_t *table) +{ + if (!mail || !mail->is_html_alternative () || !table) + { + return 0; + } + + int related = 0; + int mixed = 0; + for (int idx = 0; !table[idx].end_of_table; idx++) + { + if (table[idx].content_id) + { + related = 1; + } + else + { + mixed = 1; + } + } + return mixed + related; +} /* Delete all attachments from TABLE except for the one we just created */ static int delete_all_attachments (LPMESSAGE message, mapi_attach_item_t *table) { HRESULT hr; int idx; if (table) for (idx=0; !table[idx].end_of_table; idx++) { if (table[idx].attach_type == ATTACHTYPE_MOSSTEMPL && table[idx].filename && !strcmp (table[idx].filename, MIMEATTACHFILENAME)) continue; hr = message->DeleteAttach (table[idx].mapipos, 0, NULL, 0); if (hr) { log_error ("%s:%s: DeleteAttach failed: hr=%#lx\n", SRCNAME, __func__, hr); return -1; } } return 0; } /* Commit changes to the attachment ATTACH and release the object. SINK needs to be passed as well and will also be closed. Note that the address of ATTACH is expected so that the fucntion can set it to NULL. */ static int close_mapi_attachment (LPATTACH *attach, sink_t sink) { HRESULT hr; LPSTREAM stream = sink ? (LPSTREAM) sink->cb_data : NULL; if (!stream) { log_error ("%s:%s: sink not setup", SRCNAME, __func__); return -1; } hr = stream->Commit (0); if (hr) { log_error ("%s:%s: Commiting output stream failed: hr=%#lx", SRCNAME, __func__, hr); return -1; } gpgol_release (stream); sink->cb_data = NULL; hr = (*attach)->SaveChanges (0); if (hr) { log_error ("%s:%s: SaveChanges of the attachment failed: hr=%#lx\n", SRCNAME, __func__, hr); return -1; } gpgol_release ((*attach)); *attach = NULL; return 0; } /* Cancel changes to the attachment ATTACH and release the object. SINK needs to be passed as well and will also be closed. Note that the address of ATTACH is expected so that the fucntion can set it to NULL. */ static void cancel_mapi_attachment (LPATTACH *attach, sink_t sink) { LPSTREAM stream = sink ? (LPSTREAM) sink->cb_data : NULL; if (stream) { stream->Revert(); gpgol_release (stream); sink->cb_data = NULL; } if (*attach) { /* Fixme: Should we try to delete it or is there a Revert method? */ gpgol_release ((*attach)); *attach = NULL; } } /* Do the final processing for a message. */ static int finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table, protocol_t protocol, int encrypt) { HRESULT hr; SPropValue prop; /* Set the message class. */ prop.ulPropTag = PR_MESSAGE_CLASS_A; if (encrypt) { prop.Value.lpszA = strdup ("IPM.Note.InfoPathForm.GpgOL.SMIME.MultipartSigned"); } else { prop.Value.lpszA = strdup ("IPM.Note.InfoPathForm.GpgOLS.SMIME.MultipartSigned"); } hr = message->SetProps(1, &prop, NULL); xfree(prop.Value.lpszA); if (hr) { log_error ("%s:%s: error setting the message class: hr=%#lx\n", SRCNAME, __func__, hr); return -1; } /* Set a special property so that we are later able to identify messages signed or encrypted by us. */ if (mapi_set_sig_status (message, "@")) { log_error ("%s:%s: error setting sigstatus", SRCNAME, __func__); return -1; } /* We also need to set the message class into our custom property. This override is at least required for encrypted messages. */ if (mapi_set_gpgol_msg_class (message, (encrypt? (protocol == PROTOCOL_SMIME? "IPM.Note.GpgOL.OpaqueEncrypted" : "IPM.Note.GpgOL.MultipartEncrypted") : "IPM.Note.GpgOL.MultipartSigned"))) { log_error ("%s:%s: error setting gpgol msgclass", SRCNAME, __func__); return -1; } /* Now delete all parts of the MAPI message except for the one attachment we just created. */ if (delete_all_attachments (message, att_table)) { log_error ("%s:%s: error deleting attachments", SRCNAME, __func__); return -1; } /* Remove the draft info so that we don't leak the information on whether the message has been signed etc. */ mapi_set_gpgol_draft_info (message, NULL); if (mapi_save_changes (message, KEEP_OPEN_READWRITE|FORCE_SAVE)) { log_error ("%s:%s: error saving changes.", SRCNAME, __func__); return -1; } return 0; } /* Sink write method used by mime_sign. We write the data to the filter and also to the EXTRASINK but we don't pass a flush request to EXTRASINK. */ static int sink_hashing_write (sink_t hashsink, const void *data, size_t datalen) { int rc; engine_filter_t filter = (engine_filter_t) hashsink->cb_data; if (!filter || !hashsink->extrasink) { log_error ("%s:%s: sink not setup for writing", SRCNAME, __func__); return -1; } rc = engine_filter (filter, data, datalen); if (!rc && data && datalen) write_buffer (hashsink->extrasink, data, datalen); return rc; } /* This function is called by the filter to collect the output which is a detached signature. */ static int collect_signature (void *opaque, const void *data, size_t datalen) { struct databuf_s *db = (databuf_s *)opaque; if (db->len + datalen >= db->size) { db->size += datalen + 1024; db->buf = (char*) xrealloc (db->buf, db->size); } memcpy (db->buf + db->len, data, datalen); db->len += datalen; return datalen; } /* Helper to create the signing header. This includes enough space for later fixup of the micalg parameter. The MIME version is only written if FIRST is set. */ static void create_top_signing_header (char *buffer, size_t buflen, protocol_t protocol, int first, const char *boundary, const char *micalg) { snprintf (buffer, buflen, "%s" "Content-Type: multipart/signed;\r\n" "\tprotocol=\"application/%s\";\r\n" "\tmicalg=%-15.15s;\r\n" "\tboundary=\"%s\"\r\n" "\r\n", first? "MIME-Version: 1.0\r\n":"", (protocol==PROTOCOL_OPENPGP? "pgp-signature":"pkcs7-signature"), micalg, boundary); } /* Add the body, either as multipart/alternative or just as the simple body part. Depending on the format set in outlook. To avoid memory duplication it takes the plain body as parameter. Boundary is the potential outer boundary of a multipart/mixed mail. If it is null we assume the multipart/alternative is the only part. return is zero on success. */ static int add_body (Mail *mail, const char *boundary, sink_t sink, const char *plain_body) { if (!plain_body) { return 0; } bool is_alternative = false; if (mail) { is_alternative = mail->is_html_alternative (); } int rc = 0; if (!is_alternative || !plain_body) { if (plain_body) { rc = write_part (sink, plain_body, strlen (plain_body), *boundary? boundary : NULL, NULL, 1); } /* Just the plain body or no body. We are done. */ return rc; } /* Add a new multipart / mixed element. */ if (boundary && write_boundary (sink, boundary, 0)) { TRACEPOINT; return 1; } /* Now for the multipart/alternative part. We never do HTML only. */ char alt_boundary [BOUNDARYSIZE+1]; generate_boundary (alt_boundary); if ((rc=write_multistring (sink, "Content-Type: multipart/alternative;\r\n", "\tboundary=\"", alt_boundary, "\"\r\n", "\r\n", /* <-- extra line */ NULL))) { TRACEPOINT; return rc; } /* Now the plain body part */ if ((rc = write_part (sink, plain_body, strlen (plain_body), alt_boundary, NULL, 1))) { TRACEPOINT; return rc; } /* Now the html body. It is somehow not accessible through PR_HTML, OutlookSpy also shows MAPI Unsported (but shows the data) strange. We just cache it. Memory is cheap :-) */ const auto html_body = mail->get_cached_html_body(); if (html_body.empty()) { log_error ("%s:%s: BUG: Body but no html body in alternative mail?", SRCNAME, __func__); } rc = write_part (sink, html_body.c_str(), html_body.size(), alt_boundary, NULL, 2); if (rc) { TRACEPOINT; return rc; } /* Finish our multipart */ return write_boundary (sink, alt_boundary, 1); } +/* Add the body and attachments. Does multipart handling. */ +static int +add_body_and_attachments (sink_t sink, LPMESSAGE message, + mapi_attach_item_t *att_table, Mail *mail, + const char *body, int n_att_usable) +{ + int related = is_related (mail, att_table); + int rc = 0; + char inner_boundary[BOUNDARYSIZE+1]; + char outer_boundary[BOUNDARYSIZE+1]; + + if (((body && n_att_usable) || n_att_usable > 1) && related == 1) + { + /* A body and at least one attachment or more than one attachment */ + generate_boundary (outer_boundary); + if ((rc=write_multistring (sink, + "Content-Type: multipart/related;\r\n", + "\tboundary=\"", outer_boundary, "\"\r\n", + NULL))) + return rc; + } + else if ((body && n_att_usable) || n_att_usable > 1) + { + generate_boundary (outer_boundary); + if ((rc=write_multistring (sink, + "Content-Type: multipart/mixed;\r\n", + "\tboundary=\"", outer_boundary, "\"\r\n", + NULL))) + return rc; + } + else + /* Only one part. */ + *outer_boundary = 0; + + if (*outer_boundary && related == 2) + { + /* We have attachments that are related to the body and unrelated + attachments. So we need another part. */ + if ((rc=write_boundary (sink, outer_boundary, 0))) + { + return rc; + } + generate_boundary (inner_boundary); + if ((rc=write_multistring (sink, + "Content-Type: multipart/related;\r\n", + "\tboundary=\"", inner_boundary, "\"\r\n", + NULL))) + { + return rc; + } + } + else + { + *inner_boundary = 0; + } + + + if ((rc=add_body (mail, *inner_boundary ? inner_boundary : outer_boundary, + sink, body))) + { + log_error ("%s:%s: Adding the body failed.", + SRCNAME, __func__); + return rc; + } + if (!rc && n_att_usable && related) + { + /* Write the related attachments. */ + rc = write_attachments (sink, message, att_table, + *inner_boundary? inner_boundary : + *outer_boundary? outer_boundary : NULL, 1); + if (rc) + { + return rc; + } + /* Close the related part if neccessary.*/ + if (*inner_boundary && (rc=write_boundary (sink, inner_boundary, 1))) + { + return rc; + } + } + + /* Now write the other attachments */ + if (!rc && n_att_usable) + rc = write_attachments (sink, message, att_table, + *outer_boundary? outer_boundary : NULL, 0); + + /* Finish the possible multipart/mixed. */ + if (*outer_boundary && (rc = write_boundary (sink, outer_boundary, 1))) + return rc; + + return rc; +} /* Main body of mime_sign without the the code to delete the original attachments. On success the function returns the current attachment table at R_ATT_TABLE or sets this to NULL on error. If TMPSINK is set no attachment will be created but the output written to that sink. */ static int do_mime_sign (LPMESSAGE message, HWND hwnd, protocol_t protocol, mapi_attach_item_t **r_att_table, sink_t tmpsink, unsigned int session_number, const char *sender, Mail *mail) { int result = -1; int rc; LPATTACH attach = NULL; struct sink_s sinkmem; sink_t sink = &sinkmem; struct sink_s hashsinkmem; sink_t hashsink = &hashsinkmem; char boundary[BOUNDARYSIZE+1]; - char inner_boundary[BOUNDARYSIZE+1]; mapi_attach_item_t *att_table = NULL; char *body = NULL; int n_att_usable; char top_header[BOUNDARYSIZE+200]; engine_filter_t filter = NULL; struct databuf_s sigbuffer; char *my_sender = NULL; *r_att_table = NULL; memset (sink, 0, sizeof *sink); memset (hashsink, 0, sizeof *hashsink); memset (&sigbuffer, 0, sizeof sigbuffer); if (tmpsink) { attach = NULL; sink = tmpsink; } else { attach = create_mapi_attachment (message, sink); if (!attach) return -1; } /* Get the attachment info and the body. */ body = mapi_get_body (message, NULL); if (body && !*body) { xfree (body); body = NULL; } att_table = mapi_create_attach_table (message, 0); n_att_usable = count_usable_attachments (att_table); if (!n_att_usable && !body) { log_debug ("%s:%s: can't sign an empty message\n", SRCNAME, __func__); result = gpg_error (GPG_ERR_NO_DATA); goto failure; } /* Prepare the signing. */ if (engine_create_filter (&filter, collect_signature, &sigbuffer)) goto failure; if (session_number) { engine_set_session_number (filter, session_number); { char *tmp = mapi_get_subject (message); engine_set_session_title (filter, tmp); xfree (tmp); } } if (sender) my_sender = xstrdup (sender); else my_sender = mapi_get_sender (message); if (engine_sign_start (filter, hwnd, protocol, my_sender, &protocol)) goto failure; protocol = check_protocol (protocol); if (protocol == PROTOCOL_UNKNOWN) { log_error ("%s:%s: no protocol selected", SRCNAME, __func__); goto failure; } /* Write the top header. */ generate_boundary (boundary); create_top_signing_header (top_header, sizeof top_header, protocol, 1, boundary, "xxx"); if ((rc = write_string (sink, top_header))) goto failure; - /* Create the inner boundary if we have a body and at least one - attachment or more than one attachment. */ - if ((body && n_att_usable) || n_att_usable > 1) - generate_boundary (inner_boundary); - else - *inner_boundary = 0; - /* Write the boundary so that it is not included in the hashing. */ if ((rc = write_boundary (sink, boundary, 0))) goto failure; /* Create a new sink for hashing and write/hash our content. */ hashsink->cb_data = filter; hashsink->extrasink = sink; hashsink->writefnc = sink_hashing_write; - /* Note that OL2003 will add an extra line after the multipart - header, thus we do the same to avoid running all through an - IConverterSession first. */ - if (*inner_boundary - && (rc=write_multistring (hashsink, - "Content-Type: multipart/mixed;\r\n", - "\tboundary=\"", inner_boundary, "\"\r\n", - "\r\n", /* <-- extra line */ - NULL))) - goto failure; - - if ((rc=add_body (mail, inner_boundary, hashsink, body))) - { - log_error ("%s:%s: Adding the body failed.", - SRCNAME, __func__); - goto failure; - } - - if (!rc && n_att_usable) - rc = write_attachments (hashsink, message, att_table, - *inner_boundary? inner_boundary : NULL); - if (rc) + /* Add the plaintext */ + if (add_body_and_attachments (hashsink, message, att_table, mail, + body, n_att_usable)) goto failure; xfree (body); body = NULL; - /* Finish the possible multipart/mixed. */ - if (*inner_boundary && (rc = write_boundary (hashsink, inner_boundary, 1))) - goto failure; - /* Here we are ready with the hashing. Flush the filter and wait for the signing process to finish. */ if ((rc = write_buffer (hashsink, NULL, 0))) goto failure; if ((rc = engine_wait (filter))) goto failure; filter = NULL; /* Not valid anymore. */ hashsink->cb_data = NULL; /* Not needed anymore. */ /* Write signature attachment. */ if ((rc = write_boundary (sink, boundary, 0))) goto failure; if (protocol == PROTOCOL_OPENPGP) { rc = write_string (sink, "Content-Type: application/pgp-signature\r\n"); } else { rc = write_string (sink, "Content-Transfer-Encoding: base64\r\n" "Content-Type: application/pkcs7-signature\r\n"); /* rc = write_string (sink, */ /* "Content-Type: application/x-pkcs7-signature\r\n" */ /* "\tname=\"smime.p7s\"\r\n" */ /* "Content-Transfer-Encoding: base64\r\n" */ /* "Content-Disposition: attachment;\r\n" */ /* "\tfilename=\"smime.p7s\"\r\n"); */ } /* About the above code: If we would add "Content-Transfer-Encoding: 7bit\r\n" to this attachment, Outlooks does not proceed with sending and even does not return any error. A wild guess is that while OL adds this header itself, it detects that it already exists and somehow gets into a problem. It is not a problem with the other parts, though. Hmmm, triggered by the top levels CT protocol parameter? Anyway, it is not required that we add it as we won't hash it. Note, that this only holds for OpenPGP; for S/MIME we need to set set CTE. We even write it before the CT because that is the same as Outlook would do it for a missing CTE. */ if (rc) goto failure; if ((rc = write_string (sink, "\r\n"))) goto failure; /* Write the signature. We add an extra CR,LF which should not harm and a terminating 0. */ collect_signature (&sigbuffer, "\r\n", 3); if ((rc = write_string (sink, sigbuffer.buf))) goto failure; /* Write the final boundary and finish the attachment. */ if ((rc = write_boundary (sink, boundary, 1))) goto failure; /* Fixup the micalg parameter. */ { HRESULT hr; LARGE_INTEGER off; LPSTREAM stream = (LPSTREAM) sink->cb_data; off.QuadPart = 0; hr = stream->Seek (off, STREAM_SEEK_SET, NULL); if (hr) { log_error ("%s:%s: seeking back to the begin failed: hr=%#lx", SRCNAME, __func__, hr); goto failure; } create_top_signing_header (top_header, sizeof top_header, protocol, 1, boundary, protocol == PROTOCOL_SMIME? "sha1":"pgp-sha1"); hr = stream->Write (top_header, strlen (top_header), NULL); if (hr) { log_error ("%s:%s: writing fixed micalg failed: hr=%#lx", SRCNAME, __func__, hr); goto failure; } /* Better seek again to the end. */ off.QuadPart = 0; hr = stream->Seek (off, STREAM_SEEK_END, NULL); if (hr) { log_error ("%s:%s: seeking back to the end failed: hr=%#lx", SRCNAME, __func__, hr); goto failure; } } if (attach) { if (close_mapi_attachment (&attach, sink)) goto failure; } result = 0; /* Everything is fine, fall through the cleanup now. */ failure: engine_cancel (filter); if (attach) cancel_mapi_attachment (&attach, sink); xfree (body); if (result) mapi_release_attach_table (att_table); else *r_att_table = att_table; xfree (sigbuffer.buf); xfree (my_sender); return result; } /* Sign the MESSAGE using PROTOCOL. If PROTOCOL is PROTOCOL_UNKNOWN the engine decides what protocol to use. On return MESSAGE is modified so that sending it will result in a properly MOSS (that is PGP or S/MIME) signed message. On failure the function tries to keep the original message intact but there is no 100% guarantee for it. */ int mime_sign (LPMESSAGE message, HWND hwnd, protocol_t protocol, const char *sender, Mail *mail) { int result = -1; mapi_attach_item_t *att_table; result = do_mime_sign (message, hwnd, protocol, &att_table, 0, engine_new_session_number (), sender, mail); if (!result) { if (!finalize_message (message, att_table, protocol, 0)) result = 0; } mapi_release_attach_table (att_table); return result; } /* Sink write method used by mime_encrypt. */ int sink_encryption_write (sink_t encsink, const void *data, size_t datalen) { engine_filter_t filter = (engine_filter_t) encsink->cb_data; if (!filter) { log_error ("%s:%s: sink not setup for writing", SRCNAME, __func__); return -1; } return engine_filter (filter, data, datalen); } #if 0 /* Not used. */ /* Sink write method used by mime_encrypt for writing Base64. */ static int sink_encryption_write_b64 (sink_t encsink, const void *data, size_t datalen) { engine_filter_t filter = encsink->cb_data; int rc; const unsigned char *p; unsigned char inbuf[4]; int idx, quads; char outbuf[6]; size_t outbuflen; if (!filter) { log_error ("%s:%s: sink not setup for writing", SRCNAME, __func__); return -1; } idx = encsink->b64.idx; assert (idx < 4); memcpy (inbuf, encsink->b64.inbuf, idx); quads = encsink->b64.quads; if (!data) /* Flush. */ { outbuflen = 0; if (idx) { outbuf[0] = bintoasc[(*inbuf>>2)&077]; if (idx == 1) { outbuf[1] = bintoasc[((*inbuf<<4)&060)&077]; outbuf[2] = '='; outbuf[3] = '='; } else { outbuf[1] = bintoasc[(((*inbuf<<4)&060)| ((inbuf[1]>>4)&017))&077]; outbuf[2] = bintoasc[((inbuf[1]<<2)&074)&077]; outbuf[3] = '='; } outbuflen = 4; quads++; } if (quads) { outbuf[outbuflen++] = '\r'; outbuf[outbuflen++] = '\n'; } if (outbuflen && (rc = engine_filter (filter, outbuf, outbuflen))) return rc; /* Send the flush command to the filter. */ if ((rc = engine_filter (filter, data, datalen))) return rc; } else { for (p = data; datalen; p++, datalen--) { inbuf[idx++] = *p; if (idx > 2) { idx = 0; outbuf[0] = bintoasc[(*inbuf>>2)&077]; outbuf[1] = bintoasc[(((*inbuf<<4)&060) |((inbuf[1] >> 4)&017))&077]; outbuf[2] = bintoasc[(((inbuf[1]<<2)&074) |((inbuf[2]>>6)&03))&077]; outbuf[3] = bintoasc[inbuf[2]&077]; outbuflen = 4; if (++quads >= (64/4)) { quads = 0; outbuf[4] = '\r'; outbuf[5] = '\n'; outbuflen += 2; } if ((rc = engine_filter (filter, outbuf, outbuflen))) return rc; } } } encsink->b64.idx = idx; memcpy (encsink->b64.inbuf, inbuf, idx); encsink->b64.quads = quads; return 0; } #endif /*Not used.*/ /* Helper from mime_encrypt. BOUNDARY is a buffer of at least BOUNDARYSIZE+1 bytes which will be set on return from that function. */ static int create_top_encryption_header (sink_t sink, protocol_t protocol, char *boundary) { int rc; if (protocol == PROTOCOL_SMIME) { *boundary = 0; rc = write_multistring (sink, "MIME-Version: 1.0\r\n" "Content-Type: application/pkcs7-mime;\r\n" "\tsmime-type=enveloped-data;\r\n" "\tname=\"smime.p7m\"\r\n" "Content-Transfer-Encoding: base64\r\n" "\r\n", NULL); } else { generate_boundary (boundary); rc = write_multistring (sink, "MIME-Version: 1.0\r\n" "Content-Type: multipart/encrypted;\r\n" "\tprotocol=\"application/pgp-encrypted\";\r\n", "\tboundary=\"", boundary, "\"\r\n", NULL); if (rc) return rc; /* Write the PGP/MIME encrypted part. */ rc = write_boundary (sink, boundary, 0); if (rc) return rc; rc = write_multistring (sink, "Content-Type: application/pgp-encrypted\r\n" "\r\n" "Version: 1\r\n", NULL); if (rc) return rc; /* And start the second part. */ rc = write_boundary (sink, boundary, 0); if (rc) return rc; rc = write_multistring (sink, "Content-Type: application/octet-stream\r\n" "\r\n", NULL); } return rc; } /* Encrypt the MESSAGE. */ int mime_encrypt (LPMESSAGE message, HWND hwnd, protocol_t protocol, char **recipients, const char *sender, Mail* mail) { int result = -1; int rc; LPATTACH attach; struct sink_s sinkmem; sink_t sink = &sinkmem; struct sink_s encsinkmem; sink_t encsink = &encsinkmem; char boundary[BOUNDARYSIZE+1]; - char inner_boundary[BOUNDARYSIZE+1]; mapi_attach_item_t *att_table = NULL; char *body = NULL; int n_att_usable; engine_filter_t filter = NULL; char *my_sender = NULL; memset (sink, 0, sizeof *sink); memset (encsink, 0, sizeof *encsink); attach = create_mapi_attachment (message, sink); if (!attach) return -1; /* Get the attachment info and the body. We need to do this before creating the engine's filter sue problem sending the cancel to the engine with nothing for the engine to process. This is actually a bug in our engine code but we better avoid triggering this bug because the engine sometimes hangs. Fixme: Needs a proper fix. */ body = mapi_get_body (message, NULL); if (body && !*body) { xfree (body); body = NULL; } att_table = mapi_create_attach_table (message, 0); n_att_usable = count_usable_attachments (att_table); if (!n_att_usable && !body) { log_debug ("%s:%s: can't encrypt an empty message\n", SRCNAME, __func__); result = gpg_error (GPG_ERR_NO_DATA); goto failure; } /* Prepare the encryption. We do this early as it is quite common that some recipient keys are not available and thus the encryption will fail early. */ if (engine_create_filter (&filter, write_buffer_for_cb, sink)) goto failure; engine_set_session_number (filter, engine_new_session_number ()); { char *tmp = mapi_get_subject (message); engine_set_session_title (filter, tmp); xfree (tmp); } if (sender) my_sender = xstrdup (sender); else my_sender = mapi_get_sender (message); if (engine_encrypt_prepare (filter, hwnd, protocol, 0, my_sender, recipients, &protocol)) goto failure; if (engine_encrypt_start (filter, 0)) goto failure; protocol = check_protocol (protocol); if (protocol == PROTOCOL_UNKNOWN) goto failure; /* Write the top header. */ rc = create_top_encryption_header (sink, protocol, boundary); if (rc) goto failure; /* Create a new sink for encrypting the following stuff. */ encsink->cb_data = filter; encsink->writefnc = sink_encryption_write; - if ((body && n_att_usable) || n_att_usable > 1) - { - /* A body and at least one attachment or more than one attachment */ - generate_boundary (inner_boundary); - if ((rc=write_multistring (encsink, - "Content-Type: multipart/mixed;\r\n", - "\tboundary=\"", inner_boundary, "\"\r\n", - NULL))) - goto failure; - } - else /* Only one part. */ - *inner_boundary = 0; - - if ((rc=add_body (mail, inner_boundary, encsink, body))) - { - log_error ("%s:%s: Adding the body failed.", - SRCNAME, __func__); - goto failure; - } - if (!rc && n_att_usable) - rc = write_attachments (encsink, message, att_table, - *inner_boundary? inner_boundary : NULL); - if (rc) + /* Add the plaintext */ + if (add_body_and_attachments (encsink, message, att_table, mail, + body, n_att_usable)) goto failure; xfree (body); body = NULL; - /* Finish the possible multipart/mixed. */ - if (*inner_boundary && (rc = write_boundary (encsink, inner_boundary, 1))) - goto failure; - /* Flush the encryption sink and wait for the encryption to get ready. */ if ((rc = write_buffer (encsink, NULL, 0))) goto failure; if ((rc = engine_wait (filter))) goto failure; filter = NULL; /* Not valid anymore. */ encsink->cb_data = NULL; /* Not needed anymore. */ if (!sink->enc_counter) { log_debug ("%s:%s: nothing received from engine", SRCNAME, __func__); goto failure; } /* Write the final boundary (for OpenPGP) and finish the attachment. */ if (*boundary && (rc = write_boundary (sink, boundary, 1))) goto failure; if (close_mapi_attachment (&attach, sink)) goto failure; if (finalize_message (message, att_table, protocol, 1)) goto failure; result = 0; /* Everything is fine, fall through the cleanup now. */ failure: engine_cancel (filter); cancel_mapi_attachment (&attach, sink); xfree (body); mapi_release_attach_table (att_table); xfree (my_sender); return result; } /* Sign and Encrypt the MESSAGE. */ int mime_sign_encrypt (LPMESSAGE message, HWND hwnd, protocol_t protocol, char **recipients, const char *sender, Mail *mail) { int result = -1; int rc = 0; HRESULT hr; LPATTACH attach; LPSTREAM tmpstream = NULL; struct sink_s sinkmem; sink_t sink = &sinkmem; struct sink_s encsinkmem; sink_t encsink = &encsinkmem; struct sink_s tmpsinkmem; sink_t tmpsink = &tmpsinkmem; char boundary[BOUNDARYSIZE+1]; mapi_attach_item_t *att_table = NULL; engine_filter_t filter = NULL; unsigned int session_number; char *my_sender = NULL; memset (sink, 0, sizeof *sink); memset (encsink, 0, sizeof *encsink); memset (tmpsink, 0, sizeof *tmpsink); attach = create_mapi_attachment (message, sink); if (!attach) return -1; /* First check that we are not trying to process an empty message which might lock up our engine. Unfortunately we need to duplicate the code we use in do_mime_sign here. FIXME: The engine should be fixed instead of using such a workaround. */ { char *body; body = mapi_get_body (message, NULL); if (body && !*body) { xfree (body); body = NULL; } att_table = mapi_create_attach_table (message, 0); if (!count_usable_attachments (att_table) && !body) result = gpg_error (GPG_ERR_NO_DATA); xfree (body); if (att_table) { mapi_release_attach_table (att_table); att_table = NULL; } if (gpg_err_code (result) == GPG_ERR_NO_DATA) { log_debug ("%s:%s: can't sign+encrypt an empty message\n", SRCNAME, __func__); goto failure; } } /* Create a temporary sink to construct the signed data. */ hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer, (SOF_UNIQUEFILENAME | STGM_DELETEONRELEASE | STGM_CREATE | STGM_READWRITE), NULL, GpgOLStr("GPG"), &tmpstream); if (FAILED (hr)) { log_error ("%s:%s: can't create temp file: hr=%#lx\n", SRCNAME, __func__, hr); rc = -1; goto failure; } tmpsink->cb_data = tmpstream; tmpsink->writefnc = sink_std_write; /* Prepare the encryption. We do this early as it is quite common that some recipients are not available and thus the encryption will fail early. This is also required to allow the UIserver to figure out the protocol to use if we have not forced one. */ if (engine_create_filter (&filter, write_buffer_for_cb, sink)) goto failure; session_number = engine_new_session_number (); engine_set_session_number (filter, session_number); { char *tmp = mapi_get_subject (message); engine_set_session_title (filter, tmp); xfree (tmp); } if (sender) my_sender = xstrdup (sender); else my_sender = mapi_get_sender (message); if ((rc=engine_encrypt_prepare (filter, hwnd, protocol, ENGINE_FLAG_SIGN_FOLLOWS, my_sender, recipients, &protocol))) goto failure; protocol = check_protocol (protocol); if (protocol == PROTOCOL_UNKNOWN) goto failure; /* Now sign the message. This creates another attachment with the complete MIME object of the signed message. We can't do the encryption in streaming mode while running the encryption because we need to fix up that ugly micalg parameter after having created the signature. Note that the protocol to use is taken from the encryption operation. */ if (do_mime_sign (message, hwnd, protocol, &att_table, tmpsink, session_number, sender, mail)) goto failure; /* Now send the actual ENCRYPT command. This split up between prepare and start is necessary to help with the implementarion of the UI-server. If we would send the ENCRYPT command immediately the UI-server might block while reading from the input stream because we are first going to do a sign operation which in trun needs the attention of the UI server. A more robust but complicated approach to the UI-server would be to delay the reading (and thus the start of the underlying encrypt operation) until the first byte has been received. */ if ((rc=engine_encrypt_start (filter, 0))) goto failure; /* Write the top header. */ rc = create_top_encryption_header (sink, protocol, boundary); if (rc) goto failure; /* Create a new sink for encrypting the temporary attachment with the signed message. */ encsink->cb_data = filter; encsink->writefnc = sink_encryption_write; /* Copy the temporary stream to the encryption sink. */ { LARGE_INTEGER off; ULONG nread; char buffer[4096]; off.QuadPart = 0; hr = tmpstream->Seek (off, STREAM_SEEK_SET, NULL); if (hr) { log_error ("%s:%s: seeking back to the begin failed: hr=%#lx", SRCNAME, __func__, hr); rc = gpg_error (GPG_ERR_EIO); goto failure; } for (;;) { hr = tmpstream->Read (buffer, sizeof buffer, &nread); if (hr) { log_error ("%s:%s: IStream::Read failed: hr=%#lx", SRCNAME, __func__, hr); rc = gpg_error (GPG_ERR_EIO); goto failure; } if (!nread) break; /* EOF */ rc = write_buffer (encsink, buffer, nread); if (rc) { log_error ("%s:%s: writing tmpstream to encsink failed: %s", SRCNAME, __func__, gpg_strerror (rc)); goto failure; } } } /* Flush the encryption sink and wait for the encryption to get ready. */ if ((rc = write_buffer (encsink, NULL, 0))) goto failure; if ((rc = engine_wait (filter))) goto failure; filter = NULL; /* Not valid anymore. */ encsink->cb_data = NULL; /* Not needed anymore. */ if (!sink->enc_counter) { log_debug ("%s:%s: nothing received from engine", SRCNAME, __func__); goto failure; } /* Write the final boundary (for OpenPGP) and finish the attachment. */ if (*boundary && (rc = write_boundary (sink, boundary, 1))) goto failure; if (close_mapi_attachment (&attach, sink)) goto failure; if (finalize_message (message, att_table, protocol, 1)) goto failure; result = 0; /* Everything is fine, fall through the cleanup now. */ failure: if (result) log_debug ("%s:%s: failed rc=%d (%s) <%s>", SRCNAME, __func__, rc, gpg_strerror (rc), gpg_strsource (rc)); engine_cancel (filter); gpgol_release (tmpstream); mapi_release_attach_table (att_table); xfree (my_sender); return result; } int restore_msg_from_moss (LPMESSAGE message, LPDISPATCH moss_att, msgtype_t type, char *msgcls) { struct sink_s sinkmem; sink_t sink = &sinkmem; char *orig = NULL; int err = -1; char boundary[BOUNDARYSIZE+1]; (void)msgcls; LPATTACH new_attach = create_mapi_attachment (message, sink); log_debug ("Restore message from moss called."); if (!new_attach) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); goto done; } // TODO MORE if (type == MSGTYPE_SMIME) { create_top_encryption_header (sink, PROTOCOL_SMIME, boundary); } else if (type == MSGTYPE_GPGOL_MULTIPART_ENCRYPTED) { create_top_encryption_header (sink, PROTOCOL_OPENPGP, boundary); } else { log_error ("%s:%s: Unsupported messagetype: %i", SRCNAME, __func__, type); goto done; } orig = get_pa_string (moss_att, PR_ATTACH_DATA_BIN_DASL); if (!orig) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); goto done; } if (write_string (sink, orig)) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); goto done; } if (*boundary && write_boundary (sink, boundary, 1)) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); goto done; } if (close_mapi_attachment (&new_attach, sink)) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); goto done; } /* Set a special property so that we are later able to identify messages signed or encrypted by us. */ if (mapi_set_sig_status (message, "@")) { log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__); goto done; } err = 0; done: xfree (orig); return err; } diff --git a/src/mymapitags.h b/src/mymapitags.h index c2d6e4f..9232c37 100644 --- a/src/mymapitags.h +++ b/src/mymapitags.h @@ -1,1076 +1,1077 @@ /* mymapitags.h - MAPI definitions * * This file defines constants as used by MAPI. This interface * definition has been compiled from similar Python code by g10 Code * GmbH. * * Revisions: * 2005-07-26 Initial version. * */ #ifndef MAPITAGS_H #define MAPITAGS_H 1 #define PT_UNSPECIFIED 0 #define PT_NULL 1 #define PT_I2 2 #define PT_LONG 3 #define PT_R4 4 #define PT_DOUBLE 5 #define PT_CURRENCY 6 #define PT_APPTIME 7 #define PT_ERROR 10 #define PT_BOOLEAN 11 #define PT_OBJECT 13 #define PT_I8 20 #define PT_STRING8 30 #define PT_UNICODE 31 #define PT_SYSTIME 64 #define PT_CLSID 72 #define PT_BINARY 258 #define PT_SHORT PT_I2 #define PT_I4 PT_LONG #define PT_FLOAT PT_R4 #define PT_R8 PT_DOUBLE #define PT_LONGLONG PT_I8 #define MV_FLAG 0x1000 #define PT_MV_I2 (MV_FLAG|PT_I2) #define PT_MV_LONG (MV_FLAG|PT_LONG) #define PT_MV_R4 (MV_FLAG|PT_R4) #define PT_MV_DOUBLE (MV_FLAG|PT_DOUBLE) #define PT_MV_CURRENCY (MV_FLAG|PT_CURRENCY) #define PT_MV_APPTIME (MV_FLAG|PT_APPTIME) #define PT_MV_SYSTIME (MV_FLAG|PT_SYSTIME) #define PT_MV_STRING8 (MV_FLAG|PT_STRING8) #define PT_MV_BINARY (MV_FLAG|PT_BINARY) #define PT_MV_UNICODE (MV_FLAG|PT_UNICODE) #define PT_MV_CLSID (MV_FLAG|PT_CLSID) #define PT_MV_I8 (MV_FLAG|PT_I8) #define PT_MV_SHORT PT_MV_I2 #define PT_MV_I4 PT_MV_LONG #define PT_MV_FLOAT PT_MV_R4 #define PT_MV_R8 PT_MV_DOUBLE #define PT_MV_LONGLONG PT_MV_I8 #define PT_TSTRING PT_UNICODE #define PT_MV_TSTRING (MV_FLAG|PT_UNICODE) #define PROP_TYPE_MASK 0x0000FFFF #define PROP_TYPE(t) ((t) & PROP_TYPE_MASK) #define PROP_ID(t) ((t)>>16) #define PROP_TAG(t,i) (((i)<<16)|(t)) #define PROP_ID_NULL 0 #define PROP_ID_INVALID 0xFFFF #define PR_NULL PROP_TAG(PT_NULL, PROP_ID_NULL) #define PR_ACKNOWLEDGEMENT_MODE PROP_TAG( PT_LONG, 0x0001) #define PR_ACKNOWLEDGEMENT_MODE PROP_TAG( PT_LONG, 0x0001) #define PR_ALTERNATE_RECIPIENT_ALLOWED PROP_TAG( PT_BOOLEAN, 0x0002) #define PR_AUTHORIZING_USERS PROP_TAG( PT_BINARY, 0x0003) #define PR_AUTO_FORWARD_COMMENT PROP_TAG( PT_TSTRING, 0x0004) #define PR_AUTO_FORWARD_COMMENT_W PROP_TAG( PT_UNICODE, 0x0004) #define PR_AUTO_FORWARD_COMMENT_W PROP_TAG( PT_UNICODE, 0x0004) #define PR_AUTO_FORWARD_COMMENT_A PROP_TAG( PT_STRING8, 0x0004) #define PR_AUTO_FORWARDED PROP_TAG( PT_BOOLEAN, 0x0005) #define PR_CONTENT_TYPE_A PROP_TAG( PT_STRING8, 0x8095) #define PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID PROP_TAG( PT_BINARY, 0x0006) #define PR_CONTENT_CORRELATOR PROP_TAG( PT_BINARY, 0x0007) #define PR_CONTENT_IDENTIFIER PROP_TAG( PT_TSTRING, 0x0008) #define PR_CONTENT_IDENTIFIER_W PROP_TAG( PT_UNICODE, 0x0008) #define PR_CONTENT_IDENTIFIER_A PROP_TAG( PT_STRING8, 0x0008) #define PR_CONTENT_LENGTH PROP_TAG( PT_LONG, 0x0009) #define PR_CONTENT_RETURN_REQUESTED PROP_TAG( PT_BOOLEAN, 0x000A) #define PR_CONVERSATION_KEY PROP_TAG( PT_BINARY, 0x000B) #define PR_CONVERSION_EITS PROP_TAG( PT_BINARY, 0x000C) #define PR_CONVERSION_WITH_LOSS_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x000D) #define PR_CONVERTED_EITS PROP_TAG( PT_BINARY, 0x000E) #define PR_DEFERRED_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x000F) #define PR_DELIVER_TIME PROP_TAG( PT_SYSTIME, 0x0010) #define PR_DISCARD_REASON PROP_TAG( PT_LONG, 0x0011) #define PR_DISCLOSURE_OF_RECIPIENTS PROP_TAG( PT_BOOLEAN, 0x0012) #define PR_DL_EXPANSION_HISTORY PROP_TAG( PT_BINARY, 0x0013) #define PR_DL_EXPANSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0014) #define PR_EXPIRY_TIME PROP_TAG( PT_SYSTIME, 0x0015) #define PR_IMPLICIT_CONVERSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0016) #define PR_IMPORTANCE PROP_TAG( PT_LONG, 0x0017) #define PR_IPM_ID PROP_TAG( PT_BINARY, 0x0018) #define PR_LATEST_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0019) #define PR_MESSAGE_CLASS PROP_TAG( PT_TSTRING, 0x001A) #define PR_MESSAGE_CLASS_W PROP_TAG( PT_UNICODE, 0x001A) #define PR_MESSAGE_CLASS_A PROP_TAG( PT_STRING8, 0x001A) #define PR_MESSAGE_DELIVERY_ID PROP_TAG( PT_BINARY, 0x001B) #define PR_MESSAGE_SECURITY_LABEL PROP_TAG( PT_BINARY, 0x001E) #define PR_OBSOLETED_IPMS PROP_TAG( PT_BINARY, 0x001F) #define PR_ORIGINALLY_INTENDED_RECIPIENT_NAME PROP_TAG( PT_BINARY, 0x0020) #define PR_ORIGINAL_EITS PROP_TAG( PT_BINARY, 0x0021) #define PR_ORIGINATOR_CERTIFICATE PROP_TAG( PT_BINARY, 0x0022) #define PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0023) #define PR_ORIGINATOR_RETURN_ADDRESS PROP_TAG( PT_BINARY, 0x0024) #define PR_PARENT_KEY PROP_TAG( PT_BINARY, 0x0025) #define PR_PRIORITY PROP_TAG( PT_LONG, 0x0026) #define PR_ORIGIN_CHECK PROP_TAG( PT_BINARY, 0x0027) #define PR_PROOF_OF_SUBMISSION_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0028) #define PR_READ_RECEIPT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0029) #define PR_RECEIPT_TIME PROP_TAG( PT_SYSTIME, 0x002A) #define PR_RECIPIENT_REASSIGNMENT_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x002B) #define PR_REDIRECTION_HISTORY PROP_TAG( PT_BINARY, 0x002C) #define PR_RELATED_IPMS PROP_TAG( PT_BINARY, 0x002D) #define PR_ORIGINAL_SENSITIVITY PROP_TAG( PT_LONG, 0x002E) #define PR_LANGUAGES PROP_TAG( PT_TSTRING, 0x002F) #define PR_LANGUAGES_W PROP_TAG( PT_UNICODE, 0x002F) #define PR_LANGUAGES_A PROP_TAG( PT_STRING8, 0x002F) #define PR_REPLY_TIME PROP_TAG( PT_SYSTIME, 0x0030) #define PR_REPORT_TAG PROP_TAG( PT_BINARY, 0x0031) #define PR_REPORT_TIME PROP_TAG( PT_SYSTIME, 0x0032) #define PR_RETURNED_IPM PROP_TAG( PT_BOOLEAN, 0x0033) #define PR_SECURITY PROP_TAG( PT_LONG, 0x0034) #define PR_INCOMPLETE_COPY PROP_TAG( PT_BOOLEAN, 0x0035) #define PR_SENSITIVITY PROP_TAG( PT_LONG, 0x0036) #define PR_SUBJECT PROP_TAG( PT_TSTRING, 0x0037) #define PR_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0037) #define PR_SUBJECT_A PROP_TAG( PT_STRING8, 0x0037) #define PR_SUBJECT_IPM PROP_TAG( PT_BINARY, 0x0038) #define PR_CLIENT_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x0039) #define PR_REPORT_NAME PROP_TAG( PT_TSTRING, 0x003A) #define PR_REPORT_NAME_W PROP_TAG( PT_UNICODE, 0x003A) #define PR_REPORT_NAME_A PROP_TAG( PT_STRING8, 0x003A) #define PR_SENT_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x003B) #define PR_X400_CONTENT_TYPE PROP_TAG( PT_BINARY, 0x003C) #define PR_SUBJECT_PREFIX PROP_TAG( PT_TSTRING, 0x003D) #define PR_SUBJECT_PREFIX_W PROP_TAG( PT_UNICODE, 0x003D) #define PR_SUBJECT_PREFIX_A PROP_TAG( PT_STRING8, 0x003D) #define PR_NON_RECEIPT_REASON PROP_TAG( PT_LONG, 0x003E) #define PR_RECEIVED_BY_ENTRYID PROP_TAG( PT_BINARY, 0x003F) #define PR_RECEIVED_BY_NAME PROP_TAG( PT_TSTRING, 0x0040) #define PR_RECEIVED_BY_NAME_W PROP_TAG( PT_UNICODE, 0x0040) #define PR_RECEIVED_BY_NAME_A PROP_TAG( PT_STRING8, 0x0040) #define PR_SENT_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x0041) #define PR_SENT_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x0042) #define PR_SENT_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x0042) #define PR_SENT_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x0042) #define PR_RCVD_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x0043) #define PR_RCVD_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x0044) #define PR_RCVD_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x0044) #define PR_RCVD_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x0044) #define PR_REPORT_ENTRYID PROP_TAG( PT_BINARY, 0x0045) #define PR_READ_RECEIPT_ENTRYID PROP_TAG( PT_BINARY, 0x0046) #define PR_MESSAGE_SUBMISSION_ID PROP_TAG( PT_BINARY, 0x0047) #define PR_PROVIDER_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x0048) #define PR_ORIGINAL_SUBJECT PROP_TAG( PT_TSTRING, 0x0049) #define PR_ORIGINAL_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0049) #define PR_ORIGINAL_SUBJECT_A PROP_TAG( PT_STRING8, 0x0049) #define PR_DISC_VAL PROP_TAG( PT_BOOLEAN, 0x004A) #define PR_ORIG_MESSAGE_CLASS PROP_TAG( PT_TSTRING, 0x004B) #define PR_ORIG_MESSAGE_CLASS_W PROP_TAG( PT_UNICODE, 0x004B) #define PR_ORIG_MESSAGE_CLASS_A PROP_TAG( PT_STRING8, 0x004B) #define PR_ORIGINAL_AUTHOR_ENTRYID PROP_TAG( PT_BINARY, 0x004C) #define PR_ORIGINAL_AUTHOR_NAME PROP_TAG( PT_TSTRING, 0x004D) #define PR_ORIGINAL_AUTHOR_NAME_W PROP_TAG( PT_UNICODE, 0x004D) #define PR_ORIGINAL_AUTHOR_NAME_A PROP_TAG( PT_STRING8, 0x004D) #define PR_ORIGINAL_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x004E) #define PR_REPLY_RECIPIENT_ENTRIES PROP_TAG( PT_BINARY, 0x004F) #define PR_REPLY_RECIPIENT_NAMES PROP_TAG( PT_TSTRING, 0x0050) #define PR_REPLY_RECIPIENT_NAMES_W PROP_TAG( PT_UNICODE, 0x0050) #define PR_REPLY_RECIPIENT_NAMES_A PROP_TAG( PT_STRING8, 0x0050) #define PR_RECEIVED_BY_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0051) #define PR_RCVD_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0052) #define PR_READ_RECEIPT_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0053) #define PR_REPORT_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0054) #define PR_ORIGINAL_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0055) #define PR_ORIGINAL_AUTHOR_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0056) #define PR_MESSAGE_TO_ME PROP_TAG( PT_BOOLEAN, 0x0057) #define PR_MESSAGE_CC_ME PROP_TAG( PT_BOOLEAN, 0x0058) #define PR_MESSAGE_RECIP_ME PROP_TAG( PT_BOOLEAN, 0x0059) #define PR_ORIGINAL_SENDER_NAME PROP_TAG( PT_TSTRING, 0x005A) #define PR_ORIGINAL_SENDER_NAME_W PROP_TAG( PT_UNICODE, 0x005A) #define PR_ORIGINAL_SENDER_NAME_A PROP_TAG( PT_STRING8, 0x005A) #define PR_ORIGINAL_SENDER_ENTRYID PROP_TAG( PT_BINARY, 0x005B) #define PR_ORIGINAL_SENDER_SEARCH_KEY PROP_TAG( PT_BINARY, 0x005C) #define PR_ORIGINAL_SENT_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x005D) #define PR_ORIGINAL_SENT_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x005D) #define PR_ORIGINAL_SENT_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x005D) #define PR_ORIGINAL_SENT_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x005E) #define PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x005F) #define PR_START_DATE PROP_TAG( PT_SYSTIME, 0x0060) #define PR_END_DATE PROP_TAG( PT_SYSTIME, 0x0061) #define PR_OWNER_APPT_ID PROP_TAG( PT_LONG, 0x0062) #define PR_RESPONSE_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0063) #define PR_SENT_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0064) #define PR_SENT_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0064) #define PR_SENT_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0064) #define PR_SENT_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0065) #define PR_SENT_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0065) #define PR_SENT_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0065) #define PR_ORIGINAL_SENDER_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0066) #define PR_ORIGINAL_SENDER_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0066) #define PR_ORIGINAL_SENDER_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0066) #define PR_ORIGINAL_SENDER_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0067) #define PR_ORIGINAL_SENDER_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0067) #define PR_ORIGINAL_SENDER_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0067) #define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0068) #define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0068) #define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0068) #define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS \ PROP_TAG( PT_TSTRING, 0x0069) #define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_W \ PROP_TAG( PT_UNICODE, 0x0069) #define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_A \ PROP_TAG( PT_STRING8, 0x0069) #define PR_CONVERSATION_TOPIC PROP_TAG( PT_TSTRING, 0x0070) #define PR_CONVERSATION_TOPIC_W PROP_TAG( PT_UNICODE, 0x0070) #define PR_CONVERSATION_TOPIC_A PROP_TAG( PT_STRING8, 0x0070) #define PR_CONVERSATION_INDEX PROP_TAG( PT_BINARY, 0x0071) #define PR_ORIGINAL_DISPLAY_BCC PROP_TAG( PT_TSTRING, 0x0072) #define PR_ORIGINAL_DISPLAY_BCC_W PROP_TAG( PT_UNICODE, 0x0072) #define PR_ORIGINAL_DISPLAY_BCC_A PROP_TAG( PT_STRING8, 0x0072) #define PR_ORIGINAL_DISPLAY_CC PROP_TAG( PT_TSTRING, 0x0073) #define PR_ORIGINAL_DISPLAY_CC_W PROP_TAG( PT_UNICODE, 0x0073) #define PR_ORIGINAL_DISPLAY_CC_A PROP_TAG( PT_STRING8, 0x0073) #define PR_ORIGINAL_DISPLAY_TO PROP_TAG( PT_TSTRING, 0x0074) #define PR_ORIGINAL_DISPLAY_TO_W PROP_TAG( PT_UNICODE, 0x0074) #define PR_ORIGINAL_DISPLAY_TO_A PROP_TAG( PT_STRING8, 0x0074) #define PR_RECEIVED_BY_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0075) #define PR_RECEIVED_BY_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0075) #define PR_RECEIVED_BY_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0075) #define PR_RECEIVED_BY_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0076) #define PR_RECEIVED_BY_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0076) #define PR_RECEIVED_BY_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0076) #define PR_RCVD_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0077) #define PR_RCVD_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0077) #define PR_RCVD_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0077) #define PR_RCVD_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0078) #define PR_RCVD_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0078) #define PR_RCVD_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0078) #define PR_ORIGINAL_AUTHOR_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0079) #define PR_ORIGINAL_AUTHOR_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0079) #define PR_ORIGINAL_AUTHOR_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0079) #define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x007A) #define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x007A) #define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x007A) #define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE PROP_TAG( PT_TSTRING, 0x007B) #define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x007B) #define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x007B) #define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS \ PROP_TAG( PT_TSTRING, 0x007C) #define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_W \ PROP_TAG( PT_UNICODE, 0x007C) #define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_A \ PROP_TAG( PT_STRING8, 0x007C) #define PR_TRANSPORT_MESSAGE_HEADERS PROP_TAG(PT_TSTRING, 0x007D) #define PR_TRANSPORT_MESSAGE_HEADERS_W PROP_TAG(PT_UNICODE, 0x007D) #define PR_TRANSPORT_MESSAGE_HEADERS_A PROP_TAG(PT_STRING8, 0x007D) #define PR_DELEGATION PROP_TAG(PT_BINARY, 0x007E) #define PR_TNEF_CORRELATION_KEY PROP_TAG(PT_BINARY, 0x007F) #define PR_BODY PROP_TAG( PT_TSTRING, 0x1000) #define PR_BODY_W PROP_TAG( PT_UNICODE, 0x1000) #define PR_BODY_A PROP_TAG( PT_STRING8, 0x1000) #define PR_REPORT_TEXT PROP_TAG( PT_TSTRING, 0x1001) #define PR_REPORT_TEXT_W PROP_TAG( PT_UNICODE, 0x1001) #define PR_REPORT_TEXT_A PROP_TAG( PT_STRING8, 0x1001) #define PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY PROP_TAG( PT_BINARY, 0x1002) #define PR_REPORTING_DL_NAME PROP_TAG( PT_BINARY, 0x1003) #define PR_REPORTING_MTA_CERTIFICATE PROP_TAG( PT_BINARY, 0x1004) #define PR_RTF_SYNC_BODY_CRC PROP_TAG( PT_LONG, 0x1006) #define PR_RTF_SYNC_BODY_COUNT PROP_TAG( PT_LONG, 0x1007) #define PR_RTF_SYNC_BODY_TAG PROP_TAG( PT_TSTRING, 0x1008) #define PR_RTF_SYNC_BODY_TAG_W PROP_TAG( PT_UNICODE, 0x1008) #define PR_RTF_SYNC_BODY_TAG_A PROP_TAG( PT_STRING8, 0x1008) #define PR_RTF_COMPRESSED PROP_TAG( PT_BINARY, 0x1009) #define PR_RTF_SYNC_PREFIX_COUNT PROP_TAG( PT_LONG, 0x1010) #define PR_RTF_SYNC_TRAILING_COUNT PROP_TAG( PT_LONG, 0x1011) #define PR_ORIGINALLY_INTENDED_RECIP_ENTRYID PROP_TAG( PT_BINARY, 0x1012) #define PR_BODY_HTML PROP_TAG( PT_TSTRING, 0x1013) #define PR_BODY_HTML_W PROP_TAG( PT_UNICODE, 0x1013) #define PR_BODY_HTML_A PROP_TAG( PT_STRING8, 0x1013) #define PR_CONTENT_INTEGRITY_CHECK PROP_TAG( PT_BINARY, 0x0C00) #define PR_EXPLICIT_CONVERSION PROP_TAG( PT_LONG, 0x0C01) #define PR_IPM_RETURN_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C02) #define PR_MESSAGE_TOKEN PROP_TAG( PT_BINARY, 0x0C03) #define PR_NDR_REASON_CODE PROP_TAG( PT_LONG, 0x0C04) #define PR_NDR_DIAG_CODE PROP_TAG( PT_LONG, 0x0C05) #define PR_NON_RECEIPT_NOTIFICATION_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C06) #define PR_DELIVERY_POINT PROP_TAG( PT_LONG, 0x0C07) #define PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED \ PROP_TAG( PT_BOOLEAN, 0x0C08) #define PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT \ PROP_TAG( PT_BINARY, 0x0C09) #define PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY \ PROP_TAG( PT_BOOLEAN, 0x0C0A) #define PR_PHYSICAL_DELIVERY_MODE PROP_TAG( PT_LONG, 0x0C0B) #define PR_PHYSICAL_DELIVERY_REPORT_REQUEST PROP_TAG( PT_LONG, 0x0C0C) #define PR_PHYSICAL_FORWARDING_ADDRESS PROP_TAG( PT_BINARY, 0x0C0D) #define PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED \ PROP_TAG( PT_BOOLEAN, 0x0C0E) #define PR_PHYSICAL_FORWARDING_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0C0F) #define PR_PHYSICAL_RENDITION_ATTRIBUTES PROP_TAG( PT_BINARY, 0x0C10) #define PR_PROOF_OF_DELIVERY PROP_TAG( PT_BINARY, 0x0C11) #define PR_PROOF_OF_DELIVERY_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C12) #define PR_RECIPIENT_CERTIFICATE PROP_TAG( PT_BINARY, 0x0C13) #define PR_RECIPIENT_NUMBER_FOR_ADVICE PROP_TAG( PT_TSTRING, 0x0C14) #define PR_RECIPIENT_NUMBER_FOR_ADVICE_W PROP_TAG( PT_UNICODE, 0x0C14) #define PR_RECIPIENT_NUMBER_FOR_ADVICE_A PROP_TAG( PT_STRING8, 0x0C14) #define PR_RECIPIENT_TYPE PROP_TAG( PT_LONG, 0x0C15) #define PR_REGISTERED_MAIL_TYPE PROP_TAG( PT_LONG, 0x0C16) #define PR_REPLY_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C17) #define PR_REQUESTED_DELIVERY_METHOD PROP_TAG( PT_LONG, 0x0C18) #define PR_SENDER_ENTRYID PROP_TAG( PT_BINARY, 0x0C19) #define PR_SENDER_NAME PROP_TAG( PT_TSTRING, 0x0C1A) #define PR_SENDER_NAME_W PROP_TAG( PT_UNICODE, 0x0C1A) #define PR_SENDER_NAME_A PROP_TAG( PT_STRING8, 0x0C1A) #define PR_SUPPLEMENTARY_INFO PROP_TAG( PT_TSTRING, 0x0C1B) #define PR_SUPPLEMENTARY_INFO_W PROP_TAG( PT_UNICODE, 0x0C1B) #define PR_SUPPLEMENTARY_INFO_A PROP_TAG( PT_STRING8, 0x0C1B) #define PR_TYPE_OF_MTS_USER PROP_TAG( PT_LONG, 0x0C1C) #define PR_SENDER_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0C1D) #define PR_SENDER_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0C1E) #define PR_SENDER_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0C1E) #define PR_SENDER_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0C1E) #define PR_SENDER_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0C1F) #define PR_SENDER_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0C1F) #define PR_SENDER_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0C1F) #define PR_CURRENT_VERSION PROP_TAG( PT_I8, 0x0E00) #define PR_DELETE_AFTER_SUBMIT PROP_TAG( PT_BOOLEAN, 0x0E01) #define PR_DISPLAY_BCC PROP_TAG( PT_TSTRING, 0x0E02) #define PR_DISPLAY_BCC_W PROP_TAG( PT_UNICODE, 0x0E02) #define PR_DISPLAY_BCC_A PROP_TAG( PT_STRING8, 0x0E02) #define PR_DISPLAY_CC PROP_TAG( PT_TSTRING, 0x0E03) #define PR_DISPLAY_CC_W PROP_TAG( PT_UNICODE, 0x0E03) #define PR_DISPLAY_CC_A PROP_TAG( PT_STRING8, 0x0E03) #define PR_DISPLAY_TO PROP_TAG( PT_TSTRING, 0x0E04) #define PR_DISPLAY_TO_W PROP_TAG( PT_UNICODE, 0x0E04) #define PR_DISPLAY_TO_A PROP_TAG( PT_STRING8, 0x0E04) #define PR_PARENT_DISPLAY PROP_TAG( PT_TSTRING, 0x0E05) #define PR_PARENT_DISPLAY_W PROP_TAG( PT_UNICODE, 0x0E05) #define PR_PARENT_DISPLAY_A PROP_TAG( PT_STRING8, 0x0E05) #define PR_MESSAGE_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0E06) #define PR_MESSAGE_FLAGS PROP_TAG( PT_LONG, 0x0E07) #define PR_MESSAGE_SIZE PROP_TAG( PT_LONG, 0x0E08) #define PR_PARENT_ENTRYID PROP_TAG( PT_BINARY, 0x0E09) #define PR_SENTMAIL_ENTRYID PROP_TAG( PT_BINARY, 0x0E0A) #define PR_CORRELATE PROP_TAG( PT_BOOLEAN, 0x0E0C) #define PR_CORRELATE_MTSID PROP_TAG( PT_BINARY, 0x0E0D) #define PR_DISCRETE_VALUES PROP_TAG( PT_BOOLEAN, 0x0E0E) #define PR_RESPONSIBILITY PROP_TAG( PT_BOOLEAN, 0x0E0F) #define PR_SPOOLER_STATUS PROP_TAG( PT_LONG, 0x0E10) #define PR_TRANSPORT_STATUS PROP_TAG( PT_LONG, 0x0E11) #define PR_MESSAGE_RECIPIENTS PROP_TAG( PT_OBJECT, 0x0E12) #define PR_MESSAGE_ATTACHMENTS PROP_TAG( PT_OBJECT, 0x0E13) #define PR_SUBMIT_FLAGS PROP_TAG( PT_LONG, 0x0E14) #define PR_RECIPIENT_STATUS PROP_TAG( PT_LONG, 0x0E15) #define PR_TRANSPORT_KEY PROP_TAG( PT_LONG, 0x0E16) #define PR_MSG_STATUS PROP_TAG( PT_LONG, 0x0E17) #define PR_MESSAGE_DOWNLOAD_TIME PROP_TAG( PT_LONG, 0x0E18) #define PR_CREATION_VERSION PROP_TAG( PT_I8, 0x0E19) #define PR_MODIFY_VERSION PROP_TAG( PT_I8, 0x0E1A) #define PR_HASATTACH PROP_TAG( PT_BOOLEAN, 0x0E1B) #define PR_BODY_CRC PROP_TAG( PT_LONG, 0x0E1C) #define PR_NORMALIZED_SUBJECT PROP_TAG( PT_TSTRING, 0x0E1D) #define PR_NORMALIZED_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0E1D) #define PR_NORMALIZED_SUBJECT_A PROP_TAG( PT_STRING8, 0x0E1D) #define PR_RTF_IN_SYNC PROP_TAG( PT_BOOLEAN, 0x0E1F) #define PR_ATTACH_SIZE PROP_TAG( PT_LONG, 0x0E20) #define PR_ATTACH_NUM PROP_TAG( PT_LONG, 0x0E21) #define PR_PREPROCESS PROP_TAG( PT_BOOLEAN, 0x0E22) #define PR_ORIGINATING_MTA_CERTIFICATE PROP_TAG( PT_BINARY, 0x0E25) #define PR_PROOF_OF_SUBMISSION PROP_TAG( PT_BINARY, 0x0E26) #define PR_PRIMARY_SEND_ACCT PROP_TAG( PT_UNICODE, 0x0E28) #define PR_ENTRYID PROP_TAG( PT_BINARY, 0x0FFF) #define PR_OBJECT_TYPE PROP_TAG( PT_LONG, 0x0FFE) #define PR_ICON PROP_TAG( PT_BINARY, 0x0FFD) #define PR_MINI_ICON PROP_TAG( PT_BINARY, 0x0FFC) #define PR_STORE_ENTRYID PROP_TAG( PT_BINARY, 0x0FFB) #define PR_STORE_RECORD_KEY PROP_TAG( PT_BINARY, 0x0FFA) #define PR_RECORD_KEY PROP_TAG( PT_BINARY, 0x0FF9) #define PR_MAPPING_SIGNATURE PROP_TAG( PT_BINARY, 0x0FF8) #define PR_ACCESS_LEVEL PROP_TAG( PT_LONG, 0x0FF7) #define PR_INSTANCE_KEY PROP_TAG( PT_BINARY, 0x0FF6) #define PR_ROW_TYPE PROP_TAG( PT_LONG, 0x0FF5) #define PR_ACCESS PROP_TAG( PT_LONG, 0x0FF4) #define PR_ROWID PROP_TAG( PT_LONG, 0x3000) #define PR_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3001) #define PR_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3001) #define PR_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3001) #define PR_ADDRTYPE PROP_TAG( PT_TSTRING, 0x3002) #define PR_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x3002) #define PR_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x3002) #define PR_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x3003) #define PR_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3003) #define PR_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x3003) #define PR_COMMENT PROP_TAG( PT_TSTRING, 0x3004) #define PR_COMMENT_W PROP_TAG( PT_UNICODE, 0x3004) #define PR_COMMENT_A PROP_TAG( PT_STRING8, 0x3004) #define PR_DEPTH PROP_TAG( PT_LONG, 0x3005) #define PR_PROVIDER_DISPLAY PROP_TAG( PT_TSTRING, 0x3006) #define PR_PROVIDER_DISPLAY_W PROP_TAG( PT_UNICODE, 0x3006) #define PR_PROVIDER_DISPLAY_A PROP_TAG( PT_STRING8, 0x3006) #define PR_CREATION_TIME PROP_TAG( PT_SYSTIME, 0x3007) #define PR_LAST_MODIFICATION_TIME PROP_TAG( PT_SYSTIME, 0x3008) #define PR_RESOURCE_FLAGS PROP_TAG( PT_LONG, 0x3009) #define PR_PROVIDER_DLL_NAME PROP_TAG( PT_TSTRING, 0x300A) #define PR_PROVIDER_DLL_NAME_W PROP_TAG( PT_UNICODE, 0x300A) #define PR_PROVIDER_DLL_NAME_A PROP_TAG( PT_STRING8, 0x300A) #define PR_SEARCH_KEY PROP_TAG( PT_BINARY, 0x300B) #define PR_PROVIDER_UID PROP_TAG( PT_BINARY, 0x300C) #define PR_PROVIDER_ORDINAL PROP_TAG( PT_LONG, 0x300D) #define PR_FORM_VERSION PROP_TAG(PT_TSTRING, 0x3301) #define PR_FORM_VERSION_W PROP_TAG(PT_UNICODE, 0x3301) #define PR_FORM_VERSION_A PROP_TAG(PT_STRING8, 0x3301) #define PR_FORM_CLSID PROP_TAG(PT_CLSID, 0x3302) #define PR_FORM_CONTACT_NAME PROP_TAG(PT_TSTRING, 0x3303) #define PR_FORM_CONTACT_NAME_W PROP_TAG(PT_UNICODE, 0x3303) #define PR_FORM_CONTACT_NAME_A PROP_TAG(PT_STRING8, 0x3303) #define PR_FORM_CATEGORY PROP_TAG(PT_TSTRING, 0x3304) #define PR_FORM_CATEGORY_W PROP_TAG(PT_UNICODE, 0x3304) #define PR_FORM_CATEGORY_A PROP_TAG(PT_STRING8, 0x3304) #define PR_FORM_CATEGORY_SUB PROP_TAG(PT_TSTRING, 0x3305) #define PR_FORM_CATEGORY_SUB_W PROP_TAG(PT_UNICODE, 0x3305) #define PR_FORM_CATEGORY_SUB_A PROP_TAG(PT_STRING8, 0x3305) #define PR_FORM_HOST_MAP PROP_TAG(PT_MV_LONG, 0x3306) #define PR_FORM_HIDDEN PROP_TAG(PT_BOOLEAN, 0x3307) #define PR_FORM_DESIGNER_NAME PROP_TAG(PT_TSTRING, 0x3308) #define PR_FORM_DESIGNER_NAME_W PROP_TAG(PT_UNICODE, 0x3308) #define PR_FORM_DESIGNER_NAME_A PROP_TAG(PT_STRING8, 0x3308) #define PR_FORM_DESIGNER_GUID PROP_TAG(PT_CLSID, 0x3309) #define PR_FORM_MESSAGE_BEHAVIOR PROP_TAG(PT_LONG, 0x330A) #define PR_DEFAULT_STORE PROP_TAG( PT_BOOLEAN, 0x3400) #define PR_STORE_SUPPORT_MASK PROP_TAG( PT_LONG, 0x340D) #define PR_STORE_STATE PROP_TAG( PT_LONG, 0x340E) #define PR_IPM_SUBTREE_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3410) #define PR_IPM_OUTBOX_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3411) #define PR_IPM_WASTEBASKET_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3412) #define PR_IPM_SENTMAIL_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3413) #define PR_MDB_PROVIDER PROP_TAG( PT_BINARY, 0x3414) #define PR_RECEIVE_FOLDER_SETTINGS PROP_TAG( PT_OBJECT, 0x3415) #define PR_VALID_FOLDER_MASK PROP_TAG( PT_LONG, 0x35DF) #define PR_IPM_SUBTREE_ENTRYID PROP_TAG( PT_BINARY, 0x35E0) #define PR_IPM_OUTBOX_ENTRYID PROP_TAG( PT_BINARY, 0x35E2) #define PR_IPM_WASTEBASKET_ENTRYID PROP_TAG( PT_BINARY, 0x35E3) #define PR_IPM_SENTMAIL_ENTRYID PROP_TAG( PT_BINARY, 0x35E4) #define PR_VIEWS_ENTRYID PROP_TAG( PT_BINARY, 0x35E5) #define PR_COMMON_VIEWS_ENTRYID PROP_TAG( PT_BINARY, 0x35E6) #define PR_FINDER_ENTRYID PROP_TAG( PT_BINARY, 0x35E7) #define PR_CONTAINER_FLAGS PROP_TAG( PT_LONG, 0x3600) #define PR_FOLDER_TYPE PROP_TAG( PT_LONG, 0x3601) #define PR_CONTENT_COUNT PROP_TAG( PT_LONG, 0x3602) #define PR_CONTENT_UNREAD PROP_TAG( PT_LONG, 0x3603) #define PR_CREATE_TEMPLATES PROP_TAG( PT_OBJECT, 0x3604) #define PR_DETAILS_TABLE PROP_TAG( PT_OBJECT, 0x3605) #define PR_SEARCH PROP_TAG( PT_OBJECT, 0x3607) #define PR_SELECTABLE PROP_TAG( PT_BOOLEAN, 0x3609) #define PR_SUBFOLDERS PROP_TAG( PT_BOOLEAN, 0x360A) #define PR_STATUS PROP_TAG( PT_LONG, 0x360B) #define PR_ANR PROP_TAG( PT_TSTRING, 0x360C) #define PR_ANR_W PROP_TAG( PT_UNICODE, 0x360C) #define PR_ANR_A PROP_TAG( PT_STRING8, 0x360C) #define PR_CONTENTS_SORT_ORDER PROP_TAG( PT_MV_LONG, 0x360D) #define PR_CONTAINER_HIERARCHY PROP_TAG( PT_OBJECT, 0x360E) #define PR_CONTAINER_CONTENTS PROP_TAG( PT_OBJECT, 0x360F) #define PR_FOLDER_ASSOCIATED_CONTENTS PROP_TAG( PT_OBJECT, 0x3610) #define PR_DEF_CREATE_DL PROP_TAG( PT_BINARY, 0x3611) #define PR_DEF_CREATE_MAILUSER PROP_TAG( PT_BINARY, 0x3612) #define PR_CONTAINER_CLASS PROP_TAG( PT_TSTRING, 0x3613) #define PR_CONTAINER_CLASS_W PROP_TAG( PT_UNICODE, 0x3613) #define PR_CONTAINER_CLASS_A PROP_TAG( PT_STRING8, 0x3613) #define PR_CONTAINER_MODIFY_VERSION PROP_TAG( PT_I8, 0x3614) #define PR_AB_PROVIDER_ID PROP_TAG( PT_BINARY, 0x3615) #define PR_DEFAULT_VIEW_ENTRYID PROP_TAG( PT_BINARY, 0x3616) #define PR_ASSOC_CONTENT_COUNT PROP_TAG( PT_LONG, 0x3617) #define PR_ATTACHMENT_X400_PARAMETERS PROP_TAG( PT_BINARY, 0x3700) #define PR_ATTACH_DATA_OBJ PROP_TAG( PT_OBJECT, 0x3701) #define PR_ATTACH_DATA_BIN PROP_TAG( PT_BINARY, 0x3701) #define PR_ATTACH_ENCODING PROP_TAG( PT_BINARY, 0x3702) #define PR_ATTACH_EXTENSION PROP_TAG( PT_TSTRING, 0x3703) #define PR_ATTACH_EXTENSION_W PROP_TAG( PT_UNICODE, 0x3703) #define PR_ATTACH_EXTENSION_A PROP_TAG( PT_STRING8, 0x3703) #define PR_ATTACH_FILENAME PROP_TAG( PT_TSTRING, 0x3704) #define PR_ATTACH_FILENAME_W PROP_TAG( PT_UNICODE, 0x3704) #define PR_ATTACH_FILENAME_A PROP_TAG( PT_STRING8, 0x3704) #define PR_ATTACH_METHOD PROP_TAG( PT_LONG, 0x3705) #define PR_ATTACH_LONG_FILENAME PROP_TAG( PT_TSTRING, 0x3707) #define PR_ATTACH_LONG_FILENAME_W PROP_TAG( PT_UNICODE, 0x3707) #define PR_ATTACH_LONG_FILENAME_A PROP_TAG( PT_STRING8, 0x3707) #define PR_ATTACH_PATHNAME PROP_TAG( PT_TSTRING, 0x3708) #define PR_ATTACH_PATHNAME_W PROP_TAG( PT_UNICODE, 0x3708) #define PR_ATTACH_PATHNAME_A PROP_TAG( PT_STRING8, 0x3708) #define PR_ATTACH_RENDERING PROP_TAG( PT_BINARY, 0x3709) #define PR_ATTACH_TAG PROP_TAG( PT_BINARY, 0x370A) #define PR_RENDERING_POSITION PROP_TAG( PT_LONG, 0x370B) #define PR_ATTACH_TRANSPORT_NAME PROP_TAG( PT_TSTRING, 0x370C) #define PR_ATTACH_TRANSPORT_NAME_W PROP_TAG( PT_UNICODE, 0x370C) #define PR_ATTACH_TRANSPORT_NAME_A PROP_TAG( PT_STRING8, 0x370C) #define PR_ATTACH_LONG_PATHNAME PROP_TAG( PT_TSTRING, 0x370D) #define PR_ATTACH_LONG_PATHNAME_W PROP_TAG( PT_UNICODE, 0x370D) #define PR_ATTACH_LONG_PATHNAME_A PROP_TAG( PT_STRING8, 0x370D) #define PR_ATTACH_MIME_TAG PROP_TAG( PT_TSTRING, 0x370E) #define PR_ATTACH_MIME_TAG_W PROP_TAG( PT_UNICODE, 0x370E) #define PR_ATTACH_MIME_TAG_A PROP_TAG( PT_STRING8, 0x370E) #define PR_ATTACH_ADDITIONAL_INFO PROP_TAG( PT_BINARY, 0x370F) +#define PR_ATTACH_CONTENT_ID PROP_TAG( PT_UNICODE, 0x3712) #define PR_DISPLAY_TYPE PROP_TAG( PT_LONG, 0x3900) #define PR_TEMPLATEID PROP_TAG( PT_BINARY, 0x3902) #define PR_PRIMARY_CAPABILITY PROP_TAG( PT_BINARY, 0x3904) #define PR_7BIT_DISPLAY_NAME PROP_TAG( PT_STRING8, 0x39FF) #define PR_ACCOUNT PROP_TAG( PT_TSTRING, 0x3A00) #define PR_ACCOUNT_W PROP_TAG( PT_UNICODE, 0x3A00) #define PR_ACCOUNT_A PROP_TAG( PT_STRING8, 0x3A00) #define PR_ALTERNATE_RECIPIENT PROP_TAG( PT_BINARY, 0x3A01) #define PR_CALLBACK_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A02) #define PR_CALLBACK_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A02) #define PR_CALLBACK_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A02) #define PR_CONVERSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x3A03) #define PR_DISCLOSE_RECIPIENTS PROP_TAG( PT_BOOLEAN, 0x3A04) #define PR_GENERATION PROP_TAG( PT_TSTRING, 0x3A05) #define PR_GENERATION_W PROP_TAG( PT_UNICODE, 0x3A05) #define PR_GENERATION_A PROP_TAG( PT_STRING8, 0x3A05) #define PR_GIVEN_NAME PROP_TAG( PT_TSTRING, 0x3A06) #define PR_GIVEN_NAME_W PROP_TAG( PT_UNICODE, 0x3A06) #define PR_GIVEN_NAME_A PROP_TAG( PT_STRING8, 0x3A06) #define PR_GOVERNMENT_ID_NUMBER PROP_TAG( PT_TSTRING, 0x3A07) #define PR_GOVERNMENT_ID_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A07) #define PR_GOVERNMENT_ID_NUMBER_A PROP_TAG( PT_STRING8, 0x3A07) #define PR_BUSINESS_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A08) #define PR_BUSINESS_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A08) #define PR_BUSINESS_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A08) #define PR_OFFICE_TELEPHONE_NUMBER PR_BUSINESS_TELEPHONE_NUMBER #define PR_OFFICE_TELEPHONE_NUMBER_W PR_BUSINESS_TELEPHONE_NUMBER_W #define PR_OFFICE_TELEPHONE_NUMBER_A PR_BUSINESS_TELEPHONE_NUMBER_A #define PR_HOME_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A09) #define PR_HOME_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A09) #define PR_HOME_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A09) #define PR_INITIALS PROP_TAG( PT_TSTRING, 0x3A0A) #define PR_INITIALS_W PROP_TAG( PT_UNICODE, 0x3A0A) #define PR_INITIALS_A PROP_TAG( PT_STRING8, 0x3A0A) #define PR_KEYWORD PROP_TAG( PT_TSTRING, 0x3A0B) #define PR_KEYWORD_W PROP_TAG( PT_UNICODE, 0x3A0B) #define PR_KEYWORD_A PROP_TAG( PT_STRING8, 0x3A0B) #define PR_LANGUAGE PROP_TAG( PT_TSTRING, 0x3A0C) #define PR_LANGUAGE_W PROP_TAG( PT_UNICODE, 0x3A0C) #define PR_LANGUAGE_A PROP_TAG( PT_STRING8, 0x3A0C) #define PR_LOCATION PROP_TAG( PT_TSTRING, 0x3A0D) #define PR_LOCATION_W PROP_TAG( PT_UNICODE, 0x3A0D) #define PR_LOCATION_A PROP_TAG( PT_STRING8, 0x3A0D) #define PR_MAIL_PERMISSION PROP_TAG( PT_BOOLEAN, 0x3A0E) #define PR_MHS_COMMON_NAME PROP_TAG( PT_TSTRING, 0x3A0F) #define PR_MHS_COMMON_NAME_W PROP_TAG( PT_UNICODE, 0x3A0F) #define PR_MHS_COMMON_NAME_A PROP_TAG( PT_STRING8, 0x3A0F) #define PR_ORGANIZATIONAL_ID_NUMBER PROP_TAG( PT_TSTRING, 0x3A10) #define PR_ORGANIZATIONAL_ID_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A10) #define PR_ORGANIZATIONAL_ID_NUMBER_A PROP_TAG( PT_STRING8, 0x3A10) #define PR_SURNAME PROP_TAG( PT_TSTRING, 0x3A11) #define PR_SURNAME_W PROP_TAG( PT_UNICODE, 0x3A11) #define PR_SURNAME_A PROP_TAG( PT_STRING8, 0x3A11) #define PR_ORIGINAL_ENTRYID PROP_TAG( PT_BINARY, 0x3A12) #define PR_ORIGINAL_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3A13) #define PR_ORIGINAL_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3A13) #define PR_ORIGINAL_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3A13) #define PR_ORIGINAL_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3A14) #define PR_POSTAL_ADDRESS PROP_TAG( PT_TSTRING, 0x3A15) #define PR_POSTAL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3A15) #define PR_POSTAL_ADDRESS_A PROP_TAG( PT_STRING8, 0x3A15) #define PR_COMPANY_NAME PROP_TAG( PT_TSTRING, 0x3A16) #define PR_COMPANY_NAME_W PROP_TAG( PT_UNICODE, 0x3A16) #define PR_COMPANY_NAME_A PROP_TAG( PT_STRING8, 0x3A16) #define PR_TITLE PROP_TAG( PT_TSTRING, 0x3A17) #define PR_TITLE_W PROP_TAG( PT_UNICODE, 0x3A17) #define PR_TITLE_A PROP_TAG( PT_STRING8, 0x3A17) #define PR_DEPARTMENT_NAME PROP_TAG( PT_TSTRING, 0x3A18) #define PR_DEPARTMENT_NAME_W PROP_TAG( PT_UNICODE, 0x3A18) #define PR_DEPARTMENT_NAME_A PROP_TAG( PT_STRING8, 0x3A18) #define PR_OFFICE_LOCATION PROP_TAG( PT_TSTRING, 0x3A19) #define PR_OFFICE_LOCATION_W PROP_TAG( PT_UNICODE, 0x3A19) #define PR_OFFICE_LOCATION_A PROP_TAG( PT_STRING8, 0x3A19) #define PR_PRIMARY_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1A) #define PR_PRIMARY_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1A) #define PR_PRIMARY_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1A) #define PR_BUSINESS2_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1B) #define PR_BUSINESS2_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1B) #define PR_BUSINESS2_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1B) #define PR_OFFICE2_TELEPHONE_NUMBER PR_BUSINESS2_TELEPHONE_NUMBER #define PR_OFFICE2_TELEPHONE_NUMBER_W PR_BUSINESS2_TELEPHONE_NUMBER_W #define PR_OFFICE2_TELEPHONE_NUMBER_A PR_BUSINESS2_TELEPHONE_NUMBER_A #define PR_MOBILE_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1C) #define PR_MOBILE_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1C) #define PR_MOBILE_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1C) #define PR_CELLULAR_TELEPHONE_NUMBER PR_MOBILE_TELEPHONE_NUMBER #define PR_CELLULAR_TELEPHONE_NUMBER_W PR_MOBILE_TELEPHONE_NUMBER_W #define PR_CELLULAR_TELEPHONE_NUMBER_A PR_MOBILE_TELEPHONE_NUMBER_A #define PR_RADIO_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1D) #define PR_RADIO_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1D) #define PR_RADIO_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1D) #define PR_CAR_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1E) #define PR_CAR_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1E) #define PR_CAR_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1E) #define PR_OTHER_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1F) #define PR_OTHER_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1F) #define PR_OTHER_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1F) #define PR_TRANSMITABLE_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3A20) #define PR_TRANSMITABLE_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3A20) #define PR_TRANSMITABLE_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3A20) #define PR_PAGER_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A21) #define PR_PAGER_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A21) #define PR_PAGER_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A21) #define PR_BEEPER_TELEPHONE_NUMBER PR_PAGER_TELEPHONE_NUMBER #define PR_BEEPER_TELEPHONE_NUMBER_W PR_PAGER_TELEPHONE_NUMBER_W #define PR_BEEPER_TELEPHONE_NUMBER_A PR_PAGER_TELEPHONE_NUMBER_A #define PR_USER_CERTIFICATE PROP_TAG( PT_BINARY, 0x3A22) #define PR_PRIMARY_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A23) #define PR_PRIMARY_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A23) #define PR_PRIMARY_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A23) #define PR_BUSINESS_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A24) #define PR_BUSINESS_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A24) #define PR_BUSINESS_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A24) #define PR_HOME_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A25) #define PR_HOME_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A25) #define PR_HOME_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A25) #define PR_COUNTRY PROP_TAG( PT_TSTRING, 0x3A26) #define PR_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A26) #define PR_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A26) #define PR_BUSINESS_ADDRESS_COUNTRY PR_COUNTRY #define PR_BUSINESS_ADDRESS_COUNTRY_W PR_COUNTRY_W #define PR_BUSINESS_ADDRESS_COUNTRY_A PR_COUNTRY_A #define PR_LOCALITY PROP_TAG( PT_TSTRING, 0x3A27) #define PR_LOCALITY_W PROP_TAG( PT_UNICODE, 0x3A27) #define PR_LOCALITY_A PROP_TAG( PT_STRING8, 0x3A27) #define PR_BUSINESS_ADDRESS_CITY PR_LOCALITY #define PR_BUSINESS_ADDRESS_CITY_W PR_LOCALITY_W #define PR_BUSINESS_ADDRESS_CITY_A PR_LOCALITY_A #define PR_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A28) #define PR_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A28) #define PR_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A28) #define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE PR_STATE_OR_PROVINCE #define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W PR_STATE_OR_PROVINCE_W #define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A PR_STATE_OR_PROVINCE_A #define PR_STREET_ADDRESS PROP_TAG( PT_TSTRING, 0x3A29) #define PR_STREET_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3A29) #define PR_STREET_ADDRESS_A PROP_TAG( PT_STRING8, 0x3A29) #define PR_BUSINESS_ADDRESS_STREET PR_STREET_ADDRESS #define PR_BUSINESS_ADDRESS_STREET_W PR_STREET_ADDRESS_W #define PR_BUSINESS_ADDRESS_STREET_A PR_STREET_ADDRESS_A #define PR_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A2A) #define PR_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A2A) #define PR_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A2A) #define PR_BUSINESS_ADDRESS_POSTAL_CODE PR_POSTAL_CODE #define PR_BUSINESS_ADDRESS_POSTAL_CODE_W PR_POSTAL_CODE_W #define PR_BUSINESS_ADDRESS_POSTAL_CODE_A PR_POSTAL_CODE_A #define PR_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A2B) #define PR_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A2B) #define PR_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A2B) #define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX PR_POST_OFFICE_BOX #define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX_W PR_POST_OFFICE_BOX_W #define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX_A PR_POST_OFFICE_BOX_A #define PR_TELEX_NUMBER PROP_TAG( PT_TSTRING, 0x3A2C) #define PR_TELEX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2C) #define PR_TELEX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2C) #define PR_ISDN_NUMBER PROP_TAG( PT_TSTRING, 0x3A2D) #define PR_ISDN_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2D) #define PR_ISDN_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2D) #define PR_ASSISTANT_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A2E) #define PR_ASSISTANT_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2E) #define PR_ASSISTANT_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2E) #define PR_HOME2_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A2F) #define PR_HOME2_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2F) #define PR_HOME2_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2F) #define PR_ASSISTANT PROP_TAG( PT_TSTRING, 0x3A30) #define PR_ASSISTANT_W PROP_TAG( PT_UNICODE, 0x3A30) #define PR_ASSISTANT_A PROP_TAG( PT_STRING8, 0x3A30) #define PR_SEND_RICH_INFO PROP_TAG( PT_BOOLEAN, 0x3A40) #define PR_WEDDING_ANNIVERSARY PROP_TAG( PT_SYSTIME, 0x3A41) #define PR_BIRTHDAY PROP_TAG( PT_SYSTIME, 0x3A42) #define PR_HOBBIES PROP_TAG( PT_TSTRING, 0x3A43) #define PR_HOBBIES_W PROP_TAG( PT_UNICODE, 0x3A43) #define PR_HOBBIES_A PROP_TAG( PT_STRING8, 0x3A43) #define PR_MIDDLE_NAME PROP_TAG( PT_TSTRING, 0x3A44) #define PR_MIDDLE_NAME_W PROP_TAG( PT_UNICODE, 0x3A44) #define PR_MIDDLE_NAME_A PROP_TAG( PT_STRING8, 0x3A44) #define PR_DISPLAY_NAME_PREFIX PROP_TAG( PT_TSTRING, 0x3A45) #define PR_DISPLAY_NAME_PREFIX_W PROP_TAG( PT_UNICODE, 0x3A45) #define PR_DISPLAY_NAME_PREFIX_A PROP_TAG( PT_STRING8, 0x3A45) #define PR_PROFESSION PROP_TAG( PT_TSTRING, 0x3A46) #define PR_PROFESSION_W PROP_TAG( PT_UNICODE, 0x3A46) #define PR_PROFESSION_A PROP_TAG( PT_STRING8, 0x3A46) #define PR_PREFERRED_BY_NAME PROP_TAG( PT_TSTRING, 0x3A47) #define PR_PREFERRED_BY_NAME_W PROP_TAG( PT_UNICODE, 0x3A47) #define PR_PREFERRED_BY_NAME_A PROP_TAG( PT_STRING8, 0x3A47) #define PR_SPOUSE_NAME PROP_TAG( PT_TSTRING, 0x3A48) #define PR_SPOUSE_NAME_W PROP_TAG( PT_UNICODE, 0x3A48) #define PR_SPOUSE_NAME_A PROP_TAG( PT_STRING8, 0x3A48) #define PR_COMPUTER_NETWORK_NAME PROP_TAG( PT_TSTRING, 0x3A49) #define PR_COMPUTER_NETWORK_NAME_W PROP_TAG( PT_UNICODE, 0x3A49) #define PR_COMPUTER_NETWORK_NAME_A PROP_TAG( PT_STRING8, 0x3A49) #define PR_CUSTOMER_ID PROP_TAG( PT_TSTRING, 0x3A4A) #define PR_CUSTOMER_ID_W PROP_TAG( PT_UNICODE, 0x3A4A) #define PR_CUSTOMER_ID_A PROP_TAG( PT_STRING8, 0x3A4A) #define PR_TTYTDD_PHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A4B) #define PR_TTYTDD_PHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A4B) #define PR_TTYTDD_PHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A4B) #define PR_FTP_SITE PROP_TAG( PT_TSTRING, 0x3A4C) #define PR_FTP_SITE_W PROP_TAG( PT_UNICODE, 0x3A4C) #define PR_FTP_SITE_A PROP_TAG( PT_STRING8, 0x3A4C) #define PR_GENDER PROP_TAG( PT_SHORT, 0x3A4D) #define PR_MANAGER_NAME PROP_TAG( PT_TSTRING, 0x3A4E) #define PR_MANAGER_NAME_W PROP_TAG( PT_UNICODE, 0x3A4E) #define PR_MANAGER_NAME_A PROP_TAG( PT_STRING8, 0x3A4E) #define PR_NICKNAME PROP_TAG( PT_TSTRING, 0x3A4F) #define PR_NICKNAME_W PROP_TAG( PT_UNICODE, 0x3A4F) #define PR_NICKNAME_A PROP_TAG( PT_STRING8, 0x3A4F) #define PR_PERSONAL_HOME_PAGE PROP_TAG( PT_TSTRING, 0x3A50) #define PR_PERSONAL_HOME_PAGE_W PROP_TAG( PT_UNICODE, 0x3A50) #define PR_PERSONAL_HOME_PAGE_A PROP_TAG( PT_STRING8, 0x3A50) #define PR_BUSINESS_HOME_PAGE PROP_TAG( PT_TSTRING, 0x3A51) #define PR_BUSINESS_HOME_PAGE_W PROP_TAG( PT_UNICODE, 0x3A51) #define PR_BUSINESS_HOME_PAGE_A PROP_TAG( PT_STRING8, 0x3A51) #define PR_CONTACT_VERSION PROP_TAG( PT_CLSID, 0x3A52) #define PR_CONTACT_ENTRYIDS PROP_TAG( PT_MV_BINARY, 0x3A53) #define PR_CONTACT_ADDRTYPES PROP_TAG( PT_MV_TSTRING, 0x3A54) #define PR_CONTACT_ADDRTYPES_W PROP_TAG( PT_MV_UNICODE, 0x3A54) #define PR_CONTACT_ADDRTYPES_A PROP_TAG( PT_MV_STRING8, 0x3A54) #define PR_CONTACT_DEFAULT_ADDRESS_INDEX PROP_TAG( PT_LONG, 0x3A55) #define PR_CONTACT_EMAIL_ADDRESSES PROP_TAG( PT_MV_TSTRING, 0x3A56) #define PR_CONTACT_EMAIL_ADDRESSES_W PROP_TAG( PT_MV_UNICODE, 0x3A56) #define PR_CONTACT_EMAIL_ADDRESSES_A PROP_TAG( PT_MV_STRING8, 0x3A56) #define PR_COMPANY_MAIN_PHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A57) #define PR_COMPANY_MAIN_PHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A57) #define PR_COMPANY_MAIN_PHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A57) #define PR_CHILDRENS_NAMES PROP_TAG( PT_MV_TSTRING, 0x3A58) #define PR_CHILDRENS_NAMES_W PROP_TAG( PT_MV_UNICODE, 0x3A58) #define PR_CHILDRENS_NAMES_A PROP_TAG( PT_MV_STRING8, 0x3A58) #define PR_HOME_ADDRESS_CITY PROP_TAG( PT_TSTRING, 0x3A59) #define PR_HOME_ADDRESS_CITY_W PROP_TAG( PT_UNICODE, 0x3A59) #define PR_HOME_ADDRESS_CITY_A PROP_TAG( PT_STRING8, 0x3A59) #define PR_HOME_ADDRESS_COUNTRY PROP_TAG( PT_TSTRING, 0x3A5A) #define PR_HOME_ADDRESS_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A5A) #define PR_HOME_ADDRESS_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A5A) #define PR_HOME_ADDRESS_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A5B) #define PR_HOME_ADDRESS_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A5B) #define PR_HOME_ADDRESS_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A5B) #define PR_HOME_ADDRESS_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A5C) #define PR_HOME_ADDRESS_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A5C) #define PR_HOME_ADDRESS_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A5C) #define PR_HOME_ADDRESS_STREET PROP_TAG( PT_TSTRING, 0x3A5D) #define PR_HOME_ADDRESS_STREET_W PROP_TAG( PT_UNICODE, 0x3A5D) #define PR_HOME_ADDRESS_STREET_A PROP_TAG( PT_STRING8, 0x3A5D) #define PR_HOME_ADDRESS_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A5E) #define PR_HOME_ADDRESS_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A5E) #define PR_HOME_ADDRESS_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A5E) #define PR_OTHER_ADDRESS_CITY PROP_TAG( PT_TSTRING, 0x3A5F) #define PR_OTHER_ADDRESS_CITY_W PROP_TAG( PT_UNICODE, 0x3A5F) #define PR_OTHER_ADDRESS_CITY_A PROP_TAG( PT_STRING8, 0x3A5F) #define PR_OTHER_ADDRESS_COUNTRY PROP_TAG( PT_TSTRING, 0x3A60) #define PR_OTHER_ADDRESS_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A60) #define PR_OTHER_ADDRESS_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A60) #define PR_OTHER_ADDRESS_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A61) #define PR_OTHER_ADDRESS_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A61) #define PR_OTHER_ADDRESS_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A61) #define PR_OTHER_ADDRESS_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A62) #define PR_OTHER_ADDRESS_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A62) #define PR_OTHER_ADDRESS_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A62) #define PR_OTHER_ADDRESS_STREET PROP_TAG( PT_TSTRING, 0x3A63) #define PR_OTHER_ADDRESS_STREET_W PROP_TAG( PT_UNICODE, 0x3A63) #define PR_OTHER_ADDRESS_STREET_A PROP_TAG( PT_STRING8, 0x3A63) #define PR_OTHER_ADDRESS_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A64) #define PR_OTHER_ADDRESS_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A64) #define PR_OTHER_ADDRESS_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A64) #define PR_STORE_PROVIDERS PROP_TAG( PT_BINARY, 0x3D00) #define PR_AB_PROVIDERS PROP_TAG( PT_BINARY, 0x3D01) #define PR_TRANSPORT_PROVIDERS PROP_TAG( PT_BINARY, 0x3D02) #define PR_DEFAULT_PROFILE PROP_TAG( PT_BOOLEAN, 0x3D04) #define PR_AB_SEARCH_PATH PROP_TAG( PT_MV_BINARY, 0x3D05) #define PR_AB_DEFAULT_DIR PROP_TAG( PT_BINARY, 0x3D06) #define PR_AB_DEFAULT_PAB PROP_TAG( PT_BINARY, 0x3D07) #define PR_FILTERING_HOOKS PROP_TAG( PT_BINARY, 0x3D08) #define PR_SERVICE_NAME PROP_TAG( PT_TSTRING, 0x3D09) #define PR_SERVICE_NAME_W PROP_TAG( PT_UNICODE, 0x3D09) #define PR_SERVICE_NAME_A PROP_TAG( PT_STRING8, 0x3D09) #define PR_SERVICE_DLL_NAME PROP_TAG( PT_TSTRING, 0x3D0A) #define PR_SERVICE_DLL_NAME_W PROP_TAG( PT_UNICODE, 0x3D0A) #define PR_SERVICE_DLL_NAME_A PROP_TAG( PT_STRING8, 0x3D0A) #define PR_SERVICE_ENTRY_NAME PROP_TAG( PT_STRING8, 0x3D0B) #define PR_SERVICE_UID PROP_TAG( PT_BINARY, 0x3D0C) #define PR_SERVICE_EXTRA_UIDS PROP_TAG( PT_BINARY, 0x3D0D) #define PR_SERVICES PROP_TAG( PT_BINARY, 0x3D0E) #define PR_SERVICE_SUPPORT_FILES PROP_TAG( PT_MV_TSTRING, 0x3D0F) #define PR_SERVICE_SUPPORT_FILES_W PROP_TAG( PT_MV_UNICODE, 0x3D0F) #define PR_SERVICE_SUPPORT_FILES_A PROP_TAG( PT_MV_STRING8, 0x3D0F) #define PR_SERVICE_DELETE_FILES PROP_TAG( PT_MV_TSTRING, 0x3D10) #define PR_SERVICE_DELETE_FILES_W PROP_TAG( PT_MV_UNICODE, 0x3D10) #define PR_SERVICE_DELETE_FILES_A PROP_TAG( PT_MV_STRING8, 0x3D10) #define PR_AB_SEARCH_PATH_UPDATE PROP_TAG( PT_BINARY, 0x3D11) #define PR_PROFILE_NAME PROP_TAG( PT_TSTRING, 0x3D12) #define PR_PROFILE_NAME_A PROP_TAG( PT_STRING8, 0x3D12) #define PR_PROFILE_NAME_W PROP_TAG( PT_UNICODE, 0x3D12) #define PR_IDENTITY_DISPLAY PROP_TAG( PT_TSTRING, 0x3E00) #define PR_IDENTITY_DISPLAY_W PROP_TAG( PT_UNICODE, 0x3E00) #define PR_IDENTITY_DISPLAY_A PROP_TAG( PT_STRING8, 0x3E00) #define PR_IDENTITY_ENTRYID PROP_TAG( PT_BINARY, 0x3E01) #define PR_RESOURCE_METHODS PROP_TAG( PT_LONG, 0x3E02) #define PR_RESOURCE_TYPE PROP_TAG( PT_LONG, 0x3E03) #define PR_STATUS_CODE PROP_TAG( PT_LONG, 0x3E04) #define PR_IDENTITY_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3E05) #define PR_OWN_STORE_ENTRYID PROP_TAG( PT_BINARY, 0x3E06) #define PR_RESOURCE_PATH PROP_TAG( PT_TSTRING, 0x3E07) #define PR_RESOURCE_PATH_W PROP_TAG( PT_UNICODE, 0x3E07) #define PR_RESOURCE_PATH_A PROP_TAG( PT_STRING8, 0x3E07) #define PR_STATUS_STRING PROP_TAG( PT_TSTRING, 0x3E08) #define PR_STATUS_STRING_W PROP_TAG( PT_UNICODE, 0x3E08) #define PR_STATUS_STRING_A PROP_TAG( PT_STRING8, 0x3E08) #define PR_X400_DEFERRED_DELIVERY_CANCEL PROP_TAG( PT_BOOLEAN, 0x3E09) #define PR_HEADER_FOLDER_ENTRYID PROP_TAG( PT_BINARY, 0x3E0A) #define PR_REMOTE_PROGRESS PROP_TAG( PT_LONG, 0x3E0B) #define PR_REMOTE_PROGRESS_TEXT PROP_TAG( PT_TSTRING, 0x3E0C) #define PR_REMOTE_PROGRESS_TEXT_W PROP_TAG( PT_UNICODE, 0x3E0C) #define PR_REMOTE_PROGRESS_TEXT_A PROP_TAG( PT_STRING8, 0x3E0C) #define PR_REMOTE_VALIDATE_OK PROP_TAG( PT_BOOLEAN, 0x3E0D) #define PR_CONTROL_FLAGS PROP_TAG( PT_LONG, 0x3F00) #define PR_CONTROL_STRUCTURE PROP_TAG( PT_BINARY, 0x3F01) #define PR_CONTROL_TYPE PROP_TAG( PT_LONG, 0x3F02) #define PR_DELTAX PROP_TAG( PT_LONG, 0x3F03) #define PR_DELTAY PROP_TAG( PT_LONG, 0x3F04) #define PR_XPOS PROP_TAG( PT_LONG, 0x3F05) #define PR_YPOS PROP_TAG( PT_LONG, 0x3F06) #define PR_CONTROL_ID PROP_TAG( PT_BINARY, 0x3F07) #define PR_INITIAL_DETAILS_PANE PROP_TAG( PT_LONG, 0x3F08) #define PR_MSG_EDITOR_FORMAT PROP_TAG( PT_LONG, 0x5903) #define PR_ATTACHMENT_HIDDEN PROP_TAG( PT_BOOLEAN, 0x7ffe) #define PR_SMTP_ADDRESS PROP_TAG( PT_TSTRING, 0x39fe) #define PR_SMTP_ADDRESS_W PROP_TAG( PT_UNICODE, 0x39fe) #define PR_SMTP_ADDRESS_A PROP_TAG( PT_STRING8, 0x39fe) #define PR_SENT_REPRESENTING_SMTP_ADDRESS PROP_TAG( PT_TSTRING, 0x5d02) #define PR_SENT_REPRESENTING_SMTP_ADDRESS_A PROP_TAG( PT_STRING8, 0x5d02) #define PR_SENT_REPRESENTING_SMTP_ADDRESS_W PROP_TAG( PT_UNICODE, 0x5d02) #define PidTagSenderSmtpAddress_W PROP_TAG( PT_UNICODE, 0x5d01) #define PROP_ID_SECURE_MIN 0x67F0 #define PROP_ID_SECURE_MAX 0x67FF #define pidExchangeXmitReservedMin 0x3FE0 #define pidExchangeNonXmitReservedMin 0x65E0 #define pidProfileMin 0x6600 #define pidStoreMin 0x6618 #define pidFolderMin 0x6638 #define pidMessageReadOnlyMin 0x6640 #define pidMessageWriteableMin 0x6658 #define pidAttachReadOnlyMin 0x666C #define pidSpecialMin 0x6670 #define pidAdminMin 0x6690 #define pidSecureProfileMin PROP_ID_SECURE_MIN #define PR_PROFILE_VERSION PROP_TAG( PT_LONG, pidProfileMin+0x00) #define PR_PROFILE_CONFIG_FLAGS PROP_TAG( PT_LONG, pidProfileMin+0x01) #define PR_PROFILE_HOME_SERVER PROP_TAG( PT_STRING8, pidProfileMin+0x02) #define PR_PROFILE_HOME_SERVER_DN PROP_TAG( PT_STRING8, pidProfileMin+0x12) #define PR_PROFILE_HOME_SERVER_ADDRS PROP_TAG( PT_MV_STRING8, \ pidProfileMin+0x13) #define PR_PROFILE_USER PROP_TAG( PT_STRING8, pidProfileMin+0x03) #define PR_PROFILE_CONNECT_FLAGS PROP_TAG( PT_LONG, pidProfileMin+0x04) #define PR_PROFILE_TRANSPORT_FLAGS PROP_TAG( PT_LONG, pidProfileMin+0x05) #define PR_PROFILE_UI_STATE PROP_TAG( PT_LONG, pidProfileMin+0x06) #define PR_PROFILE_UNRESOLVED_NAME PROP_TAG( PT_STRING8, pidProfileMin+0x07) #define PR_PROFILE_UNRESOLVED_SERVER PROP_TAG( PT_STRING8, pidProfileMin+0x08) #define PR_PROFILE_BINDING_ORDER PROP_TAG( PT_STRING8, pidProfileMin+0x09) #define PR_PROFILE_MAX_RESTRICT PROP_TAG( PT_LONG, pidProfileMin+0x0D) #define PR_PROFILE_AB_FILES_PATH PROP_TAG( PT_STRING8, pidProfileMin+0xE) #define PR_PROFILE_OFFLINE_STORE_PATH PROP_TAG( PT_STRING8,pidProfileMin+0x10) #define PR_PROFILE_OFFLINE_INFO PROP_TAG( PT_BINARY, pidProfileMin+0x11) #define PR_PROFILE_ADDR_INFO PROP_TAG( PT_BINARY, pidSpecialMin+0x17) #define PR_PROFILE_OPTIONS_DATA PROP_TAG( PT_BINARY, pidSpecialMin+0x19) #define PR_PROFILE_SECURE_MAILBOX PROP_TAG( PT_BINARY, \ pidSecureProfileMin + 0) #define PR_DISABLE_WINSOCK PROP_TAG( PT_LONG, pidProfileMin+0x18) #define PR_OST_ENCRYPTION PROP_TAG( PT_LONG, 0x6702) #define PR_PROFILE_OPEN_FLAGS PROP_TAG( PT_LONG, pidProfileMin+0x09) #define PR_PROFILE_TYPE PROP_TAG( PT_LONG, pidProfileMin+0x0A) #define PR_PROFILE_MAILBOX PROP_TAG( PT_STRING8, pidProfileMin+0x0B) #define PR_PROFILE_SERVER PROP_TAG( PT_STRING8, pidProfileMin+0x0C) #define PR_PROFILE_SERVER_DN PROP_TAG( PT_STRING8, pidProfileMin+0x14) #define PR_PROFILE_FAVFLD_DISPLAY_NAME PROP_TAG(PT_STRING8,pidProfileMin+0x0F) #define PR_PROFILE_FAVFLD_COMMENT PROP_TAG(PT_STRING8, pidProfileMin+0x15) #define PR_PROFILE_ALLPUB_DISPLAY_NAME PROP_TAG(PT_STRING8,pidProfileMin+0x16) #define PR_PROFILE_ALLPUB_COMMENT PROP_TAG(PT_STRING8, pidProfileMin+0x17) #define OSTF_NO_ENCRYPTION 0x80000000 #define OSTF_COMPRESSABLE_ENCRYPTION 0x40000000 #define OSTF_BEST_ENCRYPTION 0x20000000 #define PR_NON_IPM_SUBTREE_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x08) #define PR_EFORMS_REGISTRY_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x09) #define PR_SPLUS_FREE_BUSY_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x0A) #define PR_OFFLINE_ADDRBOOK_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x0B) #define PR_EFORMS_FOR_LOCALE_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x0C) #define PR_FREE_BUSY_FOR_LOCAL_SITE_ENTRYID \ PROP_TAG( PT_BINARY, pidStoreMin+0x0D) #define PR_ADDRBOOK_FOR_LOCAL_SITE_ENTRYID \ PROP_TAG( PT_BINARY, pidStoreMin+0x0E) #define PR_OFFLINE_MESSAGE_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x0F) #define PR_IPM_FAVORITES_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x18) #define PR_IPM_PUBLIC_FOLDERS_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x19) #define PR_GW_MTSIN_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x10) #define PR_GW_MTSOUT_ENTRYID PROP_TAG( PT_BINARY, pidStoreMin+0x11) #define PR_TRANSFER_ENABLED PROP_TAG( PT_BOOLEAN,pidStoreMin+0x12) #define PR_TEST_LINE_SPEED PROP_TAG( PT_BINARY, pidStoreMin+0x13) #define PR_HIERARCHY_SYNCHRONIZER PROP_TAG( PT_OBJECT, pidStoreMin+0x14) #define PR_CONTENTS_SYNCHRONIZER PROP_TAG( PT_OBJECT, pidStoreMin+0x15) #define PR_COLLECTOR PROP_TAG( PT_OBJECT, pidStoreMin+0x16) #define PR_FAST_TRANSFER PROP_TAG( PT_OBJECT, pidStoreMin+0x17) #define PR_STORE_OFFLINE PROP_TAG( PT_BOOLEAN,pidStoreMin+0x1A) #define PR_IN_TRANSIT PROP_TAG( PT_BOOLEAN,pidStoreMin) #define PR_REPLICATION_STYLE PROP_TAG( PT_LONG, pidAdminMin) #define PR_REPLICATION_SCHEDULE PROP_TAG( PT_BINARY, pidAdminMin+0x01) #define PR_REPLICATION_MESSAGE_PRIORITY PROP_TAG( PT_LONG, pidAdminMin+0x02) #define PR_OVERALL_MSG_AGE_LIMIT PROP_TAG( PT_LONG, pidAdminMin+0x03 ) #define PR_REPLICATION_ALWAYS_INTERVAL PROP_TAG( PT_LONG, pidAdminMin+0x04 ) #define PR_REPLICATION_MSG_SIZE PROP_TAG( PT_LONG, pidAdminMin+0x05 ) #define REPLICATION_MESSAGE_SIZE_LIMIT_DEFAULT 100 #define STYLE_DEFAULT (-1) #define STYLE_NEVER 0 #define STYLE_NORMAL 1 #define STYLE_ALWAYS 2 #define STYLE_ALWAYS_INTERVAL_DEFAULT 15 #define PR_SOURCE_KEY PROP_TAG( PT_BINARY, pidExchangeNonXmitReservedMin+0x0) #define PR_PARENT_SOURCE_KEY \ PROP_TAG( PT_BINARY, pidExchangeNonXmitReservedMin+0x1) #define PR_CHANGE_KEY PROP_TAG( PT_BINARY, pidExchangeNonXmitReservedMin+0x2) #define PR_PREDECESSOR_CHANGE_LIST \ PROP_TAG( PT_BINARY, pidExchangeNonXmitReservedMin+0x3) #define PR_FOLDER_CHILD_COUNT PROP_TAG( PT_LONG, pidFolderMin) #define PR_RIGHTS PROP_TAG( PT_LONG, pidFolderMin+1) #define PR_HAS_RULES PROP_TAG( PT_BOOLEAN, pidFolderMin+2) #define PR_ACL_TABLE PROP_TAG( PT_OBJECT, pidExchangeXmitReservedMin) #define PR_RULES_TABLE PROP_TAG( PT_OBJECT, pidExchangeXmitReservedMin+1) #define PR_ADDRESS_BOOK_ENTRYID PROP_TAG( PT_BINARY, pidFolderMin+0x03) #define PR_ACL_DATA PROP_TAG( PT_BINARY, pidExchangeXmitReservedMin) #define PR_RULES_DATA PROP_TAG( PT_BINARY, pidExchangeXmitReservedMin+0x1) #define PR_FOLDER_DESIGN_FLAGS \ PROP_TAG( PT_LONG, pidExchangeXmitReservedMin+0x2) #define PR_DESIGN_IN_PROGRESS \ PROP_TAG( PT_BOOLEAN, pidExchangeXmitReservedMin+0x4) #define PR_SECURE_ORIGINATION \ PROP_TAG( PT_BOOLEAN, pidExchangeXmitReservedMin+0x5) #define PR_PUBLISH_IN_ADDRESS_BOOK \ PROP_TAG( PT_BOOLEAN, pidExchangeXmitReservedMin+0x6) #define PR_RESOLVE_METHOD PROP_TAG( PT_LONG, pidExchangeXmitReservedMin+0x7) #define PR_ADDRESS_BOOK_DISPLAY_NAME \ PROP_TAG( PT_TSTRING, pidExchangeXmitReservedMin+0x8) #define PR_EFORMS_LOCALE_ID PROP_TAG( PT_LONG, pidExchangeXmitReservedMin+0x9) #define PR_REPLICA_LIST PROP_TAG( PT_BINARY, pidAdminMin+0x8) #define PR_OVERALL_AGE_LIMIT PROP_TAG( PT_LONG, pidAdminMin+0x9) #define RESOLVE_METHOD_DEFAULT 0 #define RESOLVE_METHOD_LAST_WRITER_WINS 1 #define RESOLVE_METHOD_NO_CONFLICT_NOTIFICATION 2 #define PR_PUBLIC_FOLDER_ENTRYID PROP_TAG( PT_BINARY, pidFolderMin+0x04) #define PR_HAS_NAMED_PROPERTIES \ PROP_TAG(PT_BOOLEAN, pidMessageReadOnlyMin+0x0A) #define PR_CREATOR_NAME \ PROP_TAG(PT_TSTRING, pidExchangeXmitReservedMin+0x18) #define PR_CREATOR_ENTRYID \ PROP_TAG(PT_BINARY, pidExchangeXmitReservedMin+0x19) #define PR_LAST_MODIFIER_NAME \ PROP_TAG(PT_TSTRING, pidExchangeXmitReservedMin+0x1A) #define PR_LAST_MODIFIER_ENTRYID \ PROP_TAG(PT_BINARY, pidExchangeXmitReservedMin+0x1B) #define PR_HAS_DAMS \ PROP_TAG( PT_BOOLEAN, pidExchangeXmitReservedMin+0xA) #define PR_RULE_TRIGGER_HISTORY \ PROP_TAG( PT_BINARY, pidExchangeXmitReservedMin+0x12) #define PR_MOVE_TO_STORE_ENTRYID \ PROP_TAG( PT_BINARY, pidExchangeXmitReservedMin+0x13) #define PR_MOVE_TO_FOLDER_ENTRYID \ PROP_TAG( PT_BINARY, pidExchangeXmitReservedMin+0x14) #define PR_REPLICA_SERVER \ PROP_TAG(PT_TSTRING, pidMessageReadOnlyMin+0x4) #define PR_DEFERRED_SEND_NUMBER \ PROP_TAG( PT_LONG, pidExchangeXmitReservedMin+0xB) #define PR_DEFERRED_SEND_UNITS \ PROP_TAG( PT_LONG, pidExchangeXmitReservedMin+0xC) #define PR_EXPIRY_NUMBER \ PROP_TAG( PT_LONG, pidExchangeXmitReservedMin+0xD) #define PR_EXPIRY_UNITS \ PROP_TAG( PT_LONG, pidExchangeXmitReservedMin+0xE) #define PR_DEFERRED_SEND_TIME \ PROP_TAG( PT_SYSTIME, pidExchangeXmitReservedMin+0xF) #define PR_GW_ADMIN_OPERATIONS PROP_TAG( PT_LONG, pidMessageWriteableMin) #define PR_P1_CONTENT PROP_TAG( PT_BINARY, 0x1100) #define PR_P1_CONTENT_TYPE PROP_TAG( PT_BINARY, 0x1101) #define PR_CLIENT_ACTIONS PROP_TAG(PT_BINARY, pidMessageReadOnlyMin+0x5) #define PR_DAM_ORIGINAL_ENTRYID PROP_TAG(PT_BINARY, pidMessageReadOnlyMin+0x6) #define PR_DAM_BACK_PATCHED PROP_TAG(PT_BOOLEAN, pidMessageReadOnlyMin+0x7) #define PR_RULE_ERROR PROP_TAG(PT_LONG, pidMessageReadOnlyMin+0x8) #define PR_RULE_ACTION_TYPE PROP_TAG(PT_LONG, pidMessageReadOnlyMin+0x9) #define PR_RULE_ACTION_NUMBER PROP_TAG(PT_LONG, pidMessageReadOnlyMin+0x10) #define PR_RULE_FOLDER_ENTRYID PROP_TAG(PT_BINARY, pidMessageReadOnlyMin+0x11) #define PR_CONFLICT_ENTRYID \ PROP_TAG(PT_BINARY, pidExchangeXmitReservedMin+0x10) #define PR_MESSAGE_LOCALE_ID \ PROP_TAG(PT_LONG, pidExchangeXmitReservedMin+0x11) #define PR_STORAGE_QUOTA_LIMIT \ PROP_TAG(PT_LONG, pidExchangeXmitReservedMin+0x15) #define PR_EXCESS_STORAGE_USED \ PROP_TAG(PT_LONG, pidExchangeXmitReservedMin+0x16) #define PR_SVR_GENERATING_QUOTA_MSG \ PROP_TAG(PT_TSTRING, pidExchangeXmitReservedMin+0x17) #define PR_DELEGATED_BY_RULE \ PROP_TAG( PT_BOOLEAN, pidExchangeXmitReservedMin+0x3) #define MSGSTATUS_IN_CONFLICT 0x800 #define PR_IN_CONFLICT PROP_TAG(PT_BOOLEAN, pidAttachReadOnlyMin) #define PR_LONGTERM_ENTRYID_FROM_TABLE PROP_TAG(PT_BINARY, pidSpecialMin) #define PR_ORIGINATOR_NAME PROP_TAG( PT_TSTRING, pidMessageWriteableMin+0x3) #define PR_ORIGINATOR_ADDR PROP_TAG( PT_TSTRING, pidMessageWriteableMin+0x4) #define PR_ORIGINATOR_ADDRTYPE \ PROP_TAG( PT_TSTRING, pidMessageWriteableMin+0x5) #define PR_ORIGINATOR_ENTRYID PROP_TAG( PT_BINARY, pidMessageWriteableMin+0x6) #define PR_ARRIVAL_TIME PROP_TAG( PT_SYSTIME, pidMessageWriteableMin+0x7) #define PR_TRACE_INFO PROP_TAG( PT_BINARY, pidMessageWriteableMin+0x8) #define PR_INTERNAL_TRACE_INFO \ PROP_TAG( PT_BINARY, pidMessageWriteableMin+0x12) #define PR_SUBJECT_TRACE_INFO PROP_TAG( PT_BINARY, pidMessageWriteableMin+0x9) #define PR_RECIPIENT_NUMBER PROP_TAG( PT_LONG, pidMessageWriteableMin+0xA) #define PR_MTS_SUBJECT_ID PROP_TAG(PT_BINARY, pidMessageWriteableMin+0xB) #define PR_REPORT_DESTINATION_NAME \ PROP_TAG(PT_TSTRING, pidMessageWriteableMin+0xC) #define PR_REPORT_DESTINATION_ENTRYID \ PROP_TAG(PT_BINARY, pidMessageWriteableMin+0xD) #define PR_CONTENT_SEARCH_KEY PROP_TAG(PT_BINARY, pidMessageWriteableMin+0xE) #define PR_FOREIGN_ID PROP_TAG(PT_BINARY, pidMessageWriteableMin+0xF) #define PR_FOREIGN_REPORT_ID PROP_TAG(PT_BINARY, pidMessageWriteableMin+0x10) #define PR_FOREIGN_SUBJECT_ID PROP_TAG(PT_BINARY, pidMessageWriteableMin+0x11) #define PR_MTS_ID PR_MESSAGE_SUBMISSION_ID #define PR_MTS_REPORT_ID PR_MESSAGE_SUBMISSION_ID #define PR_FOLDER_FLAGS PROP_TAG( PT_LONG, pidAdminMin+0x18 ) #define PR_LAST_ACCESS_TIME PROP_TAG( PT_SYSTIME,pidAdminMin+0x19) #define PR_RESTRICTION_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x1A ) #define PR_CATEG_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x1B ) #define PR_CACHED_COLUMN_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x1C ) #define PR_NORMAL_MSG_W_ATTACH_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x1D ) #define PR_ASSOC_MSG_W_ATTACH_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x1E ) #define PR_RECIPIENT_ON_NORMAL_MSG_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x1F ) #define PR_RECIPIENT_ON_ASSOC_MSG_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x20 ) #define PR_ATTACH_ON_NORMAL_MSG_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x21 ) #define PR_ATTACH_ON_ASSOC_MSG_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x22 ) #define PR_NORMAL_MESSAGE_SIZE PROP_TAG( PT_LONG, pidAdminMin+0x23 ) #define PR_NORMAL_MESSAGE_SIZE_EXTENDED PROP_TAG( PT_I8, pidAdminMin+0x23 ) #define PR_ASSOC_MESSAGE_SIZE PROP_TAG( PT_LONG, pidAdminMin+0x24 ) #define PR_ASSOC_MESSAGE_SIZE_EXTENDED PROP_TAG( PT_I8, pidAdminMin+0x24 ) #define PR_FOLDER_PATHNAME PROP_TAG(PT_TSTRING, pidAdminMin+0x25 ) #define PR_OWNER_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x26 ) #define PR_CONTACT_COUNT PROP_TAG( PT_LONG, pidAdminMin+0x27 ) #define PR_MESSAGE_SIZE_EXTENDED PROP_TAG(PT_I8, PROP_ID(PR_MESSAGE_SIZE)) #endif /*MAPITAGS_H*/