4 * Copyright 2006 Robert Shearman for CodeWeavers
5 * Copyright 2007 Huw Davies for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
35 #include "wine/list.h"
36 #include "wine/debug.h"
38 #include "inetcomm_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
46 DWORD flags; /* MIMEPROPFLAGS */
54 } property_list_entry_t;
56 static const property_t default_props[] =
58 {"References", PID_HDR_REFS, 0, VT_LPSTR},
59 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
60 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
61 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
62 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
63 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
64 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
65 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
66 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
67 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
68 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
69 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
70 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
71 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
72 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME, VT_LPSTR},
73 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
74 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
75 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
76 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
90 const property_t *prop;
95 typedef struct MimeBody
97 const IMimeBodyVtbl *lpVtbl;
103 struct list new_props; /* FIXME: This should be in a PropertySchema */
105 char *content_pri_type;
106 char *content_sub_type;
107 ENCODINGTYPE encoding;
110 BODYOFFSETS body_offsets;
113 static inline MimeBody *impl_from_IMimeBody( IMimeBody *iface )
115 return (MimeBody *)((char*)iface - FIELD_OFFSET(MimeBody, lpVtbl));
118 static LPSTR strdupA(LPCSTR str)
121 int len = strlen(str);
122 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
123 memcpy(ret, str, len + 1);
127 #define PARSER_BUF_SIZE 1024
129 /*****************************************************
130 * copy_headers_to_buf [internal]
132 * Copies the headers into a '\0' terminated memory block and leave
133 * the stream's current position set to after the blank line.
135 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
138 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
150 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
154 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
162 hr = IStream_Read(stm, buf + offset, size - offset, &read);
163 if(FAILED(hr)) goto fail;
168 if(read == 0) done = 1;
170 while(!done && (end = strstr(buf + last_end, "\r\n")))
172 DWORD new_end = end - buf + 2;
173 if(new_end - last_end == 2)
176 off.QuadPart = new_end;
177 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
190 HeapFree(GetProcessHeap(), 0, buf);
194 static header_t *read_prop(MimeBody *body, char **ptr)
196 char *colon = strchr(*ptr, ':');
197 const property_t *prop;
200 if(!colon) return NULL;
204 for(prop = default_props; prop->name; prop++)
206 if(!strcasecmp(*ptr, prop->name))
208 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
215 property_list_entry_t *prop_entry;
216 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
218 if(!strcasecmp(*ptr, prop_entry->prop.name))
220 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
221 prop = &prop_entry->prop;
227 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
228 prop_entry->prop.name = strdupA(*ptr);
229 prop_entry->prop.id = body->next_prop_id++;
230 prop_entry->prop.flags = 0;
231 prop_entry->prop.default_vt = VT_LPSTR;
232 list_add_tail(&body->new_props, &prop_entry->entry);
233 prop = &prop_entry->prop;
234 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
238 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
240 PropVariantInit(&ret->value);
241 list_init(&ret->params);
247 static void unfold_header(char *header, int len)
249 char *start = header, *cp = header;
252 while(*cp == ' ' || *cp == '\t')
258 memmove(start, cp, len + 1);
260 cp = strstr(start, "\r\n");
267 } while(*cp == ' ' || *cp == '\t');
272 static char *unquote_string(const char *str)
277 while(*str == ' ' || *str == '\t') str++;
285 for(cp = ret; *cp; cp++)
288 memmove(cp, cp + 1, strlen(cp + 1) + 1);
293 WARN("quote in unquoted string\n");
305 static void add_param(header_t *header, const char *p)
307 const char *key = p, *value, *cp = p;
311 TRACE("got param %s\n", p);
313 while (*key == ' ' || *key == '\t' ) key++;
315 cp = strchr(key, '=');
318 WARN("malformed parameter - skipping\n");
322 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
323 memcpy(name, key, cp - key);
324 name[cp - key] = '\0';
328 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
330 param->value = unquote_string(value);
331 list_add_tail(&header->params, ¶m->entry);
334 static void split_params(header_t *header, char *value)
336 char *cp = value, *start = value;
342 if(!in_quote && *cp == ';')
345 if(done_value) add_param(header, start);
350 in_quote = !in_quote;
353 if(done_value) add_param(header, start);
356 static void read_value(header_t *header, char **cur)
358 char *end = *cur, *value;
362 end = strstr(end, "\r\n");
364 } while(*end == ' ' || *end == '\t');
367 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
368 memcpy(value, *cur, len);
371 unfold_header(value, len);
372 TRACE("value %s\n", debugstr_a(value));
374 if(header->prop->flags & MPF_HASPARAMS)
376 split_params(header, value);
377 TRACE("value w/o params %s\n", debugstr_a(value));
380 header->value.vt = VT_LPSTR;
381 header->value.u.pszVal = value;
386 static void init_content_type(MimeBody *body, header_t *header)
391 if(header->prop->id != PID_HDR_CNTTYPE)
393 ERR("called with header %s\n", header->prop->name);
397 slash = strchr(header->value.u.pszVal, '/');
400 WARN("malformed context type value\n");
403 len = slash - header->value.u.pszVal;
404 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
405 memcpy(body->content_pri_type, header->value.u.pszVal, len);
406 body->content_pri_type[len] = '\0';
407 body->content_sub_type = strdupA(slash + 1);
410 static HRESULT parse_headers(MimeBody *body, IStream *stm)
412 char *header_buf, *cur_header_ptr;
416 hr = copy_headers_to_buf(stm, &header_buf);
417 if(FAILED(hr)) return hr;
419 cur_header_ptr = header_buf;
420 while((header = read_prop(body, &cur_header_ptr)))
422 read_value(header, &cur_header_ptr);
423 list_add_tail(&body->headers, &header->entry);
425 if(header->prop->id == PID_HDR_CNTTYPE)
426 init_content_type(body, header);
429 HeapFree(GetProcessHeap(), 0, header_buf);
433 static void empty_param_list(struct list *list)
435 param_t *param, *cursor2;
437 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
439 list_remove(¶m->entry);
440 HeapFree(GetProcessHeap(), 0, param->name);
441 HeapFree(GetProcessHeap(), 0, param->value);
442 HeapFree(GetProcessHeap(), 0, param);
446 static void empty_header_list(struct list *list)
448 header_t *header, *cursor2;
450 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
452 list_remove(&header->entry);
453 PropVariantClear(&header->value);
454 empty_param_list(&header->params);
455 HeapFree(GetProcessHeap(), 0, header);
459 static void empty_new_prop_list(struct list *list)
461 property_list_entry_t *prop, *cursor2;
463 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
465 list_remove(&prop->entry);
466 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
467 HeapFree(GetProcessHeap(), 0, prop);
471 static void release_data(REFIID riid, void *data)
475 if(IsEqualIID(riid, &IID_IStream))
476 IStream_Release((IStream *)data);
478 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
481 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
487 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
489 if(!strcasecmp(name, header->prop->name))
496 return MIME_E_NOT_FOUND;
499 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
503 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
507 if (IsEqualIID(riid, &IID_IUnknown) ||
508 IsEqualIID(riid, &IID_IPersist) ||
509 IsEqualIID(riid, &IID_IPersistStreamInit) ||
510 IsEqualIID(riid, &IID_IMimePropertySet) ||
511 IsEqualIID(riid, &IID_IMimeBody))
518 IUnknown_AddRef((IUnknown*)*ppvObject);
522 FIXME("no interface for %s\n", debugstr_guid(riid));
523 return E_NOINTERFACE;
526 static ULONG WINAPI MimeBody_AddRef(IMimeBody* iface)
528 MimeBody *This = impl_from_IMimeBody(iface);
529 TRACE("(%p)->()\n", iface);
530 return InterlockedIncrement(&This->refs);
533 static ULONG WINAPI MimeBody_Release(IMimeBody* iface)
535 MimeBody *This = impl_from_IMimeBody(iface);
538 TRACE("(%p)->()\n", iface);
540 refs = InterlockedDecrement(&This->refs);
543 empty_header_list(&This->headers);
544 empty_new_prop_list(&This->new_props);
546 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
547 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
549 release_data(&This->data_iid, This->data);
551 HeapFree(GetProcessHeap(), 0, This);
557 static HRESULT WINAPI MimeBody_GetClassID(
566 static HRESULT WINAPI MimeBody_IsDirty(
573 static HRESULT WINAPI MimeBody_Load(
577 MimeBody *This = impl_from_IMimeBody(iface);
578 TRACE("(%p)->(%p)\n", iface, pStm);
579 return parse_headers(This, pStm);
582 static HRESULT WINAPI MimeBody_Save(
591 static HRESULT WINAPI MimeBody_GetSizeMax(
593 ULARGE_INTEGER* pcbSize)
599 static HRESULT WINAPI MimeBody_InitNew(
602 TRACE("%p->()\n", iface);
606 static HRESULT WINAPI MimeBody_GetPropInfo(
609 LPMIMEPROPINFO pInfo)
615 static HRESULT WINAPI MimeBody_SetPropInfo(
618 LPCMIMEPROPINFO pInfo)
624 static HRESULT WINAPI MimeBody_GetProp(
628 LPPROPVARIANT pValue)
630 MimeBody *This = impl_from_IMimeBody(iface);
631 TRACE("(%p)->(%s, %d, %p)\n", This, pszName, dwFlags, pValue);
633 if(!strcasecmp(pszName, "att:pri-content-type"))
635 PropVariantClear(pValue);
636 pValue->vt = VT_LPSTR;
637 pValue->u.pszVal = strdupA(This->content_pri_type);
645 static HRESULT WINAPI MimeBody_SetProp(
649 LPCPROPVARIANT pValue)
655 static HRESULT WINAPI MimeBody_AppendProp(
659 LPPROPVARIANT pValue)
665 static HRESULT WINAPI MimeBody_DeleteProp(
673 static HRESULT WINAPI MimeBody_CopyProps(
677 IMimePropertySet* pPropertySet)
683 static HRESULT WINAPI MimeBody_MoveProps(
687 IMimePropertySet* pPropertySet)
693 static HRESULT WINAPI MimeBody_DeleteExcept(
702 static HRESULT WINAPI MimeBody_QueryProp(
707 boolean fCaseSensitive)
713 static HRESULT WINAPI MimeBody_GetCharset(
715 LPHCHARSET phCharset)
722 static HRESULT WINAPI MimeBody_SetCharset(
725 CSETAPPLYTYPE applytype)
731 static HRESULT WINAPI MimeBody_GetParameters(
735 LPMIMEPARAMINFO* pprgParam)
737 MimeBody *This = impl_from_IMimeBody(iface);
741 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
746 hr = find_prop(This, pszName, &header);
747 if(hr != S_OK) return hr;
749 *pcParams = list_count(&header->params);
752 IMimeAllocator *alloc;
756 MimeOleGetAllocator(&alloc);
758 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
759 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
763 len = strlen(param->name) + 1;
764 info->pszName = IMimeAllocator_Alloc(alloc, len);
765 memcpy(info->pszName, param->name, len);
766 len = strlen(param->value) + 1;
767 info->pszData = IMimeAllocator_Alloc(alloc, len);
768 memcpy(info->pszData, param->value, len);
771 IMimeAllocator_Release(alloc);
776 static HRESULT WINAPI MimeBody_IsContentType(
781 MimeBody *This = impl_from_IMimeBody(iface);
783 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
786 const char *pri = This->content_pri_type;
787 if(!pri) pri = "text";
788 if(strcasecmp(pri, pszPriType)) return S_FALSE;
793 const char *sub = This->content_sub_type;
794 if(!sub) sub = "plain";
795 if(strcasecmp(sub, pszSubType)) return S_FALSE;
801 static HRESULT WINAPI MimeBody_BindToObject(
810 static HRESULT WINAPI MimeBody_Clone(
812 IMimePropertySet** ppPropertySet)
818 static HRESULT WINAPI MimeBody_SetOption(
821 LPCPROPVARIANT pValue)
823 FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
827 static HRESULT WINAPI MimeBody_GetOption(
830 LPPROPVARIANT pValue)
832 FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
836 static HRESULT WINAPI MimeBody_EnumProps(
839 IMimeEnumProperties** ppEnum)
845 static HRESULT WINAPI MimeBody_IsType(
847 IMSGBODYTYPE bodytype)
849 FIXME("(%p)->(%d): stub\n", iface, bodytype);
853 static HRESULT WINAPI MimeBody_SetDisplayName(
861 static HRESULT WINAPI MimeBody_GetDisplayName(
869 static HRESULT WINAPI MimeBody_GetOffsets(
871 LPBODYOFFSETS pOffsets)
873 MimeBody *This = impl_from_IMimeBody(iface);
874 TRACE("(%p)->(%p)\n", This, pOffsets);
876 *pOffsets = This->body_offsets;
878 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
882 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
884 ENCODINGTYPE* pietEncoding)
886 MimeBody *This = impl_from_IMimeBody(iface);
888 TRACE("(%p)->(%p)\n", This, pietEncoding);
890 *pietEncoding = This->encoding;
894 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
896 ENCODINGTYPE ietEncoding)
898 MimeBody *This = impl_from_IMimeBody(iface);
900 TRACE("(%p)->(%d)\n", This, ietEncoding);
902 This->encoding = ietEncoding;
906 static HRESULT WINAPI MimeBody_GetEstimatedSize(
908 ENCODINGTYPE ietEncoding,
915 static HRESULT WINAPI MimeBody_GetDataHere(
917 ENCODINGTYPE ietEncoding,
924 static HRESULT WINAPI MimeBody_GetData(
926 ENCODINGTYPE ietEncoding,
929 MimeBody *This = impl_from_IMimeBody(iface);
930 FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
932 *ppStream = This->data;
933 IStream_AddRef(*ppStream);
937 static HRESULT WINAPI MimeBody_SetData(
939 ENCODINGTYPE ietEncoding,
945 MimeBody *This = impl_from_IMimeBody(iface);
946 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
947 debugstr_guid(riid), pvObject);
949 if(IsEqualIID(riid, &IID_IStream))
950 IStream_AddRef((IStream *)pvObject);
953 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
958 FIXME("release old data\n");
960 This->data_iid = *riid;
961 This->data = pvObject;
963 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
965 /* FIXME: Update the content type.
966 If pszPriType == NULL use 'application'
967 If pszSubType == NULL use 'octet-stream' */
972 static HRESULT WINAPI MimeBody_EmptyData(
979 static HRESULT WINAPI MimeBody_CopyTo(
987 static HRESULT WINAPI MimeBody_GetTransmitInfo(
989 LPTRANSMITINFO pTransmitInfo)
995 static HRESULT WINAPI MimeBody_SaveToFile(
997 ENCODINGTYPE ietEncoding,
1004 static HRESULT WINAPI MimeBody_GetHandle(
1008 MimeBody *This = impl_from_IMimeBody(iface);
1009 TRACE("(%p)->(%p)\n", iface, phBody);
1011 *phBody = This->handle;
1012 return This->handle ? S_OK : MIME_E_NO_DATA;
1015 static IMimeBodyVtbl body_vtbl =
1017 MimeBody_QueryInterface,
1020 MimeBody_GetClassID,
1024 MimeBody_GetSizeMax,
1026 MimeBody_GetPropInfo,
1027 MimeBody_SetPropInfo,
1030 MimeBody_AppendProp,
1031 MimeBody_DeleteProp,
1034 MimeBody_DeleteExcept,
1036 MimeBody_GetCharset,
1037 MimeBody_SetCharset,
1038 MimeBody_GetParameters,
1039 MimeBody_IsContentType,
1040 MimeBody_BindToObject,
1046 MimeBody_SetDisplayName,
1047 MimeBody_GetDisplayName,
1048 MimeBody_GetOffsets,
1049 MimeBody_GetCurrentEncoding,
1050 MimeBody_SetCurrentEncoding,
1051 MimeBody_GetEstimatedSize,
1052 MimeBody_GetDataHere,
1057 MimeBody_GetTransmitInfo,
1058 MimeBody_SaveToFile,
1062 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1064 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1065 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1067 body->body_offsets = *offsets;
1071 #define FIRST_CUSTOM_PROP_ID 0x100
1073 HRESULT MimeBody_create(IUnknown *outer, void **obj)
1076 BODYOFFSETS body_offsets;
1080 if(outer) return CLASS_E_NOAGGREGATION;
1082 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1083 if (!This) return E_OUTOFMEMORY;
1085 This->lpVtbl = &body_vtbl;
1087 This->handle = NULL;
1088 list_init(&This->headers);
1089 list_init(&This->new_props);
1090 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1091 This->content_pri_type = NULL;
1092 This->content_sub_type = NULL;
1093 This->encoding = IET_7BIT;
1095 This->data_iid = IID_NULL;
1097 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1098 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1099 MimeBody_set_offsets(This, &body_offsets);
1101 *obj = (IMimeBody *)&This->lpVtbl;
1107 IStreamVtbl *lpVtbl;
1111 ULARGE_INTEGER pos, start, length;
1114 static inline sub_stream_t *impl_from_IStream( IStream *iface )
1116 return (sub_stream_t *)((char*)iface - FIELD_OFFSET(sub_stream_t, lpVtbl));
1119 static HRESULT WINAPI sub_stream_QueryInterface(
1124 sub_stream_t *This = impl_from_IStream(iface);
1126 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1129 if(IsEqualIID(riid, &IID_IUnknown) ||
1130 IsEqualIID(riid, &IID_ISequentialStream) ||
1131 IsEqualIID(riid, &IID_IStream))
1133 IStream_AddRef(iface);
1137 return E_NOINTERFACE;
1140 static ULONG WINAPI sub_stream_AddRef(
1143 sub_stream_t *This = impl_from_IStream(iface);
1145 TRACE("(%p)\n", This);
1146 return InterlockedIncrement(&This->refs);
1149 static ULONG WINAPI sub_stream_Release(
1152 sub_stream_t *This = impl_from_IStream(iface);
1155 TRACE("(%p)\n", This);
1156 refs = InterlockedDecrement(&This->refs);
1159 IStream_Release(This->base);
1160 HeapFree(GetProcessHeap(), 0, This);
1165 static HRESULT WINAPI sub_stream_Read(
1171 sub_stream_t *This = impl_from_IStream(iface);
1173 ULARGE_INTEGER base_pos;
1174 LARGE_INTEGER tmp_pos;
1176 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
1178 tmp_pos.QuadPart = 0;
1179 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_CUR, &base_pos);
1180 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
1181 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1183 if(This->pos.QuadPart + cb > This->length.QuadPart)
1184 cb = This->length.QuadPart - This->pos.QuadPart;
1186 hr = IStream_Read(This->base, pv, cb, pcbRead);
1188 This->pos.QuadPart += *pcbRead;
1190 tmp_pos.QuadPart = base_pos.QuadPart;
1191 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1196 static HRESULT WINAPI sub_stream_Write(
1206 static HRESULT WINAPI sub_stream_Seek(
1208 LARGE_INTEGER dlibMove,
1210 ULARGE_INTEGER *plibNewPosition)
1212 sub_stream_t *This = impl_from_IStream(iface);
1213 LARGE_INTEGER new_pos;
1215 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
1219 case STREAM_SEEK_SET:
1222 case STREAM_SEEK_CUR:
1223 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
1225 case STREAM_SEEK_END:
1226 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
1229 return STG_E_INVALIDFUNCTION;
1232 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
1233 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
1235 This->pos.QuadPart = new_pos.QuadPart;
1237 if(plibNewPosition) *plibNewPosition = This->pos;
1241 static HRESULT WINAPI sub_stream_SetSize(
1243 ULARGE_INTEGER libNewSize)
1249 static HRESULT WINAPI sub_stream_CopyTo(
1253 ULARGE_INTEGER *pcbRead,
1254 ULARGE_INTEGER *pcbWritten)
1257 BYTE tmpBuffer[128];
1258 ULONG bytesRead, bytesWritten, copySize;
1259 ULARGE_INTEGER totalBytesRead;
1260 ULARGE_INTEGER totalBytesWritten;
1262 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
1264 totalBytesRead.QuadPart = 0;
1265 totalBytesWritten.QuadPart = 0;
1267 while ( cb.QuadPart > 0 )
1269 if ( cb.QuadPart >= sizeof(tmpBuffer) )
1270 copySize = sizeof(tmpBuffer);
1272 copySize = cb.u.LowPart;
1274 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1275 if (FAILED(hr)) break;
1277 totalBytesRead.QuadPart += bytesRead;
1281 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1282 if (FAILED(hr)) break;
1283 totalBytesWritten.QuadPart += bytesWritten;
1286 if (bytesRead != copySize)
1289 cb.QuadPart -= bytesRead;
1292 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
1293 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
1298 static HRESULT WINAPI sub_stream_Commit(
1300 DWORD grfCommitFlags)
1306 static HRESULT WINAPI sub_stream_Revert(
1313 static HRESULT WINAPI sub_stream_LockRegion(
1315 ULARGE_INTEGER libOffset,
1323 static HRESULT WINAPI sub_stream_UnlockRegion(
1325 ULARGE_INTEGER libOffset,
1333 static HRESULT WINAPI sub_stream_Stat(
1338 sub_stream_t *This = impl_from_IStream(iface);
1339 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
1340 memset(pstatstg, 0, sizeof(*pstatstg));
1341 pstatstg->cbSize = This->length;
1345 static HRESULT WINAPI sub_stream_Clone(
1353 static struct IStreamVtbl sub_stream_vtbl =
1355 sub_stream_QueryInterface,
1365 sub_stream_LockRegion,
1366 sub_stream_UnlockRegion,
1371 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
1376 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1377 if(!This) return E_OUTOFMEMORY;
1379 This->lpVtbl = &sub_stream_vtbl;
1381 This->start = start;
1382 This->length = length;
1383 This->pos.QuadPart = 0;
1384 IStream_AddRef(stream);
1385 This->base = stream;
1387 *out = (IStream*)&This->lpVtbl;
1392 typedef struct body_t
1396 IMimeBody *mime_body;
1398 struct body_t *parent;
1399 struct list children;
1402 typedef struct MimeMessage
1404 const IMimeMessageVtbl *lpVtbl;
1409 struct list body_tree;
1413 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1415 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1417 if (IsEqualIID(riid, &IID_IUnknown) ||
1418 IsEqualIID(riid, &IID_IPersist) ||
1419 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1420 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1421 IsEqualIID(riid, &IID_IMimeMessage))
1424 IUnknown_AddRef(iface);
1428 FIXME("no interface for %s\n", debugstr_guid(riid));
1430 return E_NOINTERFACE;
1433 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1435 MimeMessage *This = (MimeMessage *)iface;
1436 TRACE("(%p)->()\n", iface);
1437 return InterlockedIncrement(&This->refs);
1440 static void empty_body_list(struct list *list)
1442 body_t *body, *cursor2;
1443 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1445 empty_body_list(&body->children);
1446 list_remove(&body->entry);
1447 IMimeBody_Release(body->mime_body);
1448 HeapFree(GetProcessHeap(), 0, body);
1452 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1454 MimeMessage *This = (MimeMessage *)iface;
1457 TRACE("(%p)->()\n", iface);
1459 refs = InterlockedDecrement(&This->refs);
1462 empty_body_list(&This->body_tree);
1464 if(This->stream) IStream_Release(This->stream);
1465 HeapFree(GetProcessHeap(), 0, This);
1471 /*** IPersist methods ***/
1472 static HRESULT WINAPI MimeMessage_GetClassID(
1473 IMimeMessage *iface,
1476 FIXME("(%p)->(%p)\n", iface, pClassID);
1480 /*** IPersistStreamInit methods ***/
1481 static HRESULT WINAPI MimeMessage_IsDirty(
1482 IMimeMessage *iface)
1484 FIXME("(%p)->()\n", iface);
1488 static body_t *new_body_entry(IMimeBody *mime_body, HBODY hbody, body_t *parent)
1490 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
1493 body->mime_body = mime_body;
1494 body->hbody = hbody;
1495 list_init(&body->children);
1496 body->parent = parent;
1504 BODYOFFSETS offsets;
1507 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
1511 int boundary_len = strlen(boundary);
1512 char *buf, *nl_boundary, *ptr, *overlap;
1513 DWORD total_read = 0;
1514 DWORD start = 0, overlap_no;
1515 offset_entry_t *cur_body = NULL;
1519 list_init(body_offsets);
1520 nl_boundary = HeapAlloc(GetProcessHeap(), 0, 4 + boundary_len + 1);
1521 memcpy(nl_boundary, "\r\n--", 4);
1522 memcpy(nl_boundary + 4, boundary, boundary_len + 1);
1524 overlap_no = boundary_len + 5;
1526 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
1529 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
1530 start = cur.u.LowPart;
1533 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
1534 if(FAILED(hr)) goto end;
1535 if(read == 0) break;
1537 overlap[read] = '\0';
1541 ptr = strstr(ptr, nl_boundary);
1544 DWORD boundary_start = start + ptr - buf;
1545 char *end = ptr + boundary_len + 4;
1547 if(*end == '\0' || *(end + 1) == '\0')
1550 if(*end == '\r' && *(end + 1) == '\n')
1554 cur_body->offsets.cbBodyEnd = boundary_start;
1555 list_add_tail(body_offsets, &cur_body->entry);
1557 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
1558 cur_body->offsets.cbBoundaryStart = boundary_start + 2; /* doesn't including the leading \r\n */
1559 cur_body->offsets.cbHeaderStart = boundary_start + boundary_len + 6;
1561 else if(*end == '-' && *(end + 1) == '-')
1565 cur_body->offsets.cbBodyEnd = boundary_start;
1566 list_add_tail(body_offsets, &cur_body->entry);
1574 if(overlap == buf) /* 1st iteration */
1576 memcpy(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
1577 overlap = buf + overlap_no;
1578 start += read - overlap_no;
1582 memcpy(buf, buf + PARSER_BUF_SIZE, overlap_no);
1588 HeapFree(GetProcessHeap(), 0, buf);
1592 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
1594 IMimeBody *mime_body;
1600 MimeBody_create(NULL, (void**)&mime_body);
1601 IMimeBody_Load(mime_body, pStm);
1603 hr = IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &cur);
1604 offset->cbBodyStart = cur.u.LowPart + offset->cbHeaderStart;
1605 if(parent) MimeBody_set_offsets(impl_from_IMimeBody(mime_body), offset);
1606 IMimeBody_SetData(mime_body, IET_BINARY, NULL, NULL, &IID_IStream, pStm);
1607 body = new_body_entry(mime_body, msg->next_hbody, parent);
1608 msg->next_hbody = (HBODY)((DWORD)msg->next_hbody + 1);
1610 if(IMimeBody_IsContentType(mime_body, "multipart", NULL) == S_OK)
1612 MIMEPARAMINFO *param_info;
1614 IMimeAllocator *alloc;
1616 hr = IMimeBody_GetParameters(mime_body, "Content-Type", &count, ¶m_info);
1617 if(hr != S_OK || count == 0) return body;
1619 MimeOleGetAllocator(&alloc);
1621 for(i = 0; i < count; i++)
1623 if(!strcasecmp(param_info[i].pszName, "boundary"))
1625 struct list offset_list;
1626 offset_entry_t *cur, *cursor2;
1627 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
1628 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
1631 IStream *sub_stream;
1632 ULARGE_INTEGER start, length;
1634 start.u.LowPart = cur->offsets.cbHeaderStart;
1635 length.u.LowPart = cur->offsets.cbBodyEnd - cur->offsets.cbHeaderStart;
1636 create_sub_stream(pStm, start, length, &sub_stream);
1637 sub_body = create_sub_body(msg, sub_stream, &cur->offsets, body);
1638 IStream_Release(sub_stream);
1639 list_add_tail(&body->children, &sub_body->entry);
1640 list_remove(&cur->entry);
1641 HeapFree(GetProcessHeap(), 0, cur);
1646 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
1647 IMimeAllocator_Release(alloc);
1652 static HRESULT WINAPI MimeMessage_Load(
1653 IMimeMessage *iface,
1656 MimeMessage *This = (MimeMessage *)iface;
1658 BODYOFFSETS offsets;
1662 TRACE("(%p)->(%p)\n", iface, pStm);
1666 FIXME("already loaded a message\n");
1670 IStream_AddRef(pStm);
1671 This->stream = pStm;
1672 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
1673 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
1675 root_body = create_sub_body(This, pStm, &offsets, NULL);
1678 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
1679 offsets.cbBodyEnd = cur.u.LowPart;
1680 MimeBody_set_offsets(impl_from_IMimeBody(root_body->mime_body), &offsets);
1682 list_add_head(&This->body_tree, &root_body->entry);
1687 static HRESULT WINAPI MimeMessage_Save(
1688 IMimeMessage *iface,
1692 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
1696 static HRESULT WINAPI MimeMessage_GetSizeMax(
1697 IMimeMessage *iface,
1698 ULARGE_INTEGER *pcbSize)
1700 FIXME("(%p)->(%p)\n", iface, pcbSize);
1704 static HRESULT WINAPI MimeMessage_InitNew(
1705 IMimeMessage *iface)
1707 FIXME("(%p)->()\n", iface);
1711 /*** IMimeMessageTree methods ***/
1712 static HRESULT WINAPI MimeMessage_GetMessageSource(
1713 IMimeMessage *iface,
1717 MimeMessage *This = (MimeMessage *)iface;
1718 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
1720 IStream_AddRef(This->stream);
1721 *ppStream = This->stream;
1725 static HRESULT WINAPI MimeMessage_GetMessageSize(
1726 IMimeMessage *iface,
1730 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
1734 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
1735 IMimeMessage *iface,
1738 FIXME("(%p)->(%p)\n", iface, pStream);
1742 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
1743 IMimeMessage *iface,
1747 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
1752 static HRESULT WINAPI MimeMessage_GetFlags(
1753 IMimeMessage *iface,
1756 FIXME("(%p)->(%p)\n", iface, pdwFlags);
1760 static HRESULT WINAPI MimeMessage_Commit(
1761 IMimeMessage *iface,
1764 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
1769 static HRESULT WINAPI MimeMessage_HandsOffStorage(
1770 IMimeMessage *iface)
1772 FIXME("(%p)->()\n", iface);
1776 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
1781 if(hbody == HBODY_ROOT)
1783 *body = LIST_ENTRY(list_head(list), body_t, entry);
1787 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
1789 if(cur->hbody == hbody)
1794 hr = find_body(&cur->children, hbody, body);
1795 if(hr == S_OK) return S_OK;
1800 static HRESULT WINAPI MimeMessage_BindToObject(
1801 IMimeMessage *iface,
1806 MimeMessage *This = (MimeMessage *)iface;
1810 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
1812 hr = find_body(&This->body_tree, hBody, &body);
1814 if(hr != S_OK) return hr;
1816 if(IsEqualIID(riid, &IID_IMimeBody))
1818 IMimeBody_AddRef(body->mime_body);
1819 *ppvObject = body->mime_body;
1823 return E_NOINTERFACE;
1826 static HRESULT WINAPI MimeMessage_SaveBody(
1827 IMimeMessage *iface,
1832 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
1836 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
1838 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
1843 if(location == IBL_ROOT)
1849 hr = find_body(&msg->body_tree, pivot, &body);
1856 *out = body->parent;
1860 list = list_head(&body->children);
1862 *out = LIST_ENTRY(list, body_t, entry);
1864 hr = MIME_E_NOT_FOUND;
1868 list = list_tail(&body->children);
1870 *out = LIST_ENTRY(list, body_t, entry);
1872 hr = MIME_E_NOT_FOUND;
1876 list = list_next(&body->parent->children, &body->entry);
1878 *out = LIST_ENTRY(list, body_t, entry);
1880 hr = MIME_E_NOT_FOUND;
1884 list = list_prev(&body->parent->children, &body->entry);
1886 *out = LIST_ENTRY(list, body_t, entry);
1888 hr = MIME_E_NOT_FOUND;
1901 static HRESULT WINAPI MimeMessage_InsertBody(
1902 IMimeMessage *iface,
1903 BODYLOCATION location,
1907 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1911 static HRESULT WINAPI MimeMessage_GetBody(
1912 IMimeMessage *iface,
1913 BODYLOCATION location,
1917 MimeMessage *This = (MimeMessage *)iface;
1921 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1923 hr = get_body(This, location, hPivot, &body);
1925 if(hr == S_OK) *phBody = body->hbody;
1930 static HRESULT WINAPI MimeMessage_DeleteBody(
1931 IMimeMessage *iface,
1935 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
1939 static HRESULT WINAPI MimeMessage_MoveBody(
1940 IMimeMessage *iface,
1942 BODYLOCATION location)
1944 FIXME("(%p)->(%d)\n", iface, location);
1948 static void count_children(body_t *body, boolean recurse, ULONG *count)
1952 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
1955 if(recurse) count_children(child, recurse, count);
1959 static HRESULT WINAPI MimeMessage_CountBodies(
1960 IMimeMessage *iface,
1966 MimeMessage *This = (MimeMessage *)iface;
1969 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
1971 hr = find_body(&This->body_tree, hParent, &body);
1972 if(hr != S_OK) return hr;
1975 count_children(body, fRecurse, pcBodies);
1980 static HRESULT find_next(IMimeMessage *msg, LPFINDBODY find_body, HBODY *out)
1983 IMimeBody *mime_body;
1986 if(find_body->dwReserved == 0)
1987 find_body->dwReserved = (DWORD)HBODY_ROOT;
1990 hr = IMimeMessage_GetBody(msg, IBL_FIRST, (HBODY)find_body->dwReserved, &next);
1992 find_body->dwReserved = (DWORD)next;
1995 hr = IMimeMessage_GetBody(msg, IBL_NEXT, (HBODY)find_body->dwReserved, &next);
1997 find_body->dwReserved = (DWORD)next;
1999 return MIME_E_NOT_FOUND;
2003 hr = IMimeMessage_BindToObject(msg, (HBODY)find_body->dwReserved, &IID_IMimeBody, (void**)&mime_body);
2004 if(IMimeBody_IsContentType(mime_body, find_body->pszPriType, find_body->pszSubType) == S_OK)
2006 IMimeBody_Release(mime_body);
2007 *out = (HBODY)find_body->dwReserved;
2010 IMimeBody_Release(mime_body);
2011 return find_next(msg, find_body, out);
2014 static HRESULT WINAPI MimeMessage_FindFirst(
2015 IMimeMessage *iface,
2016 LPFINDBODY pFindBody,
2019 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2021 pFindBody->dwReserved = 0;
2022 return find_next(iface, pFindBody, phBody);
2025 static HRESULT WINAPI MimeMessage_FindNext(
2026 IMimeMessage *iface,
2027 LPFINDBODY pFindBody,
2030 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2032 return find_next(iface, pFindBody, phBody);
2035 static HRESULT WINAPI MimeMessage_ResolveURL(
2036 IMimeMessage *iface,
2043 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2047 static HRESULT WINAPI MimeMessage_ToMultipart(
2048 IMimeMessage *iface,
2051 LPHBODY phMultipart)
2053 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2057 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2058 IMimeMessage *iface,
2060 LPBODYOFFSETS pOffsets)
2062 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2066 static HRESULT WINAPI MimeMessage_GetCharset(
2067 IMimeMessage *iface,
2068 LPHCHARSET phCharset)
2070 FIXME("(%p)->(%p)\n", iface, phCharset);
2075 static HRESULT WINAPI MimeMessage_SetCharset(
2076 IMimeMessage *iface,
2078 CSETAPPLYTYPE applytype)
2080 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2084 static HRESULT WINAPI MimeMessage_IsBodyType(
2085 IMimeMessage *iface,
2087 IMSGBODYTYPE bodytype)
2090 IMimeBody *mime_body;
2091 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2093 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2094 if(hr != S_OK) return hr;
2096 hr = IMimeBody_IsType(mime_body, bodytype);
2097 MimeBody_Release(mime_body);
2101 static HRESULT WINAPI MimeMessage_IsContentType(
2102 IMimeMessage *iface,
2108 IMimeBody *mime_body;
2109 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, pszPriType, pszSubType);
2111 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2112 if(FAILED(hr)) return hr;
2114 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2115 IMimeBody_Release(mime_body);
2119 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2120 IMimeMessage *iface,
2125 boolean fCaseSensitive)
2127 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2131 static HRESULT WINAPI MimeMessage_GetBodyProp(
2132 IMimeMessage *iface,
2136 LPPROPVARIANT pValue)
2139 IMimeBody *mime_body;
2141 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2143 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2144 if(hr != S_OK) return hr;
2146 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2147 IMimeBody_Release(mime_body);
2152 static HRESULT WINAPI MimeMessage_SetBodyProp(
2153 IMimeMessage *iface,
2157 LPCPROPVARIANT pValue)
2159 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2163 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2164 IMimeMessage *iface,
2168 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2172 static HRESULT WINAPI MimeMessage_SetOption(
2173 IMimeMessage *iface,
2175 LPCPROPVARIANT pValue)
2177 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2181 static HRESULT WINAPI MimeMessage_GetOption(
2182 IMimeMessage *iface,
2184 LPPROPVARIANT pValue)
2186 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2190 /*** IMimeMessage methods ***/
2191 static HRESULT WINAPI MimeMessage_CreateWebPage(
2192 IMimeMessage *iface,
2194 LPWEBPAGEOPTIONS pOptions,
2195 IMimeMessageCallback *pCallback,
2196 IMoniker **ppMoniker)
2198 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2203 static HRESULT WINAPI MimeMessage_GetProp(
2204 IMimeMessage *iface,
2207 LPPROPVARIANT pValue)
2209 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2213 static HRESULT WINAPI MimeMessage_SetProp(
2214 IMimeMessage *iface,
2217 LPCPROPVARIANT pValue)
2219 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2223 static HRESULT WINAPI MimeMessage_DeleteProp(
2224 IMimeMessage *iface,
2227 FIXME("(%p)->(%s)\n", iface, pszName);
2231 static HRESULT WINAPI MimeMessage_QueryProp(
2232 IMimeMessage *iface,
2236 boolean fCaseSensitive)
2238 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2242 static HRESULT WINAPI MimeMessage_GetTextBody(
2243 IMimeMessage *iface,
2245 ENCODINGTYPE ietEncoding,
2251 FINDBODY find_struct;
2252 IMimeBody *mime_body;
2253 static char text[] = "text";
2254 static char plain[] = "plain";
2255 static char html[] = "html";
2257 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2259 find_struct.pszPriType = text;
2264 find_struct.pszSubType = plain;
2267 find_struct.pszSubType = html;
2270 return MIME_E_INVALID_TEXT_TYPE;
2273 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2276 TRACE("not found hr %08x\n", hr);
2281 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2283 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2285 IMimeBody_Release(mime_body);
2289 static HRESULT WINAPI MimeMessage_SetTextBody(
2290 IMimeMessage *iface,
2292 ENCODINGTYPE ietEncoding,
2297 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2301 static HRESULT WINAPI MimeMessage_AttachObject(
2302 IMimeMessage *iface,
2307 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2311 static HRESULT WINAPI MimeMessage_AttachFile(
2312 IMimeMessage *iface,
2317 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2321 static HRESULT WINAPI MimeMessage_AttachURL(
2322 IMimeMessage *iface,
2330 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2334 static HRESULT WINAPI MimeMessage_GetAttachments(
2335 IMimeMessage *iface,
2337 LPHBODY *pprghAttach)
2340 FINDBODY find_struct;
2345 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2348 array = CoTaskMemAlloc(size * sizeof(HBODY));
2350 find_struct.pszPriType = find_struct.pszSubType = NULL;
2351 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2354 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2355 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2358 if(*pcAttach + 1 > size)
2361 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2363 array[*pcAttach] = hbody;
2366 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2369 *pprghAttach = array;
2373 static HRESULT WINAPI MimeMessage_GetAddressTable(
2374 IMimeMessage *iface,
2375 IMimeAddressTable **ppTable)
2377 FIXME("(%p)->(%p)\n", iface, ppTable);
2381 static HRESULT WINAPI MimeMessage_GetSender(
2382 IMimeMessage *iface,
2383 LPADDRESSPROPS pAddress)
2385 FIXME("(%p)->(%p)\n", iface, pAddress);
2389 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2390 IMimeMessage *iface,
2393 LPADDRESSLIST pList)
2395 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2399 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2400 IMimeMessage *iface,
2402 ADDRESSFORMAT format,
2405 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2409 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2410 IMimeMessage *iface,
2413 IMimeEnumAddressTypes **ppEnum)
2415 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2419 static HRESULT WINAPI MimeMessage_SplitMessage(
2420 IMimeMessage *iface,
2422 IMimeMessageParts **ppParts)
2424 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
2428 static HRESULT WINAPI MimeMessage_GetRootMoniker(
2429 IMimeMessage *iface,
2430 IMoniker **ppMoniker)
2432 FIXME("(%p)->(%p)\n", iface, ppMoniker);
2436 static const IMimeMessageVtbl MimeMessageVtbl =
2438 MimeMessage_QueryInterface,
2440 MimeMessage_Release,
2441 MimeMessage_GetClassID,
2442 MimeMessage_IsDirty,
2445 MimeMessage_GetSizeMax,
2446 MimeMessage_InitNew,
2447 MimeMessage_GetMessageSource,
2448 MimeMessage_GetMessageSize,
2449 MimeMessage_LoadOffsetTable,
2450 MimeMessage_SaveOffsetTable,
2451 MimeMessage_GetFlags,
2453 MimeMessage_HandsOffStorage,
2454 MimeMessage_BindToObject,
2455 MimeMessage_SaveBody,
2456 MimeMessage_InsertBody,
2457 MimeMessage_GetBody,
2458 MimeMessage_DeleteBody,
2459 MimeMessage_MoveBody,
2460 MimeMessage_CountBodies,
2461 MimeMessage_FindFirst,
2462 MimeMessage_FindNext,
2463 MimeMessage_ResolveURL,
2464 MimeMessage_ToMultipart,
2465 MimeMessage_GetBodyOffsets,
2466 MimeMessage_GetCharset,
2467 MimeMessage_SetCharset,
2468 MimeMessage_IsBodyType,
2469 MimeMessage_IsContentType,
2470 MimeMessage_QueryBodyProp,
2471 MimeMessage_GetBodyProp,
2472 MimeMessage_SetBodyProp,
2473 MimeMessage_DeleteBodyProp,
2474 MimeMessage_SetOption,
2475 MimeMessage_GetOption,
2476 MimeMessage_CreateWebPage,
2477 MimeMessage_GetProp,
2478 MimeMessage_SetProp,
2479 MimeMessage_DeleteProp,
2480 MimeMessage_QueryProp,
2481 MimeMessage_GetTextBody,
2482 MimeMessage_SetTextBody,
2483 MimeMessage_AttachObject,
2484 MimeMessage_AttachFile,
2485 MimeMessage_AttachURL,
2486 MimeMessage_GetAttachments,
2487 MimeMessage_GetAddressTable,
2488 MimeMessage_GetSender,
2489 MimeMessage_GetAddressTypes,
2490 MimeMessage_GetAddressFormat,
2491 MimeMessage_EnumAddressTypes,
2492 MimeMessage_SplitMessage,
2493 MimeMessage_GetRootMoniker,
2496 /***********************************************************************
2497 * MimeOleCreateMessage (INETCOMM.@)
2499 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
2503 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
2507 FIXME("outer unknown not supported yet\n");
2513 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2514 if (!This) return E_OUTOFMEMORY;
2516 This->lpVtbl = &MimeMessageVtbl;
2518 This->stream = NULL;
2519 list_init(&This->body_tree);
2520 This->next_hbody = (HBODY)1;
2522 *ppMessage = (IMimeMessage *)&This->lpVtbl;
2526 /***********************************************************************
2527 * MimeOleSetCompatMode (INETCOMM.@)
2529 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
2531 FIXME("(0x%x)\n", dwMode);
2535 /***********************************************************************
2536 * MimeOleCreateVirtualStream (INETCOMM.@)
2538 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
2541 FIXME("(%p)\n", ppStream);
2543 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
2547 typedef struct MimeSecurity
2549 const IMimeSecurityVtbl *lpVtbl;
2554 static HRESULT WINAPI MimeSecurity_QueryInterface(
2555 IMimeSecurity* iface,
2559 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
2561 if (IsEqualIID(riid, &IID_IUnknown) ||
2562 IsEqualIID(riid, &IID_IMimeSecurity))
2565 IUnknown_AddRef(iface);
2569 FIXME("no interface for %s\n", debugstr_guid(riid));
2571 return E_NOINTERFACE;
2574 static ULONG WINAPI MimeSecurity_AddRef(
2575 IMimeSecurity* iface)
2577 MimeSecurity *This = (MimeSecurity *)iface;
2578 TRACE("(%p)->()\n", iface);
2579 return InterlockedIncrement(&This->refs);
2582 static ULONG WINAPI MimeSecurity_Release(
2583 IMimeSecurity* iface)
2585 MimeSecurity *This = (MimeSecurity *)iface;
2588 TRACE("(%p)->()\n", iface);
2590 refs = InterlockedDecrement(&This->refs);
2593 HeapFree(GetProcessHeap(), 0, This);
2599 static HRESULT WINAPI MimeSecurity_InitNew(
2600 IMimeSecurity* iface)
2602 FIXME("(%p)->(): stub\n", iface);
2606 static HRESULT WINAPI MimeSecurity_CheckInit(
2607 IMimeSecurity* iface)
2609 FIXME("(%p)->(): stub\n", iface);
2613 static HRESULT WINAPI MimeSecurity_EncodeMessage(
2614 IMimeSecurity* iface,
2615 IMimeMessageTree* pTree,
2618 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
2622 static HRESULT WINAPI MimeSecurity_EncodeBody(
2623 IMimeSecurity* iface,
2624 IMimeMessageTree* pTree,
2628 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
2632 static HRESULT WINAPI MimeSecurity_DecodeMessage(
2633 IMimeSecurity* iface,
2634 IMimeMessageTree* pTree,
2637 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
2641 static HRESULT WINAPI MimeSecurity_DecodeBody(
2642 IMimeSecurity* iface,
2643 IMimeMessageTree* pTree,
2647 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
2651 static HRESULT WINAPI MimeSecurity_EnumCertificates(
2652 IMimeSecurity* iface,
2658 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
2662 static HRESULT WINAPI MimeSecurity_GetCertificateName(
2663 IMimeSecurity* iface,
2664 const PCX509CERT pX509Cert,
2665 const CERTNAMETYPE cn,
2668 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
2672 static HRESULT WINAPI MimeSecurity_GetMessageType(
2673 IMimeSecurity* iface,
2674 const HWND hwndParent,
2678 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
2682 static HRESULT WINAPI MimeSecurity_GetCertData(
2683 IMimeSecurity* iface,
2684 const PCX509CERT pX509Cert,
2685 const CERTDATAID dataid,
2686 LPPROPVARIANT pValue)
2688 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
2693 static const IMimeSecurityVtbl MimeSecurityVtbl =
2695 MimeSecurity_QueryInterface,
2696 MimeSecurity_AddRef,
2697 MimeSecurity_Release,
2698 MimeSecurity_InitNew,
2699 MimeSecurity_CheckInit,
2700 MimeSecurity_EncodeMessage,
2701 MimeSecurity_EncodeBody,
2702 MimeSecurity_DecodeMessage,
2703 MimeSecurity_DecodeBody,
2704 MimeSecurity_EnumCertificates,
2705 MimeSecurity_GetCertificateName,
2706 MimeSecurity_GetMessageType,
2707 MimeSecurity_GetCertData
2710 /***********************************************************************
2711 * MimeOleCreateSecurity (INETCOMM.@)
2713 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
2717 TRACE("(%p)\n", ppSecurity);
2721 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2722 if (!This) return E_OUTOFMEMORY;
2724 This->lpVtbl = &MimeSecurityVtbl;
2727 *ppSecurity = (IMimeSecurity *)&This->lpVtbl;
2734 IMimeAllocatorVtbl *lpVtbl;
2737 static HRESULT WINAPI MimeAlloc_QueryInterface(
2738 IMimeAllocator* iface,
2742 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
2744 if (IsEqualIID(riid, &IID_IUnknown) ||
2745 IsEqualIID(riid, &IID_IMalloc) ||
2746 IsEqualIID(riid, &IID_IMimeAllocator))
2749 IUnknown_AddRef(iface);
2753 FIXME("no interface for %s\n", debugstr_guid(riid));
2755 return E_NOINTERFACE;
2758 static ULONG WINAPI MimeAlloc_AddRef(
2759 IMimeAllocator* iface)
2764 static ULONG WINAPI MimeAlloc_Release(
2765 IMimeAllocator* iface)
2770 static LPVOID WINAPI MimeAlloc_Alloc(
2771 IMimeAllocator* iface,
2774 return CoTaskMemAlloc(cb);
2777 static LPVOID WINAPI MimeAlloc_Realloc(
2778 IMimeAllocator* iface,
2782 return CoTaskMemRealloc(pv, cb);
2785 static void WINAPI MimeAlloc_Free(
2786 IMimeAllocator* iface,
2792 static ULONG WINAPI MimeAlloc_GetSize(
2793 IMimeAllocator* iface,
2800 static int WINAPI MimeAlloc_DidAlloc(
2801 IMimeAllocator* iface,
2808 static void WINAPI MimeAlloc_HeapMinimize(
2809 IMimeAllocator* iface)
2815 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
2816 IMimeAllocator* iface,
2818 LPMIMEPARAMINFO prgParam,
2822 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
2824 for(i = 0; i < cParams; i++)
2826 IMimeAllocator_Free(iface, prgParam[i].pszName);
2827 IMimeAllocator_Free(iface, prgParam[i].pszData);
2829 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
2833 static HRESULT WINAPI MimeAlloc_FreeAddressList(
2834 IMimeAllocator* iface,
2835 LPADDRESSLIST pList)
2841 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
2842 IMimeAllocator* iface,
2843 LPADDRESSPROPS pAddress)
2849 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
2850 IMimeAllocator* iface,
2852 IUnknown **prgpUnknown,
2860 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
2861 IMimeAllocator* iface,
2863 LPENUMHEADERROW prgRow,
2870 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
2871 IMimeAllocator* iface,
2873 LPENUMPROPERTY prgProp,
2880 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
2881 IMimeAllocator* iface,
2882 THUMBBLOB *pthumbprint)
2889 static HRESULT WINAPI MimeAlloc_PropVariantClear(
2890 IMimeAllocator* iface,
2891 LPPROPVARIANT pProp)
2897 static IMimeAllocatorVtbl mime_alloc_vtbl =
2899 MimeAlloc_QueryInterface,
2907 MimeAlloc_HeapMinimize,
2908 MimeAlloc_FreeParamInfoArray,
2909 MimeAlloc_FreeAddressList,
2910 MimeAlloc_FreeAddressProps,
2911 MimeAlloc_ReleaseObjects,
2912 MimeAlloc_FreeEnumHeaderRowArray,
2913 MimeAlloc_FreeEnumPropertyArray,
2914 MimeAlloc_FreeThumbprint,
2915 MimeAlloc_PropVariantClear
2918 static MimeAllocator mime_allocator =
2923 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
2925 if(outer) return CLASS_E_NOAGGREGATION;
2927 *obj = &mime_allocator;
2931 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
2933 return MimeAllocator_create(NULL, (void**)alloc);
2936 HRESULT WINAPI MimeOleGetCharsetInfo(HCHARSET hCharset, LPINETCSETINFO pCsetInfo)
2938 FIXME("(%p, %p)\n", hCharset, pCsetInfo);
2939 if(!hCharset) return E_INVALIDARG;