po: Fix a mistake in Dutch translation.
[wine.git] / dlls / inetcomm / mimeole.c
blob6a6cbd89fd35e37a123d37dd2f6ecdacb2b2b8d4
1 /*
2 * MIME OLE Interfaces
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
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "ole2.h"
33 #include "mimeole.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
38 #include "inetcomm_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
42 typedef struct
44 LPCSTR name;
45 DWORD id;
46 DWORD flags; /* MIMEPROPFLAGS */
47 VARTYPE default_vt;
48 } property_t;
50 typedef struct
52 struct list entry;
53 property_t prop;
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 | MPF_HASPARAMS, 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},
77 {NULL, 0, 0, 0}
80 typedef struct
82 struct list entry;
83 char *name;
84 char *value;
85 } param_t;
87 typedef struct
89 struct list entry;
90 const property_t *prop;
91 PROPVARIANT value;
92 struct list params;
93 } header_t;
95 typedef struct MimeBody
97 IMimeBody IMimeBody_iface;
98 LONG ref;
100 HBODY handle;
102 struct list headers;
103 struct list new_props; /* FIXME: This should be in a PropertySchema */
104 DWORD next_prop_id;
105 char *content_pri_type;
106 char *content_sub_type;
107 ENCODINGTYPE encoding;
108 void *data;
109 IID data_iid;
110 BODYOFFSETS body_offsets;
111 } MimeBody;
113 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
115 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
118 static LPSTR strdupA(LPCSTR str)
120 char *ret;
121 int len = strlen(str);
122 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
123 memcpy(ret, str, len + 1);
124 return ret;
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)
137 char *buf = NULL;
138 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
139 HRESULT hr;
140 BOOL done = FALSE;
142 *ptr = NULL;
146 char *end;
147 DWORD read;
149 if(!buf)
150 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
151 else
153 size *= 2;
154 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
156 if(!buf)
158 hr = E_OUTOFMEMORY;
159 goto fail;
162 hr = IStream_Read(stm, buf + offset, size - offset, &read);
163 if(FAILED(hr)) goto fail;
165 offset += read;
166 buf[offset] = '\0';
168 if(read == 0) done = TRUE;
170 while(!done && (end = strstr(buf + last_end, "\r\n")))
172 DWORD new_end = end - buf + 2;
173 if(new_end - last_end == 2)
175 LARGE_INTEGER off;
176 off.QuadPart = new_end;
177 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
178 buf[new_end] = '\0';
179 done = TRUE;
181 else
182 last_end = new_end;
184 } while(!done);
186 *ptr = buf;
187 return S_OK;
189 fail:
190 HeapFree(GetProcessHeap(), 0, buf);
191 return hr;
194 static header_t *read_prop(MimeBody *body, char **ptr)
196 char *colon = strchr(*ptr, ':');
197 const property_t *prop;
198 header_t *ret;
200 if(!colon) return NULL;
202 *colon = '\0';
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);
209 break;
213 if(!prop->name)
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;
222 break;
225 if(!prop->name)
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));
239 ret->prop = prop;
240 PropVariantInit(&ret->value);
241 list_init(&ret->params);
242 *ptr = colon + 1;
244 return ret;
247 static void unfold_header(char *header, int len)
249 char *start = header, *cp = header;
251 do {
252 while(*cp == ' ' || *cp == '\t')
254 cp++;
255 len--;
257 if(cp != start)
258 memmove(start, cp, len + 1);
260 cp = strstr(start, "\r\n");
261 len -= (cp - start);
262 start = cp;
263 *start = ' ';
264 start++;
265 len--;
266 cp += 2;
267 } while(*cp == ' ' || *cp == '\t');
269 *(start - 1) = '\0';
272 static char *unquote_string(const char *str)
274 BOOL quoted = FALSE;
275 char *ret, *cp;
277 while(*str == ' ' || *str == '\t') str++;
279 if(*str == '"')
281 quoted = TRUE;
282 str++;
284 ret = strdupA(str);
285 for(cp = ret; *cp; cp++)
287 if(*cp == '\\')
288 memmove(cp, cp + 1, strlen(cp + 1) + 1);
289 else if(*cp == '"')
291 if(!quoted)
293 WARN("quote in unquoted string\n");
295 else
297 *cp = '\0';
298 break;
302 return ret;
305 static void add_param(header_t *header, const char *p)
307 const char *key = p, *value, *cp = p;
308 param_t *param;
309 char *name;
311 TRACE("got param %s\n", p);
313 while (*key == ' ' || *key == '\t' ) key++;
315 cp = strchr(key, '=');
316 if(!cp)
318 WARN("malformed parameter - skipping\n");
319 return;
322 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
323 memcpy(name, key, cp - key);
324 name[cp - key] = '\0';
326 value = cp + 1;
328 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
329 param->name = name;
330 param->value = unquote_string(value);
331 list_add_tail(&header->params, &param->entry);
334 static void split_params(header_t *header, char *value)
336 char *cp = value, *start = value;
337 BOOL in_quotes = FALSE, done_value = FALSE;
339 while(*cp)
341 if(!in_quotes && *cp == ';')
343 *cp = '\0';
344 if(done_value) add_param(header, start);
345 done_value = TRUE;
346 start = cp + 1;
348 else if(*cp == '"')
349 in_quotes = !in_quotes;
350 cp++;
352 if(done_value) add_param(header, start);
355 static void read_value(header_t *header, char **cur)
357 char *end = *cur, *value;
358 DWORD len;
360 do {
361 end = strstr(end, "\r\n");
362 end += 2;
363 } while(*end == ' ' || *end == '\t');
365 len = end - *cur;
366 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
367 memcpy(value, *cur, len);
368 value[len] = '\0';
370 unfold_header(value, len);
371 TRACE("value %s\n", debugstr_a(value));
373 if(header->prop->flags & MPF_HASPARAMS)
375 split_params(header, value);
376 TRACE("value w/o params %s\n", debugstr_a(value));
379 header->value.vt = VT_LPSTR;
380 header->value.u.pszVal = value;
382 *cur = end;
385 static void init_content_type(MimeBody *body, header_t *header)
387 char *slash;
388 DWORD len;
390 if(header->prop->id != PID_HDR_CNTTYPE)
392 ERR("called with header %s\n", header->prop->name);
393 return;
396 slash = strchr(header->value.u.pszVal, '/');
397 if(!slash)
399 WARN("malformed context type value\n");
400 return;
402 len = slash - header->value.u.pszVal;
403 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
404 memcpy(body->content_pri_type, header->value.u.pszVal, len);
405 body->content_pri_type[len] = '\0';
406 body->content_sub_type = strdupA(slash + 1);
409 static HRESULT parse_headers(MimeBody *body, IStream *stm)
411 char *header_buf, *cur_header_ptr;
412 HRESULT hr;
413 header_t *header;
415 hr = copy_headers_to_buf(stm, &header_buf);
416 if(FAILED(hr)) return hr;
418 cur_header_ptr = header_buf;
419 while((header = read_prop(body, &cur_header_ptr)))
421 read_value(header, &cur_header_ptr);
422 list_add_tail(&body->headers, &header->entry);
424 if(header->prop->id == PID_HDR_CNTTYPE)
425 init_content_type(body, header);
428 HeapFree(GetProcessHeap(), 0, header_buf);
429 return hr;
432 static void empty_param_list(struct list *list)
434 param_t *param, *cursor2;
436 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
438 list_remove(&param->entry);
439 HeapFree(GetProcessHeap(), 0, param->name);
440 HeapFree(GetProcessHeap(), 0, param->value);
441 HeapFree(GetProcessHeap(), 0, param);
445 static void empty_header_list(struct list *list)
447 header_t *header, *cursor2;
449 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
451 list_remove(&header->entry);
452 PropVariantClear(&header->value);
453 empty_param_list(&header->params);
454 HeapFree(GetProcessHeap(), 0, header);
458 static void empty_new_prop_list(struct list *list)
460 property_list_entry_t *prop, *cursor2;
462 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
464 list_remove(&prop->entry);
465 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
466 HeapFree(GetProcessHeap(), 0, prop);
470 static void release_data(REFIID riid, void *data)
472 if(!data) return;
474 if(IsEqualIID(riid, &IID_IStream))
475 IStream_Release((IStream *)data);
476 else
477 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
480 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
482 header_t *header;
484 *prop = NULL;
486 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
488 if(!strcasecmp(name, header->prop->name))
490 *prop = header;
491 return S_OK;
495 return MIME_E_NOT_FOUND;
498 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
499 REFIID riid,
500 void** ppvObject)
502 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
504 *ppvObject = NULL;
506 if (IsEqualIID(riid, &IID_IUnknown) ||
507 IsEqualIID(riid, &IID_IPersist) ||
508 IsEqualIID(riid, &IID_IPersistStreamInit) ||
509 IsEqualIID(riid, &IID_IMimePropertySet) ||
510 IsEqualIID(riid, &IID_IMimeBody))
512 *ppvObject = iface;
515 if(*ppvObject)
517 IUnknown_AddRef((IUnknown*)*ppvObject);
518 return S_OK;
521 FIXME("no interface for %s\n", debugstr_guid(riid));
522 return E_NOINTERFACE;
525 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
527 MimeBody *This = impl_from_IMimeBody(iface);
528 LONG ref = InterlockedIncrement(&This->ref);
530 TRACE("(%p) ref=%d\n", This, ref);
532 return ref;
535 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
537 MimeBody *This = impl_from_IMimeBody(iface);
538 LONG ref = InterlockedDecrement(&This->ref);
540 TRACE("(%p) ref=%d\n", This, ref);
542 if (!ref)
544 empty_header_list(&This->headers);
545 empty_new_prop_list(&This->new_props);
547 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
548 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
550 release_data(&This->data_iid, This->data);
552 HeapFree(GetProcessHeap(), 0, This);
555 return ref;
558 static HRESULT WINAPI MimeBody_GetClassID(
559 IMimeBody* iface,
560 CLSID* pClassID)
562 FIXME("stub\n");
563 return E_NOTIMPL;
567 static HRESULT WINAPI MimeBody_IsDirty(
568 IMimeBody* iface)
570 FIXME("stub\n");
571 return E_NOTIMPL;
574 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
576 MimeBody *This = impl_from_IMimeBody(iface);
577 TRACE("(%p)->(%p)\n", iface, pStm);
578 return parse_headers(This, pStm);
581 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
583 FIXME("stub\n");
584 return E_NOTIMPL;
587 static HRESULT WINAPI MimeBody_GetSizeMax(
588 IMimeBody* iface,
589 ULARGE_INTEGER* pcbSize)
591 FIXME("stub\n");
592 return E_NOTIMPL;
595 static HRESULT WINAPI MimeBody_InitNew(
596 IMimeBody* iface)
598 TRACE("%p->()\n", iface);
599 return S_OK;
602 static HRESULT WINAPI MimeBody_GetPropInfo(
603 IMimeBody* iface,
604 LPCSTR pszName,
605 LPMIMEPROPINFO pInfo)
607 FIXME("stub\n");
608 return E_NOTIMPL;
611 static HRESULT WINAPI MimeBody_SetPropInfo(
612 IMimeBody* iface,
613 LPCSTR pszName,
614 LPCMIMEPROPINFO pInfo)
616 FIXME("stub\n");
617 return E_NOTIMPL;
620 static HRESULT WINAPI MimeBody_GetProp(
621 IMimeBody* iface,
622 LPCSTR pszName,
623 DWORD dwFlags,
624 LPPROPVARIANT pValue)
626 MimeBody *This = impl_from_IMimeBody(iface);
627 TRACE("(%p)->(%s, %d, %p)\n", This, pszName, dwFlags, pValue);
629 if(!strcasecmp(pszName, "att:pri-content-type"))
631 PropVariantClear(pValue);
632 pValue->vt = VT_LPSTR;
633 pValue->u.pszVal = strdupA(This->content_pri_type);
634 return S_OK;
637 FIXME("stub!\n");
638 return E_FAIL;
641 static HRESULT WINAPI MimeBody_SetProp(
642 IMimeBody* iface,
643 LPCSTR pszName,
644 DWORD dwFlags,
645 LPCPROPVARIANT pValue)
647 FIXME("stub\n");
648 return E_NOTIMPL;
651 static HRESULT WINAPI MimeBody_AppendProp(
652 IMimeBody* iface,
653 LPCSTR pszName,
654 DWORD dwFlags,
655 LPPROPVARIANT pValue)
657 FIXME("stub\n");
658 return E_NOTIMPL;
661 static HRESULT WINAPI MimeBody_DeleteProp(
662 IMimeBody* iface,
663 LPCSTR pszName)
665 FIXME("stub\n");
666 return E_NOTIMPL;
669 static HRESULT WINAPI MimeBody_CopyProps(
670 IMimeBody* iface,
671 ULONG cNames,
672 LPCSTR* prgszName,
673 IMimePropertySet* pPropertySet)
675 FIXME("stub\n");
676 return E_NOTIMPL;
679 static HRESULT WINAPI MimeBody_MoveProps(
680 IMimeBody* iface,
681 ULONG cNames,
682 LPCSTR* prgszName,
683 IMimePropertySet* pPropertySet)
685 FIXME("stub\n");
686 return E_NOTIMPL;
689 static HRESULT WINAPI MimeBody_DeleteExcept(
690 IMimeBody* iface,
691 ULONG cNames,
692 LPCSTR* prgszName)
694 FIXME("stub\n");
695 return E_NOTIMPL;
698 static HRESULT WINAPI MimeBody_QueryProp(
699 IMimeBody* iface,
700 LPCSTR pszName,
701 LPCSTR pszCriteria,
702 boolean fSubString,
703 boolean fCaseSensitive)
705 FIXME("stub\n");
706 return E_NOTIMPL;
709 static HRESULT WINAPI MimeBody_GetCharset(
710 IMimeBody* iface,
711 LPHCHARSET phCharset)
713 FIXME("stub\n");
714 *phCharset = NULL;
715 return S_OK;
718 static HRESULT WINAPI MimeBody_SetCharset(
719 IMimeBody* iface,
720 HCHARSET hCharset,
721 CSETAPPLYTYPE applytype)
723 FIXME("stub\n");
724 return E_NOTIMPL;
727 static HRESULT WINAPI MimeBody_GetParameters(
728 IMimeBody* iface,
729 LPCSTR pszName,
730 ULONG* pcParams,
731 LPMIMEPARAMINFO* pprgParam)
733 MimeBody *This = impl_from_IMimeBody(iface);
734 HRESULT hr;
735 header_t *header;
737 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
739 *pprgParam = NULL;
740 *pcParams = 0;
742 hr = find_prop(This, pszName, &header);
743 if(hr != S_OK) return hr;
745 *pcParams = list_count(&header->params);
746 if(*pcParams)
748 IMimeAllocator *alloc;
749 param_t *param;
750 MIMEPARAMINFO *info;
752 MimeOleGetAllocator(&alloc);
754 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
755 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
757 int len;
759 len = strlen(param->name) + 1;
760 info->pszName = IMimeAllocator_Alloc(alloc, len);
761 memcpy(info->pszName, param->name, len);
762 len = strlen(param->value) + 1;
763 info->pszData = IMimeAllocator_Alloc(alloc, len);
764 memcpy(info->pszData, param->value, len);
765 info++;
767 IMimeAllocator_Release(alloc);
769 return S_OK;
772 static HRESULT WINAPI MimeBody_IsContentType(
773 IMimeBody* iface,
774 LPCSTR pszPriType,
775 LPCSTR pszSubType)
777 MimeBody *This = impl_from_IMimeBody(iface);
779 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
780 if(pszPriType)
782 const char *pri = This->content_pri_type;
783 if(!pri) pri = "text";
784 if(strcasecmp(pri, pszPriType)) return S_FALSE;
787 if(pszSubType)
789 const char *sub = This->content_sub_type;
790 if(!sub) sub = "plain";
791 if(strcasecmp(sub, pszSubType)) return S_FALSE;
794 return S_OK;
797 static HRESULT WINAPI MimeBody_BindToObject(
798 IMimeBody* iface,
799 REFIID riid,
800 void** ppvObject)
802 FIXME("stub\n");
803 return E_NOTIMPL;
806 static HRESULT WINAPI MimeBody_Clone(
807 IMimeBody* iface,
808 IMimePropertySet** ppPropertySet)
810 FIXME("stub\n");
811 return E_NOTIMPL;
814 static HRESULT WINAPI MimeBody_SetOption(
815 IMimeBody* iface,
816 const TYPEDID oid,
817 LPCPROPVARIANT pValue)
819 HRESULT hr = E_NOTIMPL;
820 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
822 if(pValue->vt != TYPEDID_TYPE(oid))
824 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
825 return E_INVALIDARG;
828 switch(oid)
830 case OID_SECURITY_HWND_OWNER:
831 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
832 hr = S_OK;
833 break;
834 default:
835 FIXME("Unhandled oid %08x\n", oid);
838 return hr;
841 static HRESULT WINAPI MimeBody_GetOption(
842 IMimeBody* iface,
843 const TYPEDID oid,
844 LPPROPVARIANT pValue)
846 FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
847 return E_NOTIMPL;
850 static HRESULT WINAPI MimeBody_EnumProps(
851 IMimeBody* iface,
852 DWORD dwFlags,
853 IMimeEnumProperties** ppEnum)
855 FIXME("stub\n");
856 return E_NOTIMPL;
859 static HRESULT WINAPI MimeBody_IsType(
860 IMimeBody* iface,
861 IMSGBODYTYPE bodytype)
863 MimeBody *This = impl_from_IMimeBody(iface);
865 TRACE("(%p)->(%d)\n", iface, bodytype);
866 switch(bodytype)
868 case IBT_EMPTY:
869 return This->data ? S_FALSE : S_OK;
870 default:
871 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
873 return S_OK;
876 static HRESULT WINAPI MimeBody_SetDisplayName(
877 IMimeBody* iface,
878 LPCSTR pszDisplay)
880 FIXME("stub\n");
881 return E_NOTIMPL;
884 static HRESULT WINAPI MimeBody_GetDisplayName(
885 IMimeBody* iface,
886 LPSTR* ppszDisplay)
888 FIXME("stub\n");
889 return E_NOTIMPL;
892 static HRESULT WINAPI MimeBody_GetOffsets(
893 IMimeBody* iface,
894 LPBODYOFFSETS pOffsets)
896 MimeBody *This = impl_from_IMimeBody(iface);
897 TRACE("(%p)->(%p)\n", This, pOffsets);
899 *pOffsets = This->body_offsets;
901 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
902 return S_OK;
905 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
906 IMimeBody* iface,
907 ENCODINGTYPE* pietEncoding)
909 MimeBody *This = impl_from_IMimeBody(iface);
911 TRACE("(%p)->(%p)\n", This, pietEncoding);
913 *pietEncoding = This->encoding;
914 return S_OK;
917 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
918 IMimeBody* iface,
919 ENCODINGTYPE ietEncoding)
921 MimeBody *This = impl_from_IMimeBody(iface);
923 TRACE("(%p)->(%d)\n", This, ietEncoding);
925 This->encoding = ietEncoding;
926 return S_OK;
929 static HRESULT WINAPI MimeBody_GetEstimatedSize(
930 IMimeBody* iface,
931 ENCODINGTYPE ietEncoding,
932 ULONG* pcbSize)
934 FIXME("stub\n");
935 return E_NOTIMPL;
938 static HRESULT WINAPI MimeBody_GetDataHere(
939 IMimeBody* iface,
940 ENCODINGTYPE ietEncoding,
941 IStream* pStream)
943 FIXME("stub\n");
944 return E_NOTIMPL;
947 static HRESULT WINAPI MimeBody_GetData(
948 IMimeBody* iface,
949 ENCODINGTYPE ietEncoding,
950 IStream** ppStream)
952 MimeBody *This = impl_from_IMimeBody(iface);
953 FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
955 *ppStream = This->data;
956 IStream_AddRef(*ppStream);
957 return S_OK;
960 static HRESULT WINAPI MimeBody_SetData(
961 IMimeBody* iface,
962 ENCODINGTYPE ietEncoding,
963 LPCSTR pszPriType,
964 LPCSTR pszSubType,
965 REFIID riid,
966 LPVOID pvObject)
968 MimeBody *This = impl_from_IMimeBody(iface);
969 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
970 debugstr_guid(riid), pvObject);
972 if(IsEqualIID(riid, &IID_IStream))
973 IStream_AddRef((IStream *)pvObject);
974 else
976 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
977 return E_INVALIDARG;
980 if(This->data)
981 FIXME("release old data\n");
983 This->data_iid = *riid;
984 This->data = pvObject;
986 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
988 /* FIXME: Update the content type.
989 If pszPriType == NULL use 'application'
990 If pszSubType == NULL use 'octet-stream' */
992 return S_OK;
995 static HRESULT WINAPI MimeBody_EmptyData(
996 IMimeBody* iface)
998 FIXME("stub\n");
999 return E_NOTIMPL;
1002 static HRESULT WINAPI MimeBody_CopyTo(
1003 IMimeBody* iface,
1004 IMimeBody* pBody)
1006 FIXME("stub\n");
1007 return E_NOTIMPL;
1010 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1011 IMimeBody* iface,
1012 LPTRANSMITINFO pTransmitInfo)
1014 FIXME("stub\n");
1015 return E_NOTIMPL;
1018 static HRESULT WINAPI MimeBody_SaveToFile(
1019 IMimeBody* iface,
1020 ENCODINGTYPE ietEncoding,
1021 LPCSTR pszFilePath)
1023 FIXME("stub\n");
1024 return E_NOTIMPL;
1027 static HRESULT WINAPI MimeBody_GetHandle(
1028 IMimeBody* iface,
1029 LPHBODY phBody)
1031 MimeBody *This = impl_from_IMimeBody(iface);
1032 TRACE("(%p)->(%p)\n", iface, phBody);
1034 *phBody = This->handle;
1035 return This->handle ? S_OK : MIME_E_NO_DATA;
1038 static IMimeBodyVtbl body_vtbl =
1040 MimeBody_QueryInterface,
1041 MimeBody_AddRef,
1042 MimeBody_Release,
1043 MimeBody_GetClassID,
1044 MimeBody_IsDirty,
1045 MimeBody_Load,
1046 MimeBody_Save,
1047 MimeBody_GetSizeMax,
1048 MimeBody_InitNew,
1049 MimeBody_GetPropInfo,
1050 MimeBody_SetPropInfo,
1051 MimeBody_GetProp,
1052 MimeBody_SetProp,
1053 MimeBody_AppendProp,
1054 MimeBody_DeleteProp,
1055 MimeBody_CopyProps,
1056 MimeBody_MoveProps,
1057 MimeBody_DeleteExcept,
1058 MimeBody_QueryProp,
1059 MimeBody_GetCharset,
1060 MimeBody_SetCharset,
1061 MimeBody_GetParameters,
1062 MimeBody_IsContentType,
1063 MimeBody_BindToObject,
1064 MimeBody_Clone,
1065 MimeBody_SetOption,
1066 MimeBody_GetOption,
1067 MimeBody_EnumProps,
1068 MimeBody_IsType,
1069 MimeBody_SetDisplayName,
1070 MimeBody_GetDisplayName,
1071 MimeBody_GetOffsets,
1072 MimeBody_GetCurrentEncoding,
1073 MimeBody_SetCurrentEncoding,
1074 MimeBody_GetEstimatedSize,
1075 MimeBody_GetDataHere,
1076 MimeBody_GetData,
1077 MimeBody_SetData,
1078 MimeBody_EmptyData,
1079 MimeBody_CopyTo,
1080 MimeBody_GetTransmitInfo,
1081 MimeBody_SaveToFile,
1082 MimeBody_GetHandle
1085 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1087 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1088 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1090 body->body_offsets = *offsets;
1091 return S_OK;
1094 #define FIRST_CUSTOM_PROP_ID 0x100
1096 static MimeBody *mimebody_create(void)
1098 MimeBody *This;
1099 BODYOFFSETS body_offsets;
1101 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1102 if (!This)
1103 return NULL;
1105 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1106 This->ref = 1;
1107 This->handle = NULL;
1108 list_init(&This->headers);
1109 list_init(&This->new_props);
1110 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1111 This->content_pri_type = NULL;
1112 This->content_sub_type = NULL;
1113 This->encoding = IET_7BIT;
1114 This->data = NULL;
1115 This->data_iid = IID_NULL;
1117 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1118 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1119 MimeBody_set_offsets(This, &body_offsets);
1121 return This;
1124 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1126 MimeBody *mb;
1128 if(outer)
1129 return CLASS_E_NOAGGREGATION;
1131 if ((mb = mimebody_create()))
1133 *ppv = &mb->IMimeBody_iface;
1134 return S_OK;
1136 else
1138 *ppv = NULL;
1139 return E_OUTOFMEMORY;
1145 typedef struct
1147 IStream IStream_iface;
1148 LONG ref;
1149 IStream *base;
1150 ULARGE_INTEGER pos, start, length;
1151 } sub_stream_t;
1153 static inline sub_stream_t *impl_from_IStream(IStream *iface)
1155 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
1158 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
1160 sub_stream_t *This = impl_from_IStream(iface);
1162 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1163 *ppv = NULL;
1165 if(IsEqualIID(riid, &IID_IUnknown) ||
1166 IsEqualIID(riid, &IID_ISequentialStream) ||
1167 IsEqualIID(riid, &IID_IStream))
1169 IStream_AddRef(iface);
1170 *ppv = iface;
1171 return S_OK;
1173 return E_NOINTERFACE;
1176 static ULONG WINAPI sub_stream_AddRef(IStream *iface)
1178 sub_stream_t *This = impl_from_IStream(iface);
1179 LONG ref = InterlockedIncrement(&This->ref);
1181 TRACE("(%p) ref=%d\n", This, ref);
1183 return ref;
1186 static ULONG WINAPI sub_stream_Release(IStream *iface)
1188 sub_stream_t *This = impl_from_IStream(iface);
1189 LONG ref = InterlockedDecrement(&This->ref);
1191 TRACE("(%p) ref=%d\n", This, ref);
1193 if(!ref)
1195 IStream_Release(This->base);
1196 HeapFree(GetProcessHeap(), 0, This);
1198 return ref;
1201 static HRESULT WINAPI sub_stream_Read(
1202 IStream* iface,
1203 void *pv,
1204 ULONG cb,
1205 ULONG *pcbRead)
1207 sub_stream_t *This = impl_from_IStream(iface);
1208 HRESULT hr;
1209 ULARGE_INTEGER base_pos;
1210 LARGE_INTEGER tmp_pos;
1212 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
1214 tmp_pos.QuadPart = 0;
1215 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_CUR, &base_pos);
1216 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
1217 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1219 if(This->pos.QuadPart + cb > This->length.QuadPart)
1220 cb = This->length.QuadPart - This->pos.QuadPart;
1222 hr = IStream_Read(This->base, pv, cb, pcbRead);
1224 This->pos.QuadPart += *pcbRead;
1226 tmp_pos.QuadPart = base_pos.QuadPart;
1227 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1229 return hr;
1232 static HRESULT WINAPI sub_stream_Write(
1233 IStream* iface,
1234 const void *pv,
1235 ULONG cb,
1236 ULONG *pcbWritten)
1238 FIXME("stub\n");
1239 return E_NOTIMPL;
1242 static HRESULT WINAPI sub_stream_Seek(
1243 IStream* iface,
1244 LARGE_INTEGER dlibMove,
1245 DWORD dwOrigin,
1246 ULARGE_INTEGER *plibNewPosition)
1248 sub_stream_t *This = impl_from_IStream(iface);
1249 LARGE_INTEGER new_pos;
1251 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
1253 switch(dwOrigin)
1255 case STREAM_SEEK_SET:
1256 new_pos = dlibMove;
1257 break;
1258 case STREAM_SEEK_CUR:
1259 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
1260 break;
1261 case STREAM_SEEK_END:
1262 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
1263 break;
1264 default:
1265 return STG_E_INVALIDFUNCTION;
1268 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
1269 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
1271 This->pos.QuadPart = new_pos.QuadPart;
1273 if(plibNewPosition) *plibNewPosition = This->pos;
1274 return S_OK;
1277 static HRESULT WINAPI sub_stream_SetSize(
1278 IStream* iface,
1279 ULARGE_INTEGER libNewSize)
1281 FIXME("stub\n");
1282 return E_NOTIMPL;
1285 static HRESULT WINAPI sub_stream_CopyTo(
1286 IStream* iface,
1287 IStream *pstm,
1288 ULARGE_INTEGER cb,
1289 ULARGE_INTEGER *pcbRead,
1290 ULARGE_INTEGER *pcbWritten)
1292 HRESULT hr = S_OK;
1293 BYTE tmpBuffer[128];
1294 ULONG bytesRead, bytesWritten, copySize;
1295 ULARGE_INTEGER totalBytesRead;
1296 ULARGE_INTEGER totalBytesWritten;
1298 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
1300 totalBytesRead.QuadPart = 0;
1301 totalBytesWritten.QuadPart = 0;
1303 while ( cb.QuadPart > 0 )
1305 if ( cb.QuadPart >= sizeof(tmpBuffer) )
1306 copySize = sizeof(tmpBuffer);
1307 else
1308 copySize = cb.u.LowPart;
1310 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1311 if (FAILED(hr)) break;
1313 totalBytesRead.QuadPart += bytesRead;
1315 if (bytesRead)
1317 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1318 if (FAILED(hr)) break;
1319 totalBytesWritten.QuadPart += bytesWritten;
1322 if (bytesRead != copySize)
1323 cb.QuadPart = 0;
1324 else
1325 cb.QuadPart -= bytesRead;
1328 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
1329 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
1331 return hr;
1334 static HRESULT WINAPI sub_stream_Commit(
1335 IStream* iface,
1336 DWORD grfCommitFlags)
1338 FIXME("stub\n");
1339 return E_NOTIMPL;
1342 static HRESULT WINAPI sub_stream_Revert(
1343 IStream* iface)
1345 FIXME("stub\n");
1346 return E_NOTIMPL;
1349 static HRESULT WINAPI sub_stream_LockRegion(
1350 IStream* iface,
1351 ULARGE_INTEGER libOffset,
1352 ULARGE_INTEGER cb,
1353 DWORD dwLockType)
1355 FIXME("stub\n");
1356 return E_NOTIMPL;
1359 static HRESULT WINAPI sub_stream_UnlockRegion(
1360 IStream* iface,
1361 ULARGE_INTEGER libOffset,
1362 ULARGE_INTEGER cb,
1363 DWORD dwLockType)
1365 FIXME("stub\n");
1366 return E_NOTIMPL;
1369 static HRESULT WINAPI sub_stream_Stat(
1370 IStream* iface,
1371 STATSTG *pstatstg,
1372 DWORD grfStatFlag)
1374 sub_stream_t *This = impl_from_IStream(iface);
1375 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
1376 memset(pstatstg, 0, sizeof(*pstatstg));
1377 pstatstg->cbSize = This->length;
1378 return S_OK;
1381 static HRESULT WINAPI sub_stream_Clone(
1382 IStream* iface,
1383 IStream **ppstm)
1385 FIXME("stub\n");
1386 return E_NOTIMPL;
1389 static struct IStreamVtbl sub_stream_vtbl =
1391 sub_stream_QueryInterface,
1392 sub_stream_AddRef,
1393 sub_stream_Release,
1394 sub_stream_Read,
1395 sub_stream_Write,
1396 sub_stream_Seek,
1397 sub_stream_SetSize,
1398 sub_stream_CopyTo,
1399 sub_stream_Commit,
1400 sub_stream_Revert,
1401 sub_stream_LockRegion,
1402 sub_stream_UnlockRegion,
1403 sub_stream_Stat,
1404 sub_stream_Clone
1407 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
1409 sub_stream_t *This;
1411 *out = NULL;
1412 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1413 if(!This) return E_OUTOFMEMORY;
1415 This->IStream_iface.lpVtbl = &sub_stream_vtbl;
1416 This->ref = 1;
1417 This->start = start;
1418 This->length = length;
1419 This->pos.QuadPart = 0;
1420 IStream_AddRef(stream);
1421 This->base = stream;
1423 *out = &This->IStream_iface;
1424 return S_OK;
1428 typedef struct body_t
1430 struct list entry;
1431 DWORD index;
1432 MimeBody *mime_body;
1434 struct body_t *parent;
1435 struct list children;
1436 } body_t;
1438 typedef struct MimeMessage
1440 IMimeMessage IMimeMessage_iface;
1441 LONG ref;
1442 IStream *stream;
1444 struct list body_tree;
1445 DWORD next_index;
1446 } MimeMessage;
1448 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1450 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1453 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1455 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1457 if (IsEqualIID(riid, &IID_IUnknown) ||
1458 IsEqualIID(riid, &IID_IPersist) ||
1459 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1460 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1461 IsEqualIID(riid, &IID_IMimeMessage))
1463 *ppv = iface;
1464 IMimeMessage_AddRef(iface);
1465 return S_OK;
1468 FIXME("no interface for %s\n", debugstr_guid(riid));
1469 *ppv = NULL;
1470 return E_NOINTERFACE;
1473 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1475 MimeMessage *This = impl_from_IMimeMessage(iface);
1476 ULONG ref = InterlockedIncrement(&This->ref);
1478 TRACE("(%p) ref=%d\n", This, ref);
1480 return ref;
1483 static void empty_body_list(struct list *list)
1485 body_t *body, *cursor2;
1486 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1488 empty_body_list(&body->children);
1489 list_remove(&body->entry);
1490 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1491 HeapFree(GetProcessHeap(), 0, body);
1495 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1497 MimeMessage *This = impl_from_IMimeMessage(iface);
1498 ULONG ref = InterlockedDecrement(&This->ref);
1500 TRACE("(%p) ref=%d\n", This, ref);
1502 if (!ref)
1504 empty_body_list(&This->body_tree);
1506 if(This->stream) IStream_Release(This->stream);
1507 HeapFree(GetProcessHeap(), 0, This);
1510 return ref;
1513 /*** IPersist methods ***/
1514 static HRESULT WINAPI MimeMessage_GetClassID(
1515 IMimeMessage *iface,
1516 CLSID *pClassID)
1518 FIXME("(%p)->(%p)\n", iface, pClassID);
1519 return E_NOTIMPL;
1522 /*** IPersistStreamInit methods ***/
1523 static HRESULT WINAPI MimeMessage_IsDirty(
1524 IMimeMessage *iface)
1526 FIXME("(%p)->()\n", iface);
1527 return E_NOTIMPL;
1530 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
1532 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
1533 if(body)
1535 body->mime_body = mime_body;
1536 body->index = index;
1537 list_init(&body->children);
1538 body->parent = parent;
1540 return body;
1543 typedef struct
1545 struct list entry;
1546 BODYOFFSETS offsets;
1547 } offset_entry_t;
1549 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
1551 HRESULT hr;
1552 DWORD read;
1553 int boundary_len = strlen(boundary);
1554 char *buf, *nl_boundary, *ptr, *overlap;
1555 DWORD start = 0, overlap_no;
1556 offset_entry_t *cur_body = NULL;
1557 ULARGE_INTEGER cur;
1558 LARGE_INTEGER zero;
1560 list_init(body_offsets);
1561 nl_boundary = HeapAlloc(GetProcessHeap(), 0, 4 + boundary_len + 1);
1562 memcpy(nl_boundary, "\r\n--", 4);
1563 memcpy(nl_boundary + 4, boundary, boundary_len + 1);
1565 overlap_no = boundary_len + 5;
1567 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
1569 zero.QuadPart = 0;
1570 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
1571 start = cur.u.LowPart;
1573 do {
1574 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
1575 if(FAILED(hr)) goto end;
1576 if(read == 0) break;
1577 overlap[read] = '\0';
1579 ptr = buf;
1580 do {
1581 ptr = strstr(ptr, nl_boundary);
1582 if(ptr)
1584 DWORD boundary_start = start + ptr - buf;
1585 char *end = ptr + boundary_len + 4;
1587 if(*end == '\0' || *(end + 1) == '\0')
1588 break;
1590 if(*end == '\r' && *(end + 1) == '\n')
1592 if(cur_body)
1594 cur_body->offsets.cbBodyEnd = boundary_start;
1595 list_add_tail(body_offsets, &cur_body->entry);
1597 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
1598 cur_body->offsets.cbBoundaryStart = boundary_start + 2; /* doesn't including the leading \r\n */
1599 cur_body->offsets.cbHeaderStart = boundary_start + boundary_len + 6;
1601 else if(*end == '-' && *(end + 1) == '-')
1603 if(cur_body)
1605 cur_body->offsets.cbBodyEnd = boundary_start;
1606 list_add_tail(body_offsets, &cur_body->entry);
1607 goto end;
1610 ptr = end + 2;
1612 } while(ptr);
1614 if(overlap == buf) /* 1st iteration */
1616 memcpy(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
1617 overlap = buf + overlap_no;
1618 start += read - overlap_no;
1620 else
1622 memcpy(buf, buf + PARSER_BUF_SIZE, overlap_no);
1623 start += read;
1625 } while(1);
1627 end:
1628 HeapFree(GetProcessHeap(), 0, nl_boundary);
1629 HeapFree(GetProcessHeap(), 0, buf);
1630 return hr;
1633 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
1635 MimeBody *mime_body;
1636 HRESULT hr;
1637 body_t *body;
1638 ULARGE_INTEGER cur;
1639 LARGE_INTEGER zero;
1641 mime_body = mimebody_create();
1642 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
1643 zero.QuadPart = 0;
1644 hr = IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &cur);
1645 offset->cbBodyStart = cur.u.LowPart + offset->cbHeaderStart;
1646 if (parent) MimeBody_set_offsets(mime_body, offset);
1647 IMimeBody_SetData(&mime_body->IMimeBody_iface, IET_BINARY, NULL, NULL, &IID_IStream, pStm);
1648 body = new_body_entry(mime_body, msg->next_index++, parent);
1650 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
1652 MIMEPARAMINFO *param_info;
1653 ULONG count, i;
1654 IMimeAllocator *alloc;
1656 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
1657 &param_info);
1658 if(hr != S_OK || count == 0) return body;
1660 MimeOleGetAllocator(&alloc);
1662 for(i = 0; i < count; i++)
1664 if(!strcasecmp(param_info[i].pszName, "boundary"))
1666 struct list offset_list;
1667 offset_entry_t *cur, *cursor2;
1668 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
1669 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
1671 body_t *sub_body;
1672 IStream *sub_stream;
1673 ULARGE_INTEGER start, length;
1675 start.QuadPart = cur->offsets.cbHeaderStart;
1676 length.QuadPart = cur->offsets.cbBodyEnd - cur->offsets.cbHeaderStart;
1677 create_sub_stream(pStm, start, length, &sub_stream);
1678 sub_body = create_sub_body(msg, sub_stream, &cur->offsets, body);
1679 IStream_Release(sub_stream);
1680 list_add_tail(&body->children, &sub_body->entry);
1681 list_remove(&cur->entry);
1682 HeapFree(GetProcessHeap(), 0, cur);
1684 break;
1687 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
1688 IMimeAllocator_Release(alloc);
1690 return body;
1693 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
1695 MimeMessage *This = impl_from_IMimeMessage(iface);
1696 body_t *root_body;
1697 BODYOFFSETS offsets;
1698 ULARGE_INTEGER cur;
1699 LARGE_INTEGER zero;
1701 TRACE("(%p)->(%p)\n", iface, pStm);
1703 if(This->stream)
1705 FIXME("already loaded a message\n");
1706 return E_FAIL;
1709 IStream_AddRef(pStm);
1710 This->stream = pStm;
1711 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
1712 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
1714 root_body = create_sub_body(This, pStm, &offsets, NULL);
1716 zero.QuadPart = 0;
1717 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
1718 offsets.cbBodyEnd = cur.u.LowPart;
1719 MimeBody_set_offsets(root_body->mime_body, &offsets);
1721 list_add_head(&This->body_tree, &root_body->entry);
1723 return S_OK;
1726 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
1728 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
1729 return E_NOTIMPL;
1732 static HRESULT WINAPI MimeMessage_GetSizeMax(
1733 IMimeMessage *iface,
1734 ULARGE_INTEGER *pcbSize)
1736 FIXME("(%p)->(%p)\n", iface, pcbSize);
1737 return E_NOTIMPL;
1740 static HRESULT WINAPI MimeMessage_InitNew(
1741 IMimeMessage *iface)
1743 FIXME("(%p)->()\n", iface);
1744 return E_NOTIMPL;
1747 /*** IMimeMessageTree methods ***/
1748 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
1749 DWORD dwFlags)
1751 MimeMessage *This = impl_from_IMimeMessage(iface);
1753 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
1755 IStream_AddRef(This->stream);
1756 *ppStream = This->stream;
1757 return S_OK;
1760 static HRESULT WINAPI MimeMessage_GetMessageSize(
1761 IMimeMessage *iface,
1762 ULONG *pcbSize,
1763 DWORD dwFlags)
1765 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
1766 return E_NOTIMPL;
1769 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
1770 IMimeMessage *iface,
1771 IStream *pStream)
1773 FIXME("(%p)->(%p)\n", iface, pStream);
1774 return E_NOTIMPL;
1777 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
1778 IMimeMessage *iface,
1779 IStream *pStream,
1780 DWORD dwFlags)
1782 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
1783 return E_NOTIMPL;
1787 static HRESULT WINAPI MimeMessage_GetFlags(
1788 IMimeMessage *iface,
1789 DWORD *pdwFlags)
1791 FIXME("(%p)->(%p)\n", iface, pdwFlags);
1792 return E_NOTIMPL;
1795 static HRESULT WINAPI MimeMessage_Commit(
1796 IMimeMessage *iface,
1797 DWORD dwFlags)
1799 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
1800 return E_NOTIMPL;
1804 static HRESULT WINAPI MimeMessage_HandsOffStorage(
1805 IMimeMessage *iface)
1807 FIXME("(%p)->()\n", iface);
1808 return E_NOTIMPL;
1811 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
1813 body_t *cur;
1814 HRESULT hr;
1816 if(hbody == HBODY_ROOT)
1818 *body = LIST_ENTRY(list_head(list), body_t, entry);
1819 return S_OK;
1822 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
1824 if(cur->index == HandleToUlong(hbody))
1826 *body = cur;
1827 return S_OK;
1829 hr = find_body(&cur->children, hbody, body);
1830 if(hr == S_OK) return S_OK;
1832 return S_FALSE;
1835 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
1836 void **ppvObject)
1838 MimeMessage *This = impl_from_IMimeMessage(iface);
1839 HRESULT hr;
1840 body_t *body;
1842 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
1844 hr = find_body(&This->body_tree, hBody, &body);
1846 if(hr != S_OK) return hr;
1848 if(IsEqualIID(riid, &IID_IMimeBody))
1850 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
1851 *ppvObject = &body->mime_body->IMimeBody_iface;
1852 return S_OK;
1855 return E_NOINTERFACE;
1858 static HRESULT WINAPI MimeMessage_SaveBody(
1859 IMimeMessage *iface,
1860 HBODY hBody,
1861 DWORD dwFlags,
1862 IStream *pStream)
1864 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
1865 return E_NOTIMPL;
1868 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
1870 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
1871 body_t *body;
1872 HRESULT hr;
1873 struct list *list;
1875 if(location == IBL_ROOT)
1877 *out = root;
1878 return S_OK;
1881 hr = find_body(&msg->body_tree, pivot, &body);
1883 if(hr == S_OK)
1885 switch(location)
1887 case IBL_PARENT:
1888 *out = body->parent;
1889 break;
1891 case IBL_FIRST:
1892 list = list_head(&body->children);
1893 if(list)
1894 *out = LIST_ENTRY(list, body_t, entry);
1895 else
1896 hr = MIME_E_NOT_FOUND;
1897 break;
1899 case IBL_LAST:
1900 list = list_tail(&body->children);
1901 if(list)
1902 *out = LIST_ENTRY(list, body_t, entry);
1903 else
1904 hr = MIME_E_NOT_FOUND;
1905 break;
1907 case IBL_NEXT:
1908 list = list_next(&body->parent->children, &body->entry);
1909 if(list)
1910 *out = LIST_ENTRY(list, body_t, entry);
1911 else
1912 hr = MIME_E_NOT_FOUND;
1913 break;
1915 case IBL_PREVIOUS:
1916 list = list_prev(&body->parent->children, &body->entry);
1917 if(list)
1918 *out = LIST_ENTRY(list, body_t, entry);
1919 else
1920 hr = MIME_E_NOT_FOUND;
1921 break;
1923 default:
1924 hr = E_FAIL;
1925 break;
1929 return hr;
1933 static HRESULT WINAPI MimeMessage_InsertBody(
1934 IMimeMessage *iface,
1935 BODYLOCATION location,
1936 HBODY hPivot,
1937 LPHBODY phBody)
1939 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1940 return E_NOTIMPL;
1943 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
1944 HBODY *phBody)
1946 MimeMessage *This = impl_from_IMimeMessage(iface);
1947 body_t *body;
1948 HRESULT hr;
1950 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1952 hr = get_body(This, location, hPivot, &body);
1954 if(hr == S_OK) *phBody = UlongToHandle(body->index);
1956 return hr;
1959 static HRESULT WINAPI MimeMessage_DeleteBody(
1960 IMimeMessage *iface,
1961 HBODY hBody,
1962 DWORD dwFlags)
1964 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
1965 return E_NOTIMPL;
1968 static HRESULT WINAPI MimeMessage_MoveBody(
1969 IMimeMessage *iface,
1970 HBODY hBody,
1971 BODYLOCATION location)
1973 FIXME("(%p)->(%d)\n", iface, location);
1974 return E_NOTIMPL;
1977 static void count_children(body_t *body, boolean recurse, ULONG *count)
1979 body_t *child;
1981 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
1983 (*count)++;
1984 if(recurse) count_children(child, recurse, count);
1988 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
1989 ULONG *pcBodies)
1991 HRESULT hr;
1992 MimeMessage *This = impl_from_IMimeMessage(iface);
1993 body_t *body;
1995 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
1997 hr = find_body(&This->body_tree, hParent, &body);
1998 if(hr != S_OK) return hr;
2000 *pcBodies = 1;
2001 count_children(body, fRecurse, pcBodies);
2003 return S_OK;
2006 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2008 struct list *ptr;
2009 HBODY next;
2011 for (;;)
2013 if (!body) ptr = list_head( &This->body_tree );
2014 else
2016 ptr = list_head( &body->children );
2017 while (!ptr)
2019 if (!body->parent) return MIME_E_NOT_FOUND;
2020 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2024 body = LIST_ENTRY( ptr, body_t, entry );
2025 next = UlongToHandle( body->index );
2026 find->dwReserved = body->index;
2027 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2028 find->pszSubType) == S_OK)
2030 *out = next;
2031 return S_OK;
2034 return MIME_E_NOT_FOUND;
2037 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2039 MimeMessage *This = impl_from_IMimeMessage(iface);
2041 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2043 pFindBody->dwReserved = 0;
2044 return find_next(This, NULL, pFindBody, phBody);
2047 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2049 MimeMessage *This = impl_from_IMimeMessage(iface);
2050 body_t *body;
2051 HRESULT hr;
2053 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2055 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2056 if (hr != S_OK) return MIME_E_NOT_FOUND;
2057 return find_next(This, body, pFindBody, phBody);
2060 static HRESULT WINAPI MimeMessage_ResolveURL(
2061 IMimeMessage *iface,
2062 HBODY hRelated,
2063 LPCSTR pszBase,
2064 LPCSTR pszURL,
2065 DWORD dwFlags,
2066 LPHBODY phBody)
2068 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2069 return E_NOTIMPL;
2072 static HRESULT WINAPI MimeMessage_ToMultipart(
2073 IMimeMessage *iface,
2074 HBODY hBody,
2075 LPCSTR pszSubType,
2076 LPHBODY phMultipart)
2078 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2079 return E_NOTIMPL;
2082 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2083 IMimeMessage *iface,
2084 HBODY hBody,
2085 LPBODYOFFSETS pOffsets)
2087 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2088 return E_NOTIMPL;
2091 static HRESULT WINAPI MimeMessage_GetCharset(
2092 IMimeMessage *iface,
2093 LPHCHARSET phCharset)
2095 FIXME("(%p)->(%p)\n", iface, phCharset);
2096 *phCharset = NULL;
2097 return S_OK;
2100 static HRESULT WINAPI MimeMessage_SetCharset(
2101 IMimeMessage *iface,
2102 HCHARSET hCharset,
2103 CSETAPPLYTYPE applytype)
2105 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2106 return E_NOTIMPL;
2109 static HRESULT WINAPI MimeMessage_IsBodyType(
2110 IMimeMessage *iface,
2111 HBODY hBody,
2112 IMSGBODYTYPE bodytype)
2114 HRESULT hr;
2115 IMimeBody *mime_body;
2116 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2118 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2119 if(hr != S_OK) return hr;
2121 hr = IMimeBody_IsType(mime_body, bodytype);
2122 MimeBody_Release(mime_body);
2123 return hr;
2126 static HRESULT WINAPI MimeMessage_IsContentType(
2127 IMimeMessage *iface,
2128 HBODY hBody,
2129 LPCSTR pszPriType,
2130 LPCSTR pszSubType)
2132 HRESULT hr;
2133 IMimeBody *mime_body;
2134 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2135 debugstr_a(pszSubType));
2137 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2138 if(FAILED(hr)) return hr;
2140 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2141 IMimeBody_Release(mime_body);
2142 return hr;
2145 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2146 IMimeMessage *iface,
2147 HBODY hBody,
2148 LPCSTR pszName,
2149 LPCSTR pszCriteria,
2150 boolean fSubString,
2151 boolean fCaseSensitive)
2153 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2154 return E_NOTIMPL;
2157 static HRESULT WINAPI MimeMessage_GetBodyProp(
2158 IMimeMessage *iface,
2159 HBODY hBody,
2160 LPCSTR pszName,
2161 DWORD dwFlags,
2162 LPPROPVARIANT pValue)
2164 HRESULT hr;
2165 IMimeBody *mime_body;
2167 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2169 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2170 if(hr != S_OK) return hr;
2172 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2173 IMimeBody_Release(mime_body);
2175 return hr;
2178 static HRESULT WINAPI MimeMessage_SetBodyProp(
2179 IMimeMessage *iface,
2180 HBODY hBody,
2181 LPCSTR pszName,
2182 DWORD dwFlags,
2183 LPCPROPVARIANT pValue)
2185 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2186 return E_NOTIMPL;
2189 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2190 IMimeMessage *iface,
2191 HBODY hBody,
2192 LPCSTR pszName)
2194 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2195 return E_NOTIMPL;
2198 static HRESULT WINAPI MimeMessage_SetOption(
2199 IMimeMessage *iface,
2200 const TYPEDID oid,
2201 LPCPROPVARIANT pValue)
2203 HRESULT hr = E_NOTIMPL;
2204 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2206 if(pValue->vt != TYPEDID_TYPE(oid))
2208 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2209 return E_INVALIDARG;
2212 switch(oid)
2214 case OID_HIDE_TNEF_ATTACHMENTS:
2215 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2216 hr = S_OK;
2217 break;
2218 case OID_SHOW_MACBINARY:
2219 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2220 hr = S_OK;
2221 break;
2222 default:
2223 FIXME("Unhandled oid %08x\n", oid);
2226 return hr;
2229 static HRESULT WINAPI MimeMessage_GetOption(
2230 IMimeMessage *iface,
2231 const TYPEDID oid,
2232 LPPROPVARIANT pValue)
2234 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2235 return E_NOTIMPL;
2238 /*** IMimeMessage methods ***/
2239 static HRESULT WINAPI MimeMessage_CreateWebPage(
2240 IMimeMessage *iface,
2241 IStream *pRootStm,
2242 LPWEBPAGEOPTIONS pOptions,
2243 IMimeMessageCallback *pCallback,
2244 IMoniker **ppMoniker)
2246 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2247 *ppMoniker = NULL;
2248 return E_NOTIMPL;
2251 static HRESULT WINAPI MimeMessage_GetProp(
2252 IMimeMessage *iface,
2253 LPCSTR pszName,
2254 DWORD dwFlags,
2255 LPPROPVARIANT pValue)
2257 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2258 return E_NOTIMPL;
2261 static HRESULT WINAPI MimeMessage_SetProp(
2262 IMimeMessage *iface,
2263 LPCSTR pszName,
2264 DWORD dwFlags,
2265 LPCPROPVARIANT pValue)
2267 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2268 return E_NOTIMPL;
2271 static HRESULT WINAPI MimeMessage_DeleteProp(
2272 IMimeMessage *iface,
2273 LPCSTR pszName)
2275 FIXME("(%p)->(%s)\n", iface, pszName);
2276 return E_NOTIMPL;
2279 static HRESULT WINAPI MimeMessage_QueryProp(
2280 IMimeMessage *iface,
2281 LPCSTR pszName,
2282 LPCSTR pszCriteria,
2283 boolean fSubString,
2284 boolean fCaseSensitive)
2286 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2287 return E_NOTIMPL;
2290 static HRESULT WINAPI MimeMessage_GetTextBody(
2291 IMimeMessage *iface,
2292 DWORD dwTxtType,
2293 ENCODINGTYPE ietEncoding,
2294 IStream **pStream,
2295 LPHBODY phBody)
2297 HRESULT hr;
2298 HBODY hbody;
2299 FINDBODY find_struct;
2300 IMimeBody *mime_body;
2301 static char text[] = "text";
2302 static char plain[] = "plain";
2303 static char html[] = "html";
2305 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2307 find_struct.pszPriType = text;
2309 switch(dwTxtType)
2311 case TXT_PLAIN:
2312 find_struct.pszSubType = plain;
2313 break;
2314 case TXT_HTML:
2315 find_struct.pszSubType = html;
2316 break;
2317 default:
2318 return MIME_E_INVALID_TEXT_TYPE;
2321 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2322 if(hr != S_OK)
2324 TRACE("not found hr %08x\n", hr);
2325 *phBody = NULL;
2326 return hr;
2329 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2331 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2332 *phBody = hbody;
2333 IMimeBody_Release(mime_body);
2334 return hr;
2337 static HRESULT WINAPI MimeMessage_SetTextBody(
2338 IMimeMessage *iface,
2339 DWORD dwTxtType,
2340 ENCODINGTYPE ietEncoding,
2341 HBODY hAlternative,
2342 IStream *pStream,
2343 LPHBODY phBody)
2345 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2346 return E_NOTIMPL;
2349 static HRESULT WINAPI MimeMessage_AttachObject(
2350 IMimeMessage *iface,
2351 REFIID riid,
2352 void *pvObject,
2353 LPHBODY phBody)
2355 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2356 return E_NOTIMPL;
2359 static HRESULT WINAPI MimeMessage_AttachFile(
2360 IMimeMessage *iface,
2361 LPCSTR pszFilePath,
2362 IStream *pstmFile,
2363 LPHBODY phBody)
2365 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2366 return E_NOTIMPL;
2369 static HRESULT WINAPI MimeMessage_AttachURL(
2370 IMimeMessage *iface,
2371 LPCSTR pszBase,
2372 LPCSTR pszURL,
2373 DWORD dwFlags,
2374 IStream *pstmURL,
2375 LPSTR *ppszCIDURL,
2376 LPHBODY phBody)
2378 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2379 return E_NOTIMPL;
2382 static HRESULT WINAPI MimeMessage_GetAttachments(
2383 IMimeMessage *iface,
2384 ULONG *pcAttach,
2385 LPHBODY *pprghAttach)
2387 HRESULT hr;
2388 FINDBODY find_struct;
2389 HBODY hbody;
2390 LPHBODY array;
2391 ULONG size = 10;
2393 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2395 *pcAttach = 0;
2396 array = CoTaskMemAlloc(size * sizeof(HBODY));
2398 find_struct.pszPriType = find_struct.pszSubType = NULL;
2399 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2400 while(hr == S_OK)
2402 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2403 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2404 if(hr != S_OK)
2406 if(*pcAttach + 1 > size)
2408 size *= 2;
2409 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2411 array[*pcAttach] = hbody;
2412 (*pcAttach)++;
2414 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2417 *pprghAttach = array;
2418 return S_OK;
2421 static HRESULT WINAPI MimeMessage_GetAddressTable(
2422 IMimeMessage *iface,
2423 IMimeAddressTable **ppTable)
2425 FIXME("(%p)->(%p)\n", iface, ppTable);
2426 return E_NOTIMPL;
2429 static HRESULT WINAPI MimeMessage_GetSender(
2430 IMimeMessage *iface,
2431 LPADDRESSPROPS pAddress)
2433 FIXME("(%p)->(%p)\n", iface, pAddress);
2434 return E_NOTIMPL;
2437 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2438 IMimeMessage *iface,
2439 DWORD dwAdrTypes,
2440 DWORD dwProps,
2441 LPADDRESSLIST pList)
2443 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2444 return E_NOTIMPL;
2447 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2448 IMimeMessage *iface,
2449 DWORD dwAdrTypes,
2450 ADDRESSFORMAT format,
2451 LPSTR *ppszFormat)
2453 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2454 return E_NOTIMPL;
2457 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2458 IMimeMessage *iface,
2459 DWORD dwAdrTypes,
2460 DWORD dwProps,
2461 IMimeEnumAddressTypes **ppEnum)
2463 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2464 return E_NOTIMPL;
2467 static HRESULT WINAPI MimeMessage_SplitMessage(
2468 IMimeMessage *iface,
2469 ULONG cbMaxPart,
2470 IMimeMessageParts **ppParts)
2472 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
2473 return E_NOTIMPL;
2476 static HRESULT WINAPI MimeMessage_GetRootMoniker(
2477 IMimeMessage *iface,
2478 IMoniker **ppMoniker)
2480 FIXME("(%p)->(%p)\n", iface, ppMoniker);
2481 return E_NOTIMPL;
2484 static const IMimeMessageVtbl MimeMessageVtbl =
2486 MimeMessage_QueryInterface,
2487 MimeMessage_AddRef,
2488 MimeMessage_Release,
2489 MimeMessage_GetClassID,
2490 MimeMessage_IsDirty,
2491 MimeMessage_Load,
2492 MimeMessage_Save,
2493 MimeMessage_GetSizeMax,
2494 MimeMessage_InitNew,
2495 MimeMessage_GetMessageSource,
2496 MimeMessage_GetMessageSize,
2497 MimeMessage_LoadOffsetTable,
2498 MimeMessage_SaveOffsetTable,
2499 MimeMessage_GetFlags,
2500 MimeMessage_Commit,
2501 MimeMessage_HandsOffStorage,
2502 MimeMessage_BindToObject,
2503 MimeMessage_SaveBody,
2504 MimeMessage_InsertBody,
2505 MimeMessage_GetBody,
2506 MimeMessage_DeleteBody,
2507 MimeMessage_MoveBody,
2508 MimeMessage_CountBodies,
2509 MimeMessage_FindFirst,
2510 MimeMessage_FindNext,
2511 MimeMessage_ResolveURL,
2512 MimeMessage_ToMultipart,
2513 MimeMessage_GetBodyOffsets,
2514 MimeMessage_GetCharset,
2515 MimeMessage_SetCharset,
2516 MimeMessage_IsBodyType,
2517 MimeMessage_IsContentType,
2518 MimeMessage_QueryBodyProp,
2519 MimeMessage_GetBodyProp,
2520 MimeMessage_SetBodyProp,
2521 MimeMessage_DeleteBodyProp,
2522 MimeMessage_SetOption,
2523 MimeMessage_GetOption,
2524 MimeMessage_CreateWebPage,
2525 MimeMessage_GetProp,
2526 MimeMessage_SetProp,
2527 MimeMessage_DeleteProp,
2528 MimeMessage_QueryProp,
2529 MimeMessage_GetTextBody,
2530 MimeMessage_SetTextBody,
2531 MimeMessage_AttachObject,
2532 MimeMessage_AttachFile,
2533 MimeMessage_AttachURL,
2534 MimeMessage_GetAttachments,
2535 MimeMessage_GetAddressTable,
2536 MimeMessage_GetSender,
2537 MimeMessage_GetAddressTypes,
2538 MimeMessage_GetAddressFormat,
2539 MimeMessage_EnumAddressTypes,
2540 MimeMessage_SplitMessage,
2541 MimeMessage_GetRootMoniker,
2544 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
2546 MimeMessage *This;
2548 TRACE("(%p, %p)\n", outer, obj);
2550 if (outer)
2552 FIXME("outer unknown not supported yet\n");
2553 return E_NOTIMPL;
2556 *obj = NULL;
2558 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2559 if (!This) return E_OUTOFMEMORY;
2561 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
2562 This->ref = 1;
2563 This->stream = NULL;
2564 list_init(&This->body_tree);
2565 This->next_index = 1;
2567 *obj = &This->IMimeMessage_iface;
2568 return S_OK;
2571 /***********************************************************************
2572 * MimeOleCreateMessage (INETCOMM.@)
2574 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
2576 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
2577 return MimeMessage_create(NULL, (void **)ppMessage);
2580 /***********************************************************************
2581 * MimeOleSetCompatMode (INETCOMM.@)
2583 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
2585 FIXME("(0x%x)\n", dwMode);
2586 return S_OK;
2589 /***********************************************************************
2590 * MimeOleCreateVirtualStream (INETCOMM.@)
2592 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
2594 HRESULT hr;
2595 FIXME("(%p)\n", ppStream);
2597 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
2598 return hr;
2601 typedef struct MimeSecurity
2603 IMimeSecurity IMimeSecurity_iface;
2604 LONG ref;
2605 } MimeSecurity;
2607 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
2609 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
2612 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
2614 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2616 if (IsEqualIID(riid, &IID_IUnknown) ||
2617 IsEqualIID(riid, &IID_IMimeSecurity))
2619 *ppv = iface;
2620 IMimeSecurity_AddRef(iface);
2621 return S_OK;
2624 FIXME("no interface for %s\n", debugstr_guid(riid));
2625 *ppv = NULL;
2626 return E_NOINTERFACE;
2629 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
2631 MimeSecurity *This = impl_from_IMimeSecurity(iface);
2632 LONG ref = InterlockedIncrement(&This->ref);
2634 TRACE("(%p) ref=%d\n", This, ref);
2636 return ref;
2639 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
2641 MimeSecurity *This = impl_from_IMimeSecurity(iface);
2642 LONG ref = InterlockedDecrement(&This->ref);
2644 TRACE("(%p) ref=%d\n", This, ref);
2646 if (!ref)
2647 HeapFree(GetProcessHeap(), 0, This);
2649 return ref;
2652 static HRESULT WINAPI MimeSecurity_InitNew(
2653 IMimeSecurity* iface)
2655 FIXME("(%p)->(): stub\n", iface);
2656 return S_OK;
2659 static HRESULT WINAPI MimeSecurity_CheckInit(
2660 IMimeSecurity* iface)
2662 FIXME("(%p)->(): stub\n", iface);
2663 return E_NOTIMPL;
2666 static HRESULT WINAPI MimeSecurity_EncodeMessage(
2667 IMimeSecurity* iface,
2668 IMimeMessageTree* pTree,
2669 DWORD dwFlags)
2671 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
2672 return E_NOTIMPL;
2675 static HRESULT WINAPI MimeSecurity_EncodeBody(
2676 IMimeSecurity* iface,
2677 IMimeMessageTree* pTree,
2678 HBODY hEncodeRoot,
2679 DWORD dwFlags)
2681 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
2682 return E_NOTIMPL;
2685 static HRESULT WINAPI MimeSecurity_DecodeMessage(
2686 IMimeSecurity* iface,
2687 IMimeMessageTree* pTree,
2688 DWORD dwFlags)
2690 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
2691 return E_NOTIMPL;
2694 static HRESULT WINAPI MimeSecurity_DecodeBody(
2695 IMimeSecurity* iface,
2696 IMimeMessageTree* pTree,
2697 HBODY hDecodeRoot,
2698 DWORD dwFlags)
2700 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
2701 return E_NOTIMPL;
2704 static HRESULT WINAPI MimeSecurity_EnumCertificates(
2705 IMimeSecurity* iface,
2706 HCAPICERTSTORE hc,
2707 DWORD dwUsage,
2708 PCX509CERT pPrev,
2709 PCX509CERT* ppCert)
2711 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
2712 return E_NOTIMPL;
2715 static HRESULT WINAPI MimeSecurity_GetCertificateName(
2716 IMimeSecurity* iface,
2717 const PCX509CERT pX509Cert,
2718 const CERTNAMETYPE cn,
2719 LPSTR* ppszName)
2721 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
2722 return E_NOTIMPL;
2725 static HRESULT WINAPI MimeSecurity_GetMessageType(
2726 IMimeSecurity* iface,
2727 const HWND hwndParent,
2728 IMimeBody* pBody,
2729 DWORD* pdwSecType)
2731 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
2732 return E_NOTIMPL;
2735 static HRESULT WINAPI MimeSecurity_GetCertData(
2736 IMimeSecurity* iface,
2737 const PCX509CERT pX509Cert,
2738 const CERTDATAID dataid,
2739 LPPROPVARIANT pValue)
2741 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
2742 return E_NOTIMPL;
2746 static const IMimeSecurityVtbl MimeSecurityVtbl =
2748 MimeSecurity_QueryInterface,
2749 MimeSecurity_AddRef,
2750 MimeSecurity_Release,
2751 MimeSecurity_InitNew,
2752 MimeSecurity_CheckInit,
2753 MimeSecurity_EncodeMessage,
2754 MimeSecurity_EncodeBody,
2755 MimeSecurity_DecodeMessage,
2756 MimeSecurity_DecodeBody,
2757 MimeSecurity_EnumCertificates,
2758 MimeSecurity_GetCertificateName,
2759 MimeSecurity_GetMessageType,
2760 MimeSecurity_GetCertData
2763 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
2765 MimeSecurity *This;
2767 *obj = NULL;
2769 if (outer) return CLASS_E_NOAGGREGATION;
2771 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2772 if (!This) return E_OUTOFMEMORY;
2774 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
2775 This->ref = 1;
2777 *obj = &This->IMimeSecurity_iface;
2778 return S_OK;
2781 /***********************************************************************
2782 * MimeOleCreateSecurity (INETCOMM.@)
2784 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
2786 return MimeSecurity_create(NULL, (void **)ppSecurity);
2789 static HRESULT WINAPI MimeAlloc_QueryInterface(
2790 IMimeAllocator* iface,
2791 REFIID riid,
2792 void **obj)
2794 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
2796 if (IsEqualIID(riid, &IID_IUnknown) ||
2797 IsEqualIID(riid, &IID_IMalloc) ||
2798 IsEqualIID(riid, &IID_IMimeAllocator))
2800 *obj = iface;
2801 IMimeAllocator_AddRef(iface);
2802 return S_OK;
2805 FIXME("no interface for %s\n", debugstr_guid(riid));
2806 *obj = NULL;
2807 return E_NOINTERFACE;
2810 static ULONG WINAPI MimeAlloc_AddRef(
2811 IMimeAllocator* iface)
2813 return 2;
2816 static ULONG WINAPI MimeAlloc_Release(
2817 IMimeAllocator* iface)
2819 return 1;
2822 static LPVOID WINAPI MimeAlloc_Alloc(
2823 IMimeAllocator* iface,
2824 ULONG cb)
2826 return CoTaskMemAlloc(cb);
2829 static LPVOID WINAPI MimeAlloc_Realloc(
2830 IMimeAllocator* iface,
2831 LPVOID pv,
2832 ULONG cb)
2834 return CoTaskMemRealloc(pv, cb);
2837 static void WINAPI MimeAlloc_Free(
2838 IMimeAllocator* iface,
2839 LPVOID pv)
2841 CoTaskMemFree(pv);
2844 static ULONG WINAPI MimeAlloc_GetSize(
2845 IMimeAllocator* iface,
2846 LPVOID pv)
2848 FIXME("stub\n");
2849 return 0;
2852 static int WINAPI MimeAlloc_DidAlloc(
2853 IMimeAllocator* iface,
2854 LPVOID pv)
2856 FIXME("stub\n");
2857 return 0;
2860 static void WINAPI MimeAlloc_HeapMinimize(
2861 IMimeAllocator* iface)
2863 FIXME("stub\n");
2864 return;
2867 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
2868 IMimeAllocator* iface,
2869 ULONG cParams,
2870 LPMIMEPARAMINFO prgParam,
2871 boolean fFreeArray)
2873 ULONG i;
2874 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
2876 for(i = 0; i < cParams; i++)
2878 IMimeAllocator_Free(iface, prgParam[i].pszName);
2879 IMimeAllocator_Free(iface, prgParam[i].pszData);
2881 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
2882 return S_OK;
2885 static HRESULT WINAPI MimeAlloc_FreeAddressList(
2886 IMimeAllocator* iface,
2887 LPADDRESSLIST pList)
2889 FIXME("stub\n");
2890 return E_NOTIMPL;
2893 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
2894 IMimeAllocator* iface,
2895 LPADDRESSPROPS pAddress)
2897 FIXME("stub\n");
2898 return E_NOTIMPL;
2901 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
2902 IMimeAllocator* iface,
2903 ULONG cObjects,
2904 IUnknown **prgpUnknown,
2905 boolean fFreeArray)
2907 FIXME("stub\n");
2908 return E_NOTIMPL;
2912 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
2913 IMimeAllocator* iface,
2914 ULONG cRows,
2915 LPENUMHEADERROW prgRow,
2916 boolean fFreeArray)
2918 FIXME("stub\n");
2919 return E_NOTIMPL;
2922 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
2923 IMimeAllocator* iface,
2924 ULONG cProps,
2925 LPENUMPROPERTY prgProp,
2926 boolean fFreeArray)
2928 FIXME("stub\n");
2929 return E_NOTIMPL;
2932 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
2933 IMimeAllocator* iface,
2934 THUMBBLOB *pthumbprint)
2936 FIXME("stub\n");
2937 return E_NOTIMPL;
2941 static HRESULT WINAPI MimeAlloc_PropVariantClear(
2942 IMimeAllocator* iface,
2943 LPPROPVARIANT pProp)
2945 FIXME("stub\n");
2946 return E_NOTIMPL;
2949 static IMimeAllocatorVtbl mime_alloc_vtbl =
2951 MimeAlloc_QueryInterface,
2952 MimeAlloc_AddRef,
2953 MimeAlloc_Release,
2954 MimeAlloc_Alloc,
2955 MimeAlloc_Realloc,
2956 MimeAlloc_Free,
2957 MimeAlloc_GetSize,
2958 MimeAlloc_DidAlloc,
2959 MimeAlloc_HeapMinimize,
2960 MimeAlloc_FreeParamInfoArray,
2961 MimeAlloc_FreeAddressList,
2962 MimeAlloc_FreeAddressProps,
2963 MimeAlloc_ReleaseObjects,
2964 MimeAlloc_FreeEnumHeaderRowArray,
2965 MimeAlloc_FreeEnumPropertyArray,
2966 MimeAlloc_FreeThumbprint,
2967 MimeAlloc_PropVariantClear
2970 static IMimeAllocator mime_allocator =
2972 &mime_alloc_vtbl
2975 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
2977 if(outer) return CLASS_E_NOAGGREGATION;
2979 *obj = &mime_allocator;
2980 return S_OK;
2983 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
2985 return MimeAllocator_create(NULL, (void**)alloc);
2988 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
2990 FIXME("(%p, %p)\n", outer, obj);
2992 *obj = NULL;
2993 if (outer) return CLASS_E_NOAGGREGATION;
2995 return MimeOleCreateVirtualStream((IStream **)obj);