rpcrt4: Store all active connections in RpcServerProtseq.
[wine.git] / dlls / inetcomm / mimeole.c
blob0ed7cef26d1b85e4df1fdf24d7ac2e67a3df6b3c
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/list.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.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=%d\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=%d\n", This, ref);
218 if(!ref)
220 IStream_Release(This->base);
221 HeapFree(GetProcessHeap(), 0, 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, %d, %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("(%08x.%08x, %x, %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, %d, %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, %08x)\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 = HeapAlloc(GetProcessHeap(), 0, 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 static LPSTR strdupA(LPCSTR str)
480 char *ret;
481 int len = strlen(str);
482 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
483 memcpy(ret, str, len + 1);
484 return ret;
487 #define PARSER_BUF_SIZE 1024
489 /*****************************************************
490 * copy_headers_to_buf [internal]
492 * Copies the headers into a '\0' terminated memory block and leave
493 * the stream's current position set to after the blank line.
495 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
497 char *buf = NULL;
498 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
499 HRESULT hr;
500 BOOL done = FALSE;
502 *ptr = NULL;
506 char *end;
507 DWORD read;
509 if(!buf)
510 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
511 else
513 size *= 2;
514 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
516 if(!buf)
518 hr = E_OUTOFMEMORY;
519 goto fail;
522 hr = IStream_Read(stm, buf + offset, size - offset, &read);
523 if(FAILED(hr)) goto fail;
525 offset += read;
526 buf[offset] = '\0';
528 if(read == 0) done = TRUE;
530 while(!done && (end = strstr(buf + last_end, "\r\n")))
532 DWORD new_end = end - buf + 2;
533 if(new_end - last_end == 2)
535 LARGE_INTEGER off;
536 off.QuadPart = (LONGLONG)new_end - offset;
537 IStream_Seek(stm, off, STREAM_SEEK_CUR, NULL);
538 buf[new_end] = '\0';
539 done = TRUE;
541 else
542 last_end = new_end;
544 } while(!done);
546 *ptr = buf;
547 return S_OK;
549 fail:
550 HeapFree(GetProcessHeap(), 0, buf);
551 return hr;
554 static header_t *read_prop(MimeBody *body, char **ptr)
556 char *colon = strchr(*ptr, ':');
557 const property_t *prop;
558 header_t *ret;
560 if(!colon) return NULL;
562 *colon = '\0';
564 for(prop = default_props; prop->name; prop++)
566 if(!lstrcmpiA(*ptr, prop->name))
568 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
569 break;
573 if(!prop->name)
575 property_list_entry_t *prop_entry;
576 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
578 if(!lstrcmpiA(*ptr, prop_entry->prop.name))
580 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
581 prop = &prop_entry->prop;
582 break;
585 if(!prop->name)
587 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
588 prop_entry->prop.name = strdupA(*ptr);
589 prop_entry->prop.id = body->next_prop_id++;
590 prop_entry->prop.flags = 0;
591 prop_entry->prop.default_vt = VT_LPSTR;
592 list_add_tail(&body->new_props, &prop_entry->entry);
593 prop = &prop_entry->prop;
594 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
598 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
599 ret->prop = prop;
600 PropVariantInit(&ret->value);
601 list_init(&ret->params);
602 *ptr = colon + 1;
604 return ret;
607 static void unfold_header(char *header, int len)
609 char *start = header, *cp = header;
611 do {
612 while(*cp == ' ' || *cp == '\t')
614 cp++;
615 len--;
617 if(cp != start)
618 memmove(start, cp, len + 1);
620 cp = strstr(start, "\r\n");
621 len -= (cp - start);
622 start = cp;
623 *start = ' ';
624 start++;
625 len--;
626 cp += 2;
627 } while(*cp == ' ' || *cp == '\t');
629 *(start - 1) = '\0';
632 static char *unquote_string(const char *str)
634 BOOL quoted = FALSE;
635 char *ret, *cp;
637 while(*str == ' ' || *str == '\t') str++;
639 if(*str == '"')
641 quoted = TRUE;
642 str++;
644 ret = strdupA(str);
645 for(cp = ret; *cp; cp++)
647 if(*cp == '\\')
648 memmove(cp, cp + 1, strlen(cp + 1) + 1);
649 else if(*cp == '"')
651 if(!quoted)
653 WARN("quote in unquoted string\n");
655 else
657 *cp = '\0';
658 break;
662 return ret;
665 static void add_param(header_t *header, const char *p)
667 const char *key = p, *value, *cp = p;
668 param_t *param;
669 char *name;
671 TRACE("got param %s\n", p);
673 while (*key == ' ' || *key == '\t' ) key++;
675 cp = strchr(key, '=');
676 if(!cp)
678 WARN("malformed parameter - skipping\n");
679 return;
682 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
683 memcpy(name, key, cp - key);
684 name[cp - key] = '\0';
686 value = cp + 1;
688 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
689 param->name = name;
690 param->value = unquote_string(value);
691 list_add_tail(&header->params, &param->entry);
694 static void split_params(header_t *header, char *value)
696 char *cp = value, *start = value;
697 BOOL in_quotes = FALSE, done_value = FALSE;
699 while(*cp)
701 if(!in_quotes && *cp == ';')
703 *cp = '\0';
704 if(done_value) add_param(header, start);
705 done_value = TRUE;
706 start = cp + 1;
708 else if(*cp == '"')
709 in_quotes = !in_quotes;
710 cp++;
712 if(done_value) add_param(header, start);
715 static void read_value(header_t *header, char **cur)
717 char *end = *cur, *value;
718 DWORD len;
720 do {
721 end = strstr(end, "\r\n");
722 end += 2;
723 } while(*end == ' ' || *end == '\t');
725 len = end - *cur;
726 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
727 memcpy(value, *cur, len);
728 value[len] = '\0';
730 unfold_header(value, len);
731 TRACE("value %s\n", debugstr_a(value));
733 if(header->prop->flags & MPF_HASPARAMS)
735 split_params(header, value);
736 TRACE("value w/o params %s\n", debugstr_a(value));
739 header->value.vt = VT_LPSTR;
740 header->value.u.pszVal = value;
742 *cur = end;
745 static void init_content_type(MimeBody *body, header_t *header)
747 char *slash;
748 DWORD len;
750 slash = strchr(header->value.u.pszVal, '/');
751 if(!slash)
753 WARN("malformed context type value\n");
754 return;
756 len = slash - header->value.u.pszVal;
757 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
758 memcpy(body->content_pri_type, header->value.u.pszVal, len);
759 body->content_pri_type[len] = '\0';
760 body->content_sub_type = strdupA(slash + 1);
763 static void init_content_encoding(MimeBody *body, header_t *header)
765 const char *encoding = header->value.u.pszVal;
767 if(!strcasecmp(encoding, "base64"))
768 body->encoding = IET_BASE64;
769 else if(!strcasecmp(encoding, "quoted-printable"))
770 body->encoding = IET_QP;
771 else if(!strcasecmp(encoding, "7bit"))
772 body->encoding = IET_7BIT;
773 else if(!strcasecmp(encoding, "8bit"))
774 body->encoding = IET_8BIT;
775 else
776 FIXME("unknown encoding %s\n", debugstr_a(encoding));
779 static HRESULT parse_headers(MimeBody *body, IStream *stm)
781 char *header_buf, *cur_header_ptr;
782 HRESULT hr;
783 header_t *header;
785 hr = copy_headers_to_buf(stm, &header_buf);
786 if(FAILED(hr)) return hr;
788 cur_header_ptr = header_buf;
789 while((header = read_prop(body, &cur_header_ptr)))
791 read_value(header, &cur_header_ptr);
792 list_add_tail(&body->headers, &header->entry);
794 switch(header->prop->id) {
795 case PID_HDR_CNTTYPE:
796 init_content_type(body, header);
797 break;
798 case PID_HDR_CNTXFER:
799 init_content_encoding(body, header);
800 break;
804 HeapFree(GetProcessHeap(), 0, header_buf);
805 return hr;
808 static void empty_param_list(struct list *list)
810 param_t *param, *cursor2;
812 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
814 list_remove(&param->entry);
815 HeapFree(GetProcessHeap(), 0, param->name);
816 HeapFree(GetProcessHeap(), 0, param->value);
817 HeapFree(GetProcessHeap(), 0, param);
821 static void empty_header_list(struct list *list)
823 header_t *header, *cursor2;
825 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
827 list_remove(&header->entry);
828 PropVariantClear(&header->value);
829 empty_param_list(&header->params);
830 HeapFree(GetProcessHeap(), 0, header);
834 static void empty_new_prop_list(struct list *list)
836 property_list_entry_t *prop, *cursor2;
838 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
840 list_remove(&prop->entry);
841 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
842 HeapFree(GetProcessHeap(), 0, prop);
846 static void release_data(REFIID riid, void *data)
848 if(!data) return;
850 if(IsEqualIID(riid, &IID_IStream))
851 IStream_Release((IStream *)data);
852 else
853 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
856 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
858 header_t *header;
860 *prop = NULL;
862 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
864 if(ISPIDSTR(name))
866 if(STRTOPID(name) == header->prop->id)
868 *prop = header;
869 return S_OK;
872 else if(!lstrcmpiA(name, header->prop->name))
874 *prop = header;
875 return S_OK;
879 return MIME_E_NOT_FOUND;
882 static const property_t *find_default_prop(const char *name)
884 const property_t *prop_def = NULL;
886 for(prop_def = default_props; prop_def->name; prop_def++)
888 if(ISPIDSTR(name))
890 if(STRTOPID(name) == prop_def->id)
892 break;
895 else if(!lstrcmpiA(name, prop_def->name))
897 break;
901 if(prop_def->id)
902 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
903 else
904 prop_def = NULL;
906 return prop_def;
909 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
910 REFIID riid,
911 void** ppvObject)
913 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
915 *ppvObject = NULL;
917 if (IsEqualIID(riid, &IID_IUnknown) ||
918 IsEqualIID(riid, &IID_IPersist) ||
919 IsEqualIID(riid, &IID_IPersistStreamInit) ||
920 IsEqualIID(riid, &IID_IMimePropertySet) ||
921 IsEqualIID(riid, &IID_IMimeBody))
923 *ppvObject = iface;
926 if(*ppvObject)
928 IUnknown_AddRef((IUnknown*)*ppvObject);
929 return S_OK;
932 FIXME("no interface for %s\n", debugstr_guid(riid));
933 return E_NOINTERFACE;
936 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
938 MimeBody *This = impl_from_IMimeBody(iface);
939 LONG ref = InterlockedIncrement(&This->ref);
941 TRACE("(%p) ref=%d\n", This, ref);
943 return ref;
946 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
948 MimeBody *This = impl_from_IMimeBody(iface);
949 LONG ref = InterlockedDecrement(&This->ref);
951 TRACE("(%p) ref=%d\n", This, ref);
953 if (!ref)
955 empty_header_list(&This->headers);
956 empty_new_prop_list(&This->new_props);
958 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
959 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
961 release_data(&This->data_iid, This->data);
963 HeapFree(GetProcessHeap(), 0, This);
966 return ref;
969 static HRESULT WINAPI MimeBody_GetClassID(
970 IMimeBody* iface,
971 CLSID* pClassID)
973 MimeBody *This = impl_from_IMimeBody(iface);
974 FIXME("(%p)->(%p) stub\n", This, pClassID);
975 return E_NOTIMPL;
979 static HRESULT WINAPI MimeBody_IsDirty(
980 IMimeBody* iface)
982 MimeBody *This = impl_from_IMimeBody(iface);
983 FIXME("(%p)->() stub\n", This);
984 return E_NOTIMPL;
987 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
989 MimeBody *This = impl_from_IMimeBody(iface);
990 TRACE("(%p)->(%p)\n", This, pStm);
991 return parse_headers(This, pStm);
994 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
996 MimeBody *This = impl_from_IMimeBody(iface);
997 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
998 return E_NOTIMPL;
1001 static HRESULT WINAPI MimeBody_GetSizeMax(
1002 IMimeBody* iface,
1003 ULARGE_INTEGER* pcbSize)
1005 MimeBody *This = impl_from_IMimeBody(iface);
1006 FIXME("(%p)->(%p) stub\n", This, pcbSize);
1007 return E_NOTIMPL;
1010 static HRESULT WINAPI MimeBody_InitNew(
1011 IMimeBody* iface)
1013 MimeBody *This = impl_from_IMimeBody(iface);
1014 TRACE("(%p)->()\n", This);
1015 return S_OK;
1018 static HRESULT WINAPI MimeBody_GetPropInfo(
1019 IMimeBody* iface,
1020 LPCSTR pszName,
1021 LPMIMEPROPINFO pInfo)
1023 MimeBody *This = impl_from_IMimeBody(iface);
1024 header_t *header;
1025 HRESULT hr;
1026 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1028 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1030 if(!pszName || !pInfo)
1031 return E_INVALIDARG;
1033 TRACE("mask 0x%04x\n", pInfo->dwMask);
1035 if(pInfo->dwMask & ~supported)
1036 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
1038 hr = find_prop(This, pszName, &header);
1039 if(hr == S_OK)
1041 if(pInfo->dwMask & PIM_CHARSET)
1042 pInfo->hCharset = 0;
1043 if(pInfo->dwMask & PIM_FLAGS)
1044 pInfo->dwFlags = 0x00000000;
1045 if(pInfo->dwMask & PIM_ROWNUMBER)
1046 pInfo->dwRowNumber = 0;
1047 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1048 pInfo->ietEncoding = 0;
1049 if(pInfo->dwMask & PIM_VALUES)
1050 pInfo->cValues = 0;
1051 if(pInfo->dwMask & PIM_PROPID)
1052 pInfo->dwPropId = header->prop->id;
1053 if(pInfo->dwMask & PIM_VTDEFAULT)
1054 pInfo->vtDefault = header->prop->default_vt;
1055 if(pInfo->dwMask & PIM_VTCURRENT)
1056 pInfo->vtCurrent = 0;
1059 return hr;
1062 static HRESULT WINAPI MimeBody_SetPropInfo(
1063 IMimeBody* iface,
1064 LPCSTR pszName,
1065 LPCMIMEPROPINFO pInfo)
1067 MimeBody *This = impl_from_IMimeBody(iface);
1068 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1069 return E_NOTIMPL;
1072 static HRESULT WINAPI MimeBody_GetProp(
1073 IMimeBody* iface,
1074 LPCSTR pszName,
1075 DWORD dwFlags,
1076 LPPROPVARIANT pValue)
1078 MimeBody *This = impl_from_IMimeBody(iface);
1079 header_t *header;
1080 HRESULT hr;
1082 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1084 if(!pszName || !pValue)
1085 return E_INVALIDARG;
1087 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1089 PropVariantClear(pValue);
1090 pValue->vt = VT_LPSTR;
1091 pValue->u.pszVal = strdupA(This->content_pri_type);
1092 return S_OK;
1095 hr = find_prop(This, pszName, &header);
1096 if(hr == S_OK)
1098 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1100 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1101 if(FAILED(hr))
1102 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1105 return hr;
1108 static HRESULT WINAPI MimeBody_SetProp(
1109 IMimeBody* iface,
1110 LPCSTR pszName,
1111 DWORD dwFlags,
1112 LPCPROPVARIANT pValue)
1114 MimeBody *This = impl_from_IMimeBody(iface);
1115 header_t *header;
1116 HRESULT hr;
1118 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1120 if(!pszName || !pValue)
1121 return E_INVALIDARG;
1123 hr = find_prop(This, pszName, &header);
1124 if(hr != S_OK)
1126 property_list_entry_t *prop_entry;
1127 const property_t *prop = NULL;
1129 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1131 if(ISPIDSTR(pszName))
1133 if(STRTOPID(pszName) == prop_entry->prop.id)
1135 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1136 prop = &prop_entry->prop;
1137 break;
1140 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1142 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1143 prop = &prop_entry->prop;
1144 break;
1148 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
1149 if(!header)
1150 return E_OUTOFMEMORY;
1152 if(!prop)
1154 const property_t *prop_def = NULL;
1155 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
1156 if(!prop_entry)
1158 HeapFree(GetProcessHeap(), 0, header);
1159 return E_OUTOFMEMORY;
1162 prop_def = find_default_prop(pszName);
1163 if(prop_def)
1165 prop_entry->prop.name = strdupA(prop_def->name);
1166 prop_entry->prop.id = prop_def->id;
1168 else
1170 if(ISPIDSTR(pszName))
1172 HeapFree(GetProcessHeap(), 0, prop_entry);
1173 HeapFree(GetProcessHeap(), 0, header);
1174 return MIME_E_NOT_FOUND;
1177 prop_entry->prop.name = strdupA(pszName);
1178 prop_entry->prop.id = This->next_prop_id++;
1181 prop_entry->prop.flags = 0;
1182 prop_entry->prop.default_vt = pValue->vt;
1183 list_add_tail(&This->new_props, &prop_entry->entry);
1184 prop = &prop_entry->prop;
1185 TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
1188 header->prop = prop;
1189 PropVariantInit(&header->value);
1190 list_init(&header->params);
1191 list_add_tail(&This->headers, &header->entry);
1194 PropVariantCopy(&header->value, pValue);
1196 return S_OK;
1199 static HRESULT WINAPI MimeBody_AppendProp(
1200 IMimeBody* iface,
1201 LPCSTR pszName,
1202 DWORD dwFlags,
1203 LPPROPVARIANT pValue)
1205 MimeBody *This = impl_from_IMimeBody(iface);
1206 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1207 return E_NOTIMPL;
1210 static HRESULT WINAPI MimeBody_DeleteProp(
1211 IMimeBody* iface,
1212 LPCSTR pszName)
1214 MimeBody *This = impl_from_IMimeBody(iface);
1215 header_t *cursor;
1216 BOOL found;
1218 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1220 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1222 if(ISPIDSTR(pszName))
1223 found = STRTOPID(pszName) == cursor->prop->id;
1224 else
1225 found = !lstrcmpiA(pszName, cursor->prop->name);
1227 if(found)
1229 list_remove(&cursor->entry);
1230 HeapFree(GetProcessHeap(), 0, cursor);
1231 return S_OK;
1235 return MIME_E_NOT_FOUND;
1238 static HRESULT WINAPI MimeBody_CopyProps(
1239 IMimeBody* iface,
1240 ULONG cNames,
1241 LPCSTR* prgszName,
1242 IMimePropertySet* pPropertySet)
1244 MimeBody *This = impl_from_IMimeBody(iface);
1245 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1246 return E_NOTIMPL;
1249 static HRESULT WINAPI MimeBody_MoveProps(
1250 IMimeBody* iface,
1251 ULONG cNames,
1252 LPCSTR* prgszName,
1253 IMimePropertySet* pPropertySet)
1255 MimeBody *This = impl_from_IMimeBody(iface);
1256 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1257 return E_NOTIMPL;
1260 static HRESULT WINAPI MimeBody_DeleteExcept(
1261 IMimeBody* iface,
1262 ULONG cNames,
1263 LPCSTR* prgszName)
1265 MimeBody *This = impl_from_IMimeBody(iface);
1266 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
1267 return E_NOTIMPL;
1270 static HRESULT WINAPI MimeBody_QueryProp(
1271 IMimeBody* iface,
1272 LPCSTR pszName,
1273 LPCSTR pszCriteria,
1274 boolean fSubString,
1275 boolean fCaseSensitive)
1277 MimeBody *This = impl_from_IMimeBody(iface);
1278 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1279 return E_NOTIMPL;
1282 static HRESULT WINAPI MimeBody_GetCharset(
1283 IMimeBody* iface,
1284 LPHCHARSET phCharset)
1286 MimeBody *This = impl_from_IMimeBody(iface);
1287 FIXME("(%p)->(%p) stub\n", This, phCharset);
1288 *phCharset = NULL;
1289 return S_OK;
1292 static HRESULT WINAPI MimeBody_SetCharset(
1293 IMimeBody* iface,
1294 HCHARSET hCharset,
1295 CSETAPPLYTYPE applytype)
1297 MimeBody *This = impl_from_IMimeBody(iface);
1298 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1299 return E_NOTIMPL;
1302 static HRESULT WINAPI MimeBody_GetParameters(
1303 IMimeBody* iface,
1304 LPCSTR pszName,
1305 ULONG* pcParams,
1306 LPMIMEPARAMINFO* pprgParam)
1308 MimeBody *This = impl_from_IMimeBody(iface);
1309 HRESULT hr;
1310 header_t *header;
1312 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1314 *pprgParam = NULL;
1315 *pcParams = 0;
1317 hr = find_prop(This, pszName, &header);
1318 if(hr != S_OK) return hr;
1320 *pcParams = list_count(&header->params);
1321 if(*pcParams)
1323 IMimeAllocator *alloc;
1324 param_t *param;
1325 MIMEPARAMINFO *info;
1327 MimeOleGetAllocator(&alloc);
1329 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1330 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1332 int len;
1334 len = strlen(param->name) + 1;
1335 info->pszName = IMimeAllocator_Alloc(alloc, len);
1336 memcpy(info->pszName, param->name, len);
1337 len = strlen(param->value) + 1;
1338 info->pszData = IMimeAllocator_Alloc(alloc, len);
1339 memcpy(info->pszData, param->value, len);
1340 info++;
1342 IMimeAllocator_Release(alloc);
1344 return S_OK;
1347 static HRESULT WINAPI MimeBody_IsContentType(
1348 IMimeBody* iface,
1349 LPCSTR pszPriType,
1350 LPCSTR pszSubType)
1352 MimeBody *This = impl_from_IMimeBody(iface);
1354 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1355 if(pszPriType)
1357 const char *pri = This->content_pri_type;
1358 if(!pri) pri = "text";
1359 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1362 if(pszSubType)
1364 const char *sub = This->content_sub_type;
1365 if(!sub) sub = "plain";
1366 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1369 return S_OK;
1372 static HRESULT WINAPI MimeBody_BindToObject(
1373 IMimeBody* iface,
1374 REFIID riid,
1375 void** ppvObject)
1377 MimeBody *This = impl_from_IMimeBody(iface);
1378 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1379 return E_NOTIMPL;
1382 static HRESULT WINAPI MimeBody_Clone(
1383 IMimeBody* iface,
1384 IMimePropertySet** ppPropertySet)
1386 MimeBody *This = impl_from_IMimeBody(iface);
1387 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1388 return E_NOTIMPL;
1391 static HRESULT WINAPI MimeBody_SetOption(
1392 IMimeBody* iface,
1393 const TYPEDID oid,
1394 LPCPROPVARIANT pValue)
1396 MimeBody *This = impl_from_IMimeBody(iface);
1397 HRESULT hr = E_NOTIMPL;
1398 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
1400 if(pValue->vt != TYPEDID_TYPE(oid))
1402 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
1403 return E_INVALIDARG;
1406 switch(oid)
1408 case OID_SECURITY_HWND_OWNER:
1409 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
1410 hr = S_OK;
1411 break;
1412 case OID_TRANSMIT_BODY_ENCODING:
1413 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
1414 hr = S_OK;
1415 break;
1416 default:
1417 FIXME("Unhandled oid %08x\n", oid);
1420 return hr;
1423 static HRESULT WINAPI MimeBody_GetOption(
1424 IMimeBody* iface,
1425 const TYPEDID oid,
1426 LPPROPVARIANT pValue)
1428 MimeBody *This = impl_from_IMimeBody(iface);
1429 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
1430 return E_NOTIMPL;
1433 static HRESULT WINAPI MimeBody_EnumProps(
1434 IMimeBody* iface,
1435 DWORD dwFlags,
1436 IMimeEnumProperties** ppEnum)
1438 MimeBody *This = impl_from_IMimeBody(iface);
1439 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
1440 return E_NOTIMPL;
1443 static HRESULT WINAPI MimeBody_IsType(
1444 IMimeBody* iface,
1445 IMSGBODYTYPE bodytype)
1447 MimeBody *This = impl_from_IMimeBody(iface);
1449 TRACE("(%p)->(%d)\n", This, bodytype);
1450 switch(bodytype)
1452 case IBT_EMPTY:
1453 return This->data ? S_FALSE : S_OK;
1454 default:
1455 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1457 return S_OK;
1460 static HRESULT WINAPI MimeBody_SetDisplayName(
1461 IMimeBody* iface,
1462 LPCSTR pszDisplay)
1464 MimeBody *This = impl_from_IMimeBody(iface);
1465 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1466 return E_NOTIMPL;
1469 static HRESULT WINAPI MimeBody_GetDisplayName(
1470 IMimeBody* iface,
1471 LPSTR* ppszDisplay)
1473 MimeBody *This = impl_from_IMimeBody(iface);
1474 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1475 return E_NOTIMPL;
1478 static HRESULT WINAPI MimeBody_GetOffsets(
1479 IMimeBody* iface,
1480 LPBODYOFFSETS pOffsets)
1482 MimeBody *This = impl_from_IMimeBody(iface);
1483 TRACE("(%p)->(%p)\n", This, pOffsets);
1485 *pOffsets = This->body_offsets;
1487 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1488 return S_OK;
1491 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1492 IMimeBody* iface,
1493 ENCODINGTYPE* pietEncoding)
1495 MimeBody *This = impl_from_IMimeBody(iface);
1497 TRACE("(%p)->(%p)\n", This, pietEncoding);
1499 *pietEncoding = This->encoding;
1500 return S_OK;
1503 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1504 IMimeBody* iface,
1505 ENCODINGTYPE ietEncoding)
1507 MimeBody *This = impl_from_IMimeBody(iface);
1509 TRACE("(%p)->(%d)\n", This, ietEncoding);
1511 This->encoding = ietEncoding;
1512 return S_OK;
1515 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1516 IMimeBody* iface,
1517 ENCODINGTYPE ietEncoding,
1518 ULONG* pcbSize)
1520 MimeBody *This = impl_from_IMimeBody(iface);
1521 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1522 return E_NOTIMPL;
1525 static HRESULT WINAPI MimeBody_GetDataHere(
1526 IMimeBody* iface,
1527 ENCODINGTYPE ietEncoding,
1528 IStream* pStream)
1530 MimeBody *This = impl_from_IMimeBody(iface);
1531 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1532 return E_NOTIMPL;
1535 static const signed char base64_decode_table[] =
1537 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1538 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1539 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1540 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1541 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1542 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1543 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1544 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1547 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1549 const unsigned char *ptr, *end;
1550 unsigned char buf[1024];
1551 LARGE_INTEGER pos;
1552 unsigned char *ret;
1553 unsigned char in[4];
1554 IStream *output;
1555 DWORD size;
1556 int n = 0;
1557 HRESULT hres;
1559 pos.QuadPart = 0;
1560 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1561 if(FAILED(hres))
1562 return hres;
1564 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1565 if(FAILED(hres))
1566 return hres;
1568 while(1) {
1569 hres = IStream_Read(input, buf, sizeof(buf), &size);
1570 if(FAILED(hres) || !size)
1571 break;
1573 ptr = ret = buf;
1574 end = buf + size;
1576 while(1) {
1577 /* skip invalid chars */
1578 while(ptr < end &&
1579 (*ptr >= sizeof(base64_decode_table)/sizeof(*base64_decode_table)
1580 || base64_decode_table[*ptr] == -1))
1581 ptr++;
1582 if(ptr == end)
1583 break;
1585 in[n++] = base64_decode_table[*ptr++];
1586 switch(n) {
1587 case 2:
1588 *ret++ = in[0] << 2 | in[1] >> 4;
1589 continue;
1590 case 3:
1591 *ret++ = in[1] << 4 | in[2] >> 2;
1592 continue;
1593 case 4:
1594 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1595 n = 0;
1599 if(ret > buf) {
1600 hres = IStream_Write(output, buf, ret - buf, NULL);
1601 if(FAILED(hres))
1602 break;
1606 if(SUCCEEDED(hres))
1607 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1608 if(FAILED(hres)) {
1609 IStream_Release(output);
1610 return hres;
1613 *ret_stream = output;
1614 return S_OK;
1617 static int hex_digit(char c)
1619 if('0' <= c && c <= '9')
1620 return c - '0';
1621 if('A' <= c && c <= 'F')
1622 return c - 'A' + 10;
1623 if('a' <= c && c <= 'f')
1624 return c - 'a' + 10;
1625 return -1;
1628 static HRESULT decode_qp(IStream *input, IStream **ret_stream)
1630 const unsigned char *ptr, *end;
1631 unsigned char *ret, prev = 0;
1632 unsigned char buf[1024];
1633 LARGE_INTEGER pos;
1634 IStream *output;
1635 DWORD size;
1636 int n = -1;
1637 HRESULT hres;
1639 pos.QuadPart = 0;
1640 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1641 if(FAILED(hres))
1642 return hres;
1644 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1645 if(FAILED(hres))
1646 return hres;
1648 while(1) {
1649 hres = IStream_Read(input, buf, sizeof(buf), &size);
1650 if(FAILED(hres) || !size)
1651 break;
1653 ptr = ret = buf;
1654 end = buf + size;
1656 while(ptr < end) {
1657 unsigned char byte = *ptr++;
1659 switch(n) {
1660 case -1:
1661 if(byte == '=')
1662 n = 0;
1663 else
1664 *ret++ = byte;
1665 continue;
1666 case 0:
1667 prev = byte;
1668 n = 1;
1669 continue;
1670 case 1:
1671 if(prev != '\r' || byte != '\n') {
1672 int h1 = hex_digit(prev), h2 = hex_digit(byte);
1673 if(h1 != -1 && h2 != -1)
1674 *ret++ = (h1 << 4) | h2;
1675 else
1676 *ret++ = '=';
1678 n = -1;
1679 continue;
1683 if(ret > buf) {
1684 hres = IStream_Write(output, buf, ret - buf, NULL);
1685 if(FAILED(hres))
1686 break;
1690 if(SUCCEEDED(hres))
1691 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1692 if(FAILED(hres)) {
1693 IStream_Release(output);
1694 return hres;
1697 *ret_stream = output;
1698 return S_OK;
1701 static HRESULT WINAPI MimeBody_GetData(
1702 IMimeBody* iface,
1703 ENCODINGTYPE ietEncoding,
1704 IStream** ppStream)
1706 MimeBody *This = impl_from_IMimeBody(iface);
1707 ULARGE_INTEGER start, size;
1708 HRESULT hres;
1710 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1712 if(This->encoding != ietEncoding) {
1713 switch(This->encoding) {
1714 case IET_BASE64:
1715 hres = decode_base64(This->data, ppStream);
1716 break;
1717 case IET_QP:
1718 hres = decode_qp(This->data, ppStream);
1719 break;
1720 default:
1721 FIXME("Decoding %d is not supported.\n", This->encoding);
1722 hres = S_FALSE;
1724 if(ietEncoding != IET_BINARY)
1725 FIXME("Encoding %d is not supported.\n", ietEncoding);
1726 if(hres != S_FALSE)
1727 return hres;
1730 start.QuadPart = 0;
1731 hres = get_stream_size(This->data, &size);
1732 if(SUCCEEDED(hres))
1733 hres = create_sub_stream(This->data, start, size, ppStream);
1734 return hres;
1737 static HRESULT WINAPI MimeBody_SetData(
1738 IMimeBody* iface,
1739 ENCODINGTYPE ietEncoding,
1740 LPCSTR pszPriType,
1741 LPCSTR pszSubType,
1742 REFIID riid,
1743 LPVOID pvObject)
1745 MimeBody *This = impl_from_IMimeBody(iface);
1746 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1747 debugstr_guid(riid), pvObject);
1749 if(IsEqualIID(riid, &IID_IStream))
1750 IStream_AddRef((IStream *)pvObject);
1751 else
1753 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1754 return E_INVALIDARG;
1757 if(This->data)
1758 FIXME("release old data\n");
1760 This->data_iid = *riid;
1761 This->data = pvObject;
1763 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1765 /* FIXME: Update the content type.
1766 If pszPriType == NULL use 'application'
1767 If pszSubType == NULL use 'octet-stream' */
1769 return S_OK;
1772 static HRESULT WINAPI MimeBody_EmptyData(
1773 IMimeBody* iface)
1775 MimeBody *This = impl_from_IMimeBody(iface);
1776 FIXME("(%p)->() stub\n", This);
1777 return E_NOTIMPL;
1780 static HRESULT WINAPI MimeBody_CopyTo(
1781 IMimeBody* iface,
1782 IMimeBody* pBody)
1784 MimeBody *This = impl_from_IMimeBody(iface);
1785 FIXME("(%p)->(%p) stub\n", This, pBody);
1786 return E_NOTIMPL;
1789 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1790 IMimeBody* iface,
1791 LPTRANSMITINFO pTransmitInfo)
1793 MimeBody *This = impl_from_IMimeBody(iface);
1794 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1795 return E_NOTIMPL;
1798 static HRESULT WINAPI MimeBody_SaveToFile(
1799 IMimeBody* iface,
1800 ENCODINGTYPE ietEncoding,
1801 LPCSTR pszFilePath)
1803 MimeBody *This = impl_from_IMimeBody(iface);
1804 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1805 return E_NOTIMPL;
1808 static HRESULT WINAPI MimeBody_GetHandle(
1809 IMimeBody* iface,
1810 LPHBODY phBody)
1812 MimeBody *This = impl_from_IMimeBody(iface);
1813 TRACE("(%p)->(%p)\n", iface, phBody);
1815 if(!phBody)
1816 return E_INVALIDARG;
1818 *phBody = This->handle;
1819 return This->handle ? S_OK : MIME_E_NO_DATA;
1822 static IMimeBodyVtbl body_vtbl =
1824 MimeBody_QueryInterface,
1825 MimeBody_AddRef,
1826 MimeBody_Release,
1827 MimeBody_GetClassID,
1828 MimeBody_IsDirty,
1829 MimeBody_Load,
1830 MimeBody_Save,
1831 MimeBody_GetSizeMax,
1832 MimeBody_InitNew,
1833 MimeBody_GetPropInfo,
1834 MimeBody_SetPropInfo,
1835 MimeBody_GetProp,
1836 MimeBody_SetProp,
1837 MimeBody_AppendProp,
1838 MimeBody_DeleteProp,
1839 MimeBody_CopyProps,
1840 MimeBody_MoveProps,
1841 MimeBody_DeleteExcept,
1842 MimeBody_QueryProp,
1843 MimeBody_GetCharset,
1844 MimeBody_SetCharset,
1845 MimeBody_GetParameters,
1846 MimeBody_IsContentType,
1847 MimeBody_BindToObject,
1848 MimeBody_Clone,
1849 MimeBody_SetOption,
1850 MimeBody_GetOption,
1851 MimeBody_EnumProps,
1852 MimeBody_IsType,
1853 MimeBody_SetDisplayName,
1854 MimeBody_GetDisplayName,
1855 MimeBody_GetOffsets,
1856 MimeBody_GetCurrentEncoding,
1857 MimeBody_SetCurrentEncoding,
1858 MimeBody_GetEstimatedSize,
1859 MimeBody_GetDataHere,
1860 MimeBody_GetData,
1861 MimeBody_SetData,
1862 MimeBody_EmptyData,
1863 MimeBody_CopyTo,
1864 MimeBody_GetTransmitInfo,
1865 MimeBody_SaveToFile,
1866 MimeBody_GetHandle
1869 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1871 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1872 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1874 body->body_offsets = *offsets;
1875 return S_OK;
1878 #define FIRST_CUSTOM_PROP_ID 0x100
1880 static MimeBody *mimebody_create(void)
1882 MimeBody *This;
1883 BODYOFFSETS body_offsets;
1885 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1886 if (!This)
1887 return NULL;
1889 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1890 This->ref = 1;
1891 This->handle = NULL;
1892 list_init(&This->headers);
1893 list_init(&This->new_props);
1894 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1895 This->content_pri_type = NULL;
1896 This->content_sub_type = NULL;
1897 This->encoding = IET_7BIT;
1898 This->data = NULL;
1899 This->data_iid = IID_NULL;
1901 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1902 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1903 MimeBody_set_offsets(This, &body_offsets);
1905 return This;
1908 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1910 MimeBody *mb;
1912 if(outer)
1913 return CLASS_E_NOAGGREGATION;
1915 if ((mb = mimebody_create()))
1917 *ppv = &mb->IMimeBody_iface;
1918 return S_OK;
1920 else
1922 *ppv = NULL;
1923 return E_OUTOFMEMORY;
1927 typedef struct body_t
1929 struct list entry;
1930 DWORD index;
1931 MimeBody *mime_body;
1933 struct body_t *parent;
1934 struct list children;
1935 } body_t;
1937 typedef struct MimeMessage
1939 IMimeMessage IMimeMessage_iface;
1940 LONG ref;
1941 IStream *stream;
1943 struct list body_tree;
1944 DWORD next_index;
1945 } MimeMessage;
1947 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1949 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1952 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1954 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1956 if (IsEqualIID(riid, &IID_IUnknown) ||
1957 IsEqualIID(riid, &IID_IPersist) ||
1958 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1959 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1960 IsEqualIID(riid, &IID_IMimeMessage))
1962 *ppv = iface;
1963 IMimeMessage_AddRef(iface);
1964 return S_OK;
1967 FIXME("no interface for %s\n", debugstr_guid(riid));
1968 *ppv = NULL;
1969 return E_NOINTERFACE;
1972 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1974 MimeMessage *This = impl_from_IMimeMessage(iface);
1975 ULONG ref = InterlockedIncrement(&This->ref);
1977 TRACE("(%p) ref=%d\n", This, ref);
1979 return ref;
1982 static void empty_body_list(struct list *list)
1984 body_t *body, *cursor2;
1985 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1987 empty_body_list(&body->children);
1988 list_remove(&body->entry);
1989 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1990 HeapFree(GetProcessHeap(), 0, body);
1994 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1996 MimeMessage *This = impl_from_IMimeMessage(iface);
1997 ULONG ref = InterlockedDecrement(&This->ref);
1999 TRACE("(%p) ref=%d\n", This, ref);
2001 if (!ref)
2003 empty_body_list(&This->body_tree);
2005 if(This->stream) IStream_Release(This->stream);
2006 HeapFree(GetProcessHeap(), 0, This);
2009 return ref;
2012 /*** IPersist methods ***/
2013 static HRESULT WINAPI MimeMessage_GetClassID(
2014 IMimeMessage *iface,
2015 CLSID *pClassID)
2017 FIXME("(%p)->(%p)\n", iface, pClassID);
2018 return E_NOTIMPL;
2021 /*** IPersistStreamInit methods ***/
2022 static HRESULT WINAPI MimeMessage_IsDirty(
2023 IMimeMessage *iface)
2025 FIXME("(%p)->()\n", iface);
2026 return E_NOTIMPL;
2029 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
2031 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
2032 if(body)
2034 body->mime_body = mime_body;
2035 body->index = index;
2036 list_init(&body->children);
2037 body->parent = parent;
2039 mime_body->handle = UlongToHandle(body->index);
2041 return body;
2044 typedef struct
2046 struct list entry;
2047 BODYOFFSETS offsets;
2048 } offset_entry_t;
2050 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
2052 HRESULT hr;
2053 DWORD read, boundary_start;
2054 int boundary_len = strlen(boundary);
2055 char *buf, *ptr, *overlap;
2056 DWORD start = 0, overlap_no;
2057 offset_entry_t *cur_body = NULL;
2058 BOOL is_first_line = TRUE;
2059 ULARGE_INTEGER cur;
2060 LARGE_INTEGER zero;
2062 list_init(body_offsets);
2064 overlap_no = boundary_len + 5;
2066 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
2068 zero.QuadPart = 0;
2069 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
2070 start = cur.u.LowPart;
2072 do {
2073 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
2074 if(FAILED(hr)) goto end;
2075 if(read == 0) break;
2076 overlap[read] = '\0';
2078 ptr = buf;
2079 while(1) {
2080 if(is_first_line) {
2081 is_first_line = FALSE;
2082 }else {
2083 ptr = strstr(ptr, "\r\n");
2084 if(!ptr)
2085 break;
2086 ptr += 2;
2089 boundary_start = start + ptr - buf;
2091 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) {
2092 ptr += boundary_len + 2;
2094 if(*ptr == '\r' && *(ptr + 1) == '\n')
2096 ptr += 2;
2097 if(cur_body)
2099 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2100 list_add_tail(body_offsets, &cur_body->entry);
2102 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
2103 cur_body->offsets.cbBoundaryStart = boundary_start;
2104 cur_body->offsets.cbHeaderStart = start + ptr - buf;
2106 else if(*ptr == '-' && *(ptr + 1) == '-')
2108 if(cur_body)
2110 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2111 list_add_tail(body_offsets, &cur_body->entry);
2112 goto end;
2118 if(overlap == buf) /* 1st iteration */
2120 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2121 overlap = buf + overlap_no;
2122 start += read - overlap_no;
2124 else
2126 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2127 start += read;
2129 } while(1);
2131 end:
2132 HeapFree(GetProcessHeap(), 0, buf);
2133 return hr;
2136 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2138 ULARGE_INTEGER start, length;
2139 MimeBody *mime_body;
2140 HRESULT hr;
2141 body_t *body;
2142 LARGE_INTEGER pos;
2144 pos.QuadPart = offset->cbHeaderStart;
2145 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL);
2147 mime_body = mimebody_create();
2148 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2150 pos.QuadPart = 0;
2151 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start);
2152 offset->cbBodyStart = start.QuadPart;
2153 if (parent) MimeBody_set_offsets(mime_body, offset);
2155 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart;
2156 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data);
2157 mime_body->data_iid = IID_IStream;
2159 body = new_body_entry(mime_body, msg->next_index++, parent);
2161 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2163 MIMEPARAMINFO *param_info;
2164 ULONG count, i;
2165 IMimeAllocator *alloc;
2167 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2168 &param_info);
2169 if(hr != S_OK || count == 0) return body;
2171 MimeOleGetAllocator(&alloc);
2173 for(i = 0; i < count; i++)
2175 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2177 struct list offset_list;
2178 offset_entry_t *cur, *cursor2;
2179 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2180 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2182 body_t *sub_body;
2184 sub_body = create_sub_body(msg, pStm, &cur->offsets, body);
2185 list_add_tail(&body->children, &sub_body->entry);
2186 list_remove(&cur->entry);
2187 HeapFree(GetProcessHeap(), 0, cur);
2189 break;
2192 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2193 IMimeAllocator_Release(alloc);
2195 return body;
2198 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2200 MimeMessage *This = impl_from_IMimeMessage(iface);
2201 body_t *root_body;
2202 BODYOFFSETS offsets;
2203 ULARGE_INTEGER cur;
2204 LARGE_INTEGER zero;
2206 TRACE("(%p)->(%p)\n", iface, pStm);
2208 if(This->stream)
2210 FIXME("already loaded a message\n");
2211 return E_FAIL;
2214 empty_body_list(&This->body_tree);
2216 IStream_AddRef(pStm);
2217 This->stream = pStm;
2218 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2219 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2221 root_body = create_sub_body(This, pStm, &offsets, NULL);
2223 zero.QuadPart = 0;
2224 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2225 offsets.cbBodyEnd = cur.u.LowPart;
2226 MimeBody_set_offsets(root_body->mime_body, &offsets);
2228 list_add_head(&This->body_tree, &root_body->entry);
2230 return S_OK;
2233 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2235 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2236 return E_NOTIMPL;
2239 static HRESULT WINAPI MimeMessage_GetSizeMax(
2240 IMimeMessage *iface,
2241 ULARGE_INTEGER *pcbSize)
2243 FIXME("(%p)->(%p)\n", iface, pcbSize);
2244 return E_NOTIMPL;
2247 static HRESULT WINAPI MimeMessage_InitNew(
2248 IMimeMessage *iface)
2250 FIXME("(%p)->()\n", iface);
2251 return E_NOTIMPL;
2254 /*** IMimeMessageTree methods ***/
2255 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2256 DWORD dwFlags)
2258 MimeMessage *This = impl_from_IMimeMessage(iface);
2260 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
2262 IStream_AddRef(This->stream);
2263 *ppStream = This->stream;
2264 return S_OK;
2267 static HRESULT WINAPI MimeMessage_GetMessageSize(
2268 IMimeMessage *iface,
2269 ULONG *pcbSize,
2270 DWORD dwFlags)
2272 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
2273 return E_NOTIMPL;
2276 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2277 IMimeMessage *iface,
2278 IStream *pStream)
2280 FIXME("(%p)->(%p)\n", iface, pStream);
2281 return E_NOTIMPL;
2284 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2285 IMimeMessage *iface,
2286 IStream *pStream,
2287 DWORD dwFlags)
2289 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
2290 return E_NOTIMPL;
2294 static HRESULT WINAPI MimeMessage_GetFlags(
2295 IMimeMessage *iface,
2296 DWORD *pdwFlags)
2298 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2299 return E_NOTIMPL;
2302 static HRESULT WINAPI MimeMessage_Commit(
2303 IMimeMessage *iface,
2304 DWORD dwFlags)
2306 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
2307 return S_OK;
2311 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2312 IMimeMessage *iface)
2314 FIXME("(%p)->()\n", iface);
2315 return E_NOTIMPL;
2318 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2320 body_t *cur;
2321 HRESULT hr;
2323 if(hbody == HBODY_ROOT)
2325 *body = LIST_ENTRY(list_head(list), body_t, entry);
2326 return S_OK;
2329 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2331 if(cur->index == HandleToUlong(hbody))
2333 *body = cur;
2334 return S_OK;
2336 hr = find_body(&cur->children, hbody, body);
2337 if(hr == S_OK) return S_OK;
2339 return S_FALSE;
2342 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2343 void **ppvObject)
2345 MimeMessage *This = impl_from_IMimeMessage(iface);
2346 HRESULT hr;
2347 body_t *body;
2349 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2351 hr = find_body(&This->body_tree, hBody, &body);
2353 if(hr != S_OK) return hr;
2355 if(IsEqualIID(riid, &IID_IMimeBody))
2357 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2358 *ppvObject = &body->mime_body->IMimeBody_iface;
2359 return S_OK;
2362 return E_NOINTERFACE;
2365 static HRESULT WINAPI MimeMessage_SaveBody(
2366 IMimeMessage *iface,
2367 HBODY hBody,
2368 DWORD dwFlags,
2369 IStream *pStream)
2371 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
2372 return E_NOTIMPL;
2375 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2377 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2378 body_t *body;
2379 HRESULT hr;
2380 struct list *list;
2382 if(location == IBL_ROOT)
2384 *out = root;
2385 return S_OK;
2388 hr = find_body(&msg->body_tree, pivot, &body);
2390 if(hr == S_OK)
2392 switch(location)
2394 case IBL_PARENT:
2395 if(body->parent)
2396 *out = body->parent;
2397 else
2398 hr = MIME_E_NOT_FOUND;
2399 break;
2401 case IBL_FIRST:
2402 list = list_head(&body->children);
2403 if(list)
2404 *out = LIST_ENTRY(list, body_t, entry);
2405 else
2406 hr = MIME_E_NOT_FOUND;
2407 break;
2409 case IBL_LAST:
2410 list = list_tail(&body->children);
2411 if(list)
2412 *out = LIST_ENTRY(list, body_t, entry);
2413 else
2414 hr = MIME_E_NOT_FOUND;
2415 break;
2417 case IBL_NEXT:
2418 list = list_next(&body->parent->children, &body->entry);
2419 if(list)
2420 *out = LIST_ENTRY(list, body_t, entry);
2421 else
2422 hr = MIME_E_NOT_FOUND;
2423 break;
2425 case IBL_PREVIOUS:
2426 list = list_prev(&body->parent->children, &body->entry);
2427 if(list)
2428 *out = LIST_ENTRY(list, body_t, entry);
2429 else
2430 hr = MIME_E_NOT_FOUND;
2431 break;
2433 default:
2434 hr = E_FAIL;
2435 break;
2439 return hr;
2443 static HRESULT WINAPI MimeMessage_InsertBody(
2444 IMimeMessage *iface,
2445 BODYLOCATION location,
2446 HBODY hPivot,
2447 LPHBODY phBody)
2449 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2450 return E_NOTIMPL;
2453 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2454 HBODY *phBody)
2456 MimeMessage *This = impl_from_IMimeMessage(iface);
2457 body_t *body;
2458 HRESULT hr;
2460 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2462 if(!phBody)
2463 return E_INVALIDARG;
2465 *phBody = NULL;
2467 hr = get_body(This, location, hPivot, &body);
2469 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2471 return hr;
2474 static HRESULT WINAPI MimeMessage_DeleteBody(
2475 IMimeMessage *iface,
2476 HBODY hBody,
2477 DWORD dwFlags)
2479 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
2480 return E_NOTIMPL;
2483 static HRESULT WINAPI MimeMessage_MoveBody(
2484 IMimeMessage *iface,
2485 HBODY hBody,
2486 BODYLOCATION location)
2488 FIXME("(%p)->(%d)\n", iface, location);
2489 return E_NOTIMPL;
2492 static void count_children(body_t *body, boolean recurse, ULONG *count)
2494 body_t *child;
2496 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2498 (*count)++;
2499 if(recurse) count_children(child, recurse, count);
2503 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2504 ULONG *pcBodies)
2506 HRESULT hr;
2507 MimeMessage *This = impl_from_IMimeMessage(iface);
2508 body_t *body;
2510 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2512 hr = find_body(&This->body_tree, hParent, &body);
2513 if(hr != S_OK) return hr;
2515 *pcBodies = 1;
2516 count_children(body, fRecurse, pcBodies);
2518 return S_OK;
2521 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2523 struct list *ptr;
2524 HBODY next;
2526 for (;;)
2528 if (!body) ptr = list_head( &This->body_tree );
2529 else
2531 ptr = list_head( &body->children );
2532 while (!ptr)
2534 if (!body->parent) return MIME_E_NOT_FOUND;
2535 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2539 body = LIST_ENTRY( ptr, body_t, entry );
2540 next = UlongToHandle( body->index );
2541 find->dwReserved = body->index;
2542 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2543 find->pszSubType) == S_OK)
2545 *out = next;
2546 return S_OK;
2549 return MIME_E_NOT_FOUND;
2552 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2554 MimeMessage *This = impl_from_IMimeMessage(iface);
2556 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2558 pFindBody->dwReserved = 0;
2559 return find_next(This, NULL, pFindBody, phBody);
2562 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2564 MimeMessage *This = impl_from_IMimeMessage(iface);
2565 body_t *body;
2566 HRESULT hr;
2568 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2570 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2571 if (hr != S_OK) return MIME_E_NOT_FOUND;
2572 return find_next(This, body, pFindBody, phBody);
2575 static HRESULT WINAPI MimeMessage_ResolveURL(
2576 IMimeMessage *iface,
2577 HBODY hRelated,
2578 LPCSTR pszBase,
2579 LPCSTR pszURL,
2580 DWORD dwFlags,
2581 LPHBODY phBody)
2583 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2584 return E_NOTIMPL;
2587 static HRESULT WINAPI MimeMessage_ToMultipart(
2588 IMimeMessage *iface,
2589 HBODY hBody,
2590 LPCSTR pszSubType,
2591 LPHBODY phMultipart)
2593 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2594 return E_NOTIMPL;
2597 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2598 IMimeMessage *iface,
2599 HBODY hBody,
2600 LPBODYOFFSETS pOffsets)
2602 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2603 return E_NOTIMPL;
2606 static HRESULT WINAPI MimeMessage_GetCharset(
2607 IMimeMessage *iface,
2608 LPHCHARSET phCharset)
2610 FIXME("(%p)->(%p)\n", iface, phCharset);
2611 *phCharset = NULL;
2612 return S_OK;
2615 static HRESULT WINAPI MimeMessage_SetCharset(
2616 IMimeMessage *iface,
2617 HCHARSET hCharset,
2618 CSETAPPLYTYPE applytype)
2620 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2621 return E_NOTIMPL;
2624 static HRESULT WINAPI MimeMessage_IsBodyType(
2625 IMimeMessage *iface,
2626 HBODY hBody,
2627 IMSGBODYTYPE bodytype)
2629 HRESULT hr;
2630 IMimeBody *mime_body;
2631 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2633 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2634 if(hr != S_OK) return hr;
2636 hr = IMimeBody_IsType(mime_body, bodytype);
2637 MimeBody_Release(mime_body);
2638 return hr;
2641 static HRESULT WINAPI MimeMessage_IsContentType(
2642 IMimeMessage *iface,
2643 HBODY hBody,
2644 LPCSTR pszPriType,
2645 LPCSTR pszSubType)
2647 HRESULT hr;
2648 IMimeBody *mime_body;
2649 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2650 debugstr_a(pszSubType));
2652 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2653 if(FAILED(hr)) return hr;
2655 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2656 IMimeBody_Release(mime_body);
2657 return hr;
2660 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2661 IMimeMessage *iface,
2662 HBODY hBody,
2663 LPCSTR pszName,
2664 LPCSTR pszCriteria,
2665 boolean fSubString,
2666 boolean fCaseSensitive)
2668 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2669 return E_NOTIMPL;
2672 static HRESULT WINAPI MimeMessage_GetBodyProp(
2673 IMimeMessage *iface,
2674 HBODY hBody,
2675 LPCSTR pszName,
2676 DWORD dwFlags,
2677 LPPROPVARIANT pValue)
2679 HRESULT hr;
2680 IMimeBody *mime_body;
2682 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2684 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2685 if(hr != S_OK) return hr;
2687 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2688 IMimeBody_Release(mime_body);
2690 return hr;
2693 static HRESULT WINAPI MimeMessage_SetBodyProp(
2694 IMimeMessage *iface,
2695 HBODY hBody,
2696 LPCSTR pszName,
2697 DWORD dwFlags,
2698 LPCPROPVARIANT pValue)
2700 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2701 return E_NOTIMPL;
2704 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2705 IMimeMessage *iface,
2706 HBODY hBody,
2707 LPCSTR pszName)
2709 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2710 return E_NOTIMPL;
2713 static HRESULT WINAPI MimeMessage_SetOption(
2714 IMimeMessage *iface,
2715 const TYPEDID oid,
2716 LPCPROPVARIANT pValue)
2718 HRESULT hr = S_OK;
2719 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2721 /* Message ID is checked before type.
2722 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2724 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2726 WARN("oid (%08x) out of range\n", oid);
2727 return MIME_E_INVALID_OPTION_ID;
2730 if(pValue->vt != TYPEDID_TYPE(oid))
2732 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2733 return S_OK;
2736 switch(oid)
2738 case OID_HIDE_TNEF_ATTACHMENTS:
2739 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2740 break;
2741 case OID_SHOW_MACBINARY:
2742 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2743 break;
2744 case OID_SAVEBODY_KEEPBOUNDARY:
2745 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal);
2746 break;
2747 case OID_CLEANUP_TREE_ON_SAVE:
2748 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal);
2749 break;
2750 default:
2751 FIXME("Unhandled oid %08x\n", oid);
2752 hr = MIME_E_INVALID_OPTION_ID;
2755 return hr;
2758 static HRESULT WINAPI MimeMessage_GetOption(
2759 IMimeMessage *iface,
2760 const TYPEDID oid,
2761 LPPROPVARIANT pValue)
2763 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2764 return E_NOTIMPL;
2767 /*** IMimeMessage methods ***/
2768 static HRESULT WINAPI MimeMessage_CreateWebPage(
2769 IMimeMessage *iface,
2770 IStream *pRootStm,
2771 LPWEBPAGEOPTIONS pOptions,
2772 IMimeMessageCallback *pCallback,
2773 IMoniker **ppMoniker)
2775 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2776 *ppMoniker = NULL;
2777 return E_NOTIMPL;
2780 static HRESULT WINAPI MimeMessage_GetProp(
2781 IMimeMessage *iface,
2782 LPCSTR pszName,
2783 DWORD dwFlags,
2784 LPPROPVARIANT pValue)
2786 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2787 return E_NOTIMPL;
2790 static HRESULT WINAPI MimeMessage_SetProp(
2791 IMimeMessage *iface,
2792 LPCSTR pszName,
2793 DWORD dwFlags,
2794 LPCPROPVARIANT pValue)
2796 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2797 return E_NOTIMPL;
2800 static HRESULT WINAPI MimeMessage_DeleteProp(
2801 IMimeMessage *iface,
2802 LPCSTR pszName)
2804 FIXME("(%p)->(%s)\n", iface, pszName);
2805 return E_NOTIMPL;
2808 static HRESULT WINAPI MimeMessage_QueryProp(
2809 IMimeMessage *iface,
2810 LPCSTR pszName,
2811 LPCSTR pszCriteria,
2812 boolean fSubString,
2813 boolean fCaseSensitive)
2815 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2816 return E_NOTIMPL;
2819 static HRESULT WINAPI MimeMessage_GetTextBody(
2820 IMimeMessage *iface,
2821 DWORD dwTxtType,
2822 ENCODINGTYPE ietEncoding,
2823 IStream **pStream,
2824 LPHBODY phBody)
2826 HRESULT hr;
2827 HBODY hbody;
2828 FINDBODY find_struct;
2829 IMimeBody *mime_body;
2830 static char text[] = "text";
2831 static char plain[] = "plain";
2832 static char html[] = "html";
2834 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2836 find_struct.pszPriType = text;
2838 switch(dwTxtType)
2840 case TXT_PLAIN:
2841 find_struct.pszSubType = plain;
2842 break;
2843 case TXT_HTML:
2844 find_struct.pszSubType = html;
2845 break;
2846 default:
2847 return MIME_E_INVALID_TEXT_TYPE;
2850 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2851 if(hr != S_OK)
2853 TRACE("not found hr %08x\n", hr);
2854 *phBody = NULL;
2855 return hr;
2858 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2860 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2861 *phBody = hbody;
2862 IMimeBody_Release(mime_body);
2863 return hr;
2866 static HRESULT WINAPI MimeMessage_SetTextBody(
2867 IMimeMessage *iface,
2868 DWORD dwTxtType,
2869 ENCODINGTYPE ietEncoding,
2870 HBODY hAlternative,
2871 IStream *pStream,
2872 LPHBODY phBody)
2874 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2875 return E_NOTIMPL;
2878 static HRESULT WINAPI MimeMessage_AttachObject(
2879 IMimeMessage *iface,
2880 REFIID riid,
2881 void *pvObject,
2882 LPHBODY phBody)
2884 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2885 return E_NOTIMPL;
2888 static HRESULT WINAPI MimeMessage_AttachFile(
2889 IMimeMessage *iface,
2890 LPCSTR pszFilePath,
2891 IStream *pstmFile,
2892 LPHBODY phBody)
2894 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2895 return E_NOTIMPL;
2898 static HRESULT WINAPI MimeMessage_AttachURL(
2899 IMimeMessage *iface,
2900 LPCSTR pszBase,
2901 LPCSTR pszURL,
2902 DWORD dwFlags,
2903 IStream *pstmURL,
2904 LPSTR *ppszCIDURL,
2905 LPHBODY phBody)
2907 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2908 return E_NOTIMPL;
2911 static HRESULT WINAPI MimeMessage_GetAttachments(
2912 IMimeMessage *iface,
2913 ULONG *pcAttach,
2914 LPHBODY *pprghAttach)
2916 HRESULT hr;
2917 FINDBODY find_struct;
2918 HBODY hbody;
2919 LPHBODY array;
2920 ULONG size = 10;
2922 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2924 *pcAttach = 0;
2925 array = CoTaskMemAlloc(size * sizeof(HBODY));
2927 find_struct.pszPriType = find_struct.pszSubType = NULL;
2928 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2929 while(hr == S_OK)
2931 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2932 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2933 if(hr != S_OK)
2935 if(*pcAttach + 1 > size)
2937 size *= 2;
2938 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2940 array[*pcAttach] = hbody;
2941 (*pcAttach)++;
2943 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2946 *pprghAttach = array;
2947 return S_OK;
2950 static HRESULT WINAPI MimeMessage_GetAddressTable(
2951 IMimeMessage *iface,
2952 IMimeAddressTable **ppTable)
2954 FIXME("(%p)->(%p)\n", iface, ppTable);
2955 return E_NOTIMPL;
2958 static HRESULT WINAPI MimeMessage_GetSender(
2959 IMimeMessage *iface,
2960 LPADDRESSPROPS pAddress)
2962 FIXME("(%p)->(%p)\n", iface, pAddress);
2963 return E_NOTIMPL;
2966 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2967 IMimeMessage *iface,
2968 DWORD dwAdrTypes,
2969 DWORD dwProps,
2970 LPADDRESSLIST pList)
2972 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2973 return E_NOTIMPL;
2976 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2977 IMimeMessage *iface,
2978 DWORD dwAdrTypes,
2979 ADDRESSFORMAT format,
2980 LPSTR *ppszFormat)
2982 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2983 return E_NOTIMPL;
2986 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2987 IMimeMessage *iface,
2988 DWORD dwAdrTypes,
2989 DWORD dwProps,
2990 IMimeEnumAddressTypes **ppEnum)
2992 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2993 return E_NOTIMPL;
2996 static HRESULT WINAPI MimeMessage_SplitMessage(
2997 IMimeMessage *iface,
2998 ULONG cbMaxPart,
2999 IMimeMessageParts **ppParts)
3001 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
3002 return E_NOTIMPL;
3005 static HRESULT WINAPI MimeMessage_GetRootMoniker(
3006 IMimeMessage *iface,
3007 IMoniker **ppMoniker)
3009 FIXME("(%p)->(%p)\n", iface, ppMoniker);
3010 return E_NOTIMPL;
3013 static const IMimeMessageVtbl MimeMessageVtbl =
3015 MimeMessage_QueryInterface,
3016 MimeMessage_AddRef,
3017 MimeMessage_Release,
3018 MimeMessage_GetClassID,
3019 MimeMessage_IsDirty,
3020 MimeMessage_Load,
3021 MimeMessage_Save,
3022 MimeMessage_GetSizeMax,
3023 MimeMessage_InitNew,
3024 MimeMessage_GetMessageSource,
3025 MimeMessage_GetMessageSize,
3026 MimeMessage_LoadOffsetTable,
3027 MimeMessage_SaveOffsetTable,
3028 MimeMessage_GetFlags,
3029 MimeMessage_Commit,
3030 MimeMessage_HandsOffStorage,
3031 MimeMessage_BindToObject,
3032 MimeMessage_SaveBody,
3033 MimeMessage_InsertBody,
3034 MimeMessage_GetBody,
3035 MimeMessage_DeleteBody,
3036 MimeMessage_MoveBody,
3037 MimeMessage_CountBodies,
3038 MimeMessage_FindFirst,
3039 MimeMessage_FindNext,
3040 MimeMessage_ResolveURL,
3041 MimeMessage_ToMultipart,
3042 MimeMessage_GetBodyOffsets,
3043 MimeMessage_GetCharset,
3044 MimeMessage_SetCharset,
3045 MimeMessage_IsBodyType,
3046 MimeMessage_IsContentType,
3047 MimeMessage_QueryBodyProp,
3048 MimeMessage_GetBodyProp,
3049 MimeMessage_SetBodyProp,
3050 MimeMessage_DeleteBodyProp,
3051 MimeMessage_SetOption,
3052 MimeMessage_GetOption,
3053 MimeMessage_CreateWebPage,
3054 MimeMessage_GetProp,
3055 MimeMessage_SetProp,
3056 MimeMessage_DeleteProp,
3057 MimeMessage_QueryProp,
3058 MimeMessage_GetTextBody,
3059 MimeMessage_SetTextBody,
3060 MimeMessage_AttachObject,
3061 MimeMessage_AttachFile,
3062 MimeMessage_AttachURL,
3063 MimeMessage_GetAttachments,
3064 MimeMessage_GetAddressTable,
3065 MimeMessage_GetSender,
3066 MimeMessage_GetAddressTypes,
3067 MimeMessage_GetAddressFormat,
3068 MimeMessage_EnumAddressTypes,
3069 MimeMessage_SplitMessage,
3070 MimeMessage_GetRootMoniker,
3073 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
3075 MimeMessage *This;
3076 MimeBody *mime_body;
3077 body_t *root_body;
3079 TRACE("(%p, %p)\n", outer, obj);
3081 if (outer)
3083 FIXME("outer unknown not supported yet\n");
3084 return E_NOTIMPL;
3087 *obj = NULL;
3089 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3090 if (!This) return E_OUTOFMEMORY;
3092 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
3093 This->ref = 1;
3094 This->stream = NULL;
3095 list_init(&This->body_tree);
3096 This->next_index = 1;
3098 mime_body = mimebody_create();
3099 root_body = new_body_entry(mime_body, This->next_index++, NULL);
3100 list_add_head(&This->body_tree, &root_body->entry);
3102 *obj = &This->IMimeMessage_iface;
3103 return S_OK;
3106 /***********************************************************************
3107 * MimeOleCreateMessage (INETCOMM.@)
3109 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
3111 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3112 return MimeMessage_create(NULL, (void **)ppMessage);
3115 /***********************************************************************
3116 * MimeOleSetCompatMode (INETCOMM.@)
3118 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3120 FIXME("(0x%x)\n", dwMode);
3121 return S_OK;
3124 /***********************************************************************
3125 * MimeOleCreateVirtualStream (INETCOMM.@)
3127 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3129 HRESULT hr;
3130 FIXME("(%p)\n", ppStream);
3132 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3133 return hr;
3136 typedef struct MimeSecurity
3138 IMimeSecurity IMimeSecurity_iface;
3139 LONG ref;
3140 } MimeSecurity;
3142 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3144 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3147 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3149 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3151 if (IsEqualIID(riid, &IID_IUnknown) ||
3152 IsEqualIID(riid, &IID_IMimeSecurity))
3154 *ppv = iface;
3155 IMimeSecurity_AddRef(iface);
3156 return S_OK;
3159 FIXME("no interface for %s\n", debugstr_guid(riid));
3160 *ppv = NULL;
3161 return E_NOINTERFACE;
3164 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3166 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3167 LONG ref = InterlockedIncrement(&This->ref);
3169 TRACE("(%p) ref=%d\n", This, ref);
3171 return ref;
3174 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3176 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3177 LONG ref = InterlockedDecrement(&This->ref);
3179 TRACE("(%p) ref=%d\n", This, ref);
3181 if (!ref)
3182 HeapFree(GetProcessHeap(), 0, This);
3184 return ref;
3187 static HRESULT WINAPI MimeSecurity_InitNew(
3188 IMimeSecurity* iface)
3190 FIXME("(%p)->(): stub\n", iface);
3191 return S_OK;
3194 static HRESULT WINAPI MimeSecurity_CheckInit(
3195 IMimeSecurity* iface)
3197 FIXME("(%p)->(): stub\n", iface);
3198 return E_NOTIMPL;
3201 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3202 IMimeSecurity* iface,
3203 IMimeMessageTree* pTree,
3204 DWORD dwFlags)
3206 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3207 return E_NOTIMPL;
3210 static HRESULT WINAPI MimeSecurity_EncodeBody(
3211 IMimeSecurity* iface,
3212 IMimeMessageTree* pTree,
3213 HBODY hEncodeRoot,
3214 DWORD dwFlags)
3216 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3217 return E_NOTIMPL;
3220 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3221 IMimeSecurity* iface,
3222 IMimeMessageTree* pTree,
3223 DWORD dwFlags)
3225 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3226 return E_NOTIMPL;
3229 static HRESULT WINAPI MimeSecurity_DecodeBody(
3230 IMimeSecurity* iface,
3231 IMimeMessageTree* pTree,
3232 HBODY hDecodeRoot,
3233 DWORD dwFlags)
3235 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3236 return E_NOTIMPL;
3239 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3240 IMimeSecurity* iface,
3241 HCAPICERTSTORE hc,
3242 DWORD dwUsage,
3243 PCX509CERT pPrev,
3244 PCX509CERT* ppCert)
3246 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3247 return E_NOTIMPL;
3250 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3251 IMimeSecurity* iface,
3252 const PCX509CERT pX509Cert,
3253 const CERTNAMETYPE cn,
3254 LPSTR* ppszName)
3256 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3257 return E_NOTIMPL;
3260 static HRESULT WINAPI MimeSecurity_GetMessageType(
3261 IMimeSecurity* iface,
3262 const HWND hwndParent,
3263 IMimeBody* pBody,
3264 DWORD* pdwSecType)
3266 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3267 return E_NOTIMPL;
3270 static HRESULT WINAPI MimeSecurity_GetCertData(
3271 IMimeSecurity* iface,
3272 const PCX509CERT pX509Cert,
3273 const CERTDATAID dataid,
3274 LPPROPVARIANT pValue)
3276 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3277 return E_NOTIMPL;
3281 static const IMimeSecurityVtbl MimeSecurityVtbl =
3283 MimeSecurity_QueryInterface,
3284 MimeSecurity_AddRef,
3285 MimeSecurity_Release,
3286 MimeSecurity_InitNew,
3287 MimeSecurity_CheckInit,
3288 MimeSecurity_EncodeMessage,
3289 MimeSecurity_EncodeBody,
3290 MimeSecurity_DecodeMessage,
3291 MimeSecurity_DecodeBody,
3292 MimeSecurity_EnumCertificates,
3293 MimeSecurity_GetCertificateName,
3294 MimeSecurity_GetMessageType,
3295 MimeSecurity_GetCertData
3298 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3300 MimeSecurity *This;
3302 *obj = NULL;
3304 if (outer) return CLASS_E_NOAGGREGATION;
3306 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3307 if (!This) return E_OUTOFMEMORY;
3309 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3310 This->ref = 1;
3312 *obj = &This->IMimeSecurity_iface;
3313 return S_OK;
3316 /***********************************************************************
3317 * MimeOleCreateSecurity (INETCOMM.@)
3319 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3321 return MimeSecurity_create(NULL, (void **)ppSecurity);
3324 static HRESULT WINAPI MimeAlloc_QueryInterface(
3325 IMimeAllocator* iface,
3326 REFIID riid,
3327 void **obj)
3329 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3331 if (IsEqualIID(riid, &IID_IUnknown) ||
3332 IsEqualIID(riid, &IID_IMalloc) ||
3333 IsEqualIID(riid, &IID_IMimeAllocator))
3335 *obj = iface;
3336 IMimeAllocator_AddRef(iface);
3337 return S_OK;
3340 FIXME("no interface for %s\n", debugstr_guid(riid));
3341 *obj = NULL;
3342 return E_NOINTERFACE;
3345 static ULONG WINAPI MimeAlloc_AddRef(
3346 IMimeAllocator* iface)
3348 return 2;
3351 static ULONG WINAPI MimeAlloc_Release(
3352 IMimeAllocator* iface)
3354 return 1;
3357 static LPVOID WINAPI MimeAlloc_Alloc(
3358 IMimeAllocator* iface,
3359 SIZE_T cb)
3361 return CoTaskMemAlloc(cb);
3364 static LPVOID WINAPI MimeAlloc_Realloc(
3365 IMimeAllocator* iface,
3366 LPVOID pv,
3367 SIZE_T cb)
3369 return CoTaskMemRealloc(pv, cb);
3372 static void WINAPI MimeAlloc_Free(
3373 IMimeAllocator* iface,
3374 LPVOID pv)
3376 CoTaskMemFree(pv);
3379 static SIZE_T WINAPI MimeAlloc_GetSize(
3380 IMimeAllocator* iface,
3381 LPVOID pv)
3383 FIXME("stub\n");
3384 return 0;
3387 static int WINAPI MimeAlloc_DidAlloc(
3388 IMimeAllocator* iface,
3389 LPVOID pv)
3391 FIXME("stub\n");
3392 return 0;
3395 static void WINAPI MimeAlloc_HeapMinimize(
3396 IMimeAllocator* iface)
3398 FIXME("stub\n");
3399 return;
3402 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3403 IMimeAllocator* iface,
3404 ULONG cParams,
3405 LPMIMEPARAMINFO prgParam,
3406 boolean fFreeArray)
3408 ULONG i;
3409 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3411 for(i = 0; i < cParams; i++)
3413 IMimeAllocator_Free(iface, prgParam[i].pszName);
3414 IMimeAllocator_Free(iface, prgParam[i].pszData);
3416 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3417 return S_OK;
3420 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3421 IMimeAllocator* iface,
3422 LPADDRESSLIST pList)
3424 FIXME("stub\n");
3425 return E_NOTIMPL;
3428 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3429 IMimeAllocator* iface,
3430 LPADDRESSPROPS pAddress)
3432 FIXME("stub\n");
3433 return E_NOTIMPL;
3436 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3437 IMimeAllocator* iface,
3438 ULONG cObjects,
3439 IUnknown **prgpUnknown,
3440 boolean fFreeArray)
3442 FIXME("stub\n");
3443 return E_NOTIMPL;
3447 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3448 IMimeAllocator* iface,
3449 ULONG cRows,
3450 LPENUMHEADERROW prgRow,
3451 boolean fFreeArray)
3453 FIXME("stub\n");
3454 return E_NOTIMPL;
3457 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3458 IMimeAllocator* iface,
3459 ULONG cProps,
3460 LPENUMPROPERTY prgProp,
3461 boolean fFreeArray)
3463 FIXME("stub\n");
3464 return E_NOTIMPL;
3467 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3468 IMimeAllocator* iface,
3469 THUMBBLOB *pthumbprint)
3471 FIXME("stub\n");
3472 return E_NOTIMPL;
3476 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3477 IMimeAllocator* iface,
3478 LPPROPVARIANT pProp)
3480 FIXME("stub\n");
3481 return E_NOTIMPL;
3484 static IMimeAllocatorVtbl mime_alloc_vtbl =
3486 MimeAlloc_QueryInterface,
3487 MimeAlloc_AddRef,
3488 MimeAlloc_Release,
3489 MimeAlloc_Alloc,
3490 MimeAlloc_Realloc,
3491 MimeAlloc_Free,
3492 MimeAlloc_GetSize,
3493 MimeAlloc_DidAlloc,
3494 MimeAlloc_HeapMinimize,
3495 MimeAlloc_FreeParamInfoArray,
3496 MimeAlloc_FreeAddressList,
3497 MimeAlloc_FreeAddressProps,
3498 MimeAlloc_ReleaseObjects,
3499 MimeAlloc_FreeEnumHeaderRowArray,
3500 MimeAlloc_FreeEnumPropertyArray,
3501 MimeAlloc_FreeThumbprint,
3502 MimeAlloc_PropVariantClear
3505 static IMimeAllocator mime_allocator =
3507 &mime_alloc_vtbl
3510 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3512 if(outer) return CLASS_E_NOAGGREGATION;
3514 *obj = &mime_allocator;
3515 return S_OK;
3518 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3520 return MimeAllocator_create(NULL, (void**)alloc);
3523 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3525 FIXME("(%p, %p)\n", outer, obj);
3527 *obj = NULL;
3528 if (outer) return CLASS_E_NOAGGREGATION;
3530 return MimeOleCreateVirtualStream((IStream **)obj);
3533 /* IMimePropertySchema Interface */
3534 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3536 propschema *This = impl_from_IMimePropertySchema(iface);
3537 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3539 *out = NULL;
3541 if (IsEqualIID(riid, &IID_IUnknown) ||
3542 IsEqualIID(riid, &IID_IMimePropertySchema))
3544 *out = iface;
3546 else
3548 FIXME("no interface for %s\n", debugstr_guid(riid));
3549 return E_NOINTERFACE;
3552 IMimePropertySchema_AddRef(iface);
3553 return S_OK;
3556 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3558 propschema *This = impl_from_IMimePropertySchema(iface);
3559 LONG ref = InterlockedIncrement(&This->ref);
3561 TRACE("(%p) ref=%d\n", This, ref);
3563 return ref;
3566 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3568 propschema *This = impl_from_IMimePropertySchema(iface);
3569 LONG ref = InterlockedDecrement(&This->ref);
3571 TRACE("(%p) ref=%d\n", This, ref);
3573 if (!ref)
3575 HeapFree(GetProcessHeap(), 0, This);
3578 return ref;
3581 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3582 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3584 propschema *This = impl_from_IMimePropertySchema(iface);
3585 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3586 return E_NOTIMPL;
3589 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3590 DWORD rownumber, VARTYPE vtdefault)
3592 propschema *This = impl_from_IMimePropertySchema(iface);
3593 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3594 return S_OK;
3597 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3599 propschema *This = impl_from_IMimePropertySchema(iface);
3600 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3601 return E_NOTIMPL;
3604 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3606 propschema *This = impl_from_IMimePropertySchema(iface);
3607 FIXME("(%p)->(%d, %p) stub\n", This, propid, name);
3608 return E_NOTIMPL;
3611 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3613 propschema *This = impl_from_IMimePropertySchema(iface);
3614 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3615 return E_NOTIMPL;
3618 static IMimePropertySchemaVtbl prop_schema_vtbl =
3620 propschema_QueryInterface,
3621 propschema_AddRef,
3622 propschema_Release,
3623 propschema_RegisterProperty,
3624 propschema_ModifyProperty,
3625 propschema_GetPropertyId,
3626 propschema_GetPropertyName,
3627 propschema_RegisterAddressType
3631 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3633 propschema *This;
3635 TRACE("(%p) stub\n", schema);
3637 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3638 if (!This)
3639 return E_OUTOFMEMORY;
3641 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3642 This->ref = 1;
3644 *schema = &This->IMimePropertySchema_iface;
3646 return S_OK;
3649 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3650 ADDRESSFORMAT addr_format, WCHAR **address)
3652 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3654 return E_NOTIMPL;
3657 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
3659 FIXME("(%s %p)\n", debugstr_guid(riid), ppv);
3660 *ppv = NULL;
3661 return E_NOINTERFACE;
3664 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface)
3666 TRACE("\n");
3667 return 2;
3670 static ULONG WINAPI mime_obj_Release(IUnknown *iface)
3672 TRACE("\n");
3673 return 1;
3676 static const IUnknownVtbl mime_obj_vtbl = {
3677 mime_obj_QueryInterface,
3678 mime_obj_AddRef,
3679 mime_obj_Release
3682 static IUnknown mime_obj = { &mime_obj_vtbl };
3684 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3685 REFIID riid, void **out, IMoniker **moniker_new)
3687 WCHAR *display_name, *mhtml_url;
3688 size_t len;
3689 HRESULT hres;
3691 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'};
3693 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3695 if(!IsEqualGUID(&IID_IUnknown, riid)) {
3696 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
3697 return E_NOINTERFACE;
3700 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name);
3701 if(FAILED(hres))
3702 return hres;
3704 TRACE("display name %s\n", debugstr_w(display_name));
3706 len = strlenW(display_name);
3707 mhtml_url = heap_alloc((len+1)*sizeof(WCHAR) + sizeof(mhtml_prefixW));
3708 if(!mhtml_url)
3709 return E_OUTOFMEMORY;
3711 memcpy(mhtml_url, mhtml_prefixW, sizeof(mhtml_prefixW));
3712 strcpyW(mhtml_url + sizeof(mhtml_prefixW)/sizeof(WCHAR), display_name);
3713 HeapFree(GetProcessHeap(), 0, display_name);
3715 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new);
3716 heap_free(mhtml_url);
3717 if(FAILED(hres))
3718 return hres;
3720 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */
3721 *out = &mime_obj;
3722 return S_OK;