wbemprox: Tweak a comment.
[wine.git] / dlls / inetcomm / mimeole.c
blob681ca820d4882fa2e5f08e8f735e92b8f4e8c64c
1 /*
2 * MIME OLE Interfaces
4 * Copyright 2006 Robert Shearman for CodeWeavers
5 * Copyright 2007 Huw Davies for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include <stdarg.h>
26 #include <stdio.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "ole2.h"
33 #include "mimeole.h"
34 #include "propvarutil.h"
36 #include "wine/heap.h"
37 #include "wine/list.h"
38 #include "wine/debug.h"
39 #include "wine/unicode.h"
41 #include "inetcomm_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
45 typedef struct
47 LPCSTR name;
48 DWORD id;
49 DWORD flags; /* MIMEPROPFLAGS */
50 VARTYPE default_vt;
51 } property_t;
53 typedef struct
55 struct list entry;
56 property_t prop;
57 } property_list_entry_t;
59 static const property_t default_props[] =
61 {"X-Newsgroup", PID_HDR_NEWSGROUP, 0, VT_LPSTR},
62 {"Newsgroups", PID_HDR_NEWSGROUPS, 0, VT_LPSTR},
63 {"References", PID_HDR_REFS, 0, VT_LPSTR},
64 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
65 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
66 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
67 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
68 {"Rr", PID_HDR_RR, 0, VT_LPSTR},
69 {"Return-Receipt-To", PID_HDR_RETRCPTO, MPF_ADDRESS, VT_LPSTR},
70 {"Apparently-To", PID_HDR_APPARTO, MPF_ADDRESS, VT_LPSTR},
71 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
72 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
73 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
74 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
75 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
76 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
77 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
78 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
79 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
80 {"Content-Description", PID_HDR_CNTDESC, MPF_MIME, VT_LPSTR},
81 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
82 {"Content-Base", PID_HDR_CNTBASE, MPF_MIME, VT_LPSTR},
83 {"Content-Location", PID_HDR_CNTLOC, MPF_MIME, VT_LPSTR},
84 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
85 {"Path", PID_HDR_PATH, 0, VT_LPSTR},
86 {"Followup-To", PID_HDR_FOLLOWUPTO, 0, VT_LPSTR},
87 {"Expires", PID_HDR_EXPIRES, 0, VT_LPSTR},
88 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
89 {"Control", PID_HDR_CONTROL, 0, VT_LPSTR},
90 {"Distribution", PID_HDR_DISTRIB, 0, VT_LPSTR},
91 {"Keywords", PID_HDR_KEYWORDS, 0, VT_LPSTR},
92 {"Summary", PID_HDR_SUMMARY, 0, VT_LPSTR},
93 {"Approved", PID_HDR_APPROVED, 0, VT_LPSTR},
94 {"Lines", PID_HDR_LINES, 0, VT_LPSTR},
95 {"Xref", PID_HDR_XREF, 0, VT_LPSTR},
96 {"Organization", PID_HDR_ORG, 0, VT_LPSTR},
97 {"X-Newsreader", PID_HDR_XNEWSRDR, 0, VT_LPSTR},
98 {"X-Priority", PID_HDR_XPRI, 0, VT_LPSTR},
99 {"X-MSMail-Priority", PID_HDR_XMSPRI, 0, VT_LPSTR},
100 {"par:content-disposition:filename", PID_PAR_FILENAME, 0, VT_LPSTR},
101 {"par:content-type:boundary", PID_PAR_BOUNDARY, 0, VT_LPSTR},
102 {"par:content-type:charset", PID_PAR_CHARSET, 0, VT_LPSTR},
103 {"par:content-type:name", PID_PAR_NAME, 0, VT_LPSTR},
104 {"att:filename", PID_ATT_FILENAME, 0, VT_LPSTR},
105 {"att:pri-content-type", PID_ATT_PRITYPE, 0, VT_LPSTR},
106 {"att:sub-content-type", PID_ATT_SUBTYPE, 0, VT_LPSTR},
107 {"att:illegal-lines", PID_ATT_ILLEGAL, 0, VT_LPSTR},
108 {"att:rendered", PID_ATT_RENDERED, 0, VT_LPSTR},
109 {"att:sent-time", PID_ATT_SENTTIME, 0, VT_LPSTR},
110 {"att:priority", PID_ATT_PRIORITY, 0, VT_LPSTR},
111 {"Comment", PID_HDR_COMMENT, 0, VT_LPSTR},
112 {"Encoding", PID_HDR_ENCODING, 0, VT_LPSTR},
113 {"Encrypted", PID_HDR_ENCRYPTED, 0, VT_LPSTR},
114 {"X-Offsets", PID_HDR_OFFSETS, 0, VT_LPSTR},
115 {"X-Unsent", PID_HDR_XUNSENT, 0, VT_LPSTR},
116 {"X-ArticleId", PID_HDR_ARTICLEID, 0, VT_LPSTR},
117 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
118 {"att:athena-server", PID_ATT_SERVER, 0, VT_LPSTR},
119 {"att:athena-account-id", PID_ATT_ACCOUNT, 0, VT_LPSTR},
120 {"att:athena-pop3-uidl", PID_ATT_UIDL, 0, VT_LPSTR},
121 {"att:athena-store-msgid", PID_ATT_STOREMSGID, 0, VT_LPSTR},
122 {"att:athena-user-name", PID_ATT_USERNAME, 0, VT_LPSTR},
123 {"att:athena-forward-to", PID_ATT_FORWARDTO, 0, VT_LPSTR},
124 {"att:athena-store-fdrid", PID_ATT_STOREFOLDERID,0, VT_LPSTR},
125 {"att:athena-ghosted", PID_ATT_GHOSTED, 0, VT_LPSTR},
126 {"att:athena-uncachedsize", PID_ATT_UNCACHEDSIZE, 0, VT_LPSTR},
127 {"att:athena-combined", PID_ATT_COMBINED, 0, VT_LPSTR},
128 {"att:auto-inlined", PID_ATT_AUTOINLINED, 0, VT_LPSTR},
129 {"Disposition-Notification-To", PID_HDR_DISP_NOTIFICATION_TO, 0, VT_LPSTR},
130 {"par:Content-Type:reply-type", PID_PAR_REPLYTYPE, 0, VT_LPSTR},
131 {"par:Content-Type:format", PID_PAR_FORMAT , 0, VT_LPSTR},
132 {"att:format", PID_ATT_FORMAT , 0, VT_LPSTR},
133 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
134 {"att:athena-account-name", PID_ATT_ACCOUNTNAME, 0, VT_LPSTR},
135 {NULL, 0, 0, 0}
138 typedef struct
140 struct list entry;
141 char *name;
142 char *value;
143 } param_t;
145 typedef struct
147 struct list entry;
148 const property_t *prop;
149 PROPVARIANT value;
150 struct list params;
151 } header_t;
153 typedef struct MimeBody
155 IMimeBody IMimeBody_iface;
156 LONG ref;
158 HBODY handle;
160 struct list headers;
161 struct list new_props; /* FIXME: This should be in a PropertySchema */
162 DWORD next_prop_id;
163 char *content_pri_type;
164 char *content_sub_type;
165 ENCODINGTYPE encoding;
166 void *data;
167 IID data_iid;
168 BODYOFFSETS body_offsets;
169 } MimeBody;
171 typedef struct
173 IStream IStream_iface;
174 LONG ref;
175 IStream *base;
176 ULARGE_INTEGER pos, start, length;
177 } sub_stream_t;
179 static inline sub_stream_t *impl_from_IStream(IStream *iface)
181 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
184 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
186 sub_stream_t *This = impl_from_IStream(iface);
188 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
189 *ppv = NULL;
191 if(IsEqualIID(riid, &IID_IUnknown) ||
192 IsEqualIID(riid, &IID_ISequentialStream) ||
193 IsEqualIID(riid, &IID_IStream))
195 IStream_AddRef(iface);
196 *ppv = iface;
197 return S_OK;
199 return E_NOINTERFACE;
202 static ULONG WINAPI sub_stream_AddRef(IStream *iface)
204 sub_stream_t *This = impl_from_IStream(iface);
205 LONG ref = InterlockedIncrement(&This->ref);
207 TRACE("(%p) ref=%d\n", This, ref);
209 return ref;
212 static ULONG WINAPI sub_stream_Release(IStream *iface)
214 sub_stream_t *This = impl_from_IStream(iface);
215 LONG ref = InterlockedDecrement(&This->ref);
217 TRACE("(%p) ref=%d\n", This, ref);
219 if(!ref)
221 IStream_Release(This->base);
222 HeapFree(GetProcessHeap(), 0, This);
224 return ref;
227 static HRESULT WINAPI sub_stream_Read(
228 IStream* iface,
229 void *pv,
230 ULONG cb,
231 ULONG *pcbRead)
233 sub_stream_t *This = impl_from_IStream(iface);
234 HRESULT hr;
235 LARGE_INTEGER tmp_pos;
237 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
239 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
240 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
242 if(This->pos.QuadPart + cb > This->length.QuadPart)
243 cb = This->length.QuadPart - This->pos.QuadPart;
245 hr = IStream_Read(This->base, pv, cb, pcbRead);
247 This->pos.QuadPart += *pcbRead;
249 return hr;
252 static HRESULT WINAPI sub_stream_Write(
253 IStream* iface,
254 const void *pv,
255 ULONG cb,
256 ULONG *pcbWritten)
258 FIXME("stub\n");
259 return E_NOTIMPL;
262 static HRESULT WINAPI sub_stream_Seek(
263 IStream* iface,
264 LARGE_INTEGER dlibMove,
265 DWORD dwOrigin,
266 ULARGE_INTEGER *plibNewPosition)
268 sub_stream_t *This = impl_from_IStream(iface);
269 LARGE_INTEGER new_pos;
271 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
273 switch(dwOrigin)
275 case STREAM_SEEK_SET:
276 new_pos = dlibMove;
277 break;
278 case STREAM_SEEK_CUR:
279 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
280 break;
281 case STREAM_SEEK_END:
282 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
283 break;
284 default:
285 return STG_E_INVALIDFUNCTION;
288 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
289 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
291 This->pos.QuadPart = new_pos.QuadPart;
293 if(plibNewPosition) *plibNewPosition = This->pos;
294 return S_OK;
297 static HRESULT WINAPI sub_stream_SetSize(
298 IStream* iface,
299 ULARGE_INTEGER libNewSize)
301 FIXME("stub\n");
302 return E_NOTIMPL;
305 static HRESULT WINAPI sub_stream_CopyTo(
306 IStream* iface,
307 IStream *pstm,
308 ULARGE_INTEGER cb,
309 ULARGE_INTEGER *pcbRead,
310 ULARGE_INTEGER *pcbWritten)
312 HRESULT hr = S_OK;
313 BYTE tmpBuffer[128];
314 ULONG bytesRead, bytesWritten, copySize;
315 ULARGE_INTEGER totalBytesRead;
316 ULARGE_INTEGER totalBytesWritten;
318 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
320 totalBytesRead.QuadPart = 0;
321 totalBytesWritten.QuadPart = 0;
323 while ( cb.QuadPart > 0 )
325 if ( cb.QuadPart >= sizeof(tmpBuffer) )
326 copySize = sizeof(tmpBuffer);
327 else
328 copySize = cb.u.LowPart;
330 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
331 if (FAILED(hr)) break;
333 totalBytesRead.QuadPart += bytesRead;
335 if (bytesRead)
337 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
338 if (FAILED(hr)) break;
339 totalBytesWritten.QuadPart += bytesWritten;
342 if (bytesRead != copySize)
343 cb.QuadPart = 0;
344 else
345 cb.QuadPart -= bytesRead;
348 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
349 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
351 return hr;
354 static HRESULT WINAPI sub_stream_Commit(
355 IStream* iface,
356 DWORD grfCommitFlags)
358 FIXME("stub\n");
359 return E_NOTIMPL;
362 static HRESULT WINAPI sub_stream_Revert(
363 IStream* iface)
365 FIXME("stub\n");
366 return E_NOTIMPL;
369 static HRESULT WINAPI sub_stream_LockRegion(
370 IStream* iface,
371 ULARGE_INTEGER libOffset,
372 ULARGE_INTEGER cb,
373 DWORD dwLockType)
375 FIXME("stub\n");
376 return E_NOTIMPL;
379 static HRESULT WINAPI sub_stream_UnlockRegion(
380 IStream* iface,
381 ULARGE_INTEGER libOffset,
382 ULARGE_INTEGER cb,
383 DWORD dwLockType)
385 FIXME("stub\n");
386 return E_NOTIMPL;
389 static HRESULT WINAPI sub_stream_Stat(
390 IStream* iface,
391 STATSTG *pstatstg,
392 DWORD grfStatFlag)
394 sub_stream_t *This = impl_from_IStream(iface);
395 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
396 memset(pstatstg, 0, sizeof(*pstatstg));
397 pstatstg->cbSize = This->length;
398 return S_OK;
401 static HRESULT WINAPI sub_stream_Clone(
402 IStream* iface,
403 IStream **ppstm)
405 FIXME("stub\n");
406 return E_NOTIMPL;
409 static struct IStreamVtbl sub_stream_vtbl =
411 sub_stream_QueryInterface,
412 sub_stream_AddRef,
413 sub_stream_Release,
414 sub_stream_Read,
415 sub_stream_Write,
416 sub_stream_Seek,
417 sub_stream_SetSize,
418 sub_stream_CopyTo,
419 sub_stream_Commit,
420 sub_stream_Revert,
421 sub_stream_LockRegion,
422 sub_stream_UnlockRegion,
423 sub_stream_Stat,
424 sub_stream_Clone
427 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
429 sub_stream_t *This;
431 *out = NULL;
432 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
433 if(!This) return E_OUTOFMEMORY;
435 This->IStream_iface.lpVtbl = &sub_stream_vtbl;
436 This->ref = 1;
437 This->start = start;
438 This->length = length;
439 This->pos.QuadPart = 0;
440 IStream_AddRef(stream);
441 This->base = stream;
443 *out = &This->IStream_iface;
444 return S_OK;
447 static HRESULT get_stream_size(IStream *stream, ULARGE_INTEGER *size)
449 STATSTG statstg = {NULL};
450 LARGE_INTEGER zero;
451 HRESULT hres;
453 hres = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
454 if(SUCCEEDED(hres)) {
455 *size = statstg.cbSize;
456 return S_OK;
459 zero.QuadPart = 0;
460 return IStream_Seek(stream, zero, STREAM_SEEK_END, size);
463 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
465 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
468 typedef struct propschema
470 IMimePropertySchema IMimePropertySchema_iface;
471 LONG ref;
472 } propschema;
474 static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
476 return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
479 static LPSTR strdupA(LPCSTR str)
481 char *ret;
482 int len = strlen(str);
483 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
484 memcpy(ret, str, len + 1);
485 return ret;
488 #define PARSER_BUF_SIZE 1024
490 /*****************************************************
491 * copy_headers_to_buf [internal]
493 * Copies the headers into a '\0' terminated memory block and leave
494 * the stream's current position set to after the blank line.
496 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
498 char *buf = NULL;
499 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
500 HRESULT hr;
501 BOOL done = FALSE;
503 *ptr = NULL;
507 char *end;
508 DWORD read;
510 if(!buf)
511 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
512 else
514 size *= 2;
515 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
517 if(!buf)
519 hr = E_OUTOFMEMORY;
520 goto fail;
523 hr = IStream_Read(stm, buf + offset, size - offset, &read);
524 if(FAILED(hr)) goto fail;
526 offset += read;
527 buf[offset] = '\0';
529 if(read == 0) done = TRUE;
531 while(!done && (end = strstr(buf + last_end, "\r\n")))
533 DWORD new_end = end - buf + 2;
534 if(new_end - last_end == 2)
536 LARGE_INTEGER off;
537 off.QuadPart = (LONGLONG)new_end - offset;
538 IStream_Seek(stm, off, STREAM_SEEK_CUR, NULL);
539 buf[new_end] = '\0';
540 done = TRUE;
542 else
543 last_end = new_end;
545 } while(!done);
547 *ptr = buf;
548 return S_OK;
550 fail:
551 HeapFree(GetProcessHeap(), 0, buf);
552 return hr;
555 static header_t *read_prop(MimeBody *body, char **ptr)
557 char *colon = strchr(*ptr, ':');
558 const property_t *prop;
559 header_t *ret;
561 if(!colon) return NULL;
563 *colon = '\0';
565 for(prop = default_props; prop->name; prop++)
567 if(!lstrcmpiA(*ptr, prop->name))
569 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
570 break;
574 if(!prop->name)
576 property_list_entry_t *prop_entry;
577 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
579 if(!lstrcmpiA(*ptr, prop_entry->prop.name))
581 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
582 prop = &prop_entry->prop;
583 break;
586 if(!prop->name)
588 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
589 prop_entry->prop.name = strdupA(*ptr);
590 prop_entry->prop.id = body->next_prop_id++;
591 prop_entry->prop.flags = 0;
592 prop_entry->prop.default_vt = VT_LPSTR;
593 list_add_tail(&body->new_props, &prop_entry->entry);
594 prop = &prop_entry->prop;
595 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
599 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
600 ret->prop = prop;
601 PropVariantInit(&ret->value);
602 list_init(&ret->params);
603 *ptr = colon + 1;
605 return ret;
608 static void unfold_header(char *header, int len)
610 char *start = header, *cp = header;
612 do {
613 while(*cp == ' ' || *cp == '\t')
615 cp++;
616 len--;
618 if(cp != start)
619 memmove(start, cp, len + 1);
621 cp = strstr(start, "\r\n");
622 len -= (cp - start);
623 start = cp;
624 *start = ' ';
625 start++;
626 len--;
627 cp += 2;
628 } while(*cp == ' ' || *cp == '\t');
630 *(start - 1) = '\0';
633 static char *unquote_string(const char *str)
635 BOOL quoted = FALSE;
636 char *ret, *cp;
638 while(*str == ' ' || *str == '\t') str++;
640 if(*str == '"')
642 quoted = TRUE;
643 str++;
645 ret = strdupA(str);
646 for(cp = ret; *cp; cp++)
648 if(*cp == '\\')
649 memmove(cp, cp + 1, strlen(cp + 1) + 1);
650 else if(*cp == '"')
652 if(!quoted)
654 WARN("quote in unquoted string\n");
656 else
658 *cp = '\0';
659 break;
663 return ret;
666 static void add_param(header_t *header, const char *p)
668 const char *key = p, *value, *cp = p;
669 param_t *param;
670 char *name;
672 TRACE("got param %s\n", p);
674 while (*key == ' ' || *key == '\t' ) key++;
676 cp = strchr(key, '=');
677 if(!cp)
679 WARN("malformed parameter - skipping\n");
680 return;
683 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
684 memcpy(name, key, cp - key);
685 name[cp - key] = '\0';
687 value = cp + 1;
689 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
690 param->name = name;
691 param->value = unquote_string(value);
692 list_add_tail(&header->params, &param->entry);
695 static void split_params(header_t *header, char *value)
697 char *cp = value, *start = value;
698 BOOL in_quotes = FALSE, done_value = FALSE;
700 while(*cp)
702 if(!in_quotes && *cp == ';')
704 *cp = '\0';
705 if(done_value) add_param(header, start);
706 done_value = TRUE;
707 start = cp + 1;
709 else if(*cp == '"')
710 in_quotes = !in_quotes;
711 cp++;
713 if(done_value) add_param(header, start);
716 static void read_value(header_t *header, char **cur)
718 char *end = *cur, *value;
719 DWORD len;
721 do {
722 end = strstr(end, "\r\n");
723 end += 2;
724 } while(*end == ' ' || *end == '\t');
726 len = end - *cur;
727 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
728 memcpy(value, *cur, len);
729 value[len] = '\0';
731 unfold_header(value, len);
732 TRACE("value %s\n", debugstr_a(value));
734 if(header->prop->flags & MPF_HASPARAMS)
736 split_params(header, value);
737 TRACE("value w/o params %s\n", debugstr_a(value));
740 header->value.vt = VT_LPSTR;
741 header->value.u.pszVal = value;
743 *cur = end;
746 static void init_content_type(MimeBody *body, header_t *header)
748 char *slash;
749 DWORD len;
751 slash = strchr(header->value.u.pszVal, '/');
752 if(!slash)
754 WARN("malformed context type value\n");
755 return;
757 len = slash - header->value.u.pszVal;
758 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
759 memcpy(body->content_pri_type, header->value.u.pszVal, len);
760 body->content_pri_type[len] = '\0';
761 body->content_sub_type = strdupA(slash + 1);
764 static void init_content_encoding(MimeBody *body, header_t *header)
766 const char *encoding = header->value.u.pszVal;
768 if(!strcasecmp(encoding, "base64"))
769 body->encoding = IET_BASE64;
770 else if(!strcasecmp(encoding, "quoted-printable"))
771 body->encoding = IET_QP;
772 else if(!strcasecmp(encoding, "7bit"))
773 body->encoding = IET_7BIT;
774 else if(!strcasecmp(encoding, "8bit"))
775 body->encoding = IET_8BIT;
776 else
777 FIXME("unknown encoding %s\n", debugstr_a(encoding));
780 static HRESULT parse_headers(MimeBody *body, IStream *stm)
782 char *header_buf, *cur_header_ptr;
783 HRESULT hr;
784 header_t *header;
786 hr = copy_headers_to_buf(stm, &header_buf);
787 if(FAILED(hr)) return hr;
789 cur_header_ptr = header_buf;
790 while((header = read_prop(body, &cur_header_ptr)))
792 read_value(header, &cur_header_ptr);
793 list_add_tail(&body->headers, &header->entry);
795 switch(header->prop->id) {
796 case PID_HDR_CNTTYPE:
797 init_content_type(body, header);
798 break;
799 case PID_HDR_CNTXFER:
800 init_content_encoding(body, header);
801 break;
805 HeapFree(GetProcessHeap(), 0, header_buf);
806 return hr;
809 static void empty_param_list(struct list *list)
811 param_t *param, *cursor2;
813 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
815 list_remove(&param->entry);
816 HeapFree(GetProcessHeap(), 0, param->name);
817 HeapFree(GetProcessHeap(), 0, param->value);
818 HeapFree(GetProcessHeap(), 0, param);
822 static void empty_header_list(struct list *list)
824 header_t *header, *cursor2;
826 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
828 list_remove(&header->entry);
829 PropVariantClear(&header->value);
830 empty_param_list(&header->params);
831 HeapFree(GetProcessHeap(), 0, header);
835 static void empty_new_prop_list(struct list *list)
837 property_list_entry_t *prop, *cursor2;
839 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
841 list_remove(&prop->entry);
842 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
843 HeapFree(GetProcessHeap(), 0, prop);
847 static void release_data(REFIID riid, void *data)
849 if(!data) return;
851 if(IsEqualIID(riid, &IID_IStream))
852 IStream_Release((IStream *)data);
853 else
854 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
857 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
859 header_t *header;
861 *prop = NULL;
863 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
865 if(ISPIDSTR(name))
867 if(STRTOPID(name) == header->prop->id)
869 *prop = header;
870 return S_OK;
873 else if(!lstrcmpiA(name, header->prop->name))
875 *prop = header;
876 return S_OK;
880 return MIME_E_NOT_FOUND;
883 static const property_t *find_default_prop(const char *name)
885 const property_t *prop_def = NULL;
887 for(prop_def = default_props; prop_def->name; prop_def++)
889 if(ISPIDSTR(name))
891 if(STRTOPID(name) == prop_def->id)
893 break;
896 else if(!lstrcmpiA(name, prop_def->name))
898 break;
902 if(prop_def->id)
903 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
904 else
905 prop_def = NULL;
907 return prop_def;
910 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
911 REFIID riid,
912 void** ppvObject)
914 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
916 *ppvObject = NULL;
918 if (IsEqualIID(riid, &IID_IUnknown) ||
919 IsEqualIID(riid, &IID_IPersist) ||
920 IsEqualIID(riid, &IID_IPersistStreamInit) ||
921 IsEqualIID(riid, &IID_IMimePropertySet) ||
922 IsEqualIID(riid, &IID_IMimeBody))
924 *ppvObject = iface;
927 if(*ppvObject)
929 IUnknown_AddRef((IUnknown*)*ppvObject);
930 return S_OK;
933 FIXME("no interface for %s\n", debugstr_guid(riid));
934 return E_NOINTERFACE;
937 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
939 MimeBody *This = impl_from_IMimeBody(iface);
940 LONG ref = InterlockedIncrement(&This->ref);
942 TRACE("(%p) ref=%d\n", This, ref);
944 return ref;
947 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
949 MimeBody *This = impl_from_IMimeBody(iface);
950 LONG ref = InterlockedDecrement(&This->ref);
952 TRACE("(%p) ref=%d\n", This, ref);
954 if (!ref)
956 empty_header_list(&This->headers);
957 empty_new_prop_list(&This->new_props);
959 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
960 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
962 release_data(&This->data_iid, This->data);
964 HeapFree(GetProcessHeap(), 0, This);
967 return ref;
970 static HRESULT WINAPI MimeBody_GetClassID(
971 IMimeBody* iface,
972 CLSID* pClassID)
974 MimeBody *This = impl_from_IMimeBody(iface);
976 TRACE("(%p)->(%p)\n", This, pClassID);
978 if(!pClassID)
979 return E_INVALIDARG;
981 *pClassID = IID_IMimeBody;
982 return S_OK;
985 static HRESULT WINAPI MimeBody_IsDirty(
986 IMimeBody* iface)
988 MimeBody *This = impl_from_IMimeBody(iface);
989 FIXME("(%p)->() stub\n", This);
990 return E_NOTIMPL;
993 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
995 MimeBody *This = impl_from_IMimeBody(iface);
996 TRACE("(%p)->(%p)\n", This, pStm);
997 return parse_headers(This, pStm);
1000 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
1002 MimeBody *This = impl_from_IMimeBody(iface);
1003 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
1004 return E_NOTIMPL;
1007 static HRESULT WINAPI MimeBody_GetSizeMax(
1008 IMimeBody* iface,
1009 ULARGE_INTEGER* pcbSize)
1011 MimeBody *This = impl_from_IMimeBody(iface);
1012 FIXME("(%p)->(%p) stub\n", This, pcbSize);
1013 return E_NOTIMPL;
1016 static HRESULT WINAPI MimeBody_InitNew(
1017 IMimeBody* iface)
1019 MimeBody *This = impl_from_IMimeBody(iface);
1020 TRACE("(%p)->()\n", This);
1021 return S_OK;
1024 static HRESULT WINAPI MimeBody_GetPropInfo(
1025 IMimeBody* iface,
1026 LPCSTR pszName,
1027 LPMIMEPROPINFO pInfo)
1029 MimeBody *This = impl_from_IMimeBody(iface);
1030 header_t *header;
1031 HRESULT hr;
1032 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1034 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1036 if(!pszName || !pInfo)
1037 return E_INVALIDARG;
1039 TRACE("mask 0x%04x\n", pInfo->dwMask);
1041 if(pInfo->dwMask & ~supported)
1042 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
1044 hr = find_prop(This, pszName, &header);
1045 if(hr == S_OK)
1047 if(pInfo->dwMask & PIM_CHARSET)
1048 pInfo->hCharset = 0;
1049 if(pInfo->dwMask & PIM_FLAGS)
1050 pInfo->dwFlags = 0x00000000;
1051 if(pInfo->dwMask & PIM_ROWNUMBER)
1052 pInfo->dwRowNumber = 0;
1053 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1054 pInfo->ietEncoding = 0;
1055 if(pInfo->dwMask & PIM_VALUES)
1056 pInfo->cValues = 0;
1057 if(pInfo->dwMask & PIM_PROPID)
1058 pInfo->dwPropId = header->prop->id;
1059 if(pInfo->dwMask & PIM_VTDEFAULT)
1060 pInfo->vtDefault = header->prop->default_vt;
1061 if(pInfo->dwMask & PIM_VTCURRENT)
1062 pInfo->vtCurrent = 0;
1065 return hr;
1068 static HRESULT WINAPI MimeBody_SetPropInfo(
1069 IMimeBody* iface,
1070 LPCSTR pszName,
1071 LPCMIMEPROPINFO pInfo)
1073 MimeBody *This = impl_from_IMimeBody(iface);
1074 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1075 return E_NOTIMPL;
1078 static HRESULT WINAPI MimeBody_GetProp(
1079 IMimeBody* iface,
1080 LPCSTR pszName,
1081 DWORD dwFlags,
1082 LPPROPVARIANT pValue)
1084 MimeBody *This = impl_from_IMimeBody(iface);
1085 header_t *header;
1086 HRESULT hr;
1088 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1090 if(!pszName || !pValue)
1091 return E_INVALIDARG;
1093 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1095 PropVariantClear(pValue);
1096 pValue->vt = VT_LPSTR;
1097 pValue->u.pszVal = strdupA(This->content_pri_type);
1098 return S_OK;
1101 hr = find_prop(This, pszName, &header);
1102 if(hr == S_OK)
1104 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1106 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1107 if(FAILED(hr))
1108 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1111 return hr;
1114 static HRESULT WINAPI MimeBody_SetProp(
1115 IMimeBody* iface,
1116 LPCSTR pszName,
1117 DWORD dwFlags,
1118 LPCPROPVARIANT pValue)
1120 MimeBody *This = impl_from_IMimeBody(iface);
1121 header_t *header;
1122 HRESULT hr;
1124 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1126 if(!pszName || !pValue)
1127 return E_INVALIDARG;
1129 hr = find_prop(This, pszName, &header);
1130 if(hr != S_OK)
1132 property_list_entry_t *prop_entry;
1133 const property_t *prop = NULL;
1135 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1137 if(ISPIDSTR(pszName))
1139 if(STRTOPID(pszName) == prop_entry->prop.id)
1141 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1142 prop = &prop_entry->prop;
1143 break;
1146 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1148 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1149 prop = &prop_entry->prop;
1150 break;
1154 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
1155 if(!header)
1156 return E_OUTOFMEMORY;
1158 if(!prop)
1160 const property_t *prop_def = NULL;
1161 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
1162 if(!prop_entry)
1164 HeapFree(GetProcessHeap(), 0, header);
1165 return E_OUTOFMEMORY;
1168 prop_def = find_default_prop(pszName);
1169 if(prop_def)
1171 prop_entry->prop.name = strdupA(prop_def->name);
1172 prop_entry->prop.id = prop_def->id;
1174 else
1176 if(ISPIDSTR(pszName))
1178 HeapFree(GetProcessHeap(), 0, prop_entry);
1179 HeapFree(GetProcessHeap(), 0, header);
1180 return MIME_E_NOT_FOUND;
1183 prop_entry->prop.name = strdupA(pszName);
1184 prop_entry->prop.id = This->next_prop_id++;
1187 prop_entry->prop.flags = 0;
1188 prop_entry->prop.default_vt = pValue->vt;
1189 list_add_tail(&This->new_props, &prop_entry->entry);
1190 prop = &prop_entry->prop;
1191 TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
1194 header->prop = prop;
1195 PropVariantInit(&header->value);
1196 list_init(&header->params);
1197 list_add_tail(&This->headers, &header->entry);
1200 PropVariantCopy(&header->value, pValue);
1202 return S_OK;
1205 static HRESULT WINAPI MimeBody_AppendProp(
1206 IMimeBody* iface,
1207 LPCSTR pszName,
1208 DWORD dwFlags,
1209 LPPROPVARIANT pValue)
1211 MimeBody *This = impl_from_IMimeBody(iface);
1212 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1213 return E_NOTIMPL;
1216 static HRESULT WINAPI MimeBody_DeleteProp(
1217 IMimeBody* iface,
1218 LPCSTR pszName)
1220 MimeBody *This = impl_from_IMimeBody(iface);
1221 header_t *cursor;
1222 BOOL found;
1224 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1226 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1228 if(ISPIDSTR(pszName))
1229 found = STRTOPID(pszName) == cursor->prop->id;
1230 else
1231 found = !lstrcmpiA(pszName, cursor->prop->name);
1233 if(found)
1235 list_remove(&cursor->entry);
1236 HeapFree(GetProcessHeap(), 0, cursor);
1237 return S_OK;
1241 return MIME_E_NOT_FOUND;
1244 static HRESULT WINAPI MimeBody_CopyProps(
1245 IMimeBody* iface,
1246 ULONG cNames,
1247 LPCSTR* prgszName,
1248 IMimePropertySet* pPropertySet)
1250 MimeBody *This = impl_from_IMimeBody(iface);
1251 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1252 return E_NOTIMPL;
1255 static HRESULT WINAPI MimeBody_MoveProps(
1256 IMimeBody* iface,
1257 ULONG cNames,
1258 LPCSTR* prgszName,
1259 IMimePropertySet* pPropertySet)
1261 MimeBody *This = impl_from_IMimeBody(iface);
1262 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1263 return E_NOTIMPL;
1266 static HRESULT WINAPI MimeBody_DeleteExcept(
1267 IMimeBody* iface,
1268 ULONG cNames,
1269 LPCSTR* prgszName)
1271 MimeBody *This = impl_from_IMimeBody(iface);
1272 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
1273 return E_NOTIMPL;
1276 static HRESULT WINAPI MimeBody_QueryProp(
1277 IMimeBody* iface,
1278 LPCSTR pszName,
1279 LPCSTR pszCriteria,
1280 boolean fSubString,
1281 boolean fCaseSensitive)
1283 MimeBody *This = impl_from_IMimeBody(iface);
1284 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1285 return E_NOTIMPL;
1288 static HRESULT WINAPI MimeBody_GetCharset(
1289 IMimeBody* iface,
1290 LPHCHARSET phCharset)
1292 MimeBody *This = impl_from_IMimeBody(iface);
1293 FIXME("(%p)->(%p) stub\n", This, phCharset);
1294 *phCharset = NULL;
1295 return S_OK;
1298 static HRESULT WINAPI MimeBody_SetCharset(
1299 IMimeBody* iface,
1300 HCHARSET hCharset,
1301 CSETAPPLYTYPE applytype)
1303 MimeBody *This = impl_from_IMimeBody(iface);
1304 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1305 return E_NOTIMPL;
1308 static HRESULT WINAPI MimeBody_GetParameters(
1309 IMimeBody* iface,
1310 LPCSTR pszName,
1311 ULONG* pcParams,
1312 LPMIMEPARAMINFO* pprgParam)
1314 MimeBody *This = impl_from_IMimeBody(iface);
1315 HRESULT hr;
1316 header_t *header;
1318 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1320 *pprgParam = NULL;
1321 *pcParams = 0;
1323 hr = find_prop(This, pszName, &header);
1324 if(hr != S_OK) return hr;
1326 *pcParams = list_count(&header->params);
1327 if(*pcParams)
1329 IMimeAllocator *alloc;
1330 param_t *param;
1331 MIMEPARAMINFO *info;
1333 MimeOleGetAllocator(&alloc);
1335 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1336 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1338 int len;
1340 len = strlen(param->name) + 1;
1341 info->pszName = IMimeAllocator_Alloc(alloc, len);
1342 memcpy(info->pszName, param->name, len);
1343 len = strlen(param->value) + 1;
1344 info->pszData = IMimeAllocator_Alloc(alloc, len);
1345 memcpy(info->pszData, param->value, len);
1346 info++;
1348 IMimeAllocator_Release(alloc);
1350 return S_OK;
1353 static HRESULT WINAPI MimeBody_IsContentType(
1354 IMimeBody* iface,
1355 LPCSTR pszPriType,
1356 LPCSTR pszSubType)
1358 MimeBody *This = impl_from_IMimeBody(iface);
1360 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1361 if(pszPriType)
1363 const char *pri = This->content_pri_type;
1364 if(!pri) pri = "text";
1365 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1368 if(pszSubType)
1370 const char *sub = This->content_sub_type;
1371 if(!sub) sub = "plain";
1372 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1375 return S_OK;
1378 static HRESULT WINAPI MimeBody_BindToObject(
1379 IMimeBody* iface,
1380 REFIID riid,
1381 void** ppvObject)
1383 MimeBody *This = impl_from_IMimeBody(iface);
1384 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1385 return E_NOTIMPL;
1388 static HRESULT WINAPI MimeBody_Clone(
1389 IMimeBody* iface,
1390 IMimePropertySet** ppPropertySet)
1392 MimeBody *This = impl_from_IMimeBody(iface);
1393 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1394 return E_NOTIMPL;
1397 static HRESULT WINAPI MimeBody_SetOption(
1398 IMimeBody* iface,
1399 const TYPEDID oid,
1400 LPCPROPVARIANT pValue)
1402 MimeBody *This = impl_from_IMimeBody(iface);
1403 HRESULT hr = E_NOTIMPL;
1404 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
1406 if(pValue->vt != TYPEDID_TYPE(oid))
1408 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
1409 return E_INVALIDARG;
1412 switch(oid)
1414 case OID_SECURITY_HWND_OWNER:
1415 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
1416 hr = S_OK;
1417 break;
1418 case OID_TRANSMIT_BODY_ENCODING:
1419 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
1420 hr = S_OK;
1421 break;
1422 default:
1423 FIXME("Unhandled oid %08x\n", oid);
1426 return hr;
1429 static HRESULT WINAPI MimeBody_GetOption(
1430 IMimeBody* iface,
1431 const TYPEDID oid,
1432 LPPROPVARIANT pValue)
1434 MimeBody *This = impl_from_IMimeBody(iface);
1435 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
1436 return E_NOTIMPL;
1439 static HRESULT WINAPI MimeBody_EnumProps(
1440 IMimeBody* iface,
1441 DWORD dwFlags,
1442 IMimeEnumProperties** ppEnum)
1444 MimeBody *This = impl_from_IMimeBody(iface);
1445 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
1446 return E_NOTIMPL;
1449 static HRESULT WINAPI MimeBody_IsType(
1450 IMimeBody* iface,
1451 IMSGBODYTYPE bodytype)
1453 MimeBody *This = impl_from_IMimeBody(iface);
1455 TRACE("(%p)->(%d)\n", This, bodytype);
1456 switch(bodytype)
1458 case IBT_EMPTY:
1459 return This->data ? S_FALSE : S_OK;
1460 default:
1461 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1463 return S_OK;
1466 static HRESULT WINAPI MimeBody_SetDisplayName(
1467 IMimeBody* iface,
1468 LPCSTR pszDisplay)
1470 MimeBody *This = impl_from_IMimeBody(iface);
1471 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1472 return E_NOTIMPL;
1475 static HRESULT WINAPI MimeBody_GetDisplayName(
1476 IMimeBody* iface,
1477 LPSTR* ppszDisplay)
1479 MimeBody *This = impl_from_IMimeBody(iface);
1480 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1481 return E_NOTIMPL;
1484 static HRESULT WINAPI MimeBody_GetOffsets(
1485 IMimeBody* iface,
1486 LPBODYOFFSETS pOffsets)
1488 MimeBody *This = impl_from_IMimeBody(iface);
1489 TRACE("(%p)->(%p)\n", This, pOffsets);
1491 *pOffsets = This->body_offsets;
1493 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1494 return S_OK;
1497 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1498 IMimeBody* iface,
1499 ENCODINGTYPE* pietEncoding)
1501 MimeBody *This = impl_from_IMimeBody(iface);
1503 TRACE("(%p)->(%p)\n", This, pietEncoding);
1505 *pietEncoding = This->encoding;
1506 return S_OK;
1509 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1510 IMimeBody* iface,
1511 ENCODINGTYPE ietEncoding)
1513 MimeBody *This = impl_from_IMimeBody(iface);
1515 TRACE("(%p)->(%d)\n", This, ietEncoding);
1517 This->encoding = ietEncoding;
1518 return S_OK;
1521 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1522 IMimeBody* iface,
1523 ENCODINGTYPE ietEncoding,
1524 ULONG* pcbSize)
1526 MimeBody *This = impl_from_IMimeBody(iface);
1527 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1528 return E_NOTIMPL;
1531 static HRESULT WINAPI MimeBody_GetDataHere(
1532 IMimeBody* iface,
1533 ENCODINGTYPE ietEncoding,
1534 IStream* pStream)
1536 MimeBody *This = impl_from_IMimeBody(iface);
1537 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1538 return E_NOTIMPL;
1541 static const signed char base64_decode_table[] =
1543 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1544 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1545 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1546 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1547 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1548 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1549 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1550 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1553 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1555 const unsigned char *ptr, *end;
1556 unsigned char buf[1024];
1557 LARGE_INTEGER pos;
1558 unsigned char *ret;
1559 unsigned char in[4];
1560 IStream *output;
1561 DWORD size;
1562 int n = 0;
1563 HRESULT hres;
1565 pos.QuadPart = 0;
1566 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1567 if(FAILED(hres))
1568 return hres;
1570 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1571 if(FAILED(hres))
1572 return hres;
1574 while(1) {
1575 hres = IStream_Read(input, buf, sizeof(buf), &size);
1576 if(FAILED(hres) || !size)
1577 break;
1579 ptr = ret = buf;
1580 end = buf + size;
1582 while(1) {
1583 /* skip invalid chars */
1584 while(ptr < end &&
1585 (*ptr >= sizeof(base64_decode_table)/sizeof(*base64_decode_table)
1586 || base64_decode_table[*ptr] == -1))
1587 ptr++;
1588 if(ptr == end)
1589 break;
1591 in[n++] = base64_decode_table[*ptr++];
1592 switch(n) {
1593 case 2:
1594 *ret++ = in[0] << 2 | in[1] >> 4;
1595 continue;
1596 case 3:
1597 *ret++ = in[1] << 4 | in[2] >> 2;
1598 continue;
1599 case 4:
1600 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1601 n = 0;
1605 if(ret > buf) {
1606 hres = IStream_Write(output, buf, ret - buf, NULL);
1607 if(FAILED(hres))
1608 break;
1612 if(SUCCEEDED(hres))
1613 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1614 if(FAILED(hres)) {
1615 IStream_Release(output);
1616 return hres;
1619 *ret_stream = output;
1620 return S_OK;
1623 static int hex_digit(char c)
1625 if('0' <= c && c <= '9')
1626 return c - '0';
1627 if('A' <= c && c <= 'F')
1628 return c - 'A' + 10;
1629 if('a' <= c && c <= 'f')
1630 return c - 'a' + 10;
1631 return -1;
1634 static HRESULT decode_qp(IStream *input, IStream **ret_stream)
1636 const unsigned char *ptr, *end;
1637 unsigned char *ret, prev = 0;
1638 unsigned char buf[1024];
1639 LARGE_INTEGER pos;
1640 IStream *output;
1641 DWORD size;
1642 int n = -1;
1643 HRESULT hres;
1645 pos.QuadPart = 0;
1646 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1647 if(FAILED(hres))
1648 return hres;
1650 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1651 if(FAILED(hres))
1652 return hres;
1654 while(1) {
1655 hres = IStream_Read(input, buf, sizeof(buf), &size);
1656 if(FAILED(hres) || !size)
1657 break;
1659 ptr = ret = buf;
1660 end = buf + size;
1662 while(ptr < end) {
1663 unsigned char byte = *ptr++;
1665 switch(n) {
1666 case -1:
1667 if(byte == '=')
1668 n = 0;
1669 else
1670 *ret++ = byte;
1671 continue;
1672 case 0:
1673 prev = byte;
1674 n = 1;
1675 continue;
1676 case 1:
1677 if(prev != '\r' || byte != '\n') {
1678 int h1 = hex_digit(prev), h2 = hex_digit(byte);
1679 if(h1 != -1 && h2 != -1)
1680 *ret++ = (h1 << 4) | h2;
1681 else
1682 *ret++ = '=';
1684 n = -1;
1685 continue;
1689 if(ret > buf) {
1690 hres = IStream_Write(output, buf, ret - buf, NULL);
1691 if(FAILED(hres))
1692 break;
1696 if(SUCCEEDED(hres))
1697 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1698 if(FAILED(hres)) {
1699 IStream_Release(output);
1700 return hres;
1703 *ret_stream = output;
1704 return S_OK;
1707 static HRESULT WINAPI MimeBody_GetData(
1708 IMimeBody* iface,
1709 ENCODINGTYPE ietEncoding,
1710 IStream** ppStream)
1712 MimeBody *This = impl_from_IMimeBody(iface);
1713 ULARGE_INTEGER start, size;
1714 HRESULT hres;
1716 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1718 if(This->encoding != ietEncoding) {
1719 switch(This->encoding) {
1720 case IET_BASE64:
1721 hres = decode_base64(This->data, ppStream);
1722 break;
1723 case IET_QP:
1724 hres = decode_qp(This->data, ppStream);
1725 break;
1726 default:
1727 FIXME("Decoding %d is not supported.\n", This->encoding);
1728 hres = S_FALSE;
1730 if(ietEncoding != IET_BINARY)
1731 FIXME("Encoding %d is not supported.\n", ietEncoding);
1732 if(hres != S_FALSE)
1733 return hres;
1736 start.QuadPart = 0;
1737 hres = get_stream_size(This->data, &size);
1738 if(SUCCEEDED(hres))
1739 hres = create_sub_stream(This->data, start, size, ppStream);
1740 return hres;
1743 static HRESULT WINAPI MimeBody_SetData(
1744 IMimeBody* iface,
1745 ENCODINGTYPE ietEncoding,
1746 LPCSTR pszPriType,
1747 LPCSTR pszSubType,
1748 REFIID riid,
1749 LPVOID pvObject)
1751 MimeBody *This = impl_from_IMimeBody(iface);
1752 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1753 debugstr_guid(riid), pvObject);
1755 if(IsEqualIID(riid, &IID_IStream))
1756 IStream_AddRef((IStream *)pvObject);
1757 else
1759 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1760 return E_INVALIDARG;
1763 if(This->data)
1764 release_data(&This->data_iid, This->data);
1766 This->data_iid = *riid;
1767 This->data = pvObject;
1769 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1771 /* FIXME: Update the content type.
1772 If pszPriType == NULL use 'application'
1773 If pszSubType == NULL use 'octet-stream' */
1775 return S_OK;
1778 static HRESULT WINAPI MimeBody_EmptyData(
1779 IMimeBody* iface)
1781 MimeBody *This = impl_from_IMimeBody(iface);
1782 FIXME("(%p)->() stub\n", This);
1783 return E_NOTIMPL;
1786 static HRESULT WINAPI MimeBody_CopyTo(
1787 IMimeBody* iface,
1788 IMimeBody* pBody)
1790 MimeBody *This = impl_from_IMimeBody(iface);
1791 FIXME("(%p)->(%p) stub\n", This, pBody);
1792 return E_NOTIMPL;
1795 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1796 IMimeBody* iface,
1797 LPTRANSMITINFO pTransmitInfo)
1799 MimeBody *This = impl_from_IMimeBody(iface);
1800 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1801 return E_NOTIMPL;
1804 static HRESULT WINAPI MimeBody_SaveToFile(
1805 IMimeBody* iface,
1806 ENCODINGTYPE ietEncoding,
1807 LPCSTR pszFilePath)
1809 MimeBody *This = impl_from_IMimeBody(iface);
1810 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1811 return E_NOTIMPL;
1814 static HRESULT WINAPI MimeBody_GetHandle(
1815 IMimeBody* iface,
1816 LPHBODY phBody)
1818 MimeBody *This = impl_from_IMimeBody(iface);
1819 TRACE("(%p)->(%p)\n", iface, phBody);
1821 if(!phBody)
1822 return E_INVALIDARG;
1824 *phBody = This->handle;
1825 return This->handle ? S_OK : MIME_E_NO_DATA;
1828 static IMimeBodyVtbl body_vtbl =
1830 MimeBody_QueryInterface,
1831 MimeBody_AddRef,
1832 MimeBody_Release,
1833 MimeBody_GetClassID,
1834 MimeBody_IsDirty,
1835 MimeBody_Load,
1836 MimeBody_Save,
1837 MimeBody_GetSizeMax,
1838 MimeBody_InitNew,
1839 MimeBody_GetPropInfo,
1840 MimeBody_SetPropInfo,
1841 MimeBody_GetProp,
1842 MimeBody_SetProp,
1843 MimeBody_AppendProp,
1844 MimeBody_DeleteProp,
1845 MimeBody_CopyProps,
1846 MimeBody_MoveProps,
1847 MimeBody_DeleteExcept,
1848 MimeBody_QueryProp,
1849 MimeBody_GetCharset,
1850 MimeBody_SetCharset,
1851 MimeBody_GetParameters,
1852 MimeBody_IsContentType,
1853 MimeBody_BindToObject,
1854 MimeBody_Clone,
1855 MimeBody_SetOption,
1856 MimeBody_GetOption,
1857 MimeBody_EnumProps,
1858 MimeBody_IsType,
1859 MimeBody_SetDisplayName,
1860 MimeBody_GetDisplayName,
1861 MimeBody_GetOffsets,
1862 MimeBody_GetCurrentEncoding,
1863 MimeBody_SetCurrentEncoding,
1864 MimeBody_GetEstimatedSize,
1865 MimeBody_GetDataHere,
1866 MimeBody_GetData,
1867 MimeBody_SetData,
1868 MimeBody_EmptyData,
1869 MimeBody_CopyTo,
1870 MimeBody_GetTransmitInfo,
1871 MimeBody_SaveToFile,
1872 MimeBody_GetHandle
1875 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1877 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1878 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1880 body->body_offsets = *offsets;
1881 return S_OK;
1884 #define FIRST_CUSTOM_PROP_ID 0x100
1886 static MimeBody *mimebody_create(void)
1888 MimeBody *This;
1889 BODYOFFSETS body_offsets;
1891 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1892 if (!This)
1893 return NULL;
1895 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1896 This->ref = 1;
1897 This->handle = NULL;
1898 list_init(&This->headers);
1899 list_init(&This->new_props);
1900 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1901 This->content_pri_type = NULL;
1902 This->content_sub_type = NULL;
1903 This->encoding = IET_7BIT;
1904 This->data = NULL;
1905 This->data_iid = IID_NULL;
1907 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1908 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1909 MimeBody_set_offsets(This, &body_offsets);
1911 return This;
1914 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1916 MimeBody *mb;
1918 if(outer)
1919 return CLASS_E_NOAGGREGATION;
1921 if ((mb = mimebody_create()))
1923 *ppv = &mb->IMimeBody_iface;
1924 return S_OK;
1926 else
1928 *ppv = NULL;
1929 return E_OUTOFMEMORY;
1933 typedef struct body_t
1935 struct list entry;
1936 DWORD index;
1937 MimeBody *mime_body;
1939 struct body_t *parent;
1940 struct list children;
1941 } body_t;
1943 typedef struct MimeMessage
1945 IMimeMessage IMimeMessage_iface;
1946 LONG ref;
1947 IStream *stream;
1949 struct list body_tree;
1950 DWORD next_index;
1951 } MimeMessage;
1953 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1955 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1958 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1960 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1962 if (IsEqualIID(riid, &IID_IUnknown) ||
1963 IsEqualIID(riid, &IID_IPersist) ||
1964 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1965 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1966 IsEqualIID(riid, &IID_IMimeMessage))
1968 *ppv = iface;
1969 IMimeMessage_AddRef(iface);
1970 return S_OK;
1973 FIXME("no interface for %s\n", debugstr_guid(riid));
1974 *ppv = NULL;
1975 return E_NOINTERFACE;
1978 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1980 MimeMessage *This = impl_from_IMimeMessage(iface);
1981 ULONG ref = InterlockedIncrement(&This->ref);
1983 TRACE("(%p) ref=%d\n", This, ref);
1985 return ref;
1988 static void empty_body_list(struct list *list)
1990 body_t *body, *cursor2;
1991 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1993 empty_body_list(&body->children);
1994 list_remove(&body->entry);
1995 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1996 HeapFree(GetProcessHeap(), 0, body);
2000 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
2002 MimeMessage *This = impl_from_IMimeMessage(iface);
2003 ULONG ref = InterlockedDecrement(&This->ref);
2005 TRACE("(%p) ref=%d\n", This, ref);
2007 if (!ref)
2009 empty_body_list(&This->body_tree);
2011 if(This->stream) IStream_Release(This->stream);
2012 HeapFree(GetProcessHeap(), 0, This);
2015 return ref;
2018 /*** IPersist methods ***/
2019 static HRESULT WINAPI MimeMessage_GetClassID(
2020 IMimeMessage *iface,
2021 CLSID *pClassID)
2023 FIXME("(%p)->(%p)\n", iface, pClassID);
2024 return E_NOTIMPL;
2027 /*** IPersistStreamInit methods ***/
2028 static HRESULT WINAPI MimeMessage_IsDirty(
2029 IMimeMessage *iface)
2031 FIXME("(%p)->()\n", iface);
2032 return E_NOTIMPL;
2035 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
2037 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
2038 if(body)
2040 body->mime_body = mime_body;
2041 body->index = index;
2042 list_init(&body->children);
2043 body->parent = parent;
2045 mime_body->handle = UlongToHandle(body->index);
2047 return body;
2050 typedef struct
2052 struct list entry;
2053 BODYOFFSETS offsets;
2054 } offset_entry_t;
2056 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
2058 HRESULT hr;
2059 DWORD read, boundary_start;
2060 int boundary_len = strlen(boundary);
2061 char *buf, *ptr, *overlap;
2062 DWORD start = 0, overlap_no;
2063 offset_entry_t *cur_body = NULL;
2064 BOOL is_first_line = TRUE;
2065 ULARGE_INTEGER cur;
2066 LARGE_INTEGER zero;
2068 list_init(body_offsets);
2070 overlap_no = boundary_len + 5;
2072 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
2074 zero.QuadPart = 0;
2075 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
2076 start = cur.u.LowPart;
2078 do {
2079 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
2080 if(FAILED(hr)) goto end;
2081 if(read == 0) break;
2082 overlap[read] = '\0';
2084 ptr = buf;
2085 while(1) {
2086 if(is_first_line) {
2087 is_first_line = FALSE;
2088 }else {
2089 ptr = strstr(ptr, "\r\n");
2090 if(!ptr)
2091 break;
2092 ptr += 2;
2095 boundary_start = start + ptr - buf;
2097 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) {
2098 ptr += boundary_len + 2;
2100 if(*ptr == '\r' && *(ptr + 1) == '\n')
2102 ptr += 2;
2103 if(cur_body)
2105 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2106 list_add_tail(body_offsets, &cur_body->entry);
2108 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
2109 cur_body->offsets.cbBoundaryStart = boundary_start;
2110 cur_body->offsets.cbHeaderStart = start + ptr - buf;
2112 else if(*ptr == '-' && *(ptr + 1) == '-')
2114 if(cur_body)
2116 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2117 list_add_tail(body_offsets, &cur_body->entry);
2118 goto end;
2124 if(overlap == buf) /* 1st iteration */
2126 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2127 overlap = buf + overlap_no;
2128 start += read - overlap_no;
2130 else
2132 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2133 start += read;
2135 } while(1);
2137 end:
2138 HeapFree(GetProcessHeap(), 0, buf);
2139 return hr;
2142 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2144 ULARGE_INTEGER start, length;
2145 MimeBody *mime_body;
2146 HRESULT hr;
2147 body_t *body;
2148 LARGE_INTEGER pos;
2150 pos.QuadPart = offset->cbHeaderStart;
2151 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL);
2153 mime_body = mimebody_create();
2154 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2156 pos.QuadPart = 0;
2157 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start);
2158 offset->cbBodyStart = start.QuadPart;
2159 if (parent) MimeBody_set_offsets(mime_body, offset);
2161 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart;
2162 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data);
2163 mime_body->data_iid = IID_IStream;
2165 body = new_body_entry(mime_body, msg->next_index++, parent);
2167 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2169 MIMEPARAMINFO *param_info;
2170 ULONG count, i;
2171 IMimeAllocator *alloc;
2173 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2174 &param_info);
2175 if(hr != S_OK || count == 0) return body;
2177 MimeOleGetAllocator(&alloc);
2179 for(i = 0; i < count; i++)
2181 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2183 struct list offset_list;
2184 offset_entry_t *cur, *cursor2;
2185 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2186 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2188 body_t *sub_body;
2190 sub_body = create_sub_body(msg, pStm, &cur->offsets, body);
2191 list_add_tail(&body->children, &sub_body->entry);
2192 list_remove(&cur->entry);
2193 HeapFree(GetProcessHeap(), 0, cur);
2195 break;
2198 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2199 IMimeAllocator_Release(alloc);
2201 return body;
2204 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2206 MimeMessage *This = impl_from_IMimeMessage(iface);
2207 body_t *root_body;
2208 BODYOFFSETS offsets;
2209 ULARGE_INTEGER cur;
2210 LARGE_INTEGER zero;
2212 TRACE("(%p)->(%p)\n", iface, pStm);
2214 if(This->stream)
2216 FIXME("already loaded a message\n");
2217 return E_FAIL;
2220 empty_body_list(&This->body_tree);
2222 IStream_AddRef(pStm);
2223 This->stream = pStm;
2224 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2225 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2227 root_body = create_sub_body(This, pStm, &offsets, NULL);
2229 zero.QuadPart = 0;
2230 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2231 offsets.cbBodyEnd = cur.u.LowPart;
2232 MimeBody_set_offsets(root_body->mime_body, &offsets);
2234 list_add_head(&This->body_tree, &root_body->entry);
2236 return S_OK;
2239 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2241 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2242 return E_NOTIMPL;
2245 static HRESULT WINAPI MimeMessage_GetSizeMax(
2246 IMimeMessage *iface,
2247 ULARGE_INTEGER *pcbSize)
2249 FIXME("(%p)->(%p)\n", iface, pcbSize);
2250 return E_NOTIMPL;
2253 static HRESULT WINAPI MimeMessage_InitNew(
2254 IMimeMessage *iface)
2256 FIXME("(%p)->()\n", iface);
2257 return E_NOTIMPL;
2260 /*** IMimeMessageTree methods ***/
2261 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2262 DWORD dwFlags)
2264 MimeMessage *This = impl_from_IMimeMessage(iface);
2266 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
2268 IStream_AddRef(This->stream);
2269 *ppStream = This->stream;
2270 return S_OK;
2273 static HRESULT WINAPI MimeMessage_GetMessageSize(
2274 IMimeMessage *iface,
2275 ULONG *pcbSize,
2276 DWORD dwFlags)
2278 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
2279 return E_NOTIMPL;
2282 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2283 IMimeMessage *iface,
2284 IStream *pStream)
2286 FIXME("(%p)->(%p)\n", iface, pStream);
2287 return E_NOTIMPL;
2290 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2291 IMimeMessage *iface,
2292 IStream *pStream,
2293 DWORD dwFlags)
2295 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
2296 return E_NOTIMPL;
2300 static HRESULT WINAPI MimeMessage_GetFlags(
2301 IMimeMessage *iface,
2302 DWORD *pdwFlags)
2304 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2305 return E_NOTIMPL;
2308 static HRESULT WINAPI MimeMessage_Commit(
2309 IMimeMessage *iface,
2310 DWORD dwFlags)
2312 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
2313 return S_OK;
2317 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2318 IMimeMessage *iface)
2320 FIXME("(%p)->()\n", iface);
2321 return E_NOTIMPL;
2324 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2326 body_t *cur;
2327 HRESULT hr;
2329 if(hbody == HBODY_ROOT)
2331 *body = LIST_ENTRY(list_head(list), body_t, entry);
2332 return S_OK;
2335 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2337 if(cur->index == HandleToUlong(hbody))
2339 *body = cur;
2340 return S_OK;
2342 hr = find_body(&cur->children, hbody, body);
2343 if(hr == S_OK) return S_OK;
2345 return S_FALSE;
2348 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2349 void **ppvObject)
2351 MimeMessage *This = impl_from_IMimeMessage(iface);
2352 HRESULT hr;
2353 body_t *body;
2355 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2357 hr = find_body(&This->body_tree, hBody, &body);
2359 if(hr != S_OK) return hr;
2361 if(IsEqualIID(riid, &IID_IMimeBody))
2363 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2364 *ppvObject = &body->mime_body->IMimeBody_iface;
2365 return S_OK;
2368 return E_NOINTERFACE;
2371 static HRESULT WINAPI MimeMessage_SaveBody(
2372 IMimeMessage *iface,
2373 HBODY hBody,
2374 DWORD dwFlags,
2375 IStream *pStream)
2377 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
2378 return E_NOTIMPL;
2381 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2383 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2384 body_t *body;
2385 HRESULT hr;
2386 struct list *list;
2388 if(location == IBL_ROOT)
2390 *out = root;
2391 return S_OK;
2394 hr = find_body(&msg->body_tree, pivot, &body);
2396 if(hr == S_OK)
2398 switch(location)
2400 case IBL_PARENT:
2401 if(body->parent)
2402 *out = body->parent;
2403 else
2404 hr = MIME_E_NOT_FOUND;
2405 break;
2407 case IBL_FIRST:
2408 list = list_head(&body->children);
2409 if(list)
2410 *out = LIST_ENTRY(list, body_t, entry);
2411 else
2412 hr = MIME_E_NOT_FOUND;
2413 break;
2415 case IBL_LAST:
2416 list = list_tail(&body->children);
2417 if(list)
2418 *out = LIST_ENTRY(list, body_t, entry);
2419 else
2420 hr = MIME_E_NOT_FOUND;
2421 break;
2423 case IBL_NEXT:
2424 list = list_next(&body->parent->children, &body->entry);
2425 if(list)
2426 *out = LIST_ENTRY(list, body_t, entry);
2427 else
2428 hr = MIME_E_NOT_FOUND;
2429 break;
2431 case IBL_PREVIOUS:
2432 list = list_prev(&body->parent->children, &body->entry);
2433 if(list)
2434 *out = LIST_ENTRY(list, body_t, entry);
2435 else
2436 hr = MIME_E_NOT_FOUND;
2437 break;
2439 default:
2440 hr = E_FAIL;
2441 break;
2445 return hr;
2449 static HRESULT WINAPI MimeMessage_InsertBody(
2450 IMimeMessage *iface,
2451 BODYLOCATION location,
2452 HBODY hPivot,
2453 LPHBODY phBody)
2455 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2456 return E_NOTIMPL;
2459 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2460 HBODY *phBody)
2462 MimeMessage *This = impl_from_IMimeMessage(iface);
2463 body_t *body;
2464 HRESULT hr;
2466 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2468 if(!phBody)
2469 return E_INVALIDARG;
2471 *phBody = NULL;
2473 hr = get_body(This, location, hPivot, &body);
2475 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2477 return hr;
2480 static HRESULT WINAPI MimeMessage_DeleteBody(
2481 IMimeMessage *iface,
2482 HBODY hBody,
2483 DWORD dwFlags)
2485 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
2486 return E_NOTIMPL;
2489 static HRESULT WINAPI MimeMessage_MoveBody(
2490 IMimeMessage *iface,
2491 HBODY hBody,
2492 BODYLOCATION location)
2494 FIXME("(%p)->(%d)\n", iface, location);
2495 return E_NOTIMPL;
2498 static void count_children(body_t *body, boolean recurse, ULONG *count)
2500 body_t *child;
2502 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2504 (*count)++;
2505 if(recurse) count_children(child, recurse, count);
2509 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2510 ULONG *pcBodies)
2512 HRESULT hr;
2513 MimeMessage *This = impl_from_IMimeMessage(iface);
2514 body_t *body;
2516 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2518 hr = find_body(&This->body_tree, hParent, &body);
2519 if(hr != S_OK) return hr;
2521 *pcBodies = 1;
2522 count_children(body, fRecurse, pcBodies);
2524 return S_OK;
2527 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2529 struct list *ptr;
2530 HBODY next;
2532 for (;;)
2534 if (!body) ptr = list_head( &This->body_tree );
2535 else
2537 ptr = list_head( &body->children );
2538 while (!ptr)
2540 if (!body->parent) return MIME_E_NOT_FOUND;
2541 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2545 body = LIST_ENTRY( ptr, body_t, entry );
2546 next = UlongToHandle( body->index );
2547 find->dwReserved = body->index;
2548 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2549 find->pszSubType) == S_OK)
2551 *out = next;
2552 return S_OK;
2555 return MIME_E_NOT_FOUND;
2558 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2560 MimeMessage *This = impl_from_IMimeMessage(iface);
2562 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2564 pFindBody->dwReserved = 0;
2565 return find_next(This, NULL, pFindBody, phBody);
2568 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2570 MimeMessage *This = impl_from_IMimeMessage(iface);
2571 body_t *body;
2572 HRESULT hr;
2574 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2576 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2577 if (hr != S_OK) return MIME_E_NOT_FOUND;
2578 return find_next(This, body, pFindBody, phBody);
2581 static HRESULT WINAPI MimeMessage_ResolveURL(
2582 IMimeMessage *iface,
2583 HBODY hRelated,
2584 LPCSTR pszBase,
2585 LPCSTR pszURL,
2586 DWORD dwFlags,
2587 LPHBODY phBody)
2589 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2590 return E_NOTIMPL;
2593 static HRESULT WINAPI MimeMessage_ToMultipart(
2594 IMimeMessage *iface,
2595 HBODY hBody,
2596 LPCSTR pszSubType,
2597 LPHBODY phMultipart)
2599 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2600 return E_NOTIMPL;
2603 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2604 IMimeMessage *iface,
2605 HBODY hBody,
2606 LPBODYOFFSETS pOffsets)
2608 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2609 return E_NOTIMPL;
2612 static HRESULT WINAPI MimeMessage_GetCharset(
2613 IMimeMessage *iface,
2614 LPHCHARSET phCharset)
2616 FIXME("(%p)->(%p)\n", iface, phCharset);
2617 *phCharset = NULL;
2618 return S_OK;
2621 static HRESULT WINAPI MimeMessage_SetCharset(
2622 IMimeMessage *iface,
2623 HCHARSET hCharset,
2624 CSETAPPLYTYPE applytype)
2626 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2627 return E_NOTIMPL;
2630 static HRESULT WINAPI MimeMessage_IsBodyType(
2631 IMimeMessage *iface,
2632 HBODY hBody,
2633 IMSGBODYTYPE bodytype)
2635 HRESULT hr;
2636 IMimeBody *mime_body;
2637 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2639 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2640 if(hr != S_OK) return hr;
2642 hr = IMimeBody_IsType(mime_body, bodytype);
2643 MimeBody_Release(mime_body);
2644 return hr;
2647 static HRESULT WINAPI MimeMessage_IsContentType(
2648 IMimeMessage *iface,
2649 HBODY hBody,
2650 LPCSTR pszPriType,
2651 LPCSTR pszSubType)
2653 HRESULT hr;
2654 IMimeBody *mime_body;
2655 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2656 debugstr_a(pszSubType));
2658 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2659 if(FAILED(hr)) return hr;
2661 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2662 IMimeBody_Release(mime_body);
2663 return hr;
2666 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2667 IMimeMessage *iface,
2668 HBODY hBody,
2669 LPCSTR pszName,
2670 LPCSTR pszCriteria,
2671 boolean fSubString,
2672 boolean fCaseSensitive)
2674 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2675 return E_NOTIMPL;
2678 static HRESULT WINAPI MimeMessage_GetBodyProp(
2679 IMimeMessage *iface,
2680 HBODY hBody,
2681 LPCSTR pszName,
2682 DWORD dwFlags,
2683 LPPROPVARIANT pValue)
2685 HRESULT hr;
2686 IMimeBody *mime_body;
2688 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2690 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2691 if(hr != S_OK) return hr;
2693 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2694 IMimeBody_Release(mime_body);
2696 return hr;
2699 static HRESULT WINAPI MimeMessage_SetBodyProp(
2700 IMimeMessage *iface,
2701 HBODY hBody,
2702 LPCSTR pszName,
2703 DWORD dwFlags,
2704 LPCPROPVARIANT pValue)
2706 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2707 return E_NOTIMPL;
2710 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2711 IMimeMessage *iface,
2712 HBODY hBody,
2713 LPCSTR pszName)
2715 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2716 return E_NOTIMPL;
2719 static HRESULT WINAPI MimeMessage_SetOption(
2720 IMimeMessage *iface,
2721 const TYPEDID oid,
2722 LPCPROPVARIANT pValue)
2724 HRESULT hr = S_OK;
2725 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2727 /* Message ID is checked before type.
2728 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2730 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2732 WARN("oid (%08x) out of range\n", oid);
2733 return MIME_E_INVALID_OPTION_ID;
2736 if(pValue->vt != TYPEDID_TYPE(oid))
2738 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2739 return S_OK;
2742 switch(oid)
2744 case OID_HIDE_TNEF_ATTACHMENTS:
2745 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2746 break;
2747 case OID_SHOW_MACBINARY:
2748 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2749 break;
2750 case OID_SAVEBODY_KEEPBOUNDARY:
2751 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal);
2752 break;
2753 case OID_CLEANUP_TREE_ON_SAVE:
2754 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal);
2755 break;
2756 default:
2757 FIXME("Unhandled oid %08x\n", oid);
2758 hr = MIME_E_INVALID_OPTION_ID;
2761 return hr;
2764 static HRESULT WINAPI MimeMessage_GetOption(
2765 IMimeMessage *iface,
2766 const TYPEDID oid,
2767 LPPROPVARIANT pValue)
2769 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2770 return E_NOTIMPL;
2773 /*** IMimeMessage methods ***/
2774 static HRESULT WINAPI MimeMessage_CreateWebPage(
2775 IMimeMessage *iface,
2776 IStream *pRootStm,
2777 LPWEBPAGEOPTIONS pOptions,
2778 IMimeMessageCallback *pCallback,
2779 IMoniker **ppMoniker)
2781 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2782 *ppMoniker = NULL;
2783 return E_NOTIMPL;
2786 static HRESULT WINAPI MimeMessage_GetProp(
2787 IMimeMessage *iface,
2788 LPCSTR pszName,
2789 DWORD dwFlags,
2790 LPPROPVARIANT pValue)
2792 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2793 return E_NOTIMPL;
2796 static HRESULT WINAPI MimeMessage_SetProp(
2797 IMimeMessage *iface,
2798 LPCSTR pszName,
2799 DWORD dwFlags,
2800 LPCPROPVARIANT pValue)
2802 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2803 return E_NOTIMPL;
2806 static HRESULT WINAPI MimeMessage_DeleteProp(
2807 IMimeMessage *iface,
2808 LPCSTR pszName)
2810 FIXME("(%p)->(%s)\n", iface, pszName);
2811 return E_NOTIMPL;
2814 static HRESULT WINAPI MimeMessage_QueryProp(
2815 IMimeMessage *iface,
2816 LPCSTR pszName,
2817 LPCSTR pszCriteria,
2818 boolean fSubString,
2819 boolean fCaseSensitive)
2821 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2822 return E_NOTIMPL;
2825 static HRESULT WINAPI MimeMessage_GetTextBody(
2826 IMimeMessage *iface,
2827 DWORD dwTxtType,
2828 ENCODINGTYPE ietEncoding,
2829 IStream **pStream,
2830 LPHBODY phBody)
2832 HRESULT hr;
2833 HBODY hbody;
2834 FINDBODY find_struct;
2835 IMimeBody *mime_body;
2836 static char text[] = "text";
2837 static char plain[] = "plain";
2838 static char html[] = "html";
2840 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2842 find_struct.pszPriType = text;
2844 switch(dwTxtType)
2846 case TXT_PLAIN:
2847 find_struct.pszSubType = plain;
2848 break;
2849 case TXT_HTML:
2850 find_struct.pszSubType = html;
2851 break;
2852 default:
2853 return MIME_E_INVALID_TEXT_TYPE;
2856 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2857 if(hr != S_OK)
2859 TRACE("not found hr %08x\n", hr);
2860 *phBody = NULL;
2861 return hr;
2864 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2866 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2867 *phBody = hbody;
2868 IMimeBody_Release(mime_body);
2869 return hr;
2872 static HRESULT WINAPI MimeMessage_SetTextBody(
2873 IMimeMessage *iface,
2874 DWORD dwTxtType,
2875 ENCODINGTYPE ietEncoding,
2876 HBODY hAlternative,
2877 IStream *pStream,
2878 LPHBODY phBody)
2880 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2881 return E_NOTIMPL;
2884 static HRESULT WINAPI MimeMessage_AttachObject(
2885 IMimeMessage *iface,
2886 REFIID riid,
2887 void *pvObject,
2888 LPHBODY phBody)
2890 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2891 return E_NOTIMPL;
2894 static HRESULT WINAPI MimeMessage_AttachFile(
2895 IMimeMessage *iface,
2896 LPCSTR pszFilePath,
2897 IStream *pstmFile,
2898 LPHBODY phBody)
2900 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2901 return E_NOTIMPL;
2904 static HRESULT WINAPI MimeMessage_AttachURL(
2905 IMimeMessage *iface,
2906 LPCSTR pszBase,
2907 LPCSTR pszURL,
2908 DWORD dwFlags,
2909 IStream *pstmURL,
2910 LPSTR *ppszCIDURL,
2911 LPHBODY phBody)
2913 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2914 return E_NOTIMPL;
2917 static HRESULT WINAPI MimeMessage_GetAttachments(
2918 IMimeMessage *iface,
2919 ULONG *pcAttach,
2920 LPHBODY *pprghAttach)
2922 HRESULT hr;
2923 FINDBODY find_struct;
2924 HBODY hbody;
2925 LPHBODY array;
2926 ULONG size = 10;
2928 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2930 *pcAttach = 0;
2931 array = CoTaskMemAlloc(size * sizeof(HBODY));
2933 find_struct.pszPriType = find_struct.pszSubType = NULL;
2934 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2935 while(hr == S_OK)
2937 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2938 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2939 if(hr != S_OK)
2941 if(*pcAttach + 1 > size)
2943 size *= 2;
2944 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2946 array[*pcAttach] = hbody;
2947 (*pcAttach)++;
2949 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2952 *pprghAttach = array;
2953 return S_OK;
2956 static HRESULT WINAPI MimeMessage_GetAddressTable(
2957 IMimeMessage *iface,
2958 IMimeAddressTable **ppTable)
2960 FIXME("(%p)->(%p)\n", iface, ppTable);
2961 return E_NOTIMPL;
2964 static HRESULT WINAPI MimeMessage_GetSender(
2965 IMimeMessage *iface,
2966 LPADDRESSPROPS pAddress)
2968 FIXME("(%p)->(%p)\n", iface, pAddress);
2969 return E_NOTIMPL;
2972 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2973 IMimeMessage *iface,
2974 DWORD dwAdrTypes,
2975 DWORD dwProps,
2976 LPADDRESSLIST pList)
2978 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2979 return E_NOTIMPL;
2982 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2983 IMimeMessage *iface,
2984 DWORD dwAdrTypes,
2985 ADDRESSFORMAT format,
2986 LPSTR *ppszFormat)
2988 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2989 return E_NOTIMPL;
2992 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2993 IMimeMessage *iface,
2994 DWORD dwAdrTypes,
2995 DWORD dwProps,
2996 IMimeEnumAddressTypes **ppEnum)
2998 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2999 return E_NOTIMPL;
3002 static HRESULT WINAPI MimeMessage_SplitMessage(
3003 IMimeMessage *iface,
3004 ULONG cbMaxPart,
3005 IMimeMessageParts **ppParts)
3007 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
3008 return E_NOTIMPL;
3011 static HRESULT WINAPI MimeMessage_GetRootMoniker(
3012 IMimeMessage *iface,
3013 IMoniker **ppMoniker)
3015 FIXME("(%p)->(%p)\n", iface, ppMoniker);
3016 return E_NOTIMPL;
3019 static const IMimeMessageVtbl MimeMessageVtbl =
3021 MimeMessage_QueryInterface,
3022 MimeMessage_AddRef,
3023 MimeMessage_Release,
3024 MimeMessage_GetClassID,
3025 MimeMessage_IsDirty,
3026 MimeMessage_Load,
3027 MimeMessage_Save,
3028 MimeMessage_GetSizeMax,
3029 MimeMessage_InitNew,
3030 MimeMessage_GetMessageSource,
3031 MimeMessage_GetMessageSize,
3032 MimeMessage_LoadOffsetTable,
3033 MimeMessage_SaveOffsetTable,
3034 MimeMessage_GetFlags,
3035 MimeMessage_Commit,
3036 MimeMessage_HandsOffStorage,
3037 MimeMessage_BindToObject,
3038 MimeMessage_SaveBody,
3039 MimeMessage_InsertBody,
3040 MimeMessage_GetBody,
3041 MimeMessage_DeleteBody,
3042 MimeMessage_MoveBody,
3043 MimeMessage_CountBodies,
3044 MimeMessage_FindFirst,
3045 MimeMessage_FindNext,
3046 MimeMessage_ResolveURL,
3047 MimeMessage_ToMultipart,
3048 MimeMessage_GetBodyOffsets,
3049 MimeMessage_GetCharset,
3050 MimeMessage_SetCharset,
3051 MimeMessage_IsBodyType,
3052 MimeMessage_IsContentType,
3053 MimeMessage_QueryBodyProp,
3054 MimeMessage_GetBodyProp,
3055 MimeMessage_SetBodyProp,
3056 MimeMessage_DeleteBodyProp,
3057 MimeMessage_SetOption,
3058 MimeMessage_GetOption,
3059 MimeMessage_CreateWebPage,
3060 MimeMessage_GetProp,
3061 MimeMessage_SetProp,
3062 MimeMessage_DeleteProp,
3063 MimeMessage_QueryProp,
3064 MimeMessage_GetTextBody,
3065 MimeMessage_SetTextBody,
3066 MimeMessage_AttachObject,
3067 MimeMessage_AttachFile,
3068 MimeMessage_AttachURL,
3069 MimeMessage_GetAttachments,
3070 MimeMessage_GetAddressTable,
3071 MimeMessage_GetSender,
3072 MimeMessage_GetAddressTypes,
3073 MimeMessage_GetAddressFormat,
3074 MimeMessage_EnumAddressTypes,
3075 MimeMessage_SplitMessage,
3076 MimeMessage_GetRootMoniker,
3079 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
3081 MimeMessage *This;
3082 MimeBody *mime_body;
3083 body_t *root_body;
3085 TRACE("(%p, %p)\n", outer, obj);
3087 if (outer)
3089 FIXME("outer unknown not supported yet\n");
3090 return E_NOTIMPL;
3093 *obj = NULL;
3095 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3096 if (!This) return E_OUTOFMEMORY;
3098 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
3099 This->ref = 1;
3100 This->stream = NULL;
3101 list_init(&This->body_tree);
3102 This->next_index = 1;
3104 mime_body = mimebody_create();
3105 root_body = new_body_entry(mime_body, This->next_index++, NULL);
3106 list_add_head(&This->body_tree, &root_body->entry);
3108 *obj = &This->IMimeMessage_iface;
3109 return S_OK;
3112 /***********************************************************************
3113 * MimeOleCreateMessage (INETCOMM.@)
3115 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
3117 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3118 return MimeMessage_create(NULL, (void **)ppMessage);
3121 /***********************************************************************
3122 * MimeOleSetCompatMode (INETCOMM.@)
3124 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3126 FIXME("(0x%x)\n", dwMode);
3127 return S_OK;
3130 /***********************************************************************
3131 * MimeOleCreateVirtualStream (INETCOMM.@)
3133 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3135 HRESULT hr;
3136 FIXME("(%p)\n", ppStream);
3138 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3139 return hr;
3142 typedef struct MimeSecurity
3144 IMimeSecurity IMimeSecurity_iface;
3145 LONG ref;
3146 } MimeSecurity;
3148 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3150 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3153 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3155 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3157 if (IsEqualIID(riid, &IID_IUnknown) ||
3158 IsEqualIID(riid, &IID_IMimeSecurity))
3160 *ppv = iface;
3161 IMimeSecurity_AddRef(iface);
3162 return S_OK;
3165 FIXME("no interface for %s\n", debugstr_guid(riid));
3166 *ppv = NULL;
3167 return E_NOINTERFACE;
3170 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3172 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3173 LONG ref = InterlockedIncrement(&This->ref);
3175 TRACE("(%p) ref=%d\n", This, ref);
3177 return ref;
3180 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3182 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3183 LONG ref = InterlockedDecrement(&This->ref);
3185 TRACE("(%p) ref=%d\n", This, ref);
3187 if (!ref)
3188 HeapFree(GetProcessHeap(), 0, This);
3190 return ref;
3193 static HRESULT WINAPI MimeSecurity_InitNew(
3194 IMimeSecurity* iface)
3196 FIXME("(%p)->(): stub\n", iface);
3197 return S_OK;
3200 static HRESULT WINAPI MimeSecurity_CheckInit(
3201 IMimeSecurity* iface)
3203 FIXME("(%p)->(): stub\n", iface);
3204 return E_NOTIMPL;
3207 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3208 IMimeSecurity* iface,
3209 IMimeMessageTree* pTree,
3210 DWORD dwFlags)
3212 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3213 return E_NOTIMPL;
3216 static HRESULT WINAPI MimeSecurity_EncodeBody(
3217 IMimeSecurity* iface,
3218 IMimeMessageTree* pTree,
3219 HBODY hEncodeRoot,
3220 DWORD dwFlags)
3222 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3223 return E_NOTIMPL;
3226 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3227 IMimeSecurity* iface,
3228 IMimeMessageTree* pTree,
3229 DWORD dwFlags)
3231 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3232 return E_NOTIMPL;
3235 static HRESULT WINAPI MimeSecurity_DecodeBody(
3236 IMimeSecurity* iface,
3237 IMimeMessageTree* pTree,
3238 HBODY hDecodeRoot,
3239 DWORD dwFlags)
3241 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3242 return E_NOTIMPL;
3245 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3246 IMimeSecurity* iface,
3247 HCAPICERTSTORE hc,
3248 DWORD dwUsage,
3249 PCX509CERT pPrev,
3250 PCX509CERT* ppCert)
3252 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3253 return E_NOTIMPL;
3256 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3257 IMimeSecurity* iface,
3258 const PCX509CERT pX509Cert,
3259 const CERTNAMETYPE cn,
3260 LPSTR* ppszName)
3262 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3263 return E_NOTIMPL;
3266 static HRESULT WINAPI MimeSecurity_GetMessageType(
3267 IMimeSecurity* iface,
3268 const HWND hwndParent,
3269 IMimeBody* pBody,
3270 DWORD* pdwSecType)
3272 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3273 return E_NOTIMPL;
3276 static HRESULT WINAPI MimeSecurity_GetCertData(
3277 IMimeSecurity* iface,
3278 const PCX509CERT pX509Cert,
3279 const CERTDATAID dataid,
3280 LPPROPVARIANT pValue)
3282 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3283 return E_NOTIMPL;
3287 static const IMimeSecurityVtbl MimeSecurityVtbl =
3289 MimeSecurity_QueryInterface,
3290 MimeSecurity_AddRef,
3291 MimeSecurity_Release,
3292 MimeSecurity_InitNew,
3293 MimeSecurity_CheckInit,
3294 MimeSecurity_EncodeMessage,
3295 MimeSecurity_EncodeBody,
3296 MimeSecurity_DecodeMessage,
3297 MimeSecurity_DecodeBody,
3298 MimeSecurity_EnumCertificates,
3299 MimeSecurity_GetCertificateName,
3300 MimeSecurity_GetMessageType,
3301 MimeSecurity_GetCertData
3304 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3306 MimeSecurity *This;
3308 *obj = NULL;
3310 if (outer) return CLASS_E_NOAGGREGATION;
3312 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3313 if (!This) return E_OUTOFMEMORY;
3315 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3316 This->ref = 1;
3318 *obj = &This->IMimeSecurity_iface;
3319 return S_OK;
3322 /***********************************************************************
3323 * MimeOleCreateSecurity (INETCOMM.@)
3325 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3327 return MimeSecurity_create(NULL, (void **)ppSecurity);
3330 static HRESULT WINAPI MimeAlloc_QueryInterface(
3331 IMimeAllocator* iface,
3332 REFIID riid,
3333 void **obj)
3335 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3337 if (IsEqualIID(riid, &IID_IUnknown) ||
3338 IsEqualIID(riid, &IID_IMalloc) ||
3339 IsEqualIID(riid, &IID_IMimeAllocator))
3341 *obj = iface;
3342 IMimeAllocator_AddRef(iface);
3343 return S_OK;
3346 FIXME("no interface for %s\n", debugstr_guid(riid));
3347 *obj = NULL;
3348 return E_NOINTERFACE;
3351 static ULONG WINAPI MimeAlloc_AddRef(
3352 IMimeAllocator* iface)
3354 return 2;
3357 static ULONG WINAPI MimeAlloc_Release(
3358 IMimeAllocator* iface)
3360 return 1;
3363 static LPVOID WINAPI MimeAlloc_Alloc(
3364 IMimeAllocator* iface,
3365 SIZE_T cb)
3367 return CoTaskMemAlloc(cb);
3370 static LPVOID WINAPI MimeAlloc_Realloc(
3371 IMimeAllocator* iface,
3372 LPVOID pv,
3373 SIZE_T cb)
3375 return CoTaskMemRealloc(pv, cb);
3378 static void WINAPI MimeAlloc_Free(
3379 IMimeAllocator* iface,
3380 LPVOID pv)
3382 CoTaskMemFree(pv);
3385 static SIZE_T WINAPI MimeAlloc_GetSize(
3386 IMimeAllocator* iface,
3387 LPVOID pv)
3389 FIXME("stub\n");
3390 return 0;
3393 static int WINAPI MimeAlloc_DidAlloc(
3394 IMimeAllocator* iface,
3395 LPVOID pv)
3397 FIXME("stub\n");
3398 return 0;
3401 static void WINAPI MimeAlloc_HeapMinimize(
3402 IMimeAllocator* iface)
3404 FIXME("stub\n");
3405 return;
3408 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3409 IMimeAllocator* iface,
3410 ULONG cParams,
3411 LPMIMEPARAMINFO prgParam,
3412 boolean fFreeArray)
3414 ULONG i;
3415 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3417 for(i = 0; i < cParams; i++)
3419 IMimeAllocator_Free(iface, prgParam[i].pszName);
3420 IMimeAllocator_Free(iface, prgParam[i].pszData);
3422 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3423 return S_OK;
3426 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3427 IMimeAllocator* iface,
3428 LPADDRESSLIST pList)
3430 FIXME("stub\n");
3431 return E_NOTIMPL;
3434 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3435 IMimeAllocator* iface,
3436 LPADDRESSPROPS pAddress)
3438 FIXME("stub\n");
3439 return E_NOTIMPL;
3442 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3443 IMimeAllocator* iface,
3444 ULONG cObjects,
3445 IUnknown **prgpUnknown,
3446 boolean fFreeArray)
3448 FIXME("stub\n");
3449 return E_NOTIMPL;
3453 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3454 IMimeAllocator* iface,
3455 ULONG cRows,
3456 LPENUMHEADERROW prgRow,
3457 boolean fFreeArray)
3459 FIXME("stub\n");
3460 return E_NOTIMPL;
3463 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3464 IMimeAllocator* iface,
3465 ULONG cProps,
3466 LPENUMPROPERTY prgProp,
3467 boolean fFreeArray)
3469 FIXME("stub\n");
3470 return E_NOTIMPL;
3473 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3474 IMimeAllocator* iface,
3475 THUMBBLOB *pthumbprint)
3477 FIXME("stub\n");
3478 return E_NOTIMPL;
3482 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3483 IMimeAllocator* iface,
3484 LPPROPVARIANT pProp)
3486 FIXME("stub\n");
3487 return E_NOTIMPL;
3490 static IMimeAllocatorVtbl mime_alloc_vtbl =
3492 MimeAlloc_QueryInterface,
3493 MimeAlloc_AddRef,
3494 MimeAlloc_Release,
3495 MimeAlloc_Alloc,
3496 MimeAlloc_Realloc,
3497 MimeAlloc_Free,
3498 MimeAlloc_GetSize,
3499 MimeAlloc_DidAlloc,
3500 MimeAlloc_HeapMinimize,
3501 MimeAlloc_FreeParamInfoArray,
3502 MimeAlloc_FreeAddressList,
3503 MimeAlloc_FreeAddressProps,
3504 MimeAlloc_ReleaseObjects,
3505 MimeAlloc_FreeEnumHeaderRowArray,
3506 MimeAlloc_FreeEnumPropertyArray,
3507 MimeAlloc_FreeThumbprint,
3508 MimeAlloc_PropVariantClear
3511 static IMimeAllocator mime_allocator =
3513 &mime_alloc_vtbl
3516 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3518 if(outer) return CLASS_E_NOAGGREGATION;
3520 *obj = &mime_allocator;
3521 return S_OK;
3524 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3526 return MimeAllocator_create(NULL, (void**)alloc);
3529 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3531 FIXME("(%p, %p)\n", outer, obj);
3533 *obj = NULL;
3534 if (outer) return CLASS_E_NOAGGREGATION;
3536 return MimeOleCreateVirtualStream((IStream **)obj);
3539 /* IMimePropertySchema Interface */
3540 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3542 propschema *This = impl_from_IMimePropertySchema(iface);
3543 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3545 *out = NULL;
3547 if (IsEqualIID(riid, &IID_IUnknown) ||
3548 IsEqualIID(riid, &IID_IMimePropertySchema))
3550 *out = iface;
3552 else
3554 FIXME("no interface for %s\n", debugstr_guid(riid));
3555 return E_NOINTERFACE;
3558 IMimePropertySchema_AddRef(iface);
3559 return S_OK;
3562 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3564 propschema *This = impl_from_IMimePropertySchema(iface);
3565 LONG ref = InterlockedIncrement(&This->ref);
3567 TRACE("(%p) ref=%d\n", This, ref);
3569 return ref;
3572 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3574 propschema *This = impl_from_IMimePropertySchema(iface);
3575 LONG ref = InterlockedDecrement(&This->ref);
3577 TRACE("(%p) ref=%d\n", This, ref);
3579 if (!ref)
3581 HeapFree(GetProcessHeap(), 0, This);
3584 return ref;
3587 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3588 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3590 propschema *This = impl_from_IMimePropertySchema(iface);
3591 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3592 return E_NOTIMPL;
3595 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3596 DWORD rownumber, VARTYPE vtdefault)
3598 propschema *This = impl_from_IMimePropertySchema(iface);
3599 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3600 return S_OK;
3603 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3605 propschema *This = impl_from_IMimePropertySchema(iface);
3606 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3607 return E_NOTIMPL;
3610 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3612 propschema *This = impl_from_IMimePropertySchema(iface);
3613 FIXME("(%p)->(%d, %p) stub\n", This, propid, name);
3614 return E_NOTIMPL;
3617 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3619 propschema *This = impl_from_IMimePropertySchema(iface);
3620 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3621 return E_NOTIMPL;
3624 static IMimePropertySchemaVtbl prop_schema_vtbl =
3626 propschema_QueryInterface,
3627 propschema_AddRef,
3628 propschema_Release,
3629 propschema_RegisterProperty,
3630 propschema_ModifyProperty,
3631 propschema_GetPropertyId,
3632 propschema_GetPropertyName,
3633 propschema_RegisterAddressType
3637 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3639 propschema *This;
3641 TRACE("(%p) stub\n", schema);
3643 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3644 if (!This)
3645 return E_OUTOFMEMORY;
3647 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3648 This->ref = 1;
3650 *schema = &This->IMimePropertySchema_iface;
3652 return S_OK;
3655 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3656 ADDRESSFORMAT addr_format, WCHAR **address)
3658 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3660 return E_NOTIMPL;
3663 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
3665 FIXME("(%s %p)\n", debugstr_guid(riid), ppv);
3666 *ppv = NULL;
3667 return E_NOINTERFACE;
3670 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface)
3672 TRACE("\n");
3673 return 2;
3676 static ULONG WINAPI mime_obj_Release(IUnknown *iface)
3678 TRACE("\n");
3679 return 1;
3682 static const IUnknownVtbl mime_obj_vtbl = {
3683 mime_obj_QueryInterface,
3684 mime_obj_AddRef,
3685 mime_obj_Release
3688 static IUnknown mime_obj = { &mime_obj_vtbl };
3690 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3691 REFIID riid, void **out, IMoniker **moniker_new)
3693 WCHAR *display_name, *mhtml_url;
3694 size_t len;
3695 HRESULT hres;
3697 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'};
3699 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3701 if(!IsEqualGUID(&IID_IUnknown, riid)) {
3702 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
3703 return E_NOINTERFACE;
3706 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name);
3707 if(FAILED(hres))
3708 return hres;
3710 TRACE("display name %s\n", debugstr_w(display_name));
3712 len = strlenW(display_name);
3713 mhtml_url = heap_alloc((len+1)*sizeof(WCHAR) + sizeof(mhtml_prefixW));
3714 if(!mhtml_url)
3715 return E_OUTOFMEMORY;
3717 memcpy(mhtml_url, mhtml_prefixW, sizeof(mhtml_prefixW));
3718 strcpyW(mhtml_url + sizeof(mhtml_prefixW)/sizeof(WCHAR), display_name);
3719 HeapFree(GetProcessHeap(), 0, display_name);
3721 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new);
3722 heap_free(mhtml_url);
3723 if(FAILED(hres))
3724 return hres;
3726 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */
3727 *out = &mime_obj;
3728 return S_OK;