wineps.drv: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / inetcomm / mimeole.c
blobdd2c00b01fa6408dda605e9ef3f4824bdcfeaab1
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 "winternl.h"
31 #include "winuser.h"
32 #include "objbase.h"
33 #include "ole2.h"
34 #include "mimeole.h"
35 #include "propvarutil.h"
37 #include "wine/list.h"
38 #include "wine/debug.h"
40 #include "inetcomm_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
44 typedef struct
46 LPCSTR name;
47 DWORD id;
48 DWORD flags; /* MIMEPROPFLAGS */
49 VARTYPE default_vt;
50 } property_t;
52 typedef struct
54 struct list entry;
55 property_t prop;
56 } property_list_entry_t;
58 static const property_t default_props[] =
60 {"X-Newsgroup", PID_HDR_NEWSGROUP, 0, VT_LPSTR},
61 {"Newsgroups", PID_HDR_NEWSGROUPS, 0, VT_LPSTR},
62 {"References", PID_HDR_REFS, 0, VT_LPSTR},
63 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
64 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
65 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
66 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
67 {"Rr", PID_HDR_RR, 0, VT_LPSTR},
68 {"Return-Receipt-To", PID_HDR_RETRCPTO, MPF_ADDRESS, VT_LPSTR},
69 {"Apparently-To", PID_HDR_APPARTO, MPF_ADDRESS, VT_LPSTR},
70 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
71 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
72 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
73 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
74 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
75 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
76 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
77 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
78 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
79 {"Content-Description", PID_HDR_CNTDESC, MPF_MIME, VT_LPSTR},
80 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
81 {"Content-Base", PID_HDR_CNTBASE, MPF_MIME, VT_LPSTR},
82 {"Content-Location", PID_HDR_CNTLOC, MPF_MIME, VT_LPSTR},
83 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
84 {"Path", PID_HDR_PATH, 0, VT_LPSTR},
85 {"Followup-To", PID_HDR_FOLLOWUPTO, 0, VT_LPSTR},
86 {"Expires", PID_HDR_EXPIRES, 0, VT_LPSTR},
87 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
88 {"Control", PID_HDR_CONTROL, 0, VT_LPSTR},
89 {"Distribution", PID_HDR_DISTRIB, 0, VT_LPSTR},
90 {"Keywords", PID_HDR_KEYWORDS, 0, VT_LPSTR},
91 {"Summary", PID_HDR_SUMMARY, 0, VT_LPSTR},
92 {"Approved", PID_HDR_APPROVED, 0, VT_LPSTR},
93 {"Lines", PID_HDR_LINES, 0, VT_LPSTR},
94 {"Xref", PID_HDR_XREF, 0, VT_LPSTR},
95 {"Organization", PID_HDR_ORG, 0, VT_LPSTR},
96 {"X-Newsreader", PID_HDR_XNEWSRDR, 0, VT_LPSTR},
97 {"X-Priority", PID_HDR_XPRI, 0, VT_LPSTR},
98 {"X-MSMail-Priority", PID_HDR_XMSPRI, 0, VT_LPSTR},
99 {"par:content-disposition:filename", PID_PAR_FILENAME, 0, VT_LPSTR},
100 {"par:content-type:boundary", PID_PAR_BOUNDARY, 0, VT_LPSTR},
101 {"par:content-type:charset", PID_PAR_CHARSET, 0, VT_LPSTR},
102 {"par:content-type:name", PID_PAR_NAME, 0, VT_LPSTR},
103 {"att:filename", PID_ATT_FILENAME, 0, VT_LPSTR},
104 {"att:pri-content-type", PID_ATT_PRITYPE, 0, VT_LPSTR},
105 {"att:sub-content-type", PID_ATT_SUBTYPE, 0, VT_LPSTR},
106 {"att:illegal-lines", PID_ATT_ILLEGAL, 0, VT_LPSTR},
107 {"att:rendered", PID_ATT_RENDERED, 0, VT_LPSTR},
108 {"att:sent-time", PID_ATT_SENTTIME, 0, VT_LPSTR},
109 {"att:priority", PID_ATT_PRIORITY, 0, VT_LPSTR},
110 {"Comment", PID_HDR_COMMENT, 0, VT_LPSTR},
111 {"Encoding", PID_HDR_ENCODING, 0, VT_LPSTR},
112 {"Encrypted", PID_HDR_ENCRYPTED, 0, VT_LPSTR},
113 {"X-Offsets", PID_HDR_OFFSETS, 0, VT_LPSTR},
114 {"X-Unsent", PID_HDR_XUNSENT, 0, VT_LPSTR},
115 {"X-ArticleId", PID_HDR_ARTICLEID, 0, VT_LPSTR},
116 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
117 {"att:athena-server", PID_ATT_SERVER, 0, VT_LPSTR},
118 {"att:athena-account-id", PID_ATT_ACCOUNT, 0, VT_LPSTR},
119 {"att:athena-pop3-uidl", PID_ATT_UIDL, 0, VT_LPSTR},
120 {"att:athena-store-msgid", PID_ATT_STOREMSGID, 0, VT_LPSTR},
121 {"att:athena-user-name", PID_ATT_USERNAME, 0, VT_LPSTR},
122 {"att:athena-forward-to", PID_ATT_FORWARDTO, 0, VT_LPSTR},
123 {"att:athena-store-fdrid", PID_ATT_STOREFOLDERID,0, VT_LPSTR},
124 {"att:athena-ghosted", PID_ATT_GHOSTED, 0, VT_LPSTR},
125 {"att:athena-uncachedsize", PID_ATT_UNCACHEDSIZE, 0, VT_LPSTR},
126 {"att:athena-combined", PID_ATT_COMBINED, 0, VT_LPSTR},
127 {"att:auto-inlined", PID_ATT_AUTOINLINED, 0, VT_LPSTR},
128 {"Disposition-Notification-To", PID_HDR_DISP_NOTIFICATION_TO, 0, VT_LPSTR},
129 {"par:Content-Type:reply-type", PID_PAR_REPLYTYPE, 0, VT_LPSTR},
130 {"par:Content-Type:format", PID_PAR_FORMAT , 0, VT_LPSTR},
131 {"att:format", PID_ATT_FORMAT , 0, VT_LPSTR},
132 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
133 {"att:athena-account-name", PID_ATT_ACCOUNTNAME, 0, VT_LPSTR},
134 {NULL, 0, 0, 0}
137 typedef struct
139 struct list entry;
140 char *name;
141 char *value;
142 } param_t;
144 typedef struct
146 struct list entry;
147 const property_t *prop;
148 PROPVARIANT value;
149 struct list params;
150 } header_t;
152 typedef struct MimeBody
154 IMimeBody IMimeBody_iface;
155 LONG ref;
157 HBODY handle;
159 struct list headers;
160 struct list new_props; /* FIXME: This should be in a PropertySchema */
161 DWORD next_prop_id;
162 char *content_pri_type;
163 char *content_sub_type;
164 ENCODINGTYPE encoding;
165 void *data;
166 IID data_iid;
167 BODYOFFSETS body_offsets;
168 } MimeBody;
170 typedef struct
172 IStream IStream_iface;
173 LONG ref;
174 IStream *base;
175 ULARGE_INTEGER pos, start, length;
176 } sub_stream_t;
178 static inline sub_stream_t *impl_from_IStream(IStream *iface)
180 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
183 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
185 sub_stream_t *This = impl_from_IStream(iface);
187 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
188 *ppv = NULL;
190 if(IsEqualIID(riid, &IID_IUnknown) ||
191 IsEqualIID(riid, &IID_ISequentialStream) ||
192 IsEqualIID(riid, &IID_IStream))
194 IStream_AddRef(iface);
195 *ppv = iface;
196 return S_OK;
198 return E_NOINTERFACE;
201 static ULONG WINAPI sub_stream_AddRef(IStream *iface)
203 sub_stream_t *This = impl_from_IStream(iface);
204 LONG ref = InterlockedIncrement(&This->ref);
206 TRACE("(%p) ref=%ld\n", This, ref);
208 return ref;
211 static ULONG WINAPI sub_stream_Release(IStream *iface)
213 sub_stream_t *This = impl_from_IStream(iface);
214 LONG ref = InterlockedDecrement(&This->ref);
216 TRACE("(%p) ref=%ld\n", This, ref);
218 if(!ref)
220 IStream_Release(This->base);
221 free(This);
223 return ref;
226 static HRESULT WINAPI sub_stream_Read(
227 IStream* iface,
228 void *pv,
229 ULONG cb,
230 ULONG *pcbRead)
232 sub_stream_t *This = impl_from_IStream(iface);
233 HRESULT hr;
234 LARGE_INTEGER tmp_pos;
236 TRACE("(%p, %ld, %p)\n", pv, cb, pcbRead);
238 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
239 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
241 if(This->pos.QuadPart + cb > This->length.QuadPart)
242 cb = This->length.QuadPart - This->pos.QuadPart;
244 hr = IStream_Read(This->base, pv, cb, pcbRead);
246 This->pos.QuadPart += *pcbRead;
248 return hr;
251 static HRESULT WINAPI sub_stream_Write(
252 IStream* iface,
253 const void *pv,
254 ULONG cb,
255 ULONG *pcbWritten)
257 FIXME("stub\n");
258 return E_NOTIMPL;
261 static HRESULT WINAPI sub_stream_Seek(
262 IStream* iface,
263 LARGE_INTEGER dlibMove,
264 DWORD dwOrigin,
265 ULARGE_INTEGER *plibNewPosition)
267 sub_stream_t *This = impl_from_IStream(iface);
268 LARGE_INTEGER new_pos;
270 TRACE("(%08lx.%08lx, %lx, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
272 switch(dwOrigin)
274 case STREAM_SEEK_SET:
275 new_pos = dlibMove;
276 break;
277 case STREAM_SEEK_CUR:
278 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
279 break;
280 case STREAM_SEEK_END:
281 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
282 break;
283 default:
284 return STG_E_INVALIDFUNCTION;
287 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
288 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
290 This->pos.QuadPart = new_pos.QuadPart;
292 if(plibNewPosition) *plibNewPosition = This->pos;
293 return S_OK;
296 static HRESULT WINAPI sub_stream_SetSize(
297 IStream* iface,
298 ULARGE_INTEGER libNewSize)
300 FIXME("stub\n");
301 return E_NOTIMPL;
304 static HRESULT WINAPI sub_stream_CopyTo(
305 IStream* iface,
306 IStream *pstm,
307 ULARGE_INTEGER cb,
308 ULARGE_INTEGER *pcbRead,
309 ULARGE_INTEGER *pcbWritten)
311 HRESULT hr = S_OK;
312 BYTE tmpBuffer[128];
313 ULONG bytesRead, bytesWritten, copySize;
314 ULARGE_INTEGER totalBytesRead;
315 ULARGE_INTEGER totalBytesWritten;
317 TRACE("(%p)->(%p, %ld, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
319 totalBytesRead.QuadPart = 0;
320 totalBytesWritten.QuadPart = 0;
322 while ( cb.QuadPart > 0 )
324 if ( cb.QuadPart >= sizeof(tmpBuffer) )
325 copySize = sizeof(tmpBuffer);
326 else
327 copySize = cb.u.LowPart;
329 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
330 if (FAILED(hr)) break;
332 totalBytesRead.QuadPart += bytesRead;
334 if (bytesRead)
336 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
337 if (FAILED(hr)) break;
338 totalBytesWritten.QuadPart += bytesWritten;
341 if (bytesRead != copySize)
342 cb.QuadPart = 0;
343 else
344 cb.QuadPart -= bytesRead;
347 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
348 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
350 return hr;
353 static HRESULT WINAPI sub_stream_Commit(
354 IStream* iface,
355 DWORD grfCommitFlags)
357 FIXME("stub\n");
358 return E_NOTIMPL;
361 static HRESULT WINAPI sub_stream_Revert(
362 IStream* iface)
364 FIXME("stub\n");
365 return E_NOTIMPL;
368 static HRESULT WINAPI sub_stream_LockRegion(
369 IStream* iface,
370 ULARGE_INTEGER libOffset,
371 ULARGE_INTEGER cb,
372 DWORD dwLockType)
374 FIXME("stub\n");
375 return E_NOTIMPL;
378 static HRESULT WINAPI sub_stream_UnlockRegion(
379 IStream* iface,
380 ULARGE_INTEGER libOffset,
381 ULARGE_INTEGER cb,
382 DWORD dwLockType)
384 FIXME("stub\n");
385 return E_NOTIMPL;
388 static HRESULT WINAPI sub_stream_Stat(
389 IStream* iface,
390 STATSTG *pstatstg,
391 DWORD grfStatFlag)
393 sub_stream_t *This = impl_from_IStream(iface);
394 FIXME("(%p)->(%p, %08lx)\n", This, pstatstg, grfStatFlag);
395 memset(pstatstg, 0, sizeof(*pstatstg));
396 pstatstg->cbSize = This->length;
397 return S_OK;
400 static HRESULT WINAPI sub_stream_Clone(
401 IStream* iface,
402 IStream **ppstm)
404 FIXME("stub\n");
405 return E_NOTIMPL;
408 static struct IStreamVtbl sub_stream_vtbl =
410 sub_stream_QueryInterface,
411 sub_stream_AddRef,
412 sub_stream_Release,
413 sub_stream_Read,
414 sub_stream_Write,
415 sub_stream_Seek,
416 sub_stream_SetSize,
417 sub_stream_CopyTo,
418 sub_stream_Commit,
419 sub_stream_Revert,
420 sub_stream_LockRegion,
421 sub_stream_UnlockRegion,
422 sub_stream_Stat,
423 sub_stream_Clone
426 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
428 sub_stream_t *This;
430 *out = NULL;
431 This = malloc(sizeof(*This));
432 if(!This) return E_OUTOFMEMORY;
434 This->IStream_iface.lpVtbl = &sub_stream_vtbl;
435 This->ref = 1;
436 This->start = start;
437 This->length = length;
438 This->pos.QuadPart = 0;
439 IStream_AddRef(stream);
440 This->base = stream;
442 *out = &This->IStream_iface;
443 return S_OK;
446 static HRESULT get_stream_size(IStream *stream, ULARGE_INTEGER *size)
448 STATSTG statstg = {NULL};
449 LARGE_INTEGER zero;
450 HRESULT hres;
452 hres = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
453 if(SUCCEEDED(hres)) {
454 *size = statstg.cbSize;
455 return S_OK;
458 zero.QuadPart = 0;
459 return IStream_Seek(stream, zero, STREAM_SEEK_END, size);
462 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
464 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
467 typedef struct propschema
469 IMimePropertySchema IMimePropertySchema_iface;
470 LONG ref;
471 } propschema;
473 static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
475 return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
478 #define PARSER_BUF_SIZE 1024
480 /*****************************************************
481 * copy_headers_to_buf [internal]
483 * Copies the headers into a '\0' terminated memory block and leave
484 * the stream's current position set to after the blank line.
486 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
488 char *buf = NULL, *new_buf;
489 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
490 HRESULT hr;
491 BOOL done = FALSE;
493 *ptr = NULL;
497 char *end;
498 DWORD read;
500 if(buf) size *= 2;
501 new_buf = realloc(buf, size + 1);
502 if(!new_buf)
504 hr = E_OUTOFMEMORY;
505 goto fail;
507 buf = new_buf;
509 hr = IStream_Read(stm, buf + offset, size - offset, &read);
510 if(FAILED(hr)) goto fail;
512 offset += read;
513 buf[offset] = '\0';
515 if(read == 0) done = TRUE;
517 while(!done && (end = strstr(buf + last_end, "\r\n")))
519 DWORD new_end = end - buf + 2;
520 if(new_end - last_end == 2)
522 LARGE_INTEGER off;
523 off.QuadPart = (LONGLONG)new_end - offset;
524 IStream_Seek(stm, off, STREAM_SEEK_CUR, NULL);
525 buf[new_end] = '\0';
526 done = TRUE;
528 else
529 last_end = new_end;
531 } while(!done);
533 *ptr = buf;
534 return S_OK;
536 fail:
537 free(buf);
538 return hr;
541 static header_t *read_prop(MimeBody *body, char **ptr)
543 char *colon = strchr(*ptr, ':');
544 const property_t *prop;
545 header_t *ret;
547 if(!colon) return NULL;
549 *colon = '\0';
551 for(prop = default_props; prop->name; prop++)
553 if(!lstrcmpiA(*ptr, prop->name))
555 TRACE("%s: found match with default property id %ld\n", *ptr, prop->id);
556 break;
560 if(!prop->name)
562 property_list_entry_t *prop_entry;
563 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
565 if(!lstrcmpiA(*ptr, prop_entry->prop.name))
567 TRACE("%s: found match with already added new property id %ld\n", *ptr, prop_entry->prop.id);
568 prop = &prop_entry->prop;
569 break;
572 if(!prop->name)
574 prop_entry = malloc(sizeof(*prop_entry));
575 prop_entry->prop.name = strdup(*ptr);
576 prop_entry->prop.id = body->next_prop_id++;
577 prop_entry->prop.flags = 0;
578 prop_entry->prop.default_vt = VT_LPSTR;
579 list_add_tail(&body->new_props, &prop_entry->entry);
580 prop = &prop_entry->prop;
581 TRACE("%s: allocating new prop id %ld\n", *ptr, prop_entry->prop.id);
585 ret = malloc(sizeof(*ret));
586 ret->prop = prop;
587 PropVariantInit(&ret->value);
588 list_init(&ret->params);
589 *ptr = colon + 1;
591 return ret;
594 static void unfold_header(char *header, int len)
596 char *start = header, *cp = header;
598 do {
599 while(*cp == ' ' || *cp == '\t')
601 cp++;
602 len--;
604 if(cp != start)
605 memmove(start, cp, len + 1);
607 cp = strstr(start, "\r\n");
608 len -= (cp - start);
609 start = cp;
610 *start = ' ';
611 start++;
612 len--;
613 cp += 2;
614 } while(*cp == ' ' || *cp == '\t');
616 *(start - 1) = '\0';
619 static char *unquote_string(const char *str)
621 BOOL quoted = FALSE;
622 char *ret, *cp;
624 while(*str == ' ' || *str == '\t') str++;
626 if(*str == '"')
628 quoted = TRUE;
629 str++;
631 ret = strdup(str);
632 for(cp = ret; *cp; cp++)
634 if(*cp == '\\')
635 memmove(cp, cp + 1, strlen(cp + 1) + 1);
636 else if(*cp == '"')
638 if(!quoted)
640 WARN("quote in unquoted string\n");
642 else
644 *cp = '\0';
645 break;
649 return ret;
652 static void add_param(header_t *header, const char *p)
654 const char *key = p, *value, *cp = p;
655 param_t *param;
656 char *name;
658 TRACE("got param %s\n", p);
660 while (*key == ' ' || *key == '\t' ) key++;
662 cp = strchr(key, '=');
663 if(!cp)
665 WARN("malformed parameter - skipping\n");
666 return;
669 name = malloc(cp - key + 1);
670 memcpy(name, key, cp - key);
671 name[cp - key] = '\0';
673 value = cp + 1;
675 param = malloc(sizeof(*param));
676 param->name = name;
677 param->value = unquote_string(value);
678 list_add_tail(&header->params, &param->entry);
681 static void split_params(header_t *header, char *value)
683 char *cp = value, *start = value;
684 BOOL in_quotes = FALSE, done_value = FALSE;
686 while(*cp)
688 if(!in_quotes && *cp == ';')
690 *cp = '\0';
691 if(done_value) add_param(header, start);
692 done_value = TRUE;
693 start = cp + 1;
695 else if(*cp == '"')
696 in_quotes = !in_quotes;
697 cp++;
699 if(done_value) add_param(header, start);
702 static void read_value(header_t *header, char **cur)
704 char *end = *cur, *value;
705 DWORD len;
707 do {
708 end = strstr(end, "\r\n");
709 end += 2;
710 } while(*end == ' ' || *end == '\t');
712 len = end - *cur;
713 value = CoTaskMemAlloc(len + 1);
714 memcpy(value, *cur, len);
715 value[len] = '\0';
717 unfold_header(value, len);
718 TRACE("value %s\n", debugstr_a(value));
720 if(header->prop->flags & MPF_HASPARAMS)
722 split_params(header, value);
723 TRACE("value w/o params %s\n", debugstr_a(value));
726 header->value.vt = VT_LPSTR;
727 header->value.pszVal = value;
729 *cur = end;
732 static void init_content_type(MimeBody *body, header_t *header)
734 char *slash;
735 DWORD len;
737 slash = strchr(header->value.pszVal, '/');
738 if(!slash)
740 WARN("malformed context type value\n");
741 return;
743 len = slash - header->value.pszVal;
744 body->content_pri_type = malloc(len + 1);
745 memcpy(body->content_pri_type, header->value.pszVal, len);
746 body->content_pri_type[len] = '\0';
747 body->content_sub_type = strdup(slash + 1);
750 static void init_content_encoding(MimeBody *body, header_t *header)
752 const char *encoding = header->value.pszVal;
754 if(!stricmp(encoding, "base64"))
755 body->encoding = IET_BASE64;
756 else if(!stricmp(encoding, "quoted-printable"))
757 body->encoding = IET_QP;
758 else if(!stricmp(encoding, "7bit"))
759 body->encoding = IET_7BIT;
760 else if(!stricmp(encoding, "8bit"))
761 body->encoding = IET_8BIT;
762 else
763 FIXME("unknown encoding %s\n", debugstr_a(encoding));
766 static HRESULT parse_headers(MimeBody *body, IStream *stm)
768 char *header_buf, *cur_header_ptr;
769 HRESULT hr;
770 header_t *header;
772 hr = copy_headers_to_buf(stm, &header_buf);
773 if(FAILED(hr)) return hr;
775 cur_header_ptr = header_buf;
776 while((header = read_prop(body, &cur_header_ptr)))
778 read_value(header, &cur_header_ptr);
779 list_add_tail(&body->headers, &header->entry);
781 switch(header->prop->id) {
782 case PID_HDR_CNTTYPE:
783 init_content_type(body, header);
784 break;
785 case PID_HDR_CNTXFER:
786 init_content_encoding(body, header);
787 break;
791 free(header_buf);
792 return hr;
795 static void empty_param_list(struct list *list)
797 param_t *param, *cursor2;
799 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
801 list_remove(&param->entry);
802 free(param->name);
803 free(param->value);
804 free(param);
808 static void free_header(header_t *header)
810 list_remove(&header->entry);
811 PropVariantClear(&header->value);
812 empty_param_list(&header->params);
813 free(header);
816 static void empty_header_list(struct list *list)
818 header_t *header, *cursor2;
820 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
822 free_header(header);
826 static void empty_new_prop_list(struct list *list)
828 property_list_entry_t *prop, *cursor2;
830 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
832 list_remove(&prop->entry);
833 free((char *)prop->prop.name);
834 free(prop);
838 static void release_data(REFIID riid, void *data)
840 if(!data) return;
842 if(IsEqualIID(riid, &IID_IStream))
843 IStream_Release((IStream *)data);
844 else
845 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
848 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
850 header_t *header;
852 *prop = NULL;
854 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
856 if(ISPIDSTR(name))
858 if(STRTOPID(name) == header->prop->id)
860 *prop = header;
861 return S_OK;
864 else if(!lstrcmpiA(name, header->prop->name))
866 *prop = header;
867 return S_OK;
871 return MIME_E_NOT_FOUND;
874 static const property_t *find_default_prop(const char *name)
876 const property_t *prop_def = NULL;
878 for(prop_def = default_props; prop_def->name; prop_def++)
880 if(ISPIDSTR(name))
882 if(STRTOPID(name) == prop_def->id)
884 break;
887 else if(!lstrcmpiA(name, prop_def->name))
889 break;
893 if(prop_def->id)
894 TRACE("%s: found match with default property id %ld\n", prop_def->name, prop_def->id);
895 else
896 prop_def = NULL;
898 return prop_def;
901 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
902 REFIID riid,
903 void** ppvObject)
905 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
907 *ppvObject = NULL;
909 if (IsEqualIID(riid, &IID_IUnknown) ||
910 IsEqualIID(riid, &IID_IPersist) ||
911 IsEqualIID(riid, &IID_IPersistStreamInit) ||
912 IsEqualIID(riid, &IID_IMimePropertySet) ||
913 IsEqualIID(riid, &IID_IMimeBody))
915 *ppvObject = iface;
918 if(*ppvObject)
920 IUnknown_AddRef((IUnknown*)*ppvObject);
921 return S_OK;
924 FIXME("no interface for %s\n", debugstr_guid(riid));
925 return E_NOINTERFACE;
928 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
930 MimeBody *This = impl_from_IMimeBody(iface);
931 LONG ref = InterlockedIncrement(&This->ref);
933 TRACE("(%p) ref=%ld\n", This, ref);
935 return ref;
938 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
940 MimeBody *This = impl_from_IMimeBody(iface);
941 LONG ref = InterlockedDecrement(&This->ref);
943 TRACE("(%p) ref=%ld\n", This, ref);
945 if (!ref)
947 empty_header_list(&This->headers);
948 empty_new_prop_list(&This->new_props);
950 free(This->content_pri_type);
951 free(This->content_sub_type);
953 release_data(&This->data_iid, This->data);
955 free(This);
958 return ref;
961 static HRESULT WINAPI MimeBody_GetClassID(
962 IMimeBody* iface,
963 CLSID* pClassID)
965 MimeBody *This = impl_from_IMimeBody(iface);
967 TRACE("(%p)->(%p)\n", This, pClassID);
969 if(!pClassID)
970 return E_INVALIDARG;
972 *pClassID = IID_IMimeBody;
973 return S_OK;
976 static HRESULT WINAPI MimeBody_IsDirty(
977 IMimeBody* iface)
979 MimeBody *This = impl_from_IMimeBody(iface);
980 FIXME("(%p)->() stub\n", This);
981 return E_NOTIMPL;
984 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
986 MimeBody *This = impl_from_IMimeBody(iface);
987 TRACE("(%p)->(%p)\n", This, pStm);
988 return parse_headers(This, pStm);
991 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
993 MimeBody *This = impl_from_IMimeBody(iface);
994 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
995 return E_NOTIMPL;
998 static HRESULT WINAPI MimeBody_GetSizeMax(
999 IMimeBody* iface,
1000 ULARGE_INTEGER* pcbSize)
1002 MimeBody *This = impl_from_IMimeBody(iface);
1003 FIXME("(%p)->(%p) stub\n", This, pcbSize);
1004 return E_NOTIMPL;
1007 static HRESULT WINAPI MimeBody_InitNew(
1008 IMimeBody* iface)
1010 MimeBody *This = impl_from_IMimeBody(iface);
1011 TRACE("(%p)->()\n", This);
1012 return S_OK;
1015 static HRESULT WINAPI MimeBody_GetPropInfo(
1016 IMimeBody* iface,
1017 LPCSTR pszName,
1018 LPMIMEPROPINFO pInfo)
1020 MimeBody *This = impl_from_IMimeBody(iface);
1021 header_t *header;
1022 HRESULT hr;
1023 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1025 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1027 if(!pszName || !pInfo)
1028 return E_INVALIDARG;
1030 TRACE("mask 0x%04lx\n", pInfo->dwMask);
1032 if(pInfo->dwMask & ~supported)
1033 FIXME("Unsupported mask flags 0x%04lx\n", pInfo->dwMask & ~supported);
1035 hr = find_prop(This, pszName, &header);
1036 if(hr == S_OK)
1038 if(pInfo->dwMask & PIM_CHARSET)
1039 pInfo->hCharset = 0;
1040 if(pInfo->dwMask & PIM_FLAGS)
1041 pInfo->dwFlags = 0x00000000;
1042 if(pInfo->dwMask & PIM_ROWNUMBER)
1043 pInfo->dwRowNumber = 0;
1044 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1045 pInfo->ietEncoding = 0;
1046 if(pInfo->dwMask & PIM_VALUES)
1047 pInfo->cValues = 0;
1048 if(pInfo->dwMask & PIM_PROPID)
1049 pInfo->dwPropId = header->prop->id;
1050 if(pInfo->dwMask & PIM_VTDEFAULT)
1051 pInfo->vtDefault = header->prop->default_vt;
1052 if(pInfo->dwMask & PIM_VTCURRENT)
1053 pInfo->vtCurrent = 0;
1056 return hr;
1059 static HRESULT WINAPI MimeBody_SetPropInfo(
1060 IMimeBody* iface,
1061 LPCSTR pszName,
1062 LPCMIMEPROPINFO pInfo)
1064 MimeBody *This = impl_from_IMimeBody(iface);
1065 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1066 return E_NOTIMPL;
1069 static HRESULT WINAPI MimeBody_GetProp(
1070 IMimeBody* iface,
1071 LPCSTR pszName,
1072 DWORD dwFlags,
1073 LPPROPVARIANT pValue)
1075 MimeBody *This = impl_from_IMimeBody(iface);
1076 header_t *header;
1077 HRESULT hr;
1079 TRACE("(%p)->(%s, 0x%lx, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1081 if(!pszName || !pValue)
1082 return E_INVALIDARG;
1084 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1086 PropVariantClear(pValue);
1087 pValue->vt = VT_LPSTR;
1088 pValue->pszVal = CoTaskMemAlloc(strlen(This->content_pri_type) + 1);
1089 strcpy(pValue->pszVal, This->content_pri_type);
1090 return S_OK;
1093 hr = find_prop(This, pszName, &header);
1094 if(hr == S_OK)
1096 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1098 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1099 if(FAILED(hr))
1100 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1103 return hr;
1106 static HRESULT WINAPI MimeBody_SetProp(
1107 IMimeBody* iface,
1108 LPCSTR pszName,
1109 DWORD dwFlags,
1110 LPCPROPVARIANT pValue)
1112 MimeBody *This = impl_from_IMimeBody(iface);
1113 header_t *header;
1114 HRESULT hr;
1116 TRACE("(%p)->(%s, 0x%lx, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1118 if(!pszName || !pValue)
1119 return E_INVALIDARG;
1121 hr = find_prop(This, pszName, &header);
1122 if(hr != S_OK)
1124 property_list_entry_t *prop_entry;
1125 const property_t *prop = NULL;
1127 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1129 if(ISPIDSTR(pszName))
1131 if(STRTOPID(pszName) == prop_entry->prop.id)
1133 TRACE("Found match with already added new property id %ld\n", prop_entry->prop.id);
1134 prop = &prop_entry->prop;
1135 break;
1138 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1140 TRACE("Found match with already added new property id %ld\n", prop_entry->prop.id);
1141 prop = &prop_entry->prop;
1142 break;
1146 header = malloc(sizeof(*header));
1147 if(!header)
1148 return E_OUTOFMEMORY;
1150 if(!prop)
1152 const property_t *prop_def = NULL;
1153 prop_entry = malloc(sizeof(*prop_entry));
1154 if(!prop_entry)
1156 free(header);
1157 return E_OUTOFMEMORY;
1160 prop_def = find_default_prop(pszName);
1161 if(prop_def)
1163 prop_entry->prop.name = strdup(prop_def->name);
1164 prop_entry->prop.id = prop_def->id;
1166 else
1168 if(ISPIDSTR(pszName))
1170 free(prop_entry);
1171 free(header);
1172 return MIME_E_NOT_FOUND;
1175 prop_entry->prop.name = strdup(pszName);
1176 prop_entry->prop.id = This->next_prop_id++;
1179 prop_entry->prop.flags = 0;
1180 prop_entry->prop.default_vt = pValue->vt;
1181 list_add_tail(&This->new_props, &prop_entry->entry);
1182 prop = &prop_entry->prop;
1183 TRACE("Allocating new prop id %ld\n", prop_entry->prop.id);
1186 header->prop = prop;
1187 PropVariantInit(&header->value);
1188 list_init(&header->params);
1189 list_add_tail(&This->headers, &header->entry);
1192 PropVariantCopy(&header->value, pValue);
1194 return S_OK;
1197 static HRESULT WINAPI MimeBody_AppendProp(
1198 IMimeBody* iface,
1199 LPCSTR pszName,
1200 DWORD dwFlags,
1201 LPPROPVARIANT pValue)
1203 MimeBody *This = impl_from_IMimeBody(iface);
1204 FIXME("(%p)->(%s, 0x%lx, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1205 return E_NOTIMPL;
1208 static HRESULT WINAPI MimeBody_DeleteProp(
1209 IMimeBody* iface,
1210 LPCSTR pszName)
1212 MimeBody *This = impl_from_IMimeBody(iface);
1213 header_t *cursor;
1214 BOOL found;
1216 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1218 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1220 if(ISPIDSTR(pszName))
1221 found = STRTOPID(pszName) == cursor->prop->id;
1222 else
1223 found = !lstrcmpiA(pszName, cursor->prop->name);
1225 if(found)
1227 free_header(cursor);
1228 return S_OK;
1232 return MIME_E_NOT_FOUND;
1235 static HRESULT WINAPI MimeBody_CopyProps(
1236 IMimeBody* iface,
1237 ULONG cNames,
1238 LPCSTR* prgszName,
1239 IMimePropertySet* pPropertySet)
1241 MimeBody *This = impl_from_IMimeBody(iface);
1242 FIXME("(%p)->(%ld, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1243 return E_NOTIMPL;
1246 static HRESULT WINAPI MimeBody_MoveProps(
1247 IMimeBody* iface,
1248 ULONG cNames,
1249 LPCSTR* prgszName,
1250 IMimePropertySet* pPropertySet)
1252 MimeBody *This = impl_from_IMimeBody(iface);
1253 FIXME("(%p)->(%ld, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1254 return E_NOTIMPL;
1257 static HRESULT WINAPI MimeBody_DeleteExcept(
1258 IMimeBody* iface,
1259 ULONG cNames,
1260 LPCSTR* prgszName)
1262 MimeBody *This = impl_from_IMimeBody(iface);
1263 FIXME("(%p)->(%ld, %p) stub\n", This, cNames, prgszName);
1264 return E_NOTIMPL;
1267 static HRESULT WINAPI MimeBody_QueryProp(
1268 IMimeBody* iface,
1269 LPCSTR pszName,
1270 LPCSTR pszCriteria,
1271 boolean fSubString,
1272 boolean fCaseSensitive)
1274 MimeBody *This = impl_from_IMimeBody(iface);
1275 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1276 return E_NOTIMPL;
1279 static HRESULT WINAPI MimeBody_GetCharset(
1280 IMimeBody* iface,
1281 LPHCHARSET phCharset)
1283 MimeBody *This = impl_from_IMimeBody(iface);
1284 FIXME("(%p)->(%p) stub\n", This, phCharset);
1285 *phCharset = NULL;
1286 return S_OK;
1289 static HRESULT WINAPI MimeBody_SetCharset(
1290 IMimeBody* iface,
1291 HCHARSET hCharset,
1292 CSETAPPLYTYPE applytype)
1294 MimeBody *This = impl_from_IMimeBody(iface);
1295 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1296 return E_NOTIMPL;
1299 static HRESULT WINAPI MimeBody_GetParameters(
1300 IMimeBody* iface,
1301 LPCSTR pszName,
1302 ULONG* pcParams,
1303 LPMIMEPARAMINFO* pprgParam)
1305 MimeBody *This = impl_from_IMimeBody(iface);
1306 HRESULT hr;
1307 header_t *header;
1309 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1311 *pprgParam = NULL;
1312 *pcParams = 0;
1314 hr = find_prop(This, pszName, &header);
1315 if(hr != S_OK) return hr;
1317 *pcParams = list_count(&header->params);
1318 if(*pcParams)
1320 IMimeAllocator *alloc;
1321 param_t *param;
1322 MIMEPARAMINFO *info;
1324 MimeOleGetAllocator(&alloc);
1326 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1327 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1329 int len;
1331 len = strlen(param->name) + 1;
1332 info->pszName = IMimeAllocator_Alloc(alloc, len);
1333 memcpy(info->pszName, param->name, len);
1334 len = strlen(param->value) + 1;
1335 info->pszData = IMimeAllocator_Alloc(alloc, len);
1336 memcpy(info->pszData, param->value, len);
1337 info++;
1339 IMimeAllocator_Release(alloc);
1341 return S_OK;
1344 static HRESULT WINAPI MimeBody_IsContentType(
1345 IMimeBody* iface,
1346 LPCSTR pszPriType,
1347 LPCSTR pszSubType)
1349 MimeBody *This = impl_from_IMimeBody(iface);
1351 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1352 if(pszPriType)
1354 const char *pri = This->content_pri_type;
1355 if(!pri) pri = "text";
1356 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1359 if(pszSubType)
1361 const char *sub = This->content_sub_type;
1362 if(!sub) sub = "plain";
1363 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1366 return S_OK;
1369 static HRESULT WINAPI MimeBody_BindToObject(
1370 IMimeBody* iface,
1371 REFIID riid,
1372 void** ppvObject)
1374 MimeBody *This = impl_from_IMimeBody(iface);
1375 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1376 return E_NOTIMPL;
1379 static HRESULT WINAPI MimeBody_Clone(
1380 IMimeBody* iface,
1381 IMimePropertySet** ppPropertySet)
1383 MimeBody *This = impl_from_IMimeBody(iface);
1384 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1385 return E_NOTIMPL;
1388 static HRESULT WINAPI MimeBody_SetOption(
1389 IMimeBody* iface,
1390 const TYPEDID oid,
1391 LPCPROPVARIANT pValue)
1393 MimeBody *This = impl_from_IMimeBody(iface);
1394 HRESULT hr = E_NOTIMPL;
1395 TRACE("(%p)->(%08lx, %p)\n", This, oid, pValue);
1397 if(pValue->vt != TYPEDID_TYPE(oid))
1399 WARN("Called with vartype %04x and oid %08lx\n", pValue->vt, oid);
1400 return E_INVALIDARG;
1403 switch(oid)
1405 case OID_SECURITY_HWND_OWNER:
1406 FIXME("OID_SECURITY_HWND_OWNER (value %08lx): ignoring\n", pValue->ulVal);
1407 hr = S_OK;
1408 break;
1409 case OID_TRANSMIT_BODY_ENCODING:
1410 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08lx): ignoring\n", pValue->ulVal);
1411 hr = S_OK;
1412 break;
1413 default:
1414 FIXME("Unhandled oid %08lx\n", oid);
1417 return hr;
1420 static HRESULT WINAPI MimeBody_GetOption(
1421 IMimeBody* iface,
1422 const TYPEDID oid,
1423 LPPROPVARIANT pValue)
1425 MimeBody *This = impl_from_IMimeBody(iface);
1426 FIXME("(%p)->(%08lx, %p): stub\n", This, oid, pValue);
1427 return E_NOTIMPL;
1430 static HRESULT WINAPI MimeBody_EnumProps(
1431 IMimeBody* iface,
1432 DWORD dwFlags,
1433 IMimeEnumProperties** ppEnum)
1435 MimeBody *This = impl_from_IMimeBody(iface);
1436 FIXME("(%p)->(0x%lx, %p) stub\n", This, dwFlags, ppEnum);
1437 return E_NOTIMPL;
1440 static HRESULT WINAPI MimeBody_IsType(
1441 IMimeBody* iface,
1442 IMSGBODYTYPE bodytype)
1444 MimeBody *This = impl_from_IMimeBody(iface);
1446 TRACE("(%p)->(%d)\n", This, bodytype);
1447 switch(bodytype)
1449 case IBT_EMPTY:
1450 return This->data ? S_FALSE : S_OK;
1451 default:
1452 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1454 return S_OK;
1457 static HRESULT WINAPI MimeBody_SetDisplayName(
1458 IMimeBody* iface,
1459 LPCSTR pszDisplay)
1461 MimeBody *This = impl_from_IMimeBody(iface);
1462 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1463 return E_NOTIMPL;
1466 static HRESULT WINAPI MimeBody_GetDisplayName(
1467 IMimeBody* iface,
1468 LPSTR* ppszDisplay)
1470 MimeBody *This = impl_from_IMimeBody(iface);
1471 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1472 return E_NOTIMPL;
1475 static HRESULT WINAPI MimeBody_GetOffsets(
1476 IMimeBody* iface,
1477 LPBODYOFFSETS pOffsets)
1479 MimeBody *This = impl_from_IMimeBody(iface);
1480 TRACE("(%p)->(%p)\n", This, pOffsets);
1482 *pOffsets = This->body_offsets;
1484 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1485 return S_OK;
1488 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1489 IMimeBody* iface,
1490 ENCODINGTYPE* pietEncoding)
1492 MimeBody *This = impl_from_IMimeBody(iface);
1494 TRACE("(%p)->(%p)\n", This, pietEncoding);
1496 *pietEncoding = This->encoding;
1497 return S_OK;
1500 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1501 IMimeBody* iface,
1502 ENCODINGTYPE ietEncoding)
1504 MimeBody *This = impl_from_IMimeBody(iface);
1506 TRACE("(%p)->(%d)\n", This, ietEncoding);
1508 This->encoding = ietEncoding;
1509 return S_OK;
1512 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1513 IMimeBody* iface,
1514 ENCODINGTYPE ietEncoding,
1515 ULONG* pcbSize)
1517 MimeBody *This = impl_from_IMimeBody(iface);
1518 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1519 return E_NOTIMPL;
1522 static HRESULT WINAPI MimeBody_GetDataHere(
1523 IMimeBody* iface,
1524 ENCODINGTYPE ietEncoding,
1525 IStream* pStream)
1527 MimeBody *This = impl_from_IMimeBody(iface);
1528 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1529 return E_NOTIMPL;
1532 static const signed char base64_decode_table[] =
1534 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1535 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1536 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1537 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1538 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1539 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1540 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1541 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1544 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1546 const unsigned char *ptr, *end;
1547 unsigned char buf[1024];
1548 LARGE_INTEGER pos;
1549 unsigned char *ret;
1550 unsigned char in[4];
1551 IStream *output;
1552 DWORD size;
1553 int n = 0;
1554 HRESULT hres;
1556 pos.QuadPart = 0;
1557 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1558 if(FAILED(hres))
1559 return hres;
1561 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1562 if(FAILED(hres))
1563 return hres;
1565 while(1) {
1566 hres = IStream_Read(input, buf, sizeof(buf), &size);
1567 if(FAILED(hres) || !size)
1568 break;
1570 ptr = ret = buf;
1571 end = buf + size;
1573 while(1) {
1574 /* skip invalid chars */
1575 while(ptr < end && (*ptr >= ARRAY_SIZE(base64_decode_table)
1576 || base64_decode_table[*ptr] == -1))
1577 ptr++;
1578 if(ptr == end)
1579 break;
1581 in[n++] = base64_decode_table[*ptr++];
1582 switch(n) {
1583 case 2:
1584 *ret++ = in[0] << 2 | in[1] >> 4;
1585 continue;
1586 case 3:
1587 *ret++ = in[1] << 4 | in[2] >> 2;
1588 continue;
1589 case 4:
1590 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1591 n = 0;
1595 if(ret > buf) {
1596 hres = IStream_Write(output, buf, ret - buf, NULL);
1597 if(FAILED(hres))
1598 break;
1602 if(SUCCEEDED(hres))
1603 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1604 if(FAILED(hres)) {
1605 IStream_Release(output);
1606 return hres;
1609 *ret_stream = output;
1610 return S_OK;
1613 static int hex_digit(char c)
1615 if('0' <= c && c <= '9')
1616 return c - '0';
1617 if('A' <= c && c <= 'F')
1618 return c - 'A' + 10;
1619 if('a' <= c && c <= 'f')
1620 return c - 'a' + 10;
1621 return -1;
1624 static HRESULT decode_qp(IStream *input, IStream **ret_stream)
1626 const unsigned char *ptr, *end;
1627 unsigned char *ret, prev = 0;
1628 unsigned char buf[1024];
1629 LARGE_INTEGER pos;
1630 IStream *output;
1631 DWORD size;
1632 int n = -1;
1633 HRESULT hres;
1635 pos.QuadPart = 0;
1636 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1637 if(FAILED(hres))
1638 return hres;
1640 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1641 if(FAILED(hres))
1642 return hres;
1644 while(1) {
1645 hres = IStream_Read(input, buf, sizeof(buf), &size);
1646 if(FAILED(hres) || !size)
1647 break;
1649 ptr = ret = buf;
1650 end = buf + size;
1652 while(ptr < end) {
1653 unsigned char byte = *ptr++;
1655 switch(n) {
1656 case -1:
1657 if(byte == '=')
1658 n = 0;
1659 else
1660 *ret++ = byte;
1661 continue;
1662 case 0:
1663 prev = byte;
1664 n = 1;
1665 continue;
1666 case 1:
1667 if(prev != '\r' || byte != '\n') {
1668 int h1 = hex_digit(prev), h2 = hex_digit(byte);
1669 if(h1 != -1 && h2 != -1)
1670 *ret++ = (h1 << 4) | h2;
1671 else
1672 *ret++ = '=';
1674 n = -1;
1675 continue;
1679 if(ret > buf) {
1680 hres = IStream_Write(output, buf, ret - buf, NULL);
1681 if(FAILED(hres))
1682 break;
1686 if(SUCCEEDED(hres))
1687 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1688 if(FAILED(hres)) {
1689 IStream_Release(output);
1690 return hres;
1693 *ret_stream = output;
1694 return S_OK;
1697 static HRESULT WINAPI MimeBody_GetData(
1698 IMimeBody* iface,
1699 ENCODINGTYPE ietEncoding,
1700 IStream** ppStream)
1702 MimeBody *This = impl_from_IMimeBody(iface);
1703 ULARGE_INTEGER start, size;
1704 HRESULT hres;
1706 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1708 if(This->encoding != ietEncoding) {
1709 switch(This->encoding) {
1710 case IET_BASE64:
1711 hres = decode_base64(This->data, ppStream);
1712 break;
1713 case IET_QP:
1714 hres = decode_qp(This->data, ppStream);
1715 break;
1716 default:
1717 FIXME("Decoding %d is not supported.\n", This->encoding);
1718 hres = S_FALSE;
1720 if(ietEncoding != IET_BINARY)
1721 FIXME("Encoding %d is not supported.\n", ietEncoding);
1722 if(hres != S_FALSE)
1723 return hres;
1726 start.QuadPart = 0;
1727 hres = get_stream_size(This->data, &size);
1728 if(SUCCEEDED(hres))
1729 hres = create_sub_stream(This->data, start, size, ppStream);
1730 return hres;
1733 static HRESULT WINAPI MimeBody_SetData(
1734 IMimeBody* iface,
1735 ENCODINGTYPE ietEncoding,
1736 LPCSTR pszPriType,
1737 LPCSTR pszSubType,
1738 REFIID riid,
1739 LPVOID pvObject)
1741 MimeBody *This = impl_from_IMimeBody(iface);
1742 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1743 debugstr_guid(riid), pvObject);
1745 if(IsEqualIID(riid, &IID_IStream))
1746 IStream_AddRef((IStream *)pvObject);
1747 else
1749 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1750 return E_INVALIDARG;
1753 if(This->data)
1754 release_data(&This->data_iid, This->data);
1756 This->data_iid = *riid;
1757 This->data = pvObject;
1759 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1761 /* FIXME: Update the content type.
1762 If pszPriType == NULL use 'application'
1763 If pszSubType == NULL use 'octet-stream' */
1765 return S_OK;
1768 static HRESULT WINAPI MimeBody_EmptyData(
1769 IMimeBody* iface)
1771 MimeBody *This = impl_from_IMimeBody(iface);
1772 FIXME("(%p)->() stub\n", This);
1773 return E_NOTIMPL;
1776 static HRESULT WINAPI MimeBody_CopyTo(
1777 IMimeBody* iface,
1778 IMimeBody* pBody)
1780 MimeBody *This = impl_from_IMimeBody(iface);
1781 FIXME("(%p)->(%p) stub\n", This, pBody);
1782 return E_NOTIMPL;
1785 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1786 IMimeBody* iface,
1787 LPTRANSMITINFO pTransmitInfo)
1789 MimeBody *This = impl_from_IMimeBody(iface);
1790 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1791 return E_NOTIMPL;
1794 static HRESULT WINAPI MimeBody_SaveToFile(
1795 IMimeBody* iface,
1796 ENCODINGTYPE ietEncoding,
1797 LPCSTR pszFilePath)
1799 MimeBody *This = impl_from_IMimeBody(iface);
1800 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1801 return E_NOTIMPL;
1804 static HRESULT WINAPI MimeBody_GetHandle(
1805 IMimeBody* iface,
1806 LPHBODY phBody)
1808 MimeBody *This = impl_from_IMimeBody(iface);
1809 TRACE("(%p)->(%p)\n", iface, phBody);
1811 if(!phBody)
1812 return E_INVALIDARG;
1814 *phBody = This->handle;
1815 return This->handle ? S_OK : MIME_E_NO_DATA;
1818 static IMimeBodyVtbl body_vtbl =
1820 MimeBody_QueryInterface,
1821 MimeBody_AddRef,
1822 MimeBody_Release,
1823 MimeBody_GetClassID,
1824 MimeBody_IsDirty,
1825 MimeBody_Load,
1826 MimeBody_Save,
1827 MimeBody_GetSizeMax,
1828 MimeBody_InitNew,
1829 MimeBody_GetPropInfo,
1830 MimeBody_SetPropInfo,
1831 MimeBody_GetProp,
1832 MimeBody_SetProp,
1833 MimeBody_AppendProp,
1834 MimeBody_DeleteProp,
1835 MimeBody_CopyProps,
1836 MimeBody_MoveProps,
1837 MimeBody_DeleteExcept,
1838 MimeBody_QueryProp,
1839 MimeBody_GetCharset,
1840 MimeBody_SetCharset,
1841 MimeBody_GetParameters,
1842 MimeBody_IsContentType,
1843 MimeBody_BindToObject,
1844 MimeBody_Clone,
1845 MimeBody_SetOption,
1846 MimeBody_GetOption,
1847 MimeBody_EnumProps,
1848 MimeBody_IsType,
1849 MimeBody_SetDisplayName,
1850 MimeBody_GetDisplayName,
1851 MimeBody_GetOffsets,
1852 MimeBody_GetCurrentEncoding,
1853 MimeBody_SetCurrentEncoding,
1854 MimeBody_GetEstimatedSize,
1855 MimeBody_GetDataHere,
1856 MimeBody_GetData,
1857 MimeBody_SetData,
1858 MimeBody_EmptyData,
1859 MimeBody_CopyTo,
1860 MimeBody_GetTransmitInfo,
1861 MimeBody_SaveToFile,
1862 MimeBody_GetHandle
1865 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1867 TRACE("setting offsets to %ld, %ld, %ld, %ld\n", offsets->cbBoundaryStart,
1868 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1870 body->body_offsets = *offsets;
1871 return S_OK;
1874 #define FIRST_CUSTOM_PROP_ID 0x100
1876 static MimeBody *mimebody_create(void)
1878 MimeBody *This;
1879 BODYOFFSETS body_offsets;
1881 This = malloc(sizeof(*This));
1882 if (!This)
1883 return NULL;
1885 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1886 This->ref = 1;
1887 This->handle = NULL;
1888 list_init(&This->headers);
1889 list_init(&This->new_props);
1890 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1891 This->content_pri_type = NULL;
1892 This->content_sub_type = NULL;
1893 This->encoding = IET_7BIT;
1894 This->data = NULL;
1895 This->data_iid = IID_NULL;
1897 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1898 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1899 MimeBody_set_offsets(This, &body_offsets);
1901 return This;
1904 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1906 MimeBody *mb;
1908 if(outer)
1909 return CLASS_E_NOAGGREGATION;
1911 if ((mb = mimebody_create()))
1913 *ppv = &mb->IMimeBody_iface;
1914 return S_OK;
1916 else
1918 *ppv = NULL;
1919 return E_OUTOFMEMORY;
1923 typedef struct body_t
1925 struct list entry;
1926 DWORD index;
1927 MimeBody *mime_body;
1929 struct body_t *parent;
1930 struct list children;
1931 } body_t;
1933 typedef struct MimeMessage
1935 IMimeMessage IMimeMessage_iface;
1936 LONG ref;
1937 IStream *stream;
1939 struct list body_tree;
1940 DWORD next_index;
1941 } MimeMessage;
1943 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1945 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1948 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1950 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1952 if (IsEqualIID(riid, &IID_IUnknown) ||
1953 IsEqualIID(riid, &IID_IPersist) ||
1954 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1955 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1956 IsEqualIID(riid, &IID_IMimeMessage))
1958 *ppv = iface;
1959 IMimeMessage_AddRef(iface);
1960 return S_OK;
1963 FIXME("no interface for %s\n", debugstr_guid(riid));
1964 *ppv = NULL;
1965 return E_NOINTERFACE;
1968 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1970 MimeMessage *This = impl_from_IMimeMessage(iface);
1971 ULONG ref = InterlockedIncrement(&This->ref);
1973 TRACE("(%p) ref=%ld\n", This, ref);
1975 return ref;
1978 static void empty_body_list(struct list *list)
1980 body_t *body, *cursor2;
1981 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1983 empty_body_list(&body->children);
1984 list_remove(&body->entry);
1985 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1986 free(body);
1990 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1992 MimeMessage *This = impl_from_IMimeMessage(iface);
1993 ULONG ref = InterlockedDecrement(&This->ref);
1995 TRACE("(%p) ref=%ld\n", This, ref);
1997 if (!ref)
1999 empty_body_list(&This->body_tree);
2001 if(This->stream) IStream_Release(This->stream);
2002 free(This);
2005 return ref;
2008 /*** IPersist methods ***/
2009 static HRESULT WINAPI MimeMessage_GetClassID(
2010 IMimeMessage *iface,
2011 CLSID *pClassID)
2013 FIXME("(%p)->(%p)\n", iface, pClassID);
2014 return E_NOTIMPL;
2017 /*** IPersistStreamInit methods ***/
2018 static HRESULT WINAPI MimeMessage_IsDirty(
2019 IMimeMessage *iface)
2021 FIXME("(%p)->()\n", iface);
2022 return E_NOTIMPL;
2025 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
2027 body_t *body = malloc(sizeof(*body));
2028 if(body)
2030 body->mime_body = mime_body;
2031 body->index = index;
2032 list_init(&body->children);
2033 body->parent = parent;
2035 mime_body->handle = UlongToHandle(body->index);
2037 return body;
2040 typedef struct
2042 struct list entry;
2043 BODYOFFSETS offsets;
2044 } offset_entry_t;
2046 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
2048 HRESULT hr;
2049 DWORD read, boundary_start;
2050 int boundary_len = strlen(boundary);
2051 char *buf, *ptr, *overlap;
2052 DWORD start = 0, overlap_no;
2053 offset_entry_t *cur_body = NULL;
2054 BOOL is_first_line = TRUE;
2055 ULARGE_INTEGER cur;
2056 LARGE_INTEGER zero;
2058 list_init(body_offsets);
2060 overlap_no = boundary_len + 5;
2062 overlap = buf = malloc(overlap_no + PARSER_BUF_SIZE + 1);
2064 zero.QuadPart = 0;
2065 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
2066 start = cur.u.LowPart;
2068 do {
2069 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
2070 if(FAILED(hr)) goto end;
2071 if(read == 0) break;
2072 overlap[read] = '\0';
2074 ptr = buf;
2075 while(1) {
2076 if(is_first_line) {
2077 is_first_line = FALSE;
2078 }else {
2079 ptr = strstr(ptr, "\r\n");
2080 if(!ptr)
2081 break;
2082 ptr += 2;
2085 boundary_start = start + ptr - buf;
2087 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) {
2088 ptr += boundary_len + 2;
2090 if(*ptr == '\r' && *(ptr + 1) == '\n')
2092 ptr += 2;
2093 if(cur_body)
2095 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2096 list_add_tail(body_offsets, &cur_body->entry);
2098 cur_body = malloc(sizeof(*cur_body));
2099 cur_body->offsets.cbBoundaryStart = boundary_start;
2100 cur_body->offsets.cbHeaderStart = start + ptr - buf;
2102 else if(*ptr == '-' && *(ptr + 1) == '-')
2104 if(cur_body)
2106 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2107 list_add_tail(body_offsets, &cur_body->entry);
2108 goto end;
2114 if(overlap == buf) /* 1st iteration */
2116 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2117 overlap = buf + overlap_no;
2118 start += read - overlap_no;
2120 else
2122 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2123 start += read;
2125 } while(1);
2127 end:
2128 free(buf);
2129 return hr;
2132 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2134 ULARGE_INTEGER start, length;
2135 MimeBody *mime_body;
2136 HRESULT hr;
2137 body_t *body;
2138 LARGE_INTEGER pos;
2140 pos.QuadPart = offset->cbHeaderStart;
2141 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL);
2143 mime_body = mimebody_create();
2144 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2146 pos.QuadPart = 0;
2147 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start);
2148 offset->cbBodyStart = start.QuadPart;
2149 if (parent) MimeBody_set_offsets(mime_body, offset);
2151 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart;
2152 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data);
2153 mime_body->data_iid = IID_IStream;
2155 body = new_body_entry(mime_body, msg->next_index++, parent);
2157 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2159 MIMEPARAMINFO *param_info;
2160 ULONG count, i;
2161 IMimeAllocator *alloc;
2163 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2164 &param_info);
2165 if(hr != S_OK || count == 0) return body;
2167 MimeOleGetAllocator(&alloc);
2169 for(i = 0; i < count; i++)
2171 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2173 struct list offset_list;
2174 offset_entry_t *cur, *cursor2;
2175 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2176 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2178 body_t *sub_body;
2180 sub_body = create_sub_body(msg, pStm, &cur->offsets, body);
2181 list_add_tail(&body->children, &sub_body->entry);
2182 list_remove(&cur->entry);
2183 free(cur);
2185 break;
2188 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2189 IMimeAllocator_Release(alloc);
2191 return body;
2194 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2196 MimeMessage *This = impl_from_IMimeMessage(iface);
2197 body_t *root_body;
2198 BODYOFFSETS offsets;
2199 ULARGE_INTEGER cur;
2200 LARGE_INTEGER zero;
2202 TRACE("(%p)->(%p)\n", iface, pStm);
2204 if(This->stream)
2206 FIXME("already loaded a message\n");
2207 return E_FAIL;
2210 empty_body_list(&This->body_tree);
2212 IStream_AddRef(pStm);
2213 This->stream = pStm;
2214 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2215 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2217 root_body = create_sub_body(This, pStm, &offsets, NULL);
2219 zero.QuadPart = 0;
2220 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2221 offsets.cbBodyEnd = cur.u.LowPart;
2222 MimeBody_set_offsets(root_body->mime_body, &offsets);
2224 list_add_head(&This->body_tree, &root_body->entry);
2226 return S_OK;
2229 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2231 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2232 return E_NOTIMPL;
2235 static HRESULT WINAPI MimeMessage_GetSizeMax(
2236 IMimeMessage *iface,
2237 ULARGE_INTEGER *pcbSize)
2239 FIXME("(%p)->(%p)\n", iface, pcbSize);
2240 return E_NOTIMPL;
2243 static HRESULT WINAPI MimeMessage_InitNew(
2244 IMimeMessage *iface)
2246 FIXME("(%p)->()\n", iface);
2247 return E_NOTIMPL;
2250 /*** IMimeMessageTree methods ***/
2251 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2252 DWORD dwFlags)
2254 MimeMessage *This = impl_from_IMimeMessage(iface);
2256 FIXME("(%p)->(%p, 0x%lx)\n", iface, ppStream, dwFlags);
2258 IStream_AddRef(This->stream);
2259 *ppStream = This->stream;
2260 return S_OK;
2263 static HRESULT WINAPI MimeMessage_GetMessageSize(
2264 IMimeMessage *iface,
2265 ULONG *pcbSize,
2266 DWORD dwFlags)
2268 FIXME("(%p)->(%p, 0x%lx)\n", iface, pcbSize, dwFlags);
2269 return E_NOTIMPL;
2272 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2273 IMimeMessage *iface,
2274 IStream *pStream)
2276 FIXME("(%p)->(%p)\n", iface, pStream);
2277 return E_NOTIMPL;
2280 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2281 IMimeMessage *iface,
2282 IStream *pStream,
2283 DWORD dwFlags)
2285 FIXME("(%p)->(%p, 0x%lx)\n", iface, pStream, dwFlags);
2286 return E_NOTIMPL;
2290 static HRESULT WINAPI MimeMessage_GetFlags(
2291 IMimeMessage *iface,
2292 DWORD *pdwFlags)
2294 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2295 return E_NOTIMPL;
2298 static HRESULT WINAPI MimeMessage_Commit(
2299 IMimeMessage *iface,
2300 DWORD dwFlags)
2302 FIXME("(%p)->(0x%lx)\n", iface, dwFlags);
2303 return S_OK;
2307 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2308 IMimeMessage *iface)
2310 FIXME("(%p)->()\n", iface);
2311 return E_NOTIMPL;
2314 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2316 body_t *cur;
2317 HRESULT hr;
2319 if(hbody == HBODY_ROOT)
2321 *body = LIST_ENTRY(list_head(list), body_t, entry);
2322 return S_OK;
2325 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2327 if(cur->index == HandleToUlong(hbody))
2329 *body = cur;
2330 return S_OK;
2332 hr = find_body(&cur->children, hbody, body);
2333 if(hr == S_OK) return S_OK;
2335 return S_FALSE;
2338 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2339 void **ppvObject)
2341 MimeMessage *This = impl_from_IMimeMessage(iface);
2342 HRESULT hr;
2343 body_t *body;
2345 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2347 hr = find_body(&This->body_tree, hBody, &body);
2349 if(hr != S_OK) return hr;
2351 if(IsEqualIID(riid, &IID_IMimeBody))
2353 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2354 *ppvObject = &body->mime_body->IMimeBody_iface;
2355 return S_OK;
2358 return E_NOINTERFACE;
2361 static HRESULT WINAPI MimeMessage_SaveBody(
2362 IMimeMessage *iface,
2363 HBODY hBody,
2364 DWORD dwFlags,
2365 IStream *pStream)
2367 FIXME("(%p)->(%p, 0x%lx, %p)\n", iface, hBody, dwFlags, pStream);
2368 return E_NOTIMPL;
2371 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2373 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2374 body_t *body;
2375 HRESULT hr;
2376 struct list *list;
2378 if(location == IBL_ROOT)
2380 *out = root;
2381 return S_OK;
2384 hr = find_body(&msg->body_tree, pivot, &body);
2386 if(hr == S_OK)
2388 switch(location)
2390 case IBL_PARENT:
2391 if(body->parent)
2392 *out = body->parent;
2393 else
2394 hr = MIME_E_NOT_FOUND;
2395 break;
2397 case IBL_FIRST:
2398 list = list_head(&body->children);
2399 if(list)
2400 *out = LIST_ENTRY(list, body_t, entry);
2401 else
2402 hr = MIME_E_NOT_FOUND;
2403 break;
2405 case IBL_LAST:
2406 list = list_tail(&body->children);
2407 if(list)
2408 *out = LIST_ENTRY(list, body_t, entry);
2409 else
2410 hr = MIME_E_NOT_FOUND;
2411 break;
2413 case IBL_NEXT:
2414 list = list_next(&body->parent->children, &body->entry);
2415 if(list)
2416 *out = LIST_ENTRY(list, body_t, entry);
2417 else
2418 hr = MIME_E_NOT_FOUND;
2419 break;
2421 case IBL_PREVIOUS:
2422 list = list_prev(&body->parent->children, &body->entry);
2423 if(list)
2424 *out = LIST_ENTRY(list, body_t, entry);
2425 else
2426 hr = MIME_E_NOT_FOUND;
2427 break;
2429 default:
2430 hr = E_FAIL;
2431 break;
2435 return hr;
2439 static HRESULT WINAPI MimeMessage_InsertBody(
2440 IMimeMessage *iface,
2441 BODYLOCATION location,
2442 HBODY hPivot,
2443 LPHBODY phBody)
2445 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2446 return E_NOTIMPL;
2449 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2450 HBODY *phBody)
2452 MimeMessage *This = impl_from_IMimeMessage(iface);
2453 body_t *body;
2454 HRESULT hr;
2456 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2458 if(!phBody)
2459 return E_INVALIDARG;
2461 *phBody = NULL;
2463 hr = get_body(This, location, hPivot, &body);
2465 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2467 return hr;
2470 static HRESULT WINAPI MimeMessage_DeleteBody(
2471 IMimeMessage *iface,
2472 HBODY hBody,
2473 DWORD dwFlags)
2475 FIXME("(%p)->(%p, %08lx)\n", iface, hBody, dwFlags);
2476 return E_NOTIMPL;
2479 static HRESULT WINAPI MimeMessage_MoveBody(
2480 IMimeMessage *iface,
2481 HBODY hBody,
2482 BODYLOCATION location)
2484 FIXME("(%p)->(%d)\n", iface, location);
2485 return E_NOTIMPL;
2488 static void count_children(body_t *body, boolean recurse, ULONG *count)
2490 body_t *child;
2492 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2494 (*count)++;
2495 if(recurse) count_children(child, recurse, count);
2499 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2500 ULONG *pcBodies)
2502 HRESULT hr;
2503 MimeMessage *This = impl_from_IMimeMessage(iface);
2504 body_t *body;
2506 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2508 hr = find_body(&This->body_tree, hParent, &body);
2509 if(hr != S_OK) return hr;
2511 *pcBodies = 1;
2512 count_children(body, fRecurse, pcBodies);
2514 return S_OK;
2517 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2519 struct list *ptr;
2520 HBODY next;
2522 for (;;)
2524 if (!body) ptr = list_head( &This->body_tree );
2525 else
2527 ptr = list_head( &body->children );
2528 while (!ptr)
2530 if (!body->parent) return MIME_E_NOT_FOUND;
2531 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2535 body = LIST_ENTRY( ptr, body_t, entry );
2536 next = UlongToHandle( body->index );
2537 find->dwReserved = body->index;
2538 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2539 find->pszSubType) == S_OK)
2541 *out = next;
2542 return S_OK;
2545 return MIME_E_NOT_FOUND;
2548 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2550 MimeMessage *This = impl_from_IMimeMessage(iface);
2552 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2554 pFindBody->dwReserved = 0;
2555 return find_next(This, NULL, pFindBody, phBody);
2558 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2560 MimeMessage *This = impl_from_IMimeMessage(iface);
2561 body_t *body;
2562 HRESULT hr;
2564 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2566 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2567 if (hr != S_OK) return MIME_E_NOT_FOUND;
2568 return find_next(This, body, pFindBody, phBody);
2571 static HRESULT WINAPI MimeMessage_ResolveURL(
2572 IMimeMessage *iface,
2573 HBODY hRelated,
2574 LPCSTR pszBase,
2575 LPCSTR pszURL,
2576 DWORD dwFlags,
2577 LPHBODY phBody)
2579 FIXME("(%p)->(%p, %s, %s, 0x%lx, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2580 return E_NOTIMPL;
2583 static HRESULT WINAPI MimeMessage_ToMultipart(
2584 IMimeMessage *iface,
2585 HBODY hBody,
2586 LPCSTR pszSubType,
2587 LPHBODY phMultipart)
2589 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2590 return E_NOTIMPL;
2593 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2594 IMimeMessage *iface,
2595 HBODY hBody,
2596 LPBODYOFFSETS pOffsets)
2598 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2599 return E_NOTIMPL;
2602 static HRESULT WINAPI MimeMessage_GetCharset(
2603 IMimeMessage *iface,
2604 LPHCHARSET phCharset)
2606 FIXME("(%p)->(%p)\n", iface, phCharset);
2607 *phCharset = NULL;
2608 return S_OK;
2611 static HRESULT WINAPI MimeMessage_SetCharset(
2612 IMimeMessage *iface,
2613 HCHARSET hCharset,
2614 CSETAPPLYTYPE applytype)
2616 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2617 return E_NOTIMPL;
2620 static HRESULT WINAPI MimeMessage_IsBodyType(
2621 IMimeMessage *iface,
2622 HBODY hBody,
2623 IMSGBODYTYPE bodytype)
2625 HRESULT hr;
2626 IMimeBody *mime_body;
2627 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2629 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2630 if(hr != S_OK) return hr;
2632 hr = IMimeBody_IsType(mime_body, bodytype);
2633 MimeBody_Release(mime_body);
2634 return hr;
2637 static HRESULT WINAPI MimeMessage_IsContentType(
2638 IMimeMessage *iface,
2639 HBODY hBody,
2640 LPCSTR pszPriType,
2641 LPCSTR pszSubType)
2643 HRESULT hr;
2644 IMimeBody *mime_body;
2645 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2646 debugstr_a(pszSubType));
2648 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2649 if(FAILED(hr)) return hr;
2651 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2652 IMimeBody_Release(mime_body);
2653 return hr;
2656 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2657 IMimeMessage *iface,
2658 HBODY hBody,
2659 LPCSTR pszName,
2660 LPCSTR pszCriteria,
2661 boolean fSubString,
2662 boolean fCaseSensitive)
2664 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2665 return E_NOTIMPL;
2668 static HRESULT WINAPI MimeMessage_GetBodyProp(
2669 IMimeMessage *iface,
2670 HBODY hBody,
2671 LPCSTR pszName,
2672 DWORD dwFlags,
2673 LPPROPVARIANT pValue)
2675 HRESULT hr;
2676 IMimeBody *mime_body;
2678 TRACE("(%p)->(%p, %s, 0x%lx, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2680 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2681 if(hr != S_OK) return hr;
2683 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2684 IMimeBody_Release(mime_body);
2686 return hr;
2689 static HRESULT WINAPI MimeMessage_SetBodyProp(
2690 IMimeMessage *iface,
2691 HBODY hBody,
2692 LPCSTR pszName,
2693 DWORD dwFlags,
2694 LPCPROPVARIANT pValue)
2696 FIXME("(%p)->(%p, %s, 0x%lx, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2697 return E_NOTIMPL;
2700 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2701 IMimeMessage *iface,
2702 HBODY hBody,
2703 LPCSTR pszName)
2705 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2706 return E_NOTIMPL;
2709 static HRESULT WINAPI MimeMessage_SetOption(
2710 IMimeMessage *iface,
2711 const TYPEDID oid,
2712 LPCPROPVARIANT pValue)
2714 HRESULT hr = S_OK;
2715 TRACE("(%p)->(%08lx, %p)\n", iface, oid, pValue);
2717 /* Message ID is checked before type.
2718 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2720 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2722 WARN("oid (%08lx) out of range\n", oid);
2723 return MIME_E_INVALID_OPTION_ID;
2726 if(pValue->vt != TYPEDID_TYPE(oid))
2728 WARN("Called with vartype %04x and oid %08lx\n", pValue->vt, oid);
2729 return S_OK;
2732 switch(oid)
2734 case OID_HIDE_TNEF_ATTACHMENTS:
2735 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->boolVal);
2736 break;
2737 case OID_SHOW_MACBINARY:
2738 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->boolVal);
2739 break;
2740 case OID_SAVEBODY_KEEPBOUNDARY:
2741 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->boolVal);
2742 break;
2743 case OID_CLEANUP_TREE_ON_SAVE:
2744 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->boolVal);
2745 break;
2746 default:
2747 FIXME("Unhandled oid %08lx\n", oid);
2748 hr = MIME_E_INVALID_OPTION_ID;
2751 return hr;
2754 static HRESULT WINAPI MimeMessage_GetOption(
2755 IMimeMessage *iface,
2756 const TYPEDID oid,
2757 LPPROPVARIANT pValue)
2759 FIXME("(%p)->(%08lx, %p)\n", iface, oid, pValue);
2760 return E_NOTIMPL;
2763 /*** IMimeMessage methods ***/
2764 static HRESULT WINAPI MimeMessage_CreateWebPage(
2765 IMimeMessage *iface,
2766 IStream *pRootStm,
2767 LPWEBPAGEOPTIONS pOptions,
2768 IMimeMessageCallback *pCallback,
2769 IMoniker **ppMoniker)
2771 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2772 *ppMoniker = NULL;
2773 return E_NOTIMPL;
2776 static HRESULT WINAPI MimeMessage_GetProp(
2777 IMimeMessage *iface,
2778 LPCSTR pszName,
2779 DWORD dwFlags,
2780 LPPROPVARIANT pValue)
2782 FIXME("(%p)->(%s, 0x%lx, %p)\n", iface, pszName, dwFlags, pValue);
2783 return E_NOTIMPL;
2786 static HRESULT WINAPI MimeMessage_SetProp(
2787 IMimeMessage *iface,
2788 LPCSTR pszName,
2789 DWORD dwFlags,
2790 LPCPROPVARIANT pValue)
2792 FIXME("(%p)->(%s, 0x%lx, %p)\n", iface, pszName, dwFlags, pValue);
2793 return E_NOTIMPL;
2796 static HRESULT WINAPI MimeMessage_DeleteProp(
2797 IMimeMessage *iface,
2798 LPCSTR pszName)
2800 FIXME("(%p)->(%s)\n", iface, pszName);
2801 return E_NOTIMPL;
2804 static HRESULT WINAPI MimeMessage_QueryProp(
2805 IMimeMessage *iface,
2806 LPCSTR pszName,
2807 LPCSTR pszCriteria,
2808 boolean fSubString,
2809 boolean fCaseSensitive)
2811 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2812 return E_NOTIMPL;
2815 static HRESULT WINAPI MimeMessage_GetTextBody(
2816 IMimeMessage *iface,
2817 DWORD dwTxtType,
2818 ENCODINGTYPE ietEncoding,
2819 IStream **pStream,
2820 LPHBODY phBody)
2822 HRESULT hr;
2823 HBODY hbody;
2824 FINDBODY find_struct;
2825 IMimeBody *mime_body;
2826 static char text[] = "text";
2827 static char plain[] = "plain";
2828 static char html[] = "html";
2830 TRACE("(%p)->(%ld, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2832 find_struct.pszPriType = text;
2834 switch(dwTxtType)
2836 case TXT_PLAIN:
2837 find_struct.pszSubType = plain;
2838 break;
2839 case TXT_HTML:
2840 find_struct.pszSubType = html;
2841 break;
2842 default:
2843 return MIME_E_INVALID_TEXT_TYPE;
2846 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2847 if(hr != S_OK)
2849 TRACE("not found hr %08lx\n", hr);
2850 *phBody = NULL;
2851 return hr;
2854 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2856 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2857 *phBody = hbody;
2858 IMimeBody_Release(mime_body);
2859 return hr;
2862 static HRESULT WINAPI MimeMessage_SetTextBody(
2863 IMimeMessage *iface,
2864 DWORD dwTxtType,
2865 ENCODINGTYPE ietEncoding,
2866 HBODY hAlternative,
2867 IStream *pStream,
2868 LPHBODY phBody)
2870 FIXME("(%p)->(%ld, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2871 return E_NOTIMPL;
2874 static HRESULT WINAPI MimeMessage_AttachObject(
2875 IMimeMessage *iface,
2876 REFIID riid,
2877 void *pvObject,
2878 LPHBODY phBody)
2880 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2881 return E_NOTIMPL;
2884 static HRESULT WINAPI MimeMessage_AttachFile(
2885 IMimeMessage *iface,
2886 LPCSTR pszFilePath,
2887 IStream *pstmFile,
2888 LPHBODY phBody)
2890 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2891 return E_NOTIMPL;
2894 static HRESULT WINAPI MimeMessage_AttachURL(
2895 IMimeMessage *iface,
2896 LPCSTR pszBase,
2897 LPCSTR pszURL,
2898 DWORD dwFlags,
2899 IStream *pstmURL,
2900 LPSTR *ppszCIDURL,
2901 LPHBODY phBody)
2903 FIXME("(%p)->(%s, %s, 0x%lx, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2904 return E_NOTIMPL;
2907 static HRESULT WINAPI MimeMessage_GetAttachments(
2908 IMimeMessage *iface,
2909 ULONG *pcAttach,
2910 LPHBODY *pprghAttach)
2912 HRESULT hr;
2913 FINDBODY find_struct;
2914 HBODY hbody;
2915 LPHBODY array;
2916 ULONG size = 10;
2918 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2920 *pcAttach = 0;
2921 array = CoTaskMemAlloc(size * sizeof(HBODY));
2923 find_struct.pszPriType = find_struct.pszSubType = NULL;
2924 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2925 while(hr == S_OK)
2927 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2928 TRACE("IsCT rets %08lx %ld\n", hr, *pcAttach);
2929 if(hr != S_OK)
2931 if(*pcAttach + 1 > size)
2933 size *= 2;
2934 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2936 array[*pcAttach] = hbody;
2937 (*pcAttach)++;
2939 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2942 *pprghAttach = array;
2943 return S_OK;
2946 static HRESULT WINAPI MimeMessage_GetAddressTable(
2947 IMimeMessage *iface,
2948 IMimeAddressTable **ppTable)
2950 FIXME("(%p)->(%p)\n", iface, ppTable);
2951 return E_NOTIMPL;
2954 static HRESULT WINAPI MimeMessage_GetSender(
2955 IMimeMessage *iface,
2956 LPADDRESSPROPS pAddress)
2958 FIXME("(%p)->(%p)\n", iface, pAddress);
2959 return E_NOTIMPL;
2962 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2963 IMimeMessage *iface,
2964 DWORD dwAdrTypes,
2965 DWORD dwProps,
2966 LPADDRESSLIST pList)
2968 FIXME("(%p)->(%ld, %ld, %p)\n", iface, dwAdrTypes, dwProps, pList);
2969 return E_NOTIMPL;
2972 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2973 IMimeMessage *iface,
2974 DWORD dwAdrTypes,
2975 ADDRESSFORMAT format,
2976 LPSTR *ppszFormat)
2978 FIXME("(%p)->(%ld, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2979 return E_NOTIMPL;
2982 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2983 IMimeMessage *iface,
2984 DWORD dwAdrTypes,
2985 DWORD dwProps,
2986 IMimeEnumAddressTypes **ppEnum)
2988 FIXME("(%p)->(%ld, %ld, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2989 return E_NOTIMPL;
2992 static HRESULT WINAPI MimeMessage_SplitMessage(
2993 IMimeMessage *iface,
2994 ULONG cbMaxPart,
2995 IMimeMessageParts **ppParts)
2997 FIXME("(%p)->(%ld, %p)\n", iface, cbMaxPart, ppParts);
2998 return E_NOTIMPL;
3001 static HRESULT WINAPI MimeMessage_GetRootMoniker(
3002 IMimeMessage *iface,
3003 IMoniker **ppMoniker)
3005 FIXME("(%p)->(%p)\n", iface, ppMoniker);
3006 return E_NOTIMPL;
3009 static const IMimeMessageVtbl MimeMessageVtbl =
3011 MimeMessage_QueryInterface,
3012 MimeMessage_AddRef,
3013 MimeMessage_Release,
3014 MimeMessage_GetClassID,
3015 MimeMessage_IsDirty,
3016 MimeMessage_Load,
3017 MimeMessage_Save,
3018 MimeMessage_GetSizeMax,
3019 MimeMessage_InitNew,
3020 MimeMessage_GetMessageSource,
3021 MimeMessage_GetMessageSize,
3022 MimeMessage_LoadOffsetTable,
3023 MimeMessage_SaveOffsetTable,
3024 MimeMessage_GetFlags,
3025 MimeMessage_Commit,
3026 MimeMessage_HandsOffStorage,
3027 MimeMessage_BindToObject,
3028 MimeMessage_SaveBody,
3029 MimeMessage_InsertBody,
3030 MimeMessage_GetBody,
3031 MimeMessage_DeleteBody,
3032 MimeMessage_MoveBody,
3033 MimeMessage_CountBodies,
3034 MimeMessage_FindFirst,
3035 MimeMessage_FindNext,
3036 MimeMessage_ResolveURL,
3037 MimeMessage_ToMultipart,
3038 MimeMessage_GetBodyOffsets,
3039 MimeMessage_GetCharset,
3040 MimeMessage_SetCharset,
3041 MimeMessage_IsBodyType,
3042 MimeMessage_IsContentType,
3043 MimeMessage_QueryBodyProp,
3044 MimeMessage_GetBodyProp,
3045 MimeMessage_SetBodyProp,
3046 MimeMessage_DeleteBodyProp,
3047 MimeMessage_SetOption,
3048 MimeMessage_GetOption,
3049 MimeMessage_CreateWebPage,
3050 MimeMessage_GetProp,
3051 MimeMessage_SetProp,
3052 MimeMessage_DeleteProp,
3053 MimeMessage_QueryProp,
3054 MimeMessage_GetTextBody,
3055 MimeMessage_SetTextBody,
3056 MimeMessage_AttachObject,
3057 MimeMessage_AttachFile,
3058 MimeMessage_AttachURL,
3059 MimeMessage_GetAttachments,
3060 MimeMessage_GetAddressTable,
3061 MimeMessage_GetSender,
3062 MimeMessage_GetAddressTypes,
3063 MimeMessage_GetAddressFormat,
3064 MimeMessage_EnumAddressTypes,
3065 MimeMessage_SplitMessage,
3066 MimeMessage_GetRootMoniker,
3069 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
3071 MimeMessage *This;
3072 MimeBody *mime_body;
3073 body_t *root_body;
3075 TRACE("(%p, %p)\n", outer, obj);
3077 if (outer)
3079 FIXME("outer unknown not supported yet\n");
3080 return E_NOTIMPL;
3083 *obj = NULL;
3085 This = malloc(sizeof(*This));
3086 if (!This) return E_OUTOFMEMORY;
3088 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
3089 This->ref = 1;
3090 This->stream = NULL;
3091 list_init(&This->body_tree);
3092 This->next_index = 1;
3094 mime_body = mimebody_create();
3095 root_body = new_body_entry(mime_body, This->next_index++, NULL);
3096 list_add_head(&This->body_tree, &root_body->entry);
3098 *obj = &This->IMimeMessage_iface;
3099 return S_OK;
3102 /***********************************************************************
3103 * MimeOleCreateMessage (INETCOMM.@)
3105 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
3107 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3108 return MimeMessage_create(NULL, (void **)ppMessage);
3111 /***********************************************************************
3112 * MimeOleSetCompatMode (INETCOMM.@)
3114 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3116 FIXME("(0x%lx)\n", dwMode);
3117 return S_OK;
3120 /***********************************************************************
3121 * MimeOleCreateVirtualStream (INETCOMM.@)
3123 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3125 HRESULT hr;
3126 FIXME("(%p)\n", ppStream);
3128 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3129 return hr;
3132 typedef struct MimeSecurity
3134 IMimeSecurity IMimeSecurity_iface;
3135 LONG ref;
3136 } MimeSecurity;
3138 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3140 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3143 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3145 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3147 if (IsEqualIID(riid, &IID_IUnknown) ||
3148 IsEqualIID(riid, &IID_IMimeSecurity))
3150 *ppv = iface;
3151 IMimeSecurity_AddRef(iface);
3152 return S_OK;
3155 FIXME("no interface for %s\n", debugstr_guid(riid));
3156 *ppv = NULL;
3157 return E_NOINTERFACE;
3160 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3162 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3163 LONG ref = InterlockedIncrement(&This->ref);
3165 TRACE("(%p) ref=%ld\n", This, ref);
3167 return ref;
3170 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3172 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3173 LONG ref = InterlockedDecrement(&This->ref);
3175 TRACE("(%p) ref=%ld\n", This, ref);
3177 if (!ref)
3178 free(This);
3180 return ref;
3183 static HRESULT WINAPI MimeSecurity_InitNew(
3184 IMimeSecurity* iface)
3186 FIXME("(%p)->(): stub\n", iface);
3187 return S_OK;
3190 static HRESULT WINAPI MimeSecurity_CheckInit(
3191 IMimeSecurity* iface)
3193 FIXME("(%p)->(): stub\n", iface);
3194 return E_NOTIMPL;
3197 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3198 IMimeSecurity* iface,
3199 IMimeMessageTree* pTree,
3200 DWORD dwFlags)
3202 FIXME("(%p)->(%p, %08lx): stub\n", iface, pTree, dwFlags);
3203 return E_NOTIMPL;
3206 static HRESULT WINAPI MimeSecurity_EncodeBody(
3207 IMimeSecurity* iface,
3208 IMimeMessageTree* pTree,
3209 HBODY hEncodeRoot,
3210 DWORD dwFlags)
3212 FIXME("(%p)->(%p, %p, %08lx): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3213 return E_NOTIMPL;
3216 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3217 IMimeSecurity* iface,
3218 IMimeMessageTree* pTree,
3219 DWORD dwFlags)
3221 FIXME("(%p)->(%p, %08lx): stub\n", iface, pTree, dwFlags);
3222 return E_NOTIMPL;
3225 static HRESULT WINAPI MimeSecurity_DecodeBody(
3226 IMimeSecurity* iface,
3227 IMimeMessageTree* pTree,
3228 HBODY hDecodeRoot,
3229 DWORD dwFlags)
3231 FIXME("(%p)->(%p, %p, %08lx): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3232 return E_NOTIMPL;
3235 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3236 IMimeSecurity* iface,
3237 HCAPICERTSTORE hc,
3238 DWORD dwUsage,
3239 PCX509CERT pPrev,
3240 PCX509CERT* ppCert)
3242 FIXME("(%p)->(%p, %08lx, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3243 return E_NOTIMPL;
3246 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3247 IMimeSecurity* iface,
3248 const PCX509CERT pX509Cert,
3249 const CERTNAMETYPE cn,
3250 LPSTR* ppszName)
3252 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3253 return E_NOTIMPL;
3256 static HRESULT WINAPI MimeSecurity_GetMessageType(
3257 IMimeSecurity* iface,
3258 const HWND hwndParent,
3259 IMimeBody* pBody,
3260 DWORD* pdwSecType)
3262 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3263 return E_NOTIMPL;
3266 static HRESULT WINAPI MimeSecurity_GetCertData(
3267 IMimeSecurity* iface,
3268 const PCX509CERT pX509Cert,
3269 const CERTDATAID dataid,
3270 LPPROPVARIANT pValue)
3272 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3273 return E_NOTIMPL;
3277 static const IMimeSecurityVtbl MimeSecurityVtbl =
3279 MimeSecurity_QueryInterface,
3280 MimeSecurity_AddRef,
3281 MimeSecurity_Release,
3282 MimeSecurity_InitNew,
3283 MimeSecurity_CheckInit,
3284 MimeSecurity_EncodeMessage,
3285 MimeSecurity_EncodeBody,
3286 MimeSecurity_DecodeMessage,
3287 MimeSecurity_DecodeBody,
3288 MimeSecurity_EnumCertificates,
3289 MimeSecurity_GetCertificateName,
3290 MimeSecurity_GetMessageType,
3291 MimeSecurity_GetCertData
3294 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3296 MimeSecurity *This;
3298 *obj = NULL;
3300 if (outer) return CLASS_E_NOAGGREGATION;
3302 This = malloc(sizeof(*This));
3303 if (!This) return E_OUTOFMEMORY;
3305 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3306 This->ref = 1;
3308 *obj = &This->IMimeSecurity_iface;
3309 return S_OK;
3312 /***********************************************************************
3313 * MimeOleCreateSecurity (INETCOMM.@)
3315 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3317 return MimeSecurity_create(NULL, (void **)ppSecurity);
3320 static HRESULT WINAPI MimeAlloc_QueryInterface(
3321 IMimeAllocator* iface,
3322 REFIID riid,
3323 void **obj)
3325 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3327 if (IsEqualIID(riid, &IID_IUnknown) ||
3328 IsEqualIID(riid, &IID_IMalloc) ||
3329 IsEqualIID(riid, &IID_IMimeAllocator))
3331 *obj = iface;
3332 IMimeAllocator_AddRef(iface);
3333 return S_OK;
3336 FIXME("no interface for %s\n", debugstr_guid(riid));
3337 *obj = NULL;
3338 return E_NOINTERFACE;
3341 static ULONG WINAPI MimeAlloc_AddRef(
3342 IMimeAllocator* iface)
3344 return 2;
3347 static ULONG WINAPI MimeAlloc_Release(
3348 IMimeAllocator* iface)
3350 return 1;
3353 static LPVOID WINAPI MimeAlloc_Alloc(
3354 IMimeAllocator* iface,
3355 SIZE_T cb)
3357 return CoTaskMemAlloc(cb);
3360 static LPVOID WINAPI MimeAlloc_Realloc(
3361 IMimeAllocator* iface,
3362 LPVOID pv,
3363 SIZE_T cb)
3365 return CoTaskMemRealloc(pv, cb);
3368 static void WINAPI MimeAlloc_Free(
3369 IMimeAllocator* iface,
3370 LPVOID pv)
3372 CoTaskMemFree(pv);
3375 static SIZE_T WINAPI MimeAlloc_GetSize(
3376 IMimeAllocator* iface,
3377 LPVOID pv)
3379 FIXME("stub\n");
3380 return 0;
3383 static int WINAPI MimeAlloc_DidAlloc(
3384 IMimeAllocator* iface,
3385 LPVOID pv)
3387 FIXME("stub\n");
3388 return 0;
3391 static void WINAPI MimeAlloc_HeapMinimize(
3392 IMimeAllocator* iface)
3394 FIXME("stub\n");
3395 return;
3398 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3399 IMimeAllocator* iface,
3400 ULONG cParams,
3401 LPMIMEPARAMINFO prgParam,
3402 boolean fFreeArray)
3404 ULONG i;
3405 TRACE("(%p)->(%ld, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3407 for(i = 0; i < cParams; i++)
3409 IMimeAllocator_Free(iface, prgParam[i].pszName);
3410 IMimeAllocator_Free(iface, prgParam[i].pszData);
3412 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3413 return S_OK;
3416 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3417 IMimeAllocator* iface,
3418 LPADDRESSLIST pList)
3420 FIXME("stub\n");
3421 return E_NOTIMPL;
3424 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3425 IMimeAllocator* iface,
3426 LPADDRESSPROPS pAddress)
3428 FIXME("stub\n");
3429 return E_NOTIMPL;
3432 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3433 IMimeAllocator* iface,
3434 ULONG cObjects,
3435 IUnknown **prgpUnknown,
3436 boolean fFreeArray)
3438 FIXME("stub\n");
3439 return E_NOTIMPL;
3443 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3444 IMimeAllocator* iface,
3445 ULONG cRows,
3446 LPENUMHEADERROW prgRow,
3447 boolean fFreeArray)
3449 FIXME("stub\n");
3450 return E_NOTIMPL;
3453 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3454 IMimeAllocator* iface,
3455 ULONG cProps,
3456 LPENUMPROPERTY prgProp,
3457 boolean fFreeArray)
3459 FIXME("stub\n");
3460 return E_NOTIMPL;
3463 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3464 IMimeAllocator* iface,
3465 THUMBBLOB *pthumbprint)
3467 FIXME("stub\n");
3468 return E_NOTIMPL;
3472 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3473 IMimeAllocator* iface,
3474 LPPROPVARIANT pProp)
3476 FIXME("stub\n");
3477 return E_NOTIMPL;
3480 static IMimeAllocatorVtbl mime_alloc_vtbl =
3482 MimeAlloc_QueryInterface,
3483 MimeAlloc_AddRef,
3484 MimeAlloc_Release,
3485 MimeAlloc_Alloc,
3486 MimeAlloc_Realloc,
3487 MimeAlloc_Free,
3488 MimeAlloc_GetSize,
3489 MimeAlloc_DidAlloc,
3490 MimeAlloc_HeapMinimize,
3491 MimeAlloc_FreeParamInfoArray,
3492 MimeAlloc_FreeAddressList,
3493 MimeAlloc_FreeAddressProps,
3494 MimeAlloc_ReleaseObjects,
3495 MimeAlloc_FreeEnumHeaderRowArray,
3496 MimeAlloc_FreeEnumPropertyArray,
3497 MimeAlloc_FreeThumbprint,
3498 MimeAlloc_PropVariantClear
3501 static IMimeAllocator mime_allocator =
3503 &mime_alloc_vtbl
3506 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3508 if(outer) return CLASS_E_NOAGGREGATION;
3510 *obj = &mime_allocator;
3511 return S_OK;
3514 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3516 return MimeAllocator_create(NULL, (void**)alloc);
3519 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3521 FIXME("(%p, %p)\n", outer, obj);
3523 *obj = NULL;
3524 if (outer) return CLASS_E_NOAGGREGATION;
3526 return MimeOleCreateVirtualStream((IStream **)obj);
3529 /* IMimePropertySchema Interface */
3530 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3532 propschema *This = impl_from_IMimePropertySchema(iface);
3533 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3535 *out = NULL;
3537 if (IsEqualIID(riid, &IID_IUnknown) ||
3538 IsEqualIID(riid, &IID_IMimePropertySchema))
3540 *out = iface;
3542 else
3544 FIXME("no interface for %s\n", debugstr_guid(riid));
3545 return E_NOINTERFACE;
3548 IMimePropertySchema_AddRef(iface);
3549 return S_OK;
3552 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3554 propschema *This = impl_from_IMimePropertySchema(iface);
3555 LONG ref = InterlockedIncrement(&This->ref);
3557 TRACE("(%p) ref=%ld\n", This, ref);
3559 return ref;
3562 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3564 propschema *This = impl_from_IMimePropertySchema(iface);
3565 LONG ref = InterlockedDecrement(&This->ref);
3567 TRACE("(%p) ref=%ld\n", This, ref);
3569 if (!ref)
3571 free(This);
3574 return ref;
3577 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3578 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3580 propschema *This = impl_from_IMimePropertySchema(iface);
3581 FIXME("(%p)->(%s, %lx, %ld, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3582 return E_NOTIMPL;
3585 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3586 DWORD rownumber, VARTYPE vtdefault)
3588 propschema *This = impl_from_IMimePropertySchema(iface);
3589 FIXME("(%p)->(%s, %lx, %ld, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3590 return S_OK;
3593 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3595 propschema *This = impl_from_IMimePropertySchema(iface);
3596 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3597 return E_NOTIMPL;
3600 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3602 propschema *This = impl_from_IMimePropertySchema(iface);
3603 FIXME("(%p)->(%ld, %p) stub\n", This, propid, name);
3604 return E_NOTIMPL;
3607 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3609 propschema *This = impl_from_IMimePropertySchema(iface);
3610 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3611 return E_NOTIMPL;
3614 static IMimePropertySchemaVtbl prop_schema_vtbl =
3616 propschema_QueryInterface,
3617 propschema_AddRef,
3618 propschema_Release,
3619 propschema_RegisterProperty,
3620 propschema_ModifyProperty,
3621 propschema_GetPropertyId,
3622 propschema_GetPropertyName,
3623 propschema_RegisterAddressType
3627 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3629 propschema *This;
3631 TRACE("(%p) stub\n", schema);
3633 This = malloc(sizeof(*This));
3634 if (!This)
3635 return E_OUTOFMEMORY;
3637 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3638 This->ref = 1;
3640 *schema = &This->IMimePropertySchema_iface;
3642 return S_OK;
3645 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3646 ADDRESSFORMAT addr_format, WCHAR **address)
3648 FIXME("(%s, %p, %ld, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3650 return E_NOTIMPL;
3653 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
3655 FIXME("(%s %p)\n", debugstr_guid(riid), ppv);
3656 *ppv = NULL;
3657 return E_NOINTERFACE;
3660 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface)
3662 TRACE("\n");
3663 return 2;
3666 static ULONG WINAPI mime_obj_Release(IUnknown *iface)
3668 TRACE("\n");
3669 return 1;
3672 static const IUnknownVtbl mime_obj_vtbl = {
3673 mime_obj_QueryInterface,
3674 mime_obj_AddRef,
3675 mime_obj_Release
3678 static IUnknown mime_obj = { &mime_obj_vtbl };
3680 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3681 REFIID riid, void **out, IMoniker **moniker_new)
3683 WCHAR *display_name, *mhtml_url;
3684 size_t len;
3685 HRESULT hres;
3687 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3689 if(!IsEqualGUID(&IID_IUnknown, riid)) {
3690 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
3691 return E_NOINTERFACE;
3694 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name);
3695 if(FAILED(hres))
3696 return hres;
3698 TRACE("display name %s\n", debugstr_w(display_name));
3700 len = lstrlenW(display_name);
3701 mhtml_url = malloc(len * sizeof(WCHAR) + sizeof(L"mhtml:"));
3702 if(!mhtml_url)
3703 return E_OUTOFMEMORY;
3705 lstrcpyW(mhtml_url, L"mhtml:");
3706 lstrcatW(mhtml_url, display_name);
3707 CoTaskMemFree(display_name);
3709 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new);
3710 free(mhtml_url);
3711 if(FAILED(hres))
3712 return hres;
3714 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */
3715 *out = &mime_obj;
3716 return S_OK;