win32u: Respect per-monitor thread dpi awareness when getting window from point.
[wine.git] / dlls / inetcomm / mimeole.c
blob5a2225b2fdf98f9d8395c571e152200e26e84595
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
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winternl.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "ole2.h"
33 #include "mimeole.h"
34 #include "propvarutil.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
39 #include "inetcomm_private.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
43 typedef struct
45 LPCSTR name;
46 DWORD id;
47 DWORD flags; /* MIMEPROPFLAGS */
48 VARTYPE default_vt;
49 } property_t;
51 typedef struct
53 struct list entry;
54 property_t prop;
55 } property_list_entry_t;
57 static const property_t default_props[] =
59 {"X-Newsgroup", PID_HDR_NEWSGROUP, 0, VT_LPSTR},
60 {"Newsgroups", PID_HDR_NEWSGROUPS, 0, VT_LPSTR},
61 {"References", PID_HDR_REFS, 0, VT_LPSTR},
62 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
63 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
64 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
65 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
66 {"Rr", PID_HDR_RR, 0, VT_LPSTR},
67 {"Return-Receipt-To", PID_HDR_RETRCPTO, MPF_ADDRESS, VT_LPSTR},
68 {"Apparently-To", PID_HDR_APPARTO, MPF_ADDRESS, VT_LPSTR},
69 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
70 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
71 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
72 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
73 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
74 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
75 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
76 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
77 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
78 {"Content-Description", PID_HDR_CNTDESC, MPF_MIME, VT_LPSTR},
79 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
80 {"Content-Base", PID_HDR_CNTBASE, MPF_MIME, VT_LPSTR},
81 {"Content-Location", PID_HDR_CNTLOC, MPF_MIME, VT_LPSTR},
82 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
83 {"Path", PID_HDR_PATH, 0, VT_LPSTR},
84 {"Followup-To", PID_HDR_FOLLOWUPTO, 0, VT_LPSTR},
85 {"Expires", PID_HDR_EXPIRES, 0, VT_LPSTR},
86 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
87 {"Control", PID_HDR_CONTROL, 0, VT_LPSTR},
88 {"Distribution", PID_HDR_DISTRIB, 0, VT_LPSTR},
89 {"Keywords", PID_HDR_KEYWORDS, 0, VT_LPSTR},
90 {"Summary", PID_HDR_SUMMARY, 0, VT_LPSTR},
91 {"Approved", PID_HDR_APPROVED, 0, VT_LPSTR},
92 {"Lines", PID_HDR_LINES, 0, VT_LPSTR},
93 {"Xref", PID_HDR_XREF, 0, VT_LPSTR},
94 {"Organization", PID_HDR_ORG, 0, VT_LPSTR},
95 {"X-Newsreader", PID_HDR_XNEWSRDR, 0, VT_LPSTR},
96 {"X-Priority", PID_HDR_XPRI, 0, VT_LPSTR},
97 {"X-MSMail-Priority", PID_HDR_XMSPRI, 0, VT_LPSTR},
98 {"par:content-disposition:filename", PID_PAR_FILENAME, 0, VT_LPSTR},
99 {"par:content-type:boundary", PID_PAR_BOUNDARY, 0, VT_LPSTR},
100 {"par:content-type:charset", PID_PAR_CHARSET, 0, VT_LPSTR},
101 {"par:content-type:name", PID_PAR_NAME, 0, VT_LPSTR},
102 {"att:filename", PID_ATT_FILENAME, 0, VT_LPSTR},
103 {"att:pri-content-type", PID_ATT_PRITYPE, 0, VT_LPSTR},
104 {"att:sub-content-type", PID_ATT_SUBTYPE, 0, VT_LPSTR},
105 {"att:illegal-lines", PID_ATT_ILLEGAL, 0, VT_LPSTR},
106 {"att:rendered", PID_ATT_RENDERED, 0, VT_LPSTR},
107 {"att:sent-time", PID_ATT_SENTTIME, 0, VT_LPSTR},
108 {"att:priority", PID_ATT_PRIORITY, 0, VT_LPSTR},
109 {"Comment", PID_HDR_COMMENT, 0, VT_LPSTR},
110 {"Encoding", PID_HDR_ENCODING, 0, VT_LPSTR},
111 {"Encrypted", PID_HDR_ENCRYPTED, 0, VT_LPSTR},
112 {"X-Offsets", PID_HDR_OFFSETS, 0, VT_LPSTR},
113 {"X-Unsent", PID_HDR_XUNSENT, 0, VT_LPSTR},
114 {"X-ArticleId", PID_HDR_ARTICLEID, 0, VT_LPSTR},
115 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
116 {"att:athena-server", PID_ATT_SERVER, 0, VT_LPSTR},
117 {"att:athena-account-id", PID_ATT_ACCOUNT, 0, VT_LPSTR},
118 {"att:athena-pop3-uidl", PID_ATT_UIDL, 0, VT_LPSTR},
119 {"att:athena-store-msgid", PID_ATT_STOREMSGID, 0, VT_LPSTR},
120 {"att:athena-user-name", PID_ATT_USERNAME, 0, VT_LPSTR},
121 {"att:athena-forward-to", PID_ATT_FORWARDTO, 0, VT_LPSTR},
122 {"att:athena-store-fdrid", PID_ATT_STOREFOLDERID,0, VT_LPSTR},
123 {"att:athena-ghosted", PID_ATT_GHOSTED, 0, VT_LPSTR},
124 {"att:athena-uncachedsize", PID_ATT_UNCACHEDSIZE, 0, VT_LPSTR},
125 {"att:athena-combined", PID_ATT_COMBINED, 0, VT_LPSTR},
126 {"att:auto-inlined", PID_ATT_AUTOINLINED, 0, VT_LPSTR},
127 {"Disposition-Notification-To", PID_HDR_DISP_NOTIFICATION_TO, 0, VT_LPSTR},
128 {"par:Content-Type:reply-type", PID_PAR_REPLYTYPE, 0, VT_LPSTR},
129 {"par:Content-Type:format", PID_PAR_FORMAT , 0, VT_LPSTR},
130 {"att:format", PID_ATT_FORMAT , 0, VT_LPSTR},
131 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
132 {"att:athena-account-name", PID_ATT_ACCOUNTNAME, 0, VT_LPSTR},
133 {NULL, 0, 0, 0}
136 typedef struct
138 struct list entry;
139 char *name;
140 char *value;
141 } param_t;
143 typedef struct
145 struct list entry;
146 const property_t *prop;
147 PROPVARIANT value;
148 struct list params;
149 } header_t;
151 typedef struct MimeBody
153 IMimeBody IMimeBody_iface;
154 LONG ref;
156 HBODY handle;
158 struct list headers;
159 struct list new_props; /* FIXME: This should be in a PropertySchema */
160 DWORD next_prop_id;
161 char *content_pri_type;
162 char *content_sub_type;
163 ENCODINGTYPE encoding;
164 void *data;
165 IID data_iid;
166 BODYOFFSETS body_offsets;
167 } MimeBody;
169 typedef struct
171 IStream IStream_iface;
172 LONG ref;
173 IStream *base;
174 ULARGE_INTEGER pos, start, length;
175 } sub_stream_t;
177 static inline sub_stream_t *impl_from_IStream(IStream *iface)
179 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
182 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
184 sub_stream_t *This = impl_from_IStream(iface);
186 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
187 *ppv = NULL;
189 if(IsEqualIID(riid, &IID_IUnknown) ||
190 IsEqualIID(riid, &IID_ISequentialStream) ||
191 IsEqualIID(riid, &IID_IStream))
193 IStream_AddRef(iface);
194 *ppv = iface;
195 return S_OK;
197 return E_NOINTERFACE;
200 static ULONG WINAPI sub_stream_AddRef(IStream *iface)
202 sub_stream_t *This = impl_from_IStream(iface);
203 LONG ref = InterlockedIncrement(&This->ref);
205 TRACE("(%p) ref=%ld\n", This, ref);
207 return ref;
210 static ULONG WINAPI sub_stream_Release(IStream *iface)
212 sub_stream_t *This = impl_from_IStream(iface);
213 LONG ref = InterlockedDecrement(&This->ref);
215 TRACE("(%p) ref=%ld\n", This, ref);
217 if(!ref)
219 IStream_Release(This->base);
220 free(This);
222 return ref;
225 static HRESULT WINAPI sub_stream_Read(
226 IStream* iface,
227 void *pv,
228 ULONG cb,
229 ULONG *pcbRead)
231 sub_stream_t *This = impl_from_IStream(iface);
232 HRESULT hr;
233 LARGE_INTEGER tmp_pos;
235 TRACE("(%p, %ld, %p)\n", pv, cb, pcbRead);
237 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
238 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
240 if(This->pos.QuadPart + cb > This->length.QuadPart)
241 cb = This->length.QuadPart - This->pos.QuadPart;
243 hr = IStream_Read(This->base, pv, cb, pcbRead);
245 This->pos.QuadPart += *pcbRead;
247 return hr;
250 static HRESULT WINAPI sub_stream_Write(
251 IStream* iface,
252 const void *pv,
253 ULONG cb,
254 ULONG *pcbWritten)
256 FIXME("stub\n");
257 return E_NOTIMPL;
260 static HRESULT WINAPI sub_stream_Seek(
261 IStream* iface,
262 LARGE_INTEGER dlibMove,
263 DWORD dwOrigin,
264 ULARGE_INTEGER *plibNewPosition)
266 sub_stream_t *This = impl_from_IStream(iface);
267 LARGE_INTEGER new_pos;
269 TRACE("(%08lx.%08lx, %lx, %p)\n", dlibMove.HighPart, dlibMove.LowPart, dwOrigin, plibNewPosition);
271 switch(dwOrigin)
273 case STREAM_SEEK_SET:
274 new_pos = dlibMove;
275 break;
276 case STREAM_SEEK_CUR:
277 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
278 break;
279 case STREAM_SEEK_END:
280 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
281 break;
282 default:
283 return STG_E_INVALIDFUNCTION;
286 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
287 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
289 This->pos.QuadPart = new_pos.QuadPart;
291 if(plibNewPosition) *plibNewPosition = This->pos;
292 return S_OK;
295 static HRESULT WINAPI sub_stream_SetSize(
296 IStream* iface,
297 ULARGE_INTEGER libNewSize)
299 FIXME("stub\n");
300 return E_NOTIMPL;
303 static HRESULT WINAPI sub_stream_CopyTo(
304 IStream* iface,
305 IStream *pstm,
306 ULARGE_INTEGER cb,
307 ULARGE_INTEGER *pcbRead,
308 ULARGE_INTEGER *pcbWritten)
310 HRESULT hr = S_OK;
311 BYTE tmpBuffer[128];
312 ULONG bytesRead, bytesWritten, copySize;
313 ULARGE_INTEGER totalBytesRead;
314 ULARGE_INTEGER totalBytesWritten;
316 TRACE("(%p)->(%p, %ld, %p, %p)\n", iface, pstm, cb.LowPart, pcbRead, pcbWritten);
318 totalBytesRead.QuadPart = 0;
319 totalBytesWritten.QuadPart = 0;
321 while ( cb.QuadPart > 0 )
323 if ( cb.QuadPart >= sizeof(tmpBuffer) )
324 copySize = sizeof(tmpBuffer);
325 else
326 copySize = cb.LowPart;
328 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
329 if (FAILED(hr)) break;
331 totalBytesRead.QuadPart += bytesRead;
333 if (bytesRead)
335 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
336 if (FAILED(hr)) break;
337 totalBytesWritten.QuadPart += bytesWritten;
340 if (bytesRead != copySize)
341 cb.QuadPart = 0;
342 else
343 cb.QuadPart -= bytesRead;
346 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
347 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
349 return hr;
352 static HRESULT WINAPI sub_stream_Commit(
353 IStream* iface,
354 DWORD grfCommitFlags)
356 FIXME("stub\n");
357 return E_NOTIMPL;
360 static HRESULT WINAPI sub_stream_Revert(
361 IStream* iface)
363 FIXME("stub\n");
364 return E_NOTIMPL;
367 static HRESULT WINAPI sub_stream_LockRegion(
368 IStream* iface,
369 ULARGE_INTEGER libOffset,
370 ULARGE_INTEGER cb,
371 DWORD dwLockType)
373 FIXME("stub\n");
374 return E_NOTIMPL;
377 static HRESULT WINAPI sub_stream_UnlockRegion(
378 IStream* iface,
379 ULARGE_INTEGER libOffset,
380 ULARGE_INTEGER cb,
381 DWORD dwLockType)
383 FIXME("stub\n");
384 return E_NOTIMPL;
387 static HRESULT WINAPI sub_stream_Stat(
388 IStream* iface,
389 STATSTG *pstatstg,
390 DWORD grfStatFlag)
392 sub_stream_t *This = impl_from_IStream(iface);
393 FIXME("(%p)->(%p, %08lx)\n", This, pstatstg, grfStatFlag);
394 memset(pstatstg, 0, sizeof(*pstatstg));
395 pstatstg->cbSize = This->length;
396 return S_OK;
399 static HRESULT WINAPI sub_stream_Clone(
400 IStream* iface,
401 IStream **ppstm)
403 FIXME("stub\n");
404 return E_NOTIMPL;
407 static struct IStreamVtbl sub_stream_vtbl =
409 sub_stream_QueryInterface,
410 sub_stream_AddRef,
411 sub_stream_Release,
412 sub_stream_Read,
413 sub_stream_Write,
414 sub_stream_Seek,
415 sub_stream_SetSize,
416 sub_stream_CopyTo,
417 sub_stream_Commit,
418 sub_stream_Revert,
419 sub_stream_LockRegion,
420 sub_stream_UnlockRegion,
421 sub_stream_Stat,
422 sub_stream_Clone
425 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
427 sub_stream_t *This;
429 *out = NULL;
430 This = malloc(sizeof(*This));
431 if(!This) return E_OUTOFMEMORY;
433 This->IStream_iface.lpVtbl = &sub_stream_vtbl;
434 This->ref = 1;
435 This->start = start;
436 This->length = length;
437 This->pos.QuadPart = 0;
438 IStream_AddRef(stream);
439 This->base = stream;
441 *out = &This->IStream_iface;
442 return S_OK;
445 static HRESULT get_stream_size(IStream *stream, ULARGE_INTEGER *size)
447 STATSTG statstg = {NULL};
448 LARGE_INTEGER zero;
449 HRESULT hres;
451 hres = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
452 if(SUCCEEDED(hres)) {
453 *size = statstg.cbSize;
454 return S_OK;
457 zero.QuadPart = 0;
458 return IStream_Seek(stream, zero, STREAM_SEEK_END, size);
461 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
463 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
466 typedef struct propschema
468 IMimePropertySchema IMimePropertySchema_iface;
469 LONG ref;
470 } propschema;
472 static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
474 return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
477 #define PARSER_BUF_SIZE 1024
479 /*****************************************************
480 * copy_headers_to_buf [internal]
482 * Copies the headers into a '\0' terminated memory block and leave
483 * the stream's current position set to after the blank line.
485 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
487 char *buf = NULL, *new_buf;
488 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
489 HRESULT hr;
490 BOOL done = FALSE;
492 *ptr = NULL;
496 char *end;
497 DWORD read;
499 if(buf) size *= 2;
500 new_buf = realloc(buf, size + 1);
501 if(!new_buf)
503 hr = E_OUTOFMEMORY;
504 goto fail;
506 buf = new_buf;
508 hr = IStream_Read(stm, buf + offset, size - offset, &read);
509 if(FAILED(hr)) goto fail;
511 offset += read;
512 buf[offset] = '\0';
514 if(read == 0) done = TRUE;
516 while(!done && (end = strstr(buf + last_end, "\r\n")))
518 DWORD new_end = end - buf + 2;
519 if(new_end - last_end == 2)
521 LARGE_INTEGER off;
522 off.QuadPart = (LONGLONG)new_end - offset;
523 IStream_Seek(stm, off, STREAM_SEEK_CUR, NULL);
524 buf[new_end] = '\0';
525 done = TRUE;
527 else
528 last_end = new_end;
530 } while(!done);
532 *ptr = buf;
533 return S_OK;
535 fail:
536 free(buf);
537 return hr;
540 static header_t *read_prop(MimeBody *body, char **ptr)
542 char *colon = strchr(*ptr, ':');
543 const property_t *prop;
544 header_t *ret;
546 if(!colon) return NULL;
548 *colon = '\0';
550 for(prop = default_props; prop->name; prop++)
552 if(!lstrcmpiA(*ptr, prop->name))
554 TRACE("%s: found match with default property id %ld\n", *ptr, prop->id);
555 break;
559 if(!prop->name)
561 property_list_entry_t *prop_entry;
562 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
564 if(!lstrcmpiA(*ptr, prop_entry->prop.name))
566 TRACE("%s: found match with already added new property id %ld\n", *ptr, prop_entry->prop.id);
567 prop = &prop_entry->prop;
568 break;
571 if(!prop->name)
573 prop_entry = malloc(sizeof(*prop_entry));
574 prop_entry->prop.name = strdup(*ptr);
575 prop_entry->prop.id = body->next_prop_id++;
576 prop_entry->prop.flags = 0;
577 prop_entry->prop.default_vt = VT_LPSTR;
578 list_add_tail(&body->new_props, &prop_entry->entry);
579 prop = &prop_entry->prop;
580 TRACE("%s: allocating new prop id %ld\n", *ptr, prop_entry->prop.id);
584 ret = malloc(sizeof(*ret));
585 ret->prop = prop;
586 PropVariantInit(&ret->value);
587 list_init(&ret->params);
588 *ptr = colon + 1;
590 return ret;
593 static void unfold_header(char *header, int len)
595 char *start = header, *cp = header;
597 do {
598 while(*cp == ' ' || *cp == '\t')
600 cp++;
601 len--;
603 if(cp != start)
604 memmove(start, cp, len + 1);
606 cp = strstr(start, "\r\n");
607 len -= (cp - start);
608 start = cp;
609 *start = ' ';
610 start++;
611 len--;
612 cp += 2;
613 } while(*cp == ' ' || *cp == '\t');
615 *(start - 1) = '\0';
618 static char *unquote_string(const char *str)
620 BOOL quoted = FALSE;
621 char *ret, *cp;
623 while(*str == ' ' || *str == '\t') str++;
625 if(*str == '"')
627 quoted = TRUE;
628 str++;
630 ret = strdup(str);
631 for(cp = ret; *cp; cp++)
633 if(*cp == '\\')
634 memmove(cp, cp + 1, strlen(cp + 1) + 1);
635 else if(*cp == '"')
637 if(!quoted)
639 WARN("quote in unquoted string\n");
641 else
643 *cp = '\0';
644 break;
648 return ret;
651 static void add_param(header_t *header, const char *p)
653 const char *key = p, *value, *cp = p;
654 param_t *param;
655 char *name;
657 TRACE("got param %s\n", p);
659 while (*key == ' ' || *key == '\t' ) key++;
661 cp = strchr(key, '=');
662 if(!cp)
664 WARN("malformed parameter - skipping\n");
665 return;
668 name = malloc(cp - key + 1);
669 memcpy(name, key, cp - key);
670 name[cp - key] = '\0';
672 value = cp + 1;
674 param = malloc(sizeof(*param));
675 param->name = name;
676 param->value = unquote_string(value);
677 list_add_tail(&header->params, &param->entry);
680 static void split_params(header_t *header, char *value)
682 char *cp = value, *start = value;
683 BOOL in_quotes = FALSE, done_value = FALSE;
685 while(*cp)
687 if(!in_quotes && *cp == ';')
689 *cp = '\0';
690 if(done_value) add_param(header, start);
691 done_value = TRUE;
692 start = cp + 1;
694 else if(*cp == '"')
695 in_quotes = !in_quotes;
696 cp++;
698 if(done_value) add_param(header, start);
701 static void read_value(header_t *header, char **cur)
703 char *end = *cur, *value;
704 DWORD len;
706 do {
707 end = strstr(end, "\r\n");
708 end += 2;
709 } while(*end == ' ' || *end == '\t');
711 len = end - *cur;
712 value = CoTaskMemAlloc(len + 1);
713 memcpy(value, *cur, len);
714 value[len] = '\0';
716 unfold_header(value, len);
717 TRACE("value %s\n", debugstr_a(value));
719 if(header->prop->flags & MPF_HASPARAMS)
721 split_params(header, value);
722 TRACE("value w/o params %s\n", debugstr_a(value));
725 header->value.vt = VT_LPSTR;
726 header->value.pszVal = value;
728 *cur = end;
731 static void init_content_type(MimeBody *body, header_t *header)
733 char *slash;
734 DWORD len;
736 slash = strchr(header->value.pszVal, '/');
737 if(!slash)
739 WARN("malformed context type value\n");
740 return;
742 len = slash - header->value.pszVal;
743 body->content_pri_type = malloc(len + 1);
744 memcpy(body->content_pri_type, header->value.pszVal, len);
745 body->content_pri_type[len] = '\0';
746 body->content_sub_type = strdup(slash + 1);
749 static void init_content_encoding(MimeBody *body, header_t *header)
751 const char *encoding = header->value.pszVal;
753 if(!stricmp(encoding, "base64"))
754 body->encoding = IET_BASE64;
755 else if(!stricmp(encoding, "quoted-printable"))
756 body->encoding = IET_QP;
757 else if(!stricmp(encoding, "7bit"))
758 body->encoding = IET_7BIT;
759 else if(!stricmp(encoding, "8bit"))
760 body->encoding = IET_8BIT;
761 else
762 FIXME("unknown encoding %s\n", debugstr_a(encoding));
765 static HRESULT parse_headers(MimeBody *body, IStream *stm)
767 char *header_buf, *cur_header_ptr;
768 HRESULT hr;
769 header_t *header;
771 hr = copy_headers_to_buf(stm, &header_buf);
772 if(FAILED(hr)) return hr;
774 cur_header_ptr = header_buf;
775 while((header = read_prop(body, &cur_header_ptr)))
777 read_value(header, &cur_header_ptr);
778 list_add_tail(&body->headers, &header->entry);
780 switch(header->prop->id) {
781 case PID_HDR_CNTTYPE:
782 init_content_type(body, header);
783 break;
784 case PID_HDR_CNTXFER:
785 init_content_encoding(body, header);
786 break;
790 free(header_buf);
791 return hr;
794 static void empty_param_list(struct list *list)
796 param_t *param, *cursor2;
798 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
800 list_remove(&param->entry);
801 free(param->name);
802 free(param->value);
803 free(param);
807 static void free_header(header_t *header)
809 list_remove(&header->entry);
810 PropVariantClear(&header->value);
811 empty_param_list(&header->params);
812 free(header);
815 static void empty_header_list(struct list *list)
817 header_t *header, *cursor2;
819 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
821 free_header(header);
825 static void empty_new_prop_list(struct list *list)
827 property_list_entry_t *prop, *cursor2;
829 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
831 list_remove(&prop->entry);
832 free((char *)prop->prop.name);
833 free(prop);
837 static void release_data(REFIID riid, void *data)
839 if(!data) return;
841 if(IsEqualIID(riid, &IID_IStream))
842 IStream_Release((IStream *)data);
843 else
844 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
847 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
849 header_t *header;
851 *prop = NULL;
853 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
855 if(ISPIDSTR(name))
857 if(STRTOPID(name) == header->prop->id)
859 *prop = header;
860 return S_OK;
863 else if(!lstrcmpiA(name, header->prop->name))
865 *prop = header;
866 return S_OK;
870 return MIME_E_NOT_FOUND;
873 static const property_t *find_default_prop(const char *name)
875 const property_t *prop_def = NULL;
877 for(prop_def = default_props; prop_def->name; prop_def++)
879 if(ISPIDSTR(name))
881 if(STRTOPID(name) == prop_def->id)
883 break;
886 else if(!lstrcmpiA(name, prop_def->name))
888 break;
892 if(prop_def->id)
893 TRACE("%s: found match with default property id %ld\n", prop_def->name, prop_def->id);
894 else
895 prop_def = NULL;
897 return prop_def;
900 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
901 REFIID riid,
902 void** ppvObject)
904 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
906 *ppvObject = NULL;
908 if (IsEqualIID(riid, &IID_IUnknown) ||
909 IsEqualIID(riid, &IID_IPersist) ||
910 IsEqualIID(riid, &IID_IPersistStreamInit) ||
911 IsEqualIID(riid, &IID_IMimePropertySet) ||
912 IsEqualIID(riid, &IID_IMimeBody))
914 *ppvObject = iface;
917 if(*ppvObject)
919 IUnknown_AddRef((IUnknown*)*ppvObject);
920 return S_OK;
923 FIXME("no interface for %s\n", debugstr_guid(riid));
924 return E_NOINTERFACE;
927 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
929 MimeBody *This = impl_from_IMimeBody(iface);
930 LONG ref = InterlockedIncrement(&This->ref);
932 TRACE("(%p) ref=%ld\n", This, ref);
934 return ref;
937 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
939 MimeBody *This = impl_from_IMimeBody(iface);
940 LONG ref = InterlockedDecrement(&This->ref);
942 TRACE("(%p) ref=%ld\n", This, ref);
944 if (!ref)
946 empty_header_list(&This->headers);
947 empty_new_prop_list(&This->new_props);
949 free(This->content_pri_type);
950 free(This->content_sub_type);
952 release_data(&This->data_iid, This->data);
954 free(This);
957 return ref;
960 static HRESULT WINAPI MimeBody_GetClassID(
961 IMimeBody* iface,
962 CLSID* pClassID)
964 MimeBody *This = impl_from_IMimeBody(iface);
966 TRACE("(%p)->(%p)\n", This, pClassID);
968 if(!pClassID)
969 return E_INVALIDARG;
971 *pClassID = IID_IMimeBody;
972 return S_OK;
975 static HRESULT WINAPI MimeBody_IsDirty(
976 IMimeBody* iface)
978 MimeBody *This = impl_from_IMimeBody(iface);
979 FIXME("(%p)->() stub\n", This);
980 return E_NOTIMPL;
983 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
985 MimeBody *This = impl_from_IMimeBody(iface);
986 TRACE("(%p)->(%p)\n", This, pStm);
987 return parse_headers(This, pStm);
990 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
992 MimeBody *This = impl_from_IMimeBody(iface);
993 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
994 return E_NOTIMPL;
997 static HRESULT WINAPI MimeBody_GetSizeMax(
998 IMimeBody* iface,
999 ULARGE_INTEGER* pcbSize)
1001 MimeBody *This = impl_from_IMimeBody(iface);
1002 FIXME("(%p)->(%p) stub\n", This, pcbSize);
1003 return E_NOTIMPL;
1006 static HRESULT WINAPI MimeBody_InitNew(
1007 IMimeBody* iface)
1009 MimeBody *This = impl_from_IMimeBody(iface);
1010 TRACE("(%p)->()\n", This);
1011 return S_OK;
1014 static HRESULT WINAPI MimeBody_GetPropInfo(
1015 IMimeBody* iface,
1016 LPCSTR pszName,
1017 LPMIMEPROPINFO pInfo)
1019 MimeBody *This = impl_from_IMimeBody(iface);
1020 header_t *header;
1021 HRESULT hr;
1022 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1024 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1026 if(!pszName || !pInfo)
1027 return E_INVALIDARG;
1029 TRACE("mask 0x%04lx\n", pInfo->dwMask);
1031 if(pInfo->dwMask & ~supported)
1032 FIXME("Unsupported mask flags 0x%04lx\n", pInfo->dwMask & ~supported);
1034 hr = find_prop(This, pszName, &header);
1035 if(hr == S_OK)
1037 if(pInfo->dwMask & PIM_CHARSET)
1038 pInfo->hCharset = 0;
1039 if(pInfo->dwMask & PIM_FLAGS)
1040 pInfo->dwFlags = 0x00000000;
1041 if(pInfo->dwMask & PIM_ROWNUMBER)
1042 pInfo->dwRowNumber = 0;
1043 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1044 pInfo->ietEncoding = 0;
1045 if(pInfo->dwMask & PIM_VALUES)
1046 pInfo->cValues = 0;
1047 if(pInfo->dwMask & PIM_PROPID)
1048 pInfo->dwPropId = header->prop->id;
1049 if(pInfo->dwMask & PIM_VTDEFAULT)
1050 pInfo->vtDefault = header->prop->default_vt;
1051 if(pInfo->dwMask & PIM_VTCURRENT)
1052 pInfo->vtCurrent = 0;
1055 return hr;
1058 static HRESULT WINAPI MimeBody_SetPropInfo(
1059 IMimeBody* iface,
1060 LPCSTR pszName,
1061 LPCMIMEPROPINFO pInfo)
1063 MimeBody *This = impl_from_IMimeBody(iface);
1064 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1065 return E_NOTIMPL;
1068 static HRESULT WINAPI MimeBody_GetProp(
1069 IMimeBody* iface,
1070 LPCSTR pszName,
1071 DWORD dwFlags,
1072 LPPROPVARIANT pValue)
1074 MimeBody *This = impl_from_IMimeBody(iface);
1075 header_t *header;
1076 HRESULT hr;
1078 TRACE("(%p)->(%s, 0x%lx, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1080 if(!pszName || !pValue)
1081 return E_INVALIDARG;
1083 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1085 PropVariantClear(pValue);
1086 pValue->vt = VT_LPSTR;
1087 pValue->pszVal = CoTaskMemAlloc(strlen(This->content_pri_type) + 1);
1088 strcpy(pValue->pszVal, This->content_pri_type);
1089 return S_OK;
1092 hr = find_prop(This, pszName, &header);
1093 if(hr == S_OK)
1095 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1097 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1098 if(FAILED(hr))
1099 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1102 return hr;
1105 static HRESULT WINAPI MimeBody_SetProp(
1106 IMimeBody* iface,
1107 LPCSTR pszName,
1108 DWORD dwFlags,
1109 LPCPROPVARIANT pValue)
1111 MimeBody *This = impl_from_IMimeBody(iface);
1112 header_t *header;
1113 HRESULT hr;
1115 TRACE("(%p)->(%s, 0x%lx, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1117 if(!pszName || !pValue)
1118 return E_INVALIDARG;
1120 hr = find_prop(This, pszName, &header);
1121 if(hr != S_OK)
1123 property_list_entry_t *prop_entry;
1124 const property_t *prop = NULL;
1126 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1128 if(ISPIDSTR(pszName))
1130 if(STRTOPID(pszName) == prop_entry->prop.id)
1132 TRACE("Found match with already added new property id %ld\n", prop_entry->prop.id);
1133 prop = &prop_entry->prop;
1134 break;
1137 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1139 TRACE("Found match with already added new property id %ld\n", prop_entry->prop.id);
1140 prop = &prop_entry->prop;
1141 break;
1145 header = malloc(sizeof(*header));
1146 if(!header)
1147 return E_OUTOFMEMORY;
1149 if(!prop)
1151 const property_t *prop_def = NULL;
1152 prop_entry = malloc(sizeof(*prop_entry));
1153 if(!prop_entry)
1155 free(header);
1156 return E_OUTOFMEMORY;
1159 prop_def = find_default_prop(pszName);
1160 if(prop_def)
1162 prop_entry->prop.name = strdup(prop_def->name);
1163 prop_entry->prop.id = prop_def->id;
1165 else
1167 if(ISPIDSTR(pszName))
1169 free(prop_entry);
1170 free(header);
1171 return MIME_E_NOT_FOUND;
1174 prop_entry->prop.name = strdup(pszName);
1175 prop_entry->prop.id = This->next_prop_id++;
1178 prop_entry->prop.flags = 0;
1179 prop_entry->prop.default_vt = pValue->vt;
1180 list_add_tail(&This->new_props, &prop_entry->entry);
1181 prop = &prop_entry->prop;
1182 TRACE("Allocating new prop id %ld\n", prop_entry->prop.id);
1185 header->prop = prop;
1186 PropVariantInit(&header->value);
1187 list_init(&header->params);
1188 list_add_tail(&This->headers, &header->entry);
1191 PropVariantCopy(&header->value, pValue);
1193 return S_OK;
1196 static HRESULT WINAPI MimeBody_AppendProp(
1197 IMimeBody* iface,
1198 LPCSTR pszName,
1199 DWORD dwFlags,
1200 LPPROPVARIANT pValue)
1202 MimeBody *This = impl_from_IMimeBody(iface);
1203 FIXME("(%p)->(%s, 0x%lx, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1204 return E_NOTIMPL;
1207 static HRESULT WINAPI MimeBody_DeleteProp(
1208 IMimeBody* iface,
1209 LPCSTR pszName)
1211 MimeBody *This = impl_from_IMimeBody(iface);
1212 header_t *cursor;
1213 BOOL found;
1215 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1217 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1219 if(ISPIDSTR(pszName))
1220 found = STRTOPID(pszName) == cursor->prop->id;
1221 else
1222 found = !lstrcmpiA(pszName, cursor->prop->name);
1224 if(found)
1226 free_header(cursor);
1227 return S_OK;
1231 return MIME_E_NOT_FOUND;
1234 static HRESULT WINAPI MimeBody_CopyProps(
1235 IMimeBody* iface,
1236 ULONG cNames,
1237 LPCSTR* prgszName,
1238 IMimePropertySet* pPropertySet)
1240 MimeBody *This = impl_from_IMimeBody(iface);
1241 FIXME("(%p)->(%ld, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1242 return E_NOTIMPL;
1245 static HRESULT WINAPI MimeBody_MoveProps(
1246 IMimeBody* iface,
1247 ULONG cNames,
1248 LPCSTR* prgszName,
1249 IMimePropertySet* pPropertySet)
1251 MimeBody *This = impl_from_IMimeBody(iface);
1252 FIXME("(%p)->(%ld, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1253 return E_NOTIMPL;
1256 static HRESULT WINAPI MimeBody_DeleteExcept(
1257 IMimeBody* iface,
1258 ULONG cNames,
1259 LPCSTR* prgszName)
1261 MimeBody *This = impl_from_IMimeBody(iface);
1262 FIXME("(%p)->(%ld, %p) stub\n", This, cNames, prgszName);
1263 return E_NOTIMPL;
1266 static HRESULT WINAPI MimeBody_QueryProp(
1267 IMimeBody* iface,
1268 LPCSTR pszName,
1269 LPCSTR pszCriteria,
1270 boolean fSubString,
1271 boolean fCaseSensitive)
1273 MimeBody *This = impl_from_IMimeBody(iface);
1274 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1275 return E_NOTIMPL;
1278 static HRESULT WINAPI MimeBody_GetCharset(
1279 IMimeBody* iface,
1280 LPHCHARSET phCharset)
1282 MimeBody *This = impl_from_IMimeBody(iface);
1283 FIXME("(%p)->(%p) stub\n", This, phCharset);
1284 *phCharset = NULL;
1285 return S_OK;
1288 static HRESULT WINAPI MimeBody_SetCharset(
1289 IMimeBody* iface,
1290 HCHARSET hCharset,
1291 CSETAPPLYTYPE applytype)
1293 MimeBody *This = impl_from_IMimeBody(iface);
1294 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1295 return E_NOTIMPL;
1298 static HRESULT WINAPI MimeBody_GetParameters(
1299 IMimeBody* iface,
1300 LPCSTR pszName,
1301 ULONG* pcParams,
1302 LPMIMEPARAMINFO* pprgParam)
1304 MimeBody *This = impl_from_IMimeBody(iface);
1305 HRESULT hr;
1306 header_t *header;
1308 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1310 *pprgParam = NULL;
1311 *pcParams = 0;
1313 hr = find_prop(This, pszName, &header);
1314 if(hr != S_OK) return hr;
1316 *pcParams = list_count(&header->params);
1317 if(*pcParams)
1319 IMimeAllocator *alloc;
1320 param_t *param;
1321 MIMEPARAMINFO *info;
1323 MimeOleGetAllocator(&alloc);
1325 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1326 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1328 int len;
1330 len = strlen(param->name) + 1;
1331 info->pszName = IMimeAllocator_Alloc(alloc, len);
1332 memcpy(info->pszName, param->name, len);
1333 len = strlen(param->value) + 1;
1334 info->pszData = IMimeAllocator_Alloc(alloc, len);
1335 memcpy(info->pszData, param->value, len);
1336 info++;
1338 IMimeAllocator_Release(alloc);
1340 return S_OK;
1343 static HRESULT WINAPI MimeBody_IsContentType(
1344 IMimeBody* iface,
1345 LPCSTR pszPriType,
1346 LPCSTR pszSubType)
1348 MimeBody *This = impl_from_IMimeBody(iface);
1350 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1351 if(pszPriType)
1353 const char *pri = This->content_pri_type;
1354 if(!pri) pri = "text";
1355 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1358 if(pszSubType)
1360 const char *sub = This->content_sub_type;
1361 if(!sub) sub = "plain";
1362 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1365 return S_OK;
1368 static HRESULT WINAPI MimeBody_BindToObject(
1369 IMimeBody* iface,
1370 REFIID riid,
1371 void** ppvObject)
1373 MimeBody *This = impl_from_IMimeBody(iface);
1374 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1375 return E_NOTIMPL;
1378 static HRESULT WINAPI MimeBody_Clone(
1379 IMimeBody* iface,
1380 IMimePropertySet** ppPropertySet)
1382 MimeBody *This = impl_from_IMimeBody(iface);
1383 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1384 return E_NOTIMPL;
1387 static HRESULT WINAPI MimeBody_SetOption(
1388 IMimeBody* iface,
1389 const TYPEDID oid,
1390 LPCPROPVARIANT pValue)
1392 MimeBody *This = impl_from_IMimeBody(iface);
1393 HRESULT hr = E_NOTIMPL;
1394 TRACE("(%p)->(%08lx, %p)\n", This, oid, pValue);
1396 if(pValue->vt != TYPEDID_TYPE(oid))
1398 WARN("Called with vartype %04x and oid %08lx\n", pValue->vt, oid);
1399 return E_INVALIDARG;
1402 switch(oid)
1404 case OID_SECURITY_HWND_OWNER:
1405 FIXME("OID_SECURITY_HWND_OWNER (value %08lx): ignoring\n", pValue->ulVal);
1406 hr = S_OK;
1407 break;
1408 case OID_TRANSMIT_BODY_ENCODING:
1409 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08lx): ignoring\n", pValue->ulVal);
1410 hr = S_OK;
1411 break;
1412 default:
1413 FIXME("Unhandled oid %08lx\n", oid);
1416 return hr;
1419 static HRESULT WINAPI MimeBody_GetOption(
1420 IMimeBody* iface,
1421 const TYPEDID oid,
1422 LPPROPVARIANT pValue)
1424 MimeBody *This = impl_from_IMimeBody(iface);
1425 FIXME("(%p)->(%08lx, %p): stub\n", This, oid, pValue);
1426 return E_NOTIMPL;
1429 static HRESULT WINAPI MimeBody_EnumProps(
1430 IMimeBody* iface,
1431 DWORD dwFlags,
1432 IMimeEnumProperties** ppEnum)
1434 MimeBody *This = impl_from_IMimeBody(iface);
1435 FIXME("(%p)->(0x%lx, %p) stub\n", This, dwFlags, ppEnum);
1436 return E_NOTIMPL;
1439 static HRESULT WINAPI MimeBody_IsType(
1440 IMimeBody* iface,
1441 IMSGBODYTYPE bodytype)
1443 MimeBody *This = impl_from_IMimeBody(iface);
1445 TRACE("(%p)->(%d)\n", This, bodytype);
1446 switch(bodytype)
1448 case IBT_EMPTY:
1449 return This->data ? S_FALSE : S_OK;
1450 default:
1451 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1453 return S_OK;
1456 static HRESULT WINAPI MimeBody_SetDisplayName(
1457 IMimeBody* iface,
1458 LPCSTR pszDisplay)
1460 MimeBody *This = impl_from_IMimeBody(iface);
1461 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1462 return E_NOTIMPL;
1465 static HRESULT WINAPI MimeBody_GetDisplayName(
1466 IMimeBody* iface,
1467 LPSTR* ppszDisplay)
1469 MimeBody *This = impl_from_IMimeBody(iface);
1470 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1471 return E_NOTIMPL;
1474 static HRESULT WINAPI MimeBody_GetOffsets(
1475 IMimeBody* iface,
1476 LPBODYOFFSETS pOffsets)
1478 MimeBody *This = impl_from_IMimeBody(iface);
1479 TRACE("(%p)->(%p)\n", This, pOffsets);
1481 *pOffsets = This->body_offsets;
1483 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1484 return S_OK;
1487 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1488 IMimeBody* iface,
1489 ENCODINGTYPE* pietEncoding)
1491 MimeBody *This = impl_from_IMimeBody(iface);
1493 TRACE("(%p)->(%p)\n", This, pietEncoding);
1495 *pietEncoding = This->encoding;
1496 return S_OK;
1499 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1500 IMimeBody* iface,
1501 ENCODINGTYPE ietEncoding)
1503 MimeBody *This = impl_from_IMimeBody(iface);
1505 TRACE("(%p)->(%d)\n", This, ietEncoding);
1507 This->encoding = ietEncoding;
1508 return S_OK;
1511 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1512 IMimeBody* iface,
1513 ENCODINGTYPE ietEncoding,
1514 ULONG* pcbSize)
1516 MimeBody *This = impl_from_IMimeBody(iface);
1517 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1518 return E_NOTIMPL;
1521 static HRESULT WINAPI MimeBody_GetDataHere(
1522 IMimeBody* iface,
1523 ENCODINGTYPE ietEncoding,
1524 IStream* pStream)
1526 MimeBody *This = impl_from_IMimeBody(iface);
1527 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1528 return E_NOTIMPL;
1531 static const signed char base64_decode_table[] =
1533 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1534 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1535 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1536 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1537 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1538 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1539 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1540 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1543 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1545 const unsigned char *ptr, *end;
1546 unsigned char buf[1024];
1547 LARGE_INTEGER pos;
1548 unsigned char *ret;
1549 unsigned char in[4];
1550 IStream *output;
1551 DWORD size;
1552 int n = 0;
1553 HRESULT hres;
1555 pos.QuadPart = 0;
1556 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1557 if(FAILED(hres))
1558 return hres;
1560 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1561 if(FAILED(hres))
1562 return hres;
1564 while(1) {
1565 hres = IStream_Read(input, buf, sizeof(buf), &size);
1566 if(FAILED(hres) || !size)
1567 break;
1569 ptr = ret = buf;
1570 end = buf + size;
1572 while(1) {
1573 /* skip invalid chars */
1574 while(ptr < end && (*ptr >= ARRAY_SIZE(base64_decode_table)
1575 || base64_decode_table[*ptr] == -1))
1576 ptr++;
1577 if(ptr == end)
1578 break;
1580 in[n++] = base64_decode_table[*ptr++];
1581 switch(n) {
1582 case 2:
1583 *ret++ = in[0] << 2 | in[1] >> 4;
1584 continue;
1585 case 3:
1586 *ret++ = in[1] << 4 | in[2] >> 2;
1587 continue;
1588 case 4:
1589 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1590 n = 0;
1594 if(ret > buf) {
1595 hres = IStream_Write(output, buf, ret - buf, NULL);
1596 if(FAILED(hres))
1597 break;
1601 if(SUCCEEDED(hres))
1602 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1603 if(FAILED(hres)) {
1604 IStream_Release(output);
1605 return hres;
1608 *ret_stream = output;
1609 return S_OK;
1612 static int hex_digit(char c)
1614 if('0' <= c && c <= '9')
1615 return c - '0';
1616 if('A' <= c && c <= 'F')
1617 return c - 'A' + 10;
1618 if('a' <= c && c <= 'f')
1619 return c - 'a' + 10;
1620 return -1;
1623 static HRESULT decode_qp(IStream *input, IStream **ret_stream)
1625 const unsigned char *ptr, *end;
1626 unsigned char *ret, prev = 0;
1627 unsigned char buf[1024];
1628 LARGE_INTEGER pos;
1629 IStream *output;
1630 DWORD size;
1631 int n = -1;
1632 HRESULT hres;
1634 pos.QuadPart = 0;
1635 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1636 if(FAILED(hres))
1637 return hres;
1639 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1640 if(FAILED(hres))
1641 return hres;
1643 while(1) {
1644 hres = IStream_Read(input, buf, sizeof(buf), &size);
1645 if(FAILED(hres) || !size)
1646 break;
1648 ptr = ret = buf;
1649 end = buf + size;
1651 while(ptr < end) {
1652 unsigned char byte = *ptr++;
1654 switch(n) {
1655 case -1:
1656 if(byte == '=')
1657 n = 0;
1658 else
1659 *ret++ = byte;
1660 continue;
1661 case 0:
1662 prev = byte;
1663 n = 1;
1664 continue;
1665 case 1:
1666 if(prev != '\r' || byte != '\n') {
1667 int h1 = hex_digit(prev), h2 = hex_digit(byte);
1668 if(h1 != -1 && h2 != -1)
1669 *ret++ = (h1 << 4) | h2;
1670 else
1671 *ret++ = '=';
1673 n = -1;
1674 continue;
1678 if(ret > buf) {
1679 hres = IStream_Write(output, buf, ret - buf, NULL);
1680 if(FAILED(hres))
1681 break;
1685 if(SUCCEEDED(hres))
1686 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1687 if(FAILED(hres)) {
1688 IStream_Release(output);
1689 return hres;
1692 *ret_stream = output;
1693 return S_OK;
1696 static HRESULT WINAPI MimeBody_GetData(
1697 IMimeBody* iface,
1698 ENCODINGTYPE ietEncoding,
1699 IStream** ppStream)
1701 MimeBody *This = impl_from_IMimeBody(iface);
1702 ULARGE_INTEGER start, size;
1703 HRESULT hres;
1705 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1707 if(This->encoding != ietEncoding) {
1708 switch(This->encoding) {
1709 case IET_BASE64:
1710 hres = decode_base64(This->data, ppStream);
1711 break;
1712 case IET_QP:
1713 hres = decode_qp(This->data, ppStream);
1714 break;
1715 default:
1716 FIXME("Decoding %d is not supported.\n", This->encoding);
1717 hres = S_FALSE;
1719 if(ietEncoding != IET_BINARY)
1720 FIXME("Encoding %d is not supported.\n", ietEncoding);
1721 if(hres != S_FALSE)
1722 return hres;
1725 start.QuadPart = 0;
1726 hres = get_stream_size(This->data, &size);
1727 if(SUCCEEDED(hres))
1728 hres = create_sub_stream(This->data, start, size, ppStream);
1729 return hres;
1732 static HRESULT WINAPI MimeBody_SetData(
1733 IMimeBody* iface,
1734 ENCODINGTYPE ietEncoding,
1735 LPCSTR pszPriType,
1736 LPCSTR pszSubType,
1737 REFIID riid,
1738 LPVOID pvObject)
1740 MimeBody *This = impl_from_IMimeBody(iface);
1741 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1742 debugstr_guid(riid), pvObject);
1744 if(IsEqualIID(riid, &IID_IStream))
1745 IStream_AddRef((IStream *)pvObject);
1746 else
1748 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1749 return E_INVALIDARG;
1752 if(This->data)
1753 release_data(&This->data_iid, This->data);
1755 This->data_iid = *riid;
1756 This->data = pvObject;
1758 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1760 /* FIXME: Update the content type.
1761 If pszPriType == NULL use 'application'
1762 If pszSubType == NULL use 'octet-stream' */
1764 return S_OK;
1767 static HRESULT WINAPI MimeBody_EmptyData(
1768 IMimeBody* iface)
1770 MimeBody *This = impl_from_IMimeBody(iface);
1771 FIXME("(%p)->() stub\n", This);
1772 return E_NOTIMPL;
1775 static HRESULT WINAPI MimeBody_CopyTo(
1776 IMimeBody* iface,
1777 IMimeBody* pBody)
1779 MimeBody *This = impl_from_IMimeBody(iface);
1780 FIXME("(%p)->(%p) stub\n", This, pBody);
1781 return E_NOTIMPL;
1784 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1785 IMimeBody* iface,
1786 LPTRANSMITINFO pTransmitInfo)
1788 MimeBody *This = impl_from_IMimeBody(iface);
1789 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1790 return E_NOTIMPL;
1793 static HRESULT WINAPI MimeBody_SaveToFile(
1794 IMimeBody* iface,
1795 ENCODINGTYPE ietEncoding,
1796 LPCSTR pszFilePath)
1798 MimeBody *This = impl_from_IMimeBody(iface);
1799 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1800 return E_NOTIMPL;
1803 static HRESULT WINAPI MimeBody_GetHandle(
1804 IMimeBody* iface,
1805 LPHBODY phBody)
1807 MimeBody *This = impl_from_IMimeBody(iface);
1808 TRACE("(%p)->(%p)\n", iface, phBody);
1810 if(!phBody)
1811 return E_INVALIDARG;
1813 *phBody = This->handle;
1814 return This->handle ? S_OK : MIME_E_NO_DATA;
1817 static IMimeBodyVtbl body_vtbl =
1819 MimeBody_QueryInterface,
1820 MimeBody_AddRef,
1821 MimeBody_Release,
1822 MimeBody_GetClassID,
1823 MimeBody_IsDirty,
1824 MimeBody_Load,
1825 MimeBody_Save,
1826 MimeBody_GetSizeMax,
1827 MimeBody_InitNew,
1828 MimeBody_GetPropInfo,
1829 MimeBody_SetPropInfo,
1830 MimeBody_GetProp,
1831 MimeBody_SetProp,
1832 MimeBody_AppendProp,
1833 MimeBody_DeleteProp,
1834 MimeBody_CopyProps,
1835 MimeBody_MoveProps,
1836 MimeBody_DeleteExcept,
1837 MimeBody_QueryProp,
1838 MimeBody_GetCharset,
1839 MimeBody_SetCharset,
1840 MimeBody_GetParameters,
1841 MimeBody_IsContentType,
1842 MimeBody_BindToObject,
1843 MimeBody_Clone,
1844 MimeBody_SetOption,
1845 MimeBody_GetOption,
1846 MimeBody_EnumProps,
1847 MimeBody_IsType,
1848 MimeBody_SetDisplayName,
1849 MimeBody_GetDisplayName,
1850 MimeBody_GetOffsets,
1851 MimeBody_GetCurrentEncoding,
1852 MimeBody_SetCurrentEncoding,
1853 MimeBody_GetEstimatedSize,
1854 MimeBody_GetDataHere,
1855 MimeBody_GetData,
1856 MimeBody_SetData,
1857 MimeBody_EmptyData,
1858 MimeBody_CopyTo,
1859 MimeBody_GetTransmitInfo,
1860 MimeBody_SaveToFile,
1861 MimeBody_GetHandle
1864 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1866 TRACE("setting offsets to %ld, %ld, %ld, %ld\n", offsets->cbBoundaryStart,
1867 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1869 body->body_offsets = *offsets;
1870 return S_OK;
1873 #define FIRST_CUSTOM_PROP_ID 0x100
1875 static MimeBody *mimebody_create(void)
1877 MimeBody *This;
1878 BODYOFFSETS body_offsets;
1880 This = malloc(sizeof(*This));
1881 if (!This)
1882 return NULL;
1884 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1885 This->ref = 1;
1886 This->handle = NULL;
1887 list_init(&This->headers);
1888 list_init(&This->new_props);
1889 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1890 This->content_pri_type = NULL;
1891 This->content_sub_type = NULL;
1892 This->encoding = IET_7BIT;
1893 This->data = NULL;
1894 This->data_iid = IID_NULL;
1896 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1897 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1898 MimeBody_set_offsets(This, &body_offsets);
1900 return This;
1903 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1905 MimeBody *mb;
1907 if(outer)
1908 return CLASS_E_NOAGGREGATION;
1910 if ((mb = mimebody_create()))
1912 *ppv = &mb->IMimeBody_iface;
1913 return S_OK;
1915 else
1917 *ppv = NULL;
1918 return E_OUTOFMEMORY;
1922 typedef struct body_t
1924 struct list entry;
1925 DWORD index;
1926 MimeBody *mime_body;
1928 struct body_t *parent;
1929 struct list children;
1930 } body_t;
1932 typedef struct MimeMessage
1934 IMimeMessage IMimeMessage_iface;
1935 LONG ref;
1936 IStream *stream;
1938 struct list body_tree;
1939 DWORD next_index;
1940 } MimeMessage;
1942 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1944 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1947 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1949 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1951 if (IsEqualIID(riid, &IID_IUnknown) ||
1952 IsEqualIID(riid, &IID_IPersist) ||
1953 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1954 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1955 IsEqualIID(riid, &IID_IMimeMessage))
1957 *ppv = iface;
1958 IMimeMessage_AddRef(iface);
1959 return S_OK;
1962 FIXME("no interface for %s\n", debugstr_guid(riid));
1963 *ppv = NULL;
1964 return E_NOINTERFACE;
1967 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1969 MimeMessage *This = impl_from_IMimeMessage(iface);
1970 ULONG ref = InterlockedIncrement(&This->ref);
1972 TRACE("(%p) ref=%ld\n", This, ref);
1974 return ref;
1977 static void empty_body_list(struct list *list)
1979 body_t *body, *cursor2;
1980 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1982 empty_body_list(&body->children);
1983 list_remove(&body->entry);
1984 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1985 free(body);
1989 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1991 MimeMessage *This = impl_from_IMimeMessage(iface);
1992 ULONG ref = InterlockedDecrement(&This->ref);
1994 TRACE("(%p) ref=%ld\n", This, ref);
1996 if (!ref)
1998 empty_body_list(&This->body_tree);
2000 if(This->stream) IStream_Release(This->stream);
2001 free(This);
2004 return ref;
2007 /*** IPersist methods ***/
2008 static HRESULT WINAPI MimeMessage_GetClassID(
2009 IMimeMessage *iface,
2010 CLSID *pClassID)
2012 FIXME("(%p)->(%p)\n", iface, pClassID);
2013 return E_NOTIMPL;
2016 /*** IPersistStreamInit methods ***/
2017 static HRESULT WINAPI MimeMessage_IsDirty(
2018 IMimeMessage *iface)
2020 FIXME("(%p)->()\n", iface);
2021 return E_NOTIMPL;
2024 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
2026 body_t *body = malloc(sizeof(*body));
2027 if(body)
2029 body->mime_body = mime_body;
2030 body->index = index;
2031 list_init(&body->children);
2032 body->parent = parent;
2034 mime_body->handle = UlongToHandle(body->index);
2036 return body;
2039 typedef struct
2041 struct list entry;
2042 BODYOFFSETS offsets;
2043 } offset_entry_t;
2045 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
2047 HRESULT hr;
2048 DWORD read, boundary_start;
2049 int boundary_len = strlen(boundary);
2050 char *buf, *ptr, *overlap;
2051 DWORD start = 0, overlap_no;
2052 offset_entry_t *cur_body = NULL;
2053 BOOL is_first_line = TRUE;
2054 ULARGE_INTEGER cur;
2055 LARGE_INTEGER zero;
2057 list_init(body_offsets);
2059 overlap_no = boundary_len + 5;
2061 overlap = buf = malloc(overlap_no + PARSER_BUF_SIZE + 1);
2063 zero.QuadPart = 0;
2064 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
2065 start = cur.LowPart;
2067 do {
2068 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
2069 if(FAILED(hr)) goto end;
2070 if(read == 0) break;
2071 overlap[read] = '\0';
2073 ptr = buf;
2074 while(1) {
2075 if(is_first_line) {
2076 is_first_line = FALSE;
2077 }else {
2078 ptr = strstr(ptr, "\r\n");
2079 if(!ptr)
2080 break;
2081 ptr += 2;
2084 boundary_start = start + ptr - buf;
2086 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) {
2087 ptr += boundary_len + 2;
2089 if(*ptr == '\r' && *(ptr + 1) == '\n')
2091 ptr += 2;
2092 if(cur_body)
2094 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2095 list_add_tail(body_offsets, &cur_body->entry);
2097 cur_body = malloc(sizeof(*cur_body));
2098 cur_body->offsets.cbBoundaryStart = boundary_start;
2099 cur_body->offsets.cbHeaderStart = start + ptr - buf;
2101 else if(*ptr == '-' && *(ptr + 1) == '-')
2103 if(cur_body)
2105 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2106 list_add_tail(body_offsets, &cur_body->entry);
2107 goto end;
2113 if(overlap == buf) /* 1st iteration */
2115 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2116 overlap = buf + overlap_no;
2117 start += read - overlap_no;
2119 else
2121 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2122 start += read;
2124 } while(1);
2126 end:
2127 free(buf);
2128 return hr;
2131 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2133 ULARGE_INTEGER start, length;
2134 MimeBody *mime_body;
2135 HRESULT hr;
2136 body_t *body;
2137 LARGE_INTEGER pos;
2139 pos.QuadPart = offset->cbHeaderStart;
2140 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL);
2142 mime_body = mimebody_create();
2143 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2145 pos.QuadPart = 0;
2146 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start);
2147 offset->cbBodyStart = start.QuadPart;
2148 if (parent) MimeBody_set_offsets(mime_body, offset);
2150 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart;
2151 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data);
2152 mime_body->data_iid = IID_IStream;
2154 body = new_body_entry(mime_body, msg->next_index++, parent);
2156 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2158 MIMEPARAMINFO *param_info;
2159 ULONG count, i;
2160 IMimeAllocator *alloc;
2162 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2163 &param_info);
2164 if(hr != S_OK || count == 0) return body;
2166 MimeOleGetAllocator(&alloc);
2168 for(i = 0; i < count; i++)
2170 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2172 struct list offset_list;
2173 offset_entry_t *cur, *cursor2;
2174 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2175 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2177 body_t *sub_body;
2179 sub_body = create_sub_body(msg, pStm, &cur->offsets, body);
2180 list_add_tail(&body->children, &sub_body->entry);
2181 list_remove(&cur->entry);
2182 free(cur);
2184 break;
2187 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2188 IMimeAllocator_Release(alloc);
2190 return body;
2193 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2195 MimeMessage *This = impl_from_IMimeMessage(iface);
2196 body_t *root_body;
2197 BODYOFFSETS offsets;
2198 ULARGE_INTEGER cur;
2199 LARGE_INTEGER zero;
2201 TRACE("(%p)->(%p)\n", iface, pStm);
2203 if(This->stream)
2205 FIXME("already loaded a message\n");
2206 return E_FAIL;
2209 empty_body_list(&This->body_tree);
2211 IStream_AddRef(pStm);
2212 This->stream = pStm;
2213 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2214 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2216 root_body = create_sub_body(This, pStm, &offsets, NULL);
2218 zero.QuadPart = 0;
2219 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2220 offsets.cbBodyEnd = cur.LowPart;
2221 MimeBody_set_offsets(root_body->mime_body, &offsets);
2223 list_add_head(&This->body_tree, &root_body->entry);
2225 return S_OK;
2228 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2230 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2231 return E_NOTIMPL;
2234 static HRESULT WINAPI MimeMessage_GetSizeMax(
2235 IMimeMessage *iface,
2236 ULARGE_INTEGER *pcbSize)
2238 FIXME("(%p)->(%p)\n", iface, pcbSize);
2239 return E_NOTIMPL;
2242 static HRESULT WINAPI MimeMessage_InitNew(
2243 IMimeMessage *iface)
2245 FIXME("(%p)->()\n", iface);
2246 return E_NOTIMPL;
2249 /*** IMimeMessageTree methods ***/
2250 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2251 DWORD dwFlags)
2253 MimeMessage *This = impl_from_IMimeMessage(iface);
2255 FIXME("(%p)->(%p, 0x%lx)\n", iface, ppStream, dwFlags);
2257 IStream_AddRef(This->stream);
2258 *ppStream = This->stream;
2259 return S_OK;
2262 static HRESULT WINAPI MimeMessage_GetMessageSize(
2263 IMimeMessage *iface,
2264 ULONG *pcbSize,
2265 DWORD dwFlags)
2267 FIXME("(%p)->(%p, 0x%lx)\n", iface, pcbSize, dwFlags);
2268 return E_NOTIMPL;
2271 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2272 IMimeMessage *iface,
2273 IStream *pStream)
2275 FIXME("(%p)->(%p)\n", iface, pStream);
2276 return E_NOTIMPL;
2279 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2280 IMimeMessage *iface,
2281 IStream *pStream,
2282 DWORD dwFlags)
2284 FIXME("(%p)->(%p, 0x%lx)\n", iface, pStream, dwFlags);
2285 return E_NOTIMPL;
2289 static HRESULT WINAPI MimeMessage_GetFlags(
2290 IMimeMessage *iface,
2291 DWORD *pdwFlags)
2293 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2294 return E_NOTIMPL;
2297 static HRESULT WINAPI MimeMessage_Commit(
2298 IMimeMessage *iface,
2299 DWORD dwFlags)
2301 FIXME("(%p)->(0x%lx)\n", iface, dwFlags);
2302 return S_OK;
2306 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2307 IMimeMessage *iface)
2309 FIXME("(%p)->()\n", iface);
2310 return E_NOTIMPL;
2313 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2315 body_t *cur;
2316 HRESULT hr;
2318 if(hbody == HBODY_ROOT)
2320 *body = LIST_ENTRY(list_head(list), body_t, entry);
2321 return S_OK;
2324 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2326 if(cur->index == HandleToUlong(hbody))
2328 *body = cur;
2329 return S_OK;
2331 hr = find_body(&cur->children, hbody, body);
2332 if(hr == S_OK) return S_OK;
2334 return S_FALSE;
2337 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2338 void **ppvObject)
2340 MimeMessage *This = impl_from_IMimeMessage(iface);
2341 HRESULT hr;
2342 body_t *body;
2344 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2346 hr = find_body(&This->body_tree, hBody, &body);
2348 if(hr != S_OK) return hr;
2350 if(IsEqualIID(riid, &IID_IMimeBody))
2352 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2353 *ppvObject = &body->mime_body->IMimeBody_iface;
2354 return S_OK;
2357 return E_NOINTERFACE;
2360 static HRESULT WINAPI MimeMessage_SaveBody(
2361 IMimeMessage *iface,
2362 HBODY hBody,
2363 DWORD dwFlags,
2364 IStream *pStream)
2366 FIXME("(%p)->(%p, 0x%lx, %p)\n", iface, hBody, dwFlags, pStream);
2367 return E_NOTIMPL;
2370 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2372 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2373 body_t *body;
2374 HRESULT hr;
2375 struct list *list;
2377 if(location == IBL_ROOT)
2379 *out = root;
2380 return S_OK;
2383 hr = find_body(&msg->body_tree, pivot, &body);
2385 if(hr == S_OK)
2387 switch(location)
2389 case IBL_PARENT:
2390 if(body->parent)
2391 *out = body->parent;
2392 else
2393 hr = MIME_E_NOT_FOUND;
2394 break;
2396 case IBL_FIRST:
2397 list = list_head(&body->children);
2398 if(list)
2399 *out = LIST_ENTRY(list, body_t, entry);
2400 else
2401 hr = MIME_E_NOT_FOUND;
2402 break;
2404 case IBL_LAST:
2405 list = list_tail(&body->children);
2406 if(list)
2407 *out = LIST_ENTRY(list, body_t, entry);
2408 else
2409 hr = MIME_E_NOT_FOUND;
2410 break;
2412 case IBL_NEXT:
2413 list = list_next(&body->parent->children, &body->entry);
2414 if(list)
2415 *out = LIST_ENTRY(list, body_t, entry);
2416 else
2417 hr = MIME_E_NOT_FOUND;
2418 break;
2420 case IBL_PREVIOUS:
2421 list = list_prev(&body->parent->children, &body->entry);
2422 if(list)
2423 *out = LIST_ENTRY(list, body_t, entry);
2424 else
2425 hr = MIME_E_NOT_FOUND;
2426 break;
2428 default:
2429 hr = E_FAIL;
2430 break;
2434 return hr;
2438 static HRESULT WINAPI MimeMessage_InsertBody(
2439 IMimeMessage *iface,
2440 BODYLOCATION location,
2441 HBODY hPivot,
2442 LPHBODY phBody)
2444 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2445 return E_NOTIMPL;
2448 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2449 HBODY *phBody)
2451 MimeMessage *This = impl_from_IMimeMessage(iface);
2452 body_t *body;
2453 HRESULT hr;
2455 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2457 if(!phBody)
2458 return E_INVALIDARG;
2460 *phBody = NULL;
2462 hr = get_body(This, location, hPivot, &body);
2464 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2466 return hr;
2469 static HRESULT WINAPI MimeMessage_DeleteBody(
2470 IMimeMessage *iface,
2471 HBODY hBody,
2472 DWORD dwFlags)
2474 FIXME("(%p)->(%p, %08lx)\n", iface, hBody, dwFlags);
2475 return E_NOTIMPL;
2478 static HRESULT WINAPI MimeMessage_MoveBody(
2479 IMimeMessage *iface,
2480 HBODY hBody,
2481 BODYLOCATION location)
2483 FIXME("(%p)->(%d)\n", iface, location);
2484 return E_NOTIMPL;
2487 static void count_children(body_t *body, boolean recurse, ULONG *count)
2489 body_t *child;
2491 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2493 (*count)++;
2494 if(recurse) count_children(child, recurse, count);
2498 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2499 ULONG *pcBodies)
2501 HRESULT hr;
2502 MimeMessage *This = impl_from_IMimeMessage(iface);
2503 body_t *body;
2505 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2507 hr = find_body(&This->body_tree, hParent, &body);
2508 if(hr != S_OK) return hr;
2510 *pcBodies = 1;
2511 count_children(body, fRecurse, pcBodies);
2513 return S_OK;
2516 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2518 struct list *ptr;
2519 HBODY next;
2521 for (;;)
2523 if (!body) ptr = list_head( &This->body_tree );
2524 else
2526 ptr = list_head( &body->children );
2527 while (!ptr)
2529 if (!body->parent) return MIME_E_NOT_FOUND;
2530 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2534 body = LIST_ENTRY( ptr, body_t, entry );
2535 next = UlongToHandle( body->index );
2536 find->dwReserved = body->index;
2537 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2538 find->pszSubType) == S_OK)
2540 *out = next;
2541 return S_OK;
2544 return MIME_E_NOT_FOUND;
2547 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2549 MimeMessage *This = impl_from_IMimeMessage(iface);
2551 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2553 pFindBody->dwReserved = 0;
2554 return find_next(This, NULL, pFindBody, phBody);
2557 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2559 MimeMessage *This = impl_from_IMimeMessage(iface);
2560 body_t *body;
2561 HRESULT hr;
2563 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2565 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2566 if (hr != S_OK) return MIME_E_NOT_FOUND;
2567 return find_next(This, body, pFindBody, phBody);
2570 static HRESULT WINAPI MimeMessage_ResolveURL(
2571 IMimeMessage *iface,
2572 HBODY hRelated,
2573 LPCSTR pszBase,
2574 LPCSTR pszURL,
2575 DWORD dwFlags,
2576 LPHBODY phBody)
2578 FIXME("(%p)->(%p, %s, %s, 0x%lx, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2579 return E_NOTIMPL;
2582 static HRESULT WINAPI MimeMessage_ToMultipart(
2583 IMimeMessage *iface,
2584 HBODY hBody,
2585 LPCSTR pszSubType,
2586 LPHBODY phMultipart)
2588 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2589 return E_NOTIMPL;
2592 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2593 IMimeMessage *iface,
2594 HBODY hBody,
2595 LPBODYOFFSETS pOffsets)
2597 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2598 return E_NOTIMPL;
2601 static HRESULT WINAPI MimeMessage_GetCharset(
2602 IMimeMessage *iface,
2603 LPHCHARSET phCharset)
2605 FIXME("(%p)->(%p)\n", iface, phCharset);
2606 *phCharset = NULL;
2607 return S_OK;
2610 static HRESULT WINAPI MimeMessage_SetCharset(
2611 IMimeMessage *iface,
2612 HCHARSET hCharset,
2613 CSETAPPLYTYPE applytype)
2615 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2616 return E_NOTIMPL;
2619 static HRESULT WINAPI MimeMessage_IsBodyType(
2620 IMimeMessage *iface,
2621 HBODY hBody,
2622 IMSGBODYTYPE bodytype)
2624 HRESULT hr;
2625 IMimeBody *mime_body;
2626 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2628 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2629 if(hr != S_OK) return hr;
2631 hr = IMimeBody_IsType(mime_body, bodytype);
2632 MimeBody_Release(mime_body);
2633 return hr;
2636 static HRESULT WINAPI MimeMessage_IsContentType(
2637 IMimeMessage *iface,
2638 HBODY hBody,
2639 LPCSTR pszPriType,
2640 LPCSTR pszSubType)
2642 HRESULT hr;
2643 IMimeBody *mime_body;
2644 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2645 debugstr_a(pszSubType));
2647 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2648 if(FAILED(hr)) return hr;
2650 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2651 IMimeBody_Release(mime_body);
2652 return hr;
2655 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2656 IMimeMessage *iface,
2657 HBODY hBody,
2658 LPCSTR pszName,
2659 LPCSTR pszCriteria,
2660 boolean fSubString,
2661 boolean fCaseSensitive)
2663 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2664 return E_NOTIMPL;
2667 static HRESULT WINAPI MimeMessage_GetBodyProp(
2668 IMimeMessage *iface,
2669 HBODY hBody,
2670 LPCSTR pszName,
2671 DWORD dwFlags,
2672 LPPROPVARIANT pValue)
2674 HRESULT hr;
2675 IMimeBody *mime_body;
2677 TRACE("(%p)->(%p, %s, 0x%lx, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2679 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2680 if(hr != S_OK) return hr;
2682 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2683 IMimeBody_Release(mime_body);
2685 return hr;
2688 static HRESULT WINAPI MimeMessage_SetBodyProp(
2689 IMimeMessage *iface,
2690 HBODY hBody,
2691 LPCSTR pszName,
2692 DWORD dwFlags,
2693 LPCPROPVARIANT pValue)
2695 FIXME("(%p)->(%p, %s, 0x%lx, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2696 return E_NOTIMPL;
2699 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2700 IMimeMessage *iface,
2701 HBODY hBody,
2702 LPCSTR pszName)
2704 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2705 return E_NOTIMPL;
2708 static HRESULT WINAPI MimeMessage_SetOption(
2709 IMimeMessage *iface,
2710 const TYPEDID oid,
2711 LPCPROPVARIANT pValue)
2713 HRESULT hr = S_OK;
2714 TRACE("(%p)->(%08lx, %p)\n", iface, oid, pValue);
2716 /* Message ID is checked before type.
2717 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2719 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2721 WARN("oid (%08lx) out of range\n", oid);
2722 return MIME_E_INVALID_OPTION_ID;
2725 if(pValue->vt != TYPEDID_TYPE(oid))
2727 WARN("Called with vartype %04x and oid %08lx\n", pValue->vt, oid);
2728 return S_OK;
2731 switch(oid)
2733 case OID_HIDE_TNEF_ATTACHMENTS:
2734 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->boolVal);
2735 break;
2736 case OID_SHOW_MACBINARY:
2737 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->boolVal);
2738 break;
2739 case OID_SAVEBODY_KEEPBOUNDARY:
2740 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->boolVal);
2741 break;
2742 case OID_CLEANUP_TREE_ON_SAVE:
2743 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->boolVal);
2744 break;
2745 default:
2746 FIXME("Unhandled oid %08lx\n", oid);
2747 hr = MIME_E_INVALID_OPTION_ID;
2750 return hr;
2753 static HRESULT WINAPI MimeMessage_GetOption(
2754 IMimeMessage *iface,
2755 const TYPEDID oid,
2756 LPPROPVARIANT pValue)
2758 FIXME("(%p)->(%08lx, %p)\n", iface, oid, pValue);
2759 return E_NOTIMPL;
2762 /*** IMimeMessage methods ***/
2763 static HRESULT WINAPI MimeMessage_CreateWebPage(
2764 IMimeMessage *iface,
2765 IStream *pRootStm,
2766 LPWEBPAGEOPTIONS pOptions,
2767 IMimeMessageCallback *pCallback,
2768 IMoniker **ppMoniker)
2770 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2771 *ppMoniker = NULL;
2772 return E_NOTIMPL;
2775 static HRESULT WINAPI MimeMessage_GetProp(
2776 IMimeMessage *iface,
2777 LPCSTR pszName,
2778 DWORD dwFlags,
2779 LPPROPVARIANT pValue)
2781 FIXME("(%p)->(%s, 0x%lx, %p)\n", iface, pszName, dwFlags, pValue);
2782 return E_NOTIMPL;
2785 static HRESULT WINAPI MimeMessage_SetProp(
2786 IMimeMessage *iface,
2787 LPCSTR pszName,
2788 DWORD dwFlags,
2789 LPCPROPVARIANT pValue)
2791 FIXME("(%p)->(%s, 0x%lx, %p)\n", iface, pszName, dwFlags, pValue);
2792 return E_NOTIMPL;
2795 static HRESULT WINAPI MimeMessage_DeleteProp(
2796 IMimeMessage *iface,
2797 LPCSTR pszName)
2799 FIXME("(%p)->(%s)\n", iface, pszName);
2800 return E_NOTIMPL;
2803 static HRESULT WINAPI MimeMessage_QueryProp(
2804 IMimeMessage *iface,
2805 LPCSTR pszName,
2806 LPCSTR pszCriteria,
2807 boolean fSubString,
2808 boolean fCaseSensitive)
2810 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2811 return E_NOTIMPL;
2814 static HRESULT WINAPI MimeMessage_GetTextBody(
2815 IMimeMessage *iface,
2816 DWORD dwTxtType,
2817 ENCODINGTYPE ietEncoding,
2818 IStream **pStream,
2819 LPHBODY phBody)
2821 HRESULT hr;
2822 HBODY hbody;
2823 FINDBODY find_struct;
2824 IMimeBody *mime_body;
2825 static char text[] = "text";
2826 static char plain[] = "plain";
2827 static char html[] = "html";
2829 TRACE("(%p)->(%ld, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2831 find_struct.pszPriType = text;
2833 switch(dwTxtType)
2835 case TXT_PLAIN:
2836 find_struct.pszSubType = plain;
2837 break;
2838 case TXT_HTML:
2839 find_struct.pszSubType = html;
2840 break;
2841 default:
2842 return MIME_E_INVALID_TEXT_TYPE;
2845 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2846 if(hr != S_OK)
2848 TRACE("not found hr %08lx\n", hr);
2849 *phBody = NULL;
2850 return hr;
2853 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2855 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2856 *phBody = hbody;
2857 IMimeBody_Release(mime_body);
2858 return hr;
2861 static HRESULT WINAPI MimeMessage_SetTextBody(
2862 IMimeMessage *iface,
2863 DWORD dwTxtType,
2864 ENCODINGTYPE ietEncoding,
2865 HBODY hAlternative,
2866 IStream *pStream,
2867 LPHBODY phBody)
2869 FIXME("(%p)->(%ld, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2870 return E_NOTIMPL;
2873 static HRESULT WINAPI MimeMessage_AttachObject(
2874 IMimeMessage *iface,
2875 REFIID riid,
2876 void *pvObject,
2877 LPHBODY phBody)
2879 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2880 return E_NOTIMPL;
2883 static HRESULT WINAPI MimeMessage_AttachFile(
2884 IMimeMessage *iface,
2885 LPCSTR pszFilePath,
2886 IStream *pstmFile,
2887 LPHBODY phBody)
2889 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2890 return E_NOTIMPL;
2893 static HRESULT WINAPI MimeMessage_AttachURL(
2894 IMimeMessage *iface,
2895 LPCSTR pszBase,
2896 LPCSTR pszURL,
2897 DWORD dwFlags,
2898 IStream *pstmURL,
2899 LPSTR *ppszCIDURL,
2900 LPHBODY phBody)
2902 FIXME("(%p)->(%s, %s, 0x%lx, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2903 return E_NOTIMPL;
2906 static HRESULT WINAPI MimeMessage_GetAttachments(
2907 IMimeMessage *iface,
2908 ULONG *pcAttach,
2909 LPHBODY *pprghAttach)
2911 HRESULT hr;
2912 FINDBODY find_struct;
2913 HBODY hbody;
2914 LPHBODY array;
2915 ULONG size = 10;
2917 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2919 *pcAttach = 0;
2920 array = CoTaskMemAlloc(size * sizeof(HBODY));
2922 find_struct.pszPriType = find_struct.pszSubType = NULL;
2923 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2924 while(hr == S_OK)
2926 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2927 TRACE("IsCT rets %08lx %ld\n", hr, *pcAttach);
2928 if(hr != S_OK)
2930 if(*pcAttach + 1 > size)
2932 size *= 2;
2933 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2935 array[*pcAttach] = hbody;
2936 (*pcAttach)++;
2938 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2941 *pprghAttach = array;
2942 return S_OK;
2945 static HRESULT WINAPI MimeMessage_GetAddressTable(
2946 IMimeMessage *iface,
2947 IMimeAddressTable **ppTable)
2949 FIXME("(%p)->(%p)\n", iface, ppTable);
2950 return E_NOTIMPL;
2953 static HRESULT WINAPI MimeMessage_GetSender(
2954 IMimeMessage *iface,
2955 LPADDRESSPROPS pAddress)
2957 FIXME("(%p)->(%p)\n", iface, pAddress);
2958 return E_NOTIMPL;
2961 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2962 IMimeMessage *iface,
2963 DWORD dwAdrTypes,
2964 DWORD dwProps,
2965 LPADDRESSLIST pList)
2967 FIXME("(%p)->(%ld, %ld, %p)\n", iface, dwAdrTypes, dwProps, pList);
2968 return E_NOTIMPL;
2971 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2972 IMimeMessage *iface,
2973 DWORD dwAdrTypes,
2974 ADDRESSFORMAT format,
2975 LPSTR *ppszFormat)
2977 FIXME("(%p)->(%ld, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2978 return E_NOTIMPL;
2981 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2982 IMimeMessage *iface,
2983 DWORD dwAdrTypes,
2984 DWORD dwProps,
2985 IMimeEnumAddressTypes **ppEnum)
2987 FIXME("(%p)->(%ld, %ld, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2988 return E_NOTIMPL;
2991 static HRESULT WINAPI MimeMessage_SplitMessage(
2992 IMimeMessage *iface,
2993 ULONG cbMaxPart,
2994 IMimeMessageParts **ppParts)
2996 FIXME("(%p)->(%ld, %p)\n", iface, cbMaxPart, ppParts);
2997 return E_NOTIMPL;
3000 static HRESULT WINAPI MimeMessage_GetRootMoniker(
3001 IMimeMessage *iface,
3002 IMoniker **ppMoniker)
3004 FIXME("(%p)->(%p)\n", iface, ppMoniker);
3005 return E_NOTIMPL;
3008 static const IMimeMessageVtbl MimeMessageVtbl =
3010 MimeMessage_QueryInterface,
3011 MimeMessage_AddRef,
3012 MimeMessage_Release,
3013 MimeMessage_GetClassID,
3014 MimeMessage_IsDirty,
3015 MimeMessage_Load,
3016 MimeMessage_Save,
3017 MimeMessage_GetSizeMax,
3018 MimeMessage_InitNew,
3019 MimeMessage_GetMessageSource,
3020 MimeMessage_GetMessageSize,
3021 MimeMessage_LoadOffsetTable,
3022 MimeMessage_SaveOffsetTable,
3023 MimeMessage_GetFlags,
3024 MimeMessage_Commit,
3025 MimeMessage_HandsOffStorage,
3026 MimeMessage_BindToObject,
3027 MimeMessage_SaveBody,
3028 MimeMessage_InsertBody,
3029 MimeMessage_GetBody,
3030 MimeMessage_DeleteBody,
3031 MimeMessage_MoveBody,
3032 MimeMessage_CountBodies,
3033 MimeMessage_FindFirst,
3034 MimeMessage_FindNext,
3035 MimeMessage_ResolveURL,
3036 MimeMessage_ToMultipart,
3037 MimeMessage_GetBodyOffsets,
3038 MimeMessage_GetCharset,
3039 MimeMessage_SetCharset,
3040 MimeMessage_IsBodyType,
3041 MimeMessage_IsContentType,
3042 MimeMessage_QueryBodyProp,
3043 MimeMessage_GetBodyProp,
3044 MimeMessage_SetBodyProp,
3045 MimeMessage_DeleteBodyProp,
3046 MimeMessage_SetOption,
3047 MimeMessage_GetOption,
3048 MimeMessage_CreateWebPage,
3049 MimeMessage_GetProp,
3050 MimeMessage_SetProp,
3051 MimeMessage_DeleteProp,
3052 MimeMessage_QueryProp,
3053 MimeMessage_GetTextBody,
3054 MimeMessage_SetTextBody,
3055 MimeMessage_AttachObject,
3056 MimeMessage_AttachFile,
3057 MimeMessage_AttachURL,
3058 MimeMessage_GetAttachments,
3059 MimeMessage_GetAddressTable,
3060 MimeMessage_GetSender,
3061 MimeMessage_GetAddressTypes,
3062 MimeMessage_GetAddressFormat,
3063 MimeMessage_EnumAddressTypes,
3064 MimeMessage_SplitMessage,
3065 MimeMessage_GetRootMoniker,
3068 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
3070 MimeMessage *This;
3071 MimeBody *mime_body;
3072 body_t *root_body;
3074 TRACE("(%p, %p)\n", outer, obj);
3076 if (outer)
3078 FIXME("outer unknown not supported yet\n");
3079 return E_NOTIMPL;
3082 *obj = NULL;
3084 This = malloc(sizeof(*This));
3085 if (!This) return E_OUTOFMEMORY;
3087 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
3088 This->ref = 1;
3089 This->stream = NULL;
3090 list_init(&This->body_tree);
3091 This->next_index = 1;
3093 mime_body = mimebody_create();
3094 root_body = new_body_entry(mime_body, This->next_index++, NULL);
3095 list_add_head(&This->body_tree, &root_body->entry);
3097 *obj = &This->IMimeMessage_iface;
3098 return S_OK;
3101 /***********************************************************************
3102 * MimeOleCreateMessage (INETCOMM.@)
3104 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
3106 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3107 return MimeMessage_create(NULL, (void **)ppMessage);
3110 /***********************************************************************
3111 * MimeOleSetCompatMode (INETCOMM.@)
3113 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3115 FIXME("(0x%lx)\n", dwMode);
3116 return S_OK;
3119 /***********************************************************************
3120 * MimeOleCreateVirtualStream (INETCOMM.@)
3122 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3124 HRESULT hr;
3125 FIXME("(%p)\n", ppStream);
3127 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3128 return hr;
3131 typedef struct MimeSecurity
3133 IMimeSecurity IMimeSecurity_iface;
3134 LONG ref;
3135 } MimeSecurity;
3137 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3139 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3142 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3144 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3146 if (IsEqualIID(riid, &IID_IUnknown) ||
3147 IsEqualIID(riid, &IID_IMimeSecurity))
3149 *ppv = iface;
3150 IMimeSecurity_AddRef(iface);
3151 return S_OK;
3154 FIXME("no interface for %s\n", debugstr_guid(riid));
3155 *ppv = NULL;
3156 return E_NOINTERFACE;
3159 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3161 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3162 LONG ref = InterlockedIncrement(&This->ref);
3164 TRACE("(%p) ref=%ld\n", This, ref);
3166 return ref;
3169 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3171 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3172 LONG ref = InterlockedDecrement(&This->ref);
3174 TRACE("(%p) ref=%ld\n", This, ref);
3176 if (!ref)
3177 free(This);
3179 return ref;
3182 static HRESULT WINAPI MimeSecurity_InitNew(
3183 IMimeSecurity* iface)
3185 FIXME("(%p)->(): stub\n", iface);
3186 return S_OK;
3189 static HRESULT WINAPI MimeSecurity_CheckInit(
3190 IMimeSecurity* iface)
3192 FIXME("(%p)->(): stub\n", iface);
3193 return E_NOTIMPL;
3196 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3197 IMimeSecurity* iface,
3198 IMimeMessageTree* pTree,
3199 DWORD dwFlags)
3201 FIXME("(%p)->(%p, %08lx): stub\n", iface, pTree, dwFlags);
3202 return E_NOTIMPL;
3205 static HRESULT WINAPI MimeSecurity_EncodeBody(
3206 IMimeSecurity* iface,
3207 IMimeMessageTree* pTree,
3208 HBODY hEncodeRoot,
3209 DWORD dwFlags)
3211 FIXME("(%p)->(%p, %p, %08lx): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3212 return E_NOTIMPL;
3215 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3216 IMimeSecurity* iface,
3217 IMimeMessageTree* pTree,
3218 DWORD dwFlags)
3220 FIXME("(%p)->(%p, %08lx): stub\n", iface, pTree, dwFlags);
3221 return E_NOTIMPL;
3224 static HRESULT WINAPI MimeSecurity_DecodeBody(
3225 IMimeSecurity* iface,
3226 IMimeMessageTree* pTree,
3227 HBODY hDecodeRoot,
3228 DWORD dwFlags)
3230 FIXME("(%p)->(%p, %p, %08lx): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3231 return E_NOTIMPL;
3234 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3235 IMimeSecurity* iface,
3236 HCAPICERTSTORE hc,
3237 DWORD dwUsage,
3238 PCX509CERT pPrev,
3239 PCX509CERT* ppCert)
3241 FIXME("(%p)->(%p, %08lx, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3242 return E_NOTIMPL;
3245 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3246 IMimeSecurity* iface,
3247 const PCX509CERT pX509Cert,
3248 const CERTNAMETYPE cn,
3249 LPSTR* ppszName)
3251 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3252 return E_NOTIMPL;
3255 static HRESULT WINAPI MimeSecurity_GetMessageType(
3256 IMimeSecurity* iface,
3257 const HWND hwndParent,
3258 IMimeBody* pBody,
3259 DWORD* pdwSecType)
3261 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3262 return E_NOTIMPL;
3265 static HRESULT WINAPI MimeSecurity_GetCertData(
3266 IMimeSecurity* iface,
3267 const PCX509CERT pX509Cert,
3268 const CERTDATAID dataid,
3269 LPPROPVARIANT pValue)
3271 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3272 return E_NOTIMPL;
3276 static const IMimeSecurityVtbl MimeSecurityVtbl =
3278 MimeSecurity_QueryInterface,
3279 MimeSecurity_AddRef,
3280 MimeSecurity_Release,
3281 MimeSecurity_InitNew,
3282 MimeSecurity_CheckInit,
3283 MimeSecurity_EncodeMessage,
3284 MimeSecurity_EncodeBody,
3285 MimeSecurity_DecodeMessage,
3286 MimeSecurity_DecodeBody,
3287 MimeSecurity_EnumCertificates,
3288 MimeSecurity_GetCertificateName,
3289 MimeSecurity_GetMessageType,
3290 MimeSecurity_GetCertData
3293 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3295 MimeSecurity *This;
3297 *obj = NULL;
3299 if (outer) return CLASS_E_NOAGGREGATION;
3301 This = malloc(sizeof(*This));
3302 if (!This) return E_OUTOFMEMORY;
3304 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3305 This->ref = 1;
3307 *obj = &This->IMimeSecurity_iface;
3308 return S_OK;
3311 /***********************************************************************
3312 * MimeOleCreateSecurity (INETCOMM.@)
3314 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3316 return MimeSecurity_create(NULL, (void **)ppSecurity);
3319 static HRESULT WINAPI MimeAlloc_QueryInterface(
3320 IMimeAllocator* iface,
3321 REFIID riid,
3322 void **obj)
3324 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3326 if (IsEqualIID(riid, &IID_IUnknown) ||
3327 IsEqualIID(riid, &IID_IMalloc) ||
3328 IsEqualIID(riid, &IID_IMimeAllocator))
3330 *obj = iface;
3331 IMimeAllocator_AddRef(iface);
3332 return S_OK;
3335 FIXME("no interface for %s\n", debugstr_guid(riid));
3336 *obj = NULL;
3337 return E_NOINTERFACE;
3340 static ULONG WINAPI MimeAlloc_AddRef(
3341 IMimeAllocator* iface)
3343 return 2;
3346 static ULONG WINAPI MimeAlloc_Release(
3347 IMimeAllocator* iface)
3349 return 1;
3352 static LPVOID WINAPI MimeAlloc_Alloc(
3353 IMimeAllocator* iface,
3354 SIZE_T cb)
3356 return CoTaskMemAlloc(cb);
3359 static LPVOID WINAPI MimeAlloc_Realloc(
3360 IMimeAllocator* iface,
3361 LPVOID pv,
3362 SIZE_T cb)
3364 return CoTaskMemRealloc(pv, cb);
3367 static void WINAPI MimeAlloc_Free(
3368 IMimeAllocator* iface,
3369 LPVOID pv)
3371 CoTaskMemFree(pv);
3374 static SIZE_T WINAPI MimeAlloc_GetSize(
3375 IMimeAllocator* iface,
3376 LPVOID pv)
3378 FIXME("stub\n");
3379 return 0;
3382 static int WINAPI MimeAlloc_DidAlloc(
3383 IMimeAllocator* iface,
3384 LPVOID pv)
3386 FIXME("stub\n");
3387 return 0;
3390 static void WINAPI MimeAlloc_HeapMinimize(
3391 IMimeAllocator* iface)
3393 FIXME("stub\n");
3394 return;
3397 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3398 IMimeAllocator* iface,
3399 ULONG cParams,
3400 LPMIMEPARAMINFO prgParam,
3401 boolean fFreeArray)
3403 ULONG i;
3404 TRACE("(%p)->(%ld, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3406 for(i = 0; i < cParams; i++)
3408 IMimeAllocator_Free(iface, prgParam[i].pszName);
3409 IMimeAllocator_Free(iface, prgParam[i].pszData);
3411 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3412 return S_OK;
3415 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3416 IMimeAllocator* iface,
3417 LPADDRESSLIST pList)
3419 FIXME("stub\n");
3420 return E_NOTIMPL;
3423 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3424 IMimeAllocator* iface,
3425 LPADDRESSPROPS pAddress)
3427 FIXME("stub\n");
3428 return E_NOTIMPL;
3431 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3432 IMimeAllocator* iface,
3433 ULONG cObjects,
3434 IUnknown **prgpUnknown,
3435 boolean fFreeArray)
3437 FIXME("stub\n");
3438 return E_NOTIMPL;
3442 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3443 IMimeAllocator* iface,
3444 ULONG cRows,
3445 LPENUMHEADERROW prgRow,
3446 boolean fFreeArray)
3448 FIXME("stub\n");
3449 return E_NOTIMPL;
3452 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3453 IMimeAllocator* iface,
3454 ULONG cProps,
3455 LPENUMPROPERTY prgProp,
3456 boolean fFreeArray)
3458 FIXME("stub\n");
3459 return E_NOTIMPL;
3462 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3463 IMimeAllocator* iface,
3464 THUMBBLOB *pthumbprint)
3466 FIXME("stub\n");
3467 return E_NOTIMPL;
3471 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3472 IMimeAllocator* iface,
3473 LPPROPVARIANT pProp)
3475 FIXME("stub\n");
3476 return E_NOTIMPL;
3479 static IMimeAllocatorVtbl mime_alloc_vtbl =
3481 MimeAlloc_QueryInterface,
3482 MimeAlloc_AddRef,
3483 MimeAlloc_Release,
3484 MimeAlloc_Alloc,
3485 MimeAlloc_Realloc,
3486 MimeAlloc_Free,
3487 MimeAlloc_GetSize,
3488 MimeAlloc_DidAlloc,
3489 MimeAlloc_HeapMinimize,
3490 MimeAlloc_FreeParamInfoArray,
3491 MimeAlloc_FreeAddressList,
3492 MimeAlloc_FreeAddressProps,
3493 MimeAlloc_ReleaseObjects,
3494 MimeAlloc_FreeEnumHeaderRowArray,
3495 MimeAlloc_FreeEnumPropertyArray,
3496 MimeAlloc_FreeThumbprint,
3497 MimeAlloc_PropVariantClear
3500 static IMimeAllocator mime_allocator =
3502 &mime_alloc_vtbl
3505 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3507 if(outer) return CLASS_E_NOAGGREGATION;
3509 *obj = &mime_allocator;
3510 return S_OK;
3513 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3515 return MimeAllocator_create(NULL, (void**)alloc);
3518 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3520 FIXME("(%p, %p)\n", outer, obj);
3522 *obj = NULL;
3523 if (outer) return CLASS_E_NOAGGREGATION;
3525 return MimeOleCreateVirtualStream((IStream **)obj);
3528 /* IMimePropertySchema Interface */
3529 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3531 propschema *This = impl_from_IMimePropertySchema(iface);
3532 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3534 *out = NULL;
3536 if (IsEqualIID(riid, &IID_IUnknown) ||
3537 IsEqualIID(riid, &IID_IMimePropertySchema))
3539 *out = iface;
3541 else
3543 FIXME("no interface for %s\n", debugstr_guid(riid));
3544 return E_NOINTERFACE;
3547 IMimePropertySchema_AddRef(iface);
3548 return S_OK;
3551 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3553 propschema *This = impl_from_IMimePropertySchema(iface);
3554 LONG ref = InterlockedIncrement(&This->ref);
3556 TRACE("(%p) ref=%ld\n", This, ref);
3558 return ref;
3561 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3563 propschema *This = impl_from_IMimePropertySchema(iface);
3564 LONG ref = InterlockedDecrement(&This->ref);
3566 TRACE("(%p) ref=%ld\n", This, ref);
3568 if (!ref)
3570 free(This);
3573 return ref;
3576 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3577 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3579 propschema *This = impl_from_IMimePropertySchema(iface);
3580 FIXME("(%p)->(%s, %lx, %ld, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3581 return E_NOTIMPL;
3584 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3585 DWORD rownumber, VARTYPE vtdefault)
3587 propschema *This = impl_from_IMimePropertySchema(iface);
3588 FIXME("(%p)->(%s, %lx, %ld, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3589 return S_OK;
3592 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3594 propschema *This = impl_from_IMimePropertySchema(iface);
3595 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3596 return E_NOTIMPL;
3599 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3601 propschema *This = impl_from_IMimePropertySchema(iface);
3602 FIXME("(%p)->(%ld, %p) stub\n", This, propid, name);
3603 return E_NOTIMPL;
3606 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3608 propschema *This = impl_from_IMimePropertySchema(iface);
3609 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3610 return E_NOTIMPL;
3613 static IMimePropertySchemaVtbl prop_schema_vtbl =
3615 propschema_QueryInterface,
3616 propschema_AddRef,
3617 propschema_Release,
3618 propschema_RegisterProperty,
3619 propschema_ModifyProperty,
3620 propschema_GetPropertyId,
3621 propschema_GetPropertyName,
3622 propschema_RegisterAddressType
3626 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3628 propschema *This;
3630 TRACE("(%p) stub\n", schema);
3632 This = malloc(sizeof(*This));
3633 if (!This)
3634 return E_OUTOFMEMORY;
3636 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3637 This->ref = 1;
3639 *schema = &This->IMimePropertySchema_iface;
3641 return S_OK;
3644 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3645 ADDRESSFORMAT addr_format, WCHAR **address)
3647 FIXME("(%s, %p, %ld, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3649 return E_NOTIMPL;
3652 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
3654 FIXME("(%s %p)\n", debugstr_guid(riid), ppv);
3655 *ppv = NULL;
3656 return E_NOINTERFACE;
3659 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface)
3661 TRACE("\n");
3662 return 2;
3665 static ULONG WINAPI mime_obj_Release(IUnknown *iface)
3667 TRACE("\n");
3668 return 1;
3671 static const IUnknownVtbl mime_obj_vtbl = {
3672 mime_obj_QueryInterface,
3673 mime_obj_AddRef,
3674 mime_obj_Release
3677 static IUnknown mime_obj = { &mime_obj_vtbl };
3679 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3680 REFIID riid, void **out, IMoniker **moniker_new)
3682 WCHAR *display_name, *mhtml_url;
3683 size_t len;
3684 HRESULT hres;
3686 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3688 if(!IsEqualGUID(&IID_IUnknown, riid)) {
3689 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
3690 return E_NOINTERFACE;
3693 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name);
3694 if(FAILED(hres))
3695 return hres;
3697 TRACE("display name %s\n", debugstr_w(display_name));
3699 len = lstrlenW(display_name);
3700 mhtml_url = malloc(len * sizeof(WCHAR) + sizeof(L"mhtml:"));
3701 if(!mhtml_url)
3702 return E_OUTOFMEMORY;
3704 lstrcpyW(mhtml_url, L"mhtml:");
3705 lstrcatW(mhtml_url, display_name);
3706 CoTaskMemFree(display_name);
3708 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new);
3709 free(mhtml_url);
3710 if(FAILED(hres))
3711 return hres;
3713 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */
3714 *out = &mime_obj;
3715 return S_OK;