urlmon: Added BindProtocol::[Un]LockRequest.
[wine] / dlls / inetcomm / mimeole.c
1 /*
2  * MIME OLE Interfaces
3  *
4  * Copyright 2006 Robert Shearman for CodeWeavers
5  * Copyright 2007 Huw Davies for CodeWeavers
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
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
35 #include "wine/list.h"
36 #include "wine/debug.h"
37
38 #include "inetcomm_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
41
42 typedef struct
43 {
44     LPCSTR     name;
45     DWORD      id;
46     DWORD      flags; /* MIMEPROPFLAGS */
47     VARTYPE    default_vt;
48 } property_t;
49
50 typedef struct
51 {
52     struct list entry;
53     property_t prop;
54 } property_list_entry_t;
55
56 static const property_t default_props[] =
57 {
58     {"References",                   PID_HDR_REFS,       0,                               VT_LPSTR},
59     {"Subject",                      PID_HDR_SUBJECT,    0,                               VT_LPSTR},
60     {"From",                         PID_HDR_FROM,       MPF_ADDRESS,                     VT_LPSTR},
61     {"Message-ID",                   PID_HDR_MESSAGEID,  0,                               VT_LPSTR},
62     {"Return-Path",                  PID_HDR_RETURNPATH, MPF_ADDRESS,                     VT_LPSTR},
63     {"Date",                         PID_HDR_DATE,       0,                               VT_LPSTR},
64     {"Received",                     PID_HDR_RECEIVED,   0,                               VT_LPSTR},
65     {"Reply-To",                     PID_HDR_REPLYTO,    MPF_ADDRESS,                     VT_LPSTR},
66     {"X-Mailer",                     PID_HDR_XMAILER,    0,                               VT_LPSTR},
67     {"Bcc",                          PID_HDR_BCC,        MPF_ADDRESS,                     VT_LPSTR},
68     {"MIME-Version",                 PID_HDR_MIMEVER,    MPF_MIME,                        VT_LPSTR},
69     {"Content-Type",                 PID_HDR_CNTTYPE,    MPF_MIME | MPF_HASPARAMS,        VT_LPSTR},
70     {"Content-Transfer-Encoding",    PID_HDR_CNTXFER,    MPF_MIME,                        VT_LPSTR},
71     {"Content-ID",                   PID_HDR_CNTID,      MPF_MIME,                        VT_LPSTR},
72     {"Content-Disposition",          PID_HDR_CNTDISP,    MPF_MIME,                        VT_LPSTR},
73     {"To",                           PID_HDR_TO,         MPF_ADDRESS,                     VT_LPSTR},
74     {"Cc",                           PID_HDR_CC,         MPF_ADDRESS,                     VT_LPSTR},
75     {"Sender",                       PID_HDR_SENDER,     MPF_ADDRESS,                     VT_LPSTR},
76     {"In-Reply-To",                  PID_HDR_INREPLYTO,  0,                               VT_LPSTR},
77     {NULL,                           0,                  0,                               0}
78 };
79
80 typedef struct
81 {
82     struct list entry;
83     char *name;
84     char *value;
85 } param_t;
86
87 typedef struct
88 {
89     struct list entry;
90     const property_t *prop;
91     PROPVARIANT value;
92     struct list params;
93 } header_t;
94
95 typedef struct MimeBody
96 {
97     const IMimeBodyVtbl *lpVtbl;
98     LONG refs;
99
100     HBODY handle;
101
102     struct list headers;
103     struct list new_props; /* FIXME: This should be in a PropertySchema */
104     DWORD next_prop_id;
105     char *content_pri_type;
106     char *content_sub_type;
107     ENCODINGTYPE encoding;
108     void *data;
109     IID data_iid;
110     BODYOFFSETS body_offsets;
111 } MimeBody;
112
113 static inline MimeBody *impl_from_IMimeBody( IMimeBody *iface )
114 {
115     return (MimeBody *)((char*)iface - FIELD_OFFSET(MimeBody, lpVtbl));
116 }
117
118 static LPSTR strdupA(LPCSTR str)
119 {
120     char *ret;
121     int len = strlen(str);
122     ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
123     memcpy(ret, str, len + 1);
124     return ret;
125 }
126
127 #define PARSER_BUF_SIZE 1024
128
129 /*****************************************************
130  *        copy_headers_to_buf [internal]
131  *
132  * Copies the headers into a '\0' terminated memory block and leave
133  * the stream's current position set to after the blank line.
134  */
135 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
136 {
137     char *buf = NULL;
138     DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
139     HRESULT hr;
140     int done = 0;
141
142     *ptr = NULL;
143
144     do
145     {
146         char *end;
147         DWORD read;
148
149         if(!buf)
150             buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
151         else
152         {
153             size *= 2;
154             buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
155         }
156         if(!buf)
157         {
158             hr = E_OUTOFMEMORY;
159             goto fail;
160         }
161
162         hr = IStream_Read(stm, buf + offset, size - offset, &read);
163         if(FAILED(hr)) goto fail;
164
165         offset += read;
166         buf[offset] = '\0';
167
168         if(read == 0) done = 1;
169
170         while(!done && (end = strstr(buf + last_end, "\r\n")))
171         {
172             DWORD new_end = end - buf + 2;
173             if(new_end - last_end == 2)
174             {
175                 LARGE_INTEGER off;
176                 off.QuadPart = new_end;
177                 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
178                 buf[new_end] = '\0';
179                 done = 1;
180             }
181             else
182                 last_end = new_end;
183         }
184     } while(!done);
185
186     *ptr = buf;
187     return S_OK;
188
189 fail:
190     HeapFree(GetProcessHeap(), 0, buf);
191     return hr;
192 }
193
194 static header_t *read_prop(MimeBody *body, char **ptr)
195 {
196     char *colon = strchr(*ptr, ':');
197     const property_t *prop;
198     header_t *ret;
199
200     if(!colon) return NULL;
201
202     *colon = '\0';
203
204     for(prop = default_props; prop->name; prop++)
205     {
206         if(!strcasecmp(*ptr, prop->name))
207         {
208             TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
209             break;
210         }
211     }
212
213     if(!prop->name)
214     {
215         property_list_entry_t *prop_entry;
216         LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
217         {
218             if(!strcasecmp(*ptr, prop_entry->prop.name))
219             {
220                 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
221                 prop = &prop_entry->prop;
222                 break;
223             }
224         }
225         if(!prop->name)
226         {
227             prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
228             prop_entry->prop.name = strdupA(*ptr);
229             prop_entry->prop.id = body->next_prop_id++;
230             prop_entry->prop.flags = 0;
231             prop_entry->prop.default_vt = VT_LPSTR;
232             list_add_tail(&body->new_props, &prop_entry->entry);
233             prop = &prop_entry->prop;
234             TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
235         }
236     }
237
238     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
239     ret->prop = prop;
240     PropVariantInit(&ret->value);
241     list_init(&ret->params);
242     *ptr = colon + 1;
243
244     return ret;
245 }
246
247 static void unfold_header(char *header, int len)
248 {
249     char *start = header, *cp = header;
250
251     do {
252         while(*cp == ' ' || *cp == '\t')
253         {
254             cp++;
255             len--;
256         }
257         if(cp != start)
258             memmove(start, cp, len + 1);
259
260         cp = strstr(start, "\r\n");
261         len -= (cp - start);
262         start = cp;
263         *start = ' ';
264         start++;
265         len--;
266         cp += 2;
267     } while(*cp == ' ' || *cp == '\t');
268
269     *(start - 1) = '\0';
270 }
271
272 static char *unquote_string(const char *str)
273 {
274     int quoted = 0;
275     char *ret, *cp;
276
277     while(*str == ' ' || *str == '\t') str++;
278
279     if(*str == '"')
280     {
281         quoted = 1;
282         str++;
283     }
284     ret = strdupA(str);
285     for(cp = ret; *cp; cp++)
286     {
287         if(*cp == '\\')
288             memmove(cp, cp + 1, strlen(cp + 1) + 1);
289         else if(*cp == '"')
290         {
291             if(!quoted)
292             {
293                 WARN("quote in unquoted string\n");
294             }
295             else
296             {
297                 *cp = '\0';
298                 break;
299             }
300         }
301     }
302     return ret;
303 }
304
305 static void add_param(header_t *header, const char *p)
306 {
307     const char *key = p, *value, *cp = p;
308     param_t *param;
309     char *name;
310
311     TRACE("got param %s\n", p);
312
313     while (*key == ' ' || *key == '\t' ) key++;
314
315     cp = strchr(key, '=');
316     if(!cp)
317     {
318         WARN("malformed parameter - skipping\n");
319         return;
320     }
321
322     name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
323     memcpy(name, key, cp - key);
324     name[cp - key] = '\0';
325
326     value = cp + 1;
327
328     param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
329     param->name = name;
330     param->value = unquote_string(value);
331     list_add_tail(&header->params, &param->entry);
332 }
333
334 static void split_params(header_t *header, char *value)
335 {
336     char *cp = value, *start = value;
337     int in_quote = 0;
338     int done_value = 0;
339
340     while(*cp)
341     {
342         if(!in_quote && *cp == ';')
343         {
344             *cp = '\0';
345             if(done_value) add_param(header, start);
346             done_value = 1;
347             start = cp + 1;
348         }
349         else if(*cp == '"')
350             in_quote = !in_quote;
351         cp++;
352     }
353     if(done_value) add_param(header, start);
354 }
355
356 static void read_value(header_t *header, char **cur)
357 {
358     char *end = *cur, *value;
359     DWORD len;
360
361     do {
362         end = strstr(end, "\r\n");
363         end += 2;
364     } while(*end == ' ' || *end == '\t');
365
366     len = end - *cur;
367     value = HeapAlloc(GetProcessHeap(), 0, len + 1);
368     memcpy(value, *cur, len);
369     value[len] = '\0';
370
371     unfold_header(value, len);
372     TRACE("value %s\n", debugstr_a(value));
373
374     if(header->prop->flags & MPF_HASPARAMS)
375     {
376         split_params(header, value);
377         TRACE("value w/o params %s\n", debugstr_a(value));
378     }
379
380     header->value.vt = VT_LPSTR;
381     header->value.u.pszVal = value;
382
383     *cur = end;
384 }
385
386 static void init_content_type(MimeBody *body, header_t *header)
387 {
388     char *slash;
389     DWORD len;
390
391     if(header->prop->id != PID_HDR_CNTTYPE)
392     {
393         ERR("called with header %s\n", header->prop->name);
394         return;
395     }
396
397     slash = strchr(header->value.u.pszVal, '/');
398     if(!slash)
399     {
400         WARN("malformed context type value\n");
401         return;
402     }
403     len = slash - header->value.u.pszVal;
404     body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
405     memcpy(body->content_pri_type, header->value.u.pszVal, len);
406     body->content_pri_type[len] = '\0';
407     body->content_sub_type = strdupA(slash + 1);
408 }
409
410 static HRESULT parse_headers(MimeBody *body, IStream *stm)
411 {
412     char *header_buf, *cur_header_ptr;
413     HRESULT hr;
414     header_t *header;
415
416     hr = copy_headers_to_buf(stm, &header_buf);
417     if(FAILED(hr)) return hr;
418
419     cur_header_ptr = header_buf;
420     while((header = read_prop(body, &cur_header_ptr)))
421     {
422         read_value(header, &cur_header_ptr);
423         list_add_tail(&body->headers, &header->entry);
424
425         if(header->prop->id == PID_HDR_CNTTYPE)
426             init_content_type(body, header);
427     }
428
429     HeapFree(GetProcessHeap(), 0, header_buf);
430     return hr;
431 }
432
433 static void empty_param_list(struct list *list)
434 {
435     param_t *param, *cursor2;
436
437     LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
438     {
439         list_remove(&param->entry);
440         HeapFree(GetProcessHeap(), 0, param->name);
441         HeapFree(GetProcessHeap(), 0, param->value);
442         HeapFree(GetProcessHeap(), 0, param);
443     }
444 }
445
446 static void empty_header_list(struct list *list)
447 {
448     header_t *header, *cursor2;
449
450     LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
451     {
452         list_remove(&header->entry);
453         PropVariantClear(&header->value);
454         empty_param_list(&header->params);
455         HeapFree(GetProcessHeap(), 0, header);
456     }
457 }
458
459 static void empty_new_prop_list(struct list *list)
460 {
461     property_list_entry_t *prop, *cursor2;
462
463     LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
464     {
465         list_remove(&prop->entry);
466         HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
467         HeapFree(GetProcessHeap(), 0, prop);
468     }
469 }
470
471 static void release_data(REFIID riid, void *data)
472 {
473     if(!data) return;
474
475     if(IsEqualIID(riid, &IID_IStream))
476         IStream_Release((IStream *)data);
477     else
478         FIXME("Unhandled data format %s\n", debugstr_guid(riid));
479 }
480
481 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
482 {
483     header_t *header;
484
485     *prop = NULL;
486
487     LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
488     {
489         if(!strcasecmp(name, header->prop->name))
490         {
491             *prop = header;
492             return S_OK;
493         }
494     }
495
496     return MIME_E_NOT_FOUND;
497 }
498
499 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
500                                      REFIID riid,
501                                      void** ppvObject)
502 {
503     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
504
505     *ppvObject = NULL;
506
507     if (IsEqualIID(riid, &IID_IUnknown) ||
508         IsEqualIID(riid, &IID_IPersist) ||
509         IsEqualIID(riid, &IID_IPersistStreamInit) ||
510         IsEqualIID(riid, &IID_IMimePropertySet) ||
511         IsEqualIID(riid, &IID_IMimeBody))
512     {
513         *ppvObject = iface;
514     }
515
516     if(*ppvObject)
517     {
518         IUnknown_AddRef((IUnknown*)*ppvObject);
519         return S_OK;
520     }
521
522     FIXME("no interface for %s\n", debugstr_guid(riid));
523     return E_NOINTERFACE;
524 }
525
526 static ULONG WINAPI MimeBody_AddRef(IMimeBody* iface)
527 {
528     MimeBody *This = impl_from_IMimeBody(iface);
529     TRACE("(%p)->()\n", iface);
530     return InterlockedIncrement(&This->refs);
531 }
532
533 static ULONG WINAPI MimeBody_Release(IMimeBody* iface)
534 {
535     MimeBody *This = impl_from_IMimeBody(iface);
536     ULONG refs;
537
538     TRACE("(%p)->()\n", iface);
539
540     refs = InterlockedDecrement(&This->refs);
541     if (!refs)
542     {
543         empty_header_list(&This->headers);
544         empty_new_prop_list(&This->new_props);
545
546         HeapFree(GetProcessHeap(), 0, This->content_pri_type);
547         HeapFree(GetProcessHeap(), 0, This->content_sub_type);
548
549         release_data(&This->data_iid, This->data);
550
551         HeapFree(GetProcessHeap(), 0, This);
552     }
553
554     return refs;
555 }
556
557 static HRESULT WINAPI MimeBody_GetClassID(
558                                  IMimeBody* iface,
559                                  CLSID* pClassID)
560 {
561     FIXME("stub\n");
562     return E_NOTIMPL;
563 }
564
565
566 static HRESULT WINAPI MimeBody_IsDirty(
567                               IMimeBody* iface)
568 {
569     FIXME("stub\n");
570     return E_NOTIMPL;
571 }
572
573 static HRESULT WINAPI MimeBody_Load(
574                            IMimeBody* iface,
575                            LPSTREAM pStm)
576 {
577     MimeBody *This = impl_from_IMimeBody(iface);
578     TRACE("(%p)->(%p)\n", iface, pStm);
579     return parse_headers(This, pStm);
580 }
581
582 static HRESULT WINAPI MimeBody_Save(
583                            IMimeBody* iface,
584                            LPSTREAM pStm,
585                            BOOL fClearDirty)
586 {
587     FIXME("stub\n");
588     return E_NOTIMPL;
589 }
590
591 static HRESULT WINAPI MimeBody_GetSizeMax(
592                                  IMimeBody* iface,
593                                  ULARGE_INTEGER* pcbSize)
594 {
595     FIXME("stub\n");
596     return E_NOTIMPL;
597 }
598
599 static HRESULT WINAPI MimeBody_InitNew(
600                               IMimeBody* iface)
601 {
602     TRACE("%p->()\n", iface);
603     return S_OK;
604 }
605
606 static HRESULT WINAPI MimeBody_GetPropInfo(
607                                   IMimeBody* iface,
608                                   LPCSTR pszName,
609                                   LPMIMEPROPINFO pInfo)
610 {
611     FIXME("stub\n");
612     return E_NOTIMPL;
613 }
614
615 static HRESULT WINAPI MimeBody_SetPropInfo(
616                                   IMimeBody* iface,
617                                   LPCSTR pszName,
618                                   LPCMIMEPROPINFO pInfo)
619 {
620     FIXME("stub\n");
621     return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI MimeBody_GetProp(
625                               IMimeBody* iface,
626                               LPCSTR pszName,
627                               DWORD dwFlags,
628                               LPPROPVARIANT pValue)
629 {
630     FIXME("stub\n");
631     return E_NOTIMPL;
632 }
633
634 static HRESULT WINAPI MimeBody_SetProp(
635                               IMimeBody* iface,
636                               LPCSTR pszName,
637                               DWORD dwFlags,
638                               LPCPROPVARIANT pValue)
639 {
640     FIXME("stub\n");
641     return E_NOTIMPL;
642 }
643
644 static HRESULT WINAPI MimeBody_AppendProp(
645                                  IMimeBody* iface,
646                                  LPCSTR pszName,
647                                  DWORD dwFlags,
648                                  LPPROPVARIANT pValue)
649 {
650     FIXME("stub\n");
651     return E_NOTIMPL;
652 }
653
654 static HRESULT WINAPI MimeBody_DeleteProp(
655                                  IMimeBody* iface,
656                                  LPCSTR pszName)
657 {
658     FIXME("stub\n");
659     return E_NOTIMPL;
660 }
661
662 static HRESULT WINAPI MimeBody_CopyProps(
663                                 IMimeBody* iface,
664                                 ULONG cNames,
665                                 LPCSTR* prgszName,
666                                 IMimePropertySet* pPropertySet)
667 {
668     FIXME("stub\n");
669     return E_NOTIMPL;
670 }
671
672 static HRESULT WINAPI MimeBody_MoveProps(
673                                 IMimeBody* iface,
674                                 ULONG cNames,
675                                 LPCSTR* prgszName,
676                                 IMimePropertySet* pPropertySet)
677 {
678     FIXME("stub\n");
679     return E_NOTIMPL;
680 }
681
682 static HRESULT WINAPI MimeBody_DeleteExcept(
683                                    IMimeBody* iface,
684                                    ULONG cNames,
685                                    LPCSTR* prgszName)
686 {
687     FIXME("stub\n");
688     return E_NOTIMPL;
689 }
690
691 static HRESULT WINAPI MimeBody_QueryProp(
692                                 IMimeBody* iface,
693                                 LPCSTR pszName,
694                                 LPCSTR pszCriteria,
695                                 boolean fSubString,
696                                 boolean fCaseSensitive)
697 {
698     FIXME("stub\n");
699     return E_NOTIMPL;
700 }
701
702 static HRESULT WINAPI MimeBody_GetCharset(
703                                  IMimeBody* iface,
704                                  LPHCHARSET phCharset)
705 {
706     FIXME("stub\n");
707     return E_NOTIMPL;
708 }
709
710 static HRESULT WINAPI MimeBody_SetCharset(
711                                  IMimeBody* iface,
712                                  HCHARSET hCharset,
713                                  CSETAPPLYTYPE applytype)
714 {
715     FIXME("stub\n");
716     return E_NOTIMPL;
717 }
718
719 static HRESULT WINAPI MimeBody_GetParameters(
720                                     IMimeBody* iface,
721                                     LPCSTR pszName,
722                                     ULONG* pcParams,
723                                     LPMIMEPARAMINFO* pprgParam)
724 {
725     MimeBody *This = impl_from_IMimeBody(iface);
726     HRESULT hr;
727     header_t *header;
728
729     TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
730
731     *pprgParam = NULL;
732     *pcParams = 0;
733
734     hr = find_prop(This, pszName, &header);
735     if(hr != S_OK) return hr;
736
737     *pcParams = list_count(&header->params);
738     if(*pcParams)
739     {
740         IMimeAllocator *alloc;
741         param_t *param;
742         MIMEPARAMINFO *info;
743
744         MimeOleGetAllocator(&alloc);
745
746         *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
747         LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
748         {
749             int len;
750
751             len = strlen(param->name) + 1;
752             info->pszName = IMimeAllocator_Alloc(alloc, len);
753             memcpy(info->pszName, param->name, len);
754             len = strlen(param->value) + 1;
755             info->pszData = IMimeAllocator_Alloc(alloc, len);
756             memcpy(info->pszData, param->value, len);
757             info++;
758         }
759         IMimeAllocator_Release(alloc);
760     }
761     return S_OK;
762 }
763
764 static HRESULT WINAPI MimeBody_IsContentType(
765                                     IMimeBody* iface,
766                                     LPCSTR pszPriType,
767                                     LPCSTR pszSubType)
768 {
769     MimeBody *This = impl_from_IMimeBody(iface);
770
771     TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
772     if(pszPriType)
773     {
774         const char *pri = This->content_pri_type;
775         if(!pri) pri = "text";
776         if(strcasecmp(pri, pszPriType)) return S_FALSE;
777     }
778
779     if(pszSubType)
780     {
781         const char *sub = This->content_sub_type;
782         if(!sub) sub = "plain";
783         if(strcasecmp(sub, pszSubType)) return S_FALSE;
784     }
785
786     return S_OK;
787 }
788
789 static HRESULT WINAPI MimeBody_BindToObject(
790                                    IMimeBody* iface,
791                                    REFIID riid,
792                                    void** ppvObject)
793 {
794     FIXME("stub\n");
795     return E_NOTIMPL;
796 }
797
798 static HRESULT WINAPI MimeBody_Clone(
799                             IMimeBody* iface,
800                             IMimePropertySet** ppPropertySet)
801 {
802     FIXME("stub\n");
803     return E_NOTIMPL;
804 }
805
806 static HRESULT WINAPI MimeBody_SetOption(
807                                 IMimeBody* iface,
808                                 const TYPEDID oid,
809                                 LPCPROPVARIANT pValue)
810 {
811     FIXME("stub\n");
812     return E_NOTIMPL;
813 }
814
815 static HRESULT WINAPI MimeBody_GetOption(
816                                 IMimeBody* iface,
817                                 const TYPEDID oid,
818                                 LPPROPVARIANT pValue)
819 {
820     FIXME("stub\n");
821     return E_NOTIMPL;
822 }
823
824 static HRESULT WINAPI MimeBody_EnumProps(
825                                 IMimeBody* iface,
826                                 DWORD dwFlags,
827                                 IMimeEnumProperties** ppEnum)
828 {
829     FIXME("stub\n");
830     return E_NOTIMPL;
831 }
832
833 static HRESULT WINAPI MimeBody_IsType(
834                              IMimeBody* iface,
835                              IMSGBODYTYPE bodytype)
836 {
837     FIXME("stub\n");
838     return E_NOTIMPL;
839 }
840
841 static HRESULT WINAPI MimeBody_SetDisplayName(
842                                      IMimeBody* iface,
843                                      LPCSTR pszDisplay)
844 {
845     FIXME("stub\n");
846     return E_NOTIMPL;
847 }
848
849 static HRESULT WINAPI MimeBody_GetDisplayName(
850                                      IMimeBody* iface,
851                                      LPSTR* ppszDisplay)
852 {
853     FIXME("stub\n");
854     return E_NOTIMPL;
855 }
856
857 static HRESULT WINAPI MimeBody_GetOffsets(
858                                  IMimeBody* iface,
859                                  LPBODYOFFSETS pOffsets)
860 {
861     MimeBody *This = impl_from_IMimeBody(iface);
862     TRACE("(%p)->(%p)\n", This, pOffsets);
863
864     *pOffsets = This->body_offsets;
865
866     if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
867     return S_OK;
868 }
869
870 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
871                                          IMimeBody* iface,
872                                          ENCODINGTYPE* pietEncoding)
873 {
874     MimeBody *This = impl_from_IMimeBody(iface);
875
876     TRACE("(%p)->(%p)\n", This, pietEncoding);
877
878     *pietEncoding = This->encoding;
879     return S_OK;
880 }
881
882 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
883                                          IMimeBody* iface,
884                                          ENCODINGTYPE ietEncoding)
885 {
886     MimeBody *This = impl_from_IMimeBody(iface);
887
888     TRACE("(%p)->(%d)\n", This, ietEncoding);
889
890     This->encoding = ietEncoding;
891     return S_OK;
892 }
893
894 static HRESULT WINAPI MimeBody_GetEstimatedSize(
895                                        IMimeBody* iface,
896                                        ENCODINGTYPE ietEncoding,
897                                        ULONG* pcbSize)
898 {
899     FIXME("stub\n");
900     return E_NOTIMPL;
901 }
902
903 static HRESULT WINAPI MimeBody_GetDataHere(
904                                   IMimeBody* iface,
905                                   ENCODINGTYPE ietEncoding,
906                                   IStream* pStream)
907 {
908     FIXME("stub\n");
909     return E_NOTIMPL;
910 }
911
912 static HRESULT WINAPI MimeBody_GetData(
913                               IMimeBody* iface,
914                               ENCODINGTYPE ietEncoding,
915                               IStream** ppStream)
916 {
917     FIXME("stub\n");
918     return E_NOTIMPL;
919 }
920
921 static HRESULT WINAPI MimeBody_SetData(
922                               IMimeBody* iface,
923                               ENCODINGTYPE ietEncoding,
924                               LPCSTR pszPriType,
925                               LPCSTR pszSubType,
926                               REFIID riid,
927                               LPVOID pvObject)
928 {
929     MimeBody *This = impl_from_IMimeBody(iface);
930     TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
931           debugstr_guid(riid), pvObject);
932
933     if(IsEqualIID(riid, &IID_IStream))
934         IStream_AddRef((IStream *)pvObject);
935     else
936     {
937         FIXME("Unhandled object type %s\n", debugstr_guid(riid));
938         return E_INVALIDARG;
939     }
940
941     if(This->data)
942         FIXME("release old data\n");
943
944     This->data_iid = *riid;
945     This->data = pvObject;
946
947     IMimeBody_SetCurrentEncoding(iface, ietEncoding);
948
949     /* FIXME: Update the content type.
950        If pszPriType == NULL use 'application'
951        If pszSubType == NULL use 'octet-stream' */
952
953     return S_OK;
954 }
955
956 static HRESULT WINAPI MimeBody_EmptyData(
957                                 IMimeBody* iface)
958 {
959     FIXME("stub\n");
960     return E_NOTIMPL;
961 }
962
963 static HRESULT WINAPI MimeBody_CopyTo(
964                              IMimeBody* iface,
965                              IMimeBody* pBody)
966 {
967     FIXME("stub\n");
968     return E_NOTIMPL;
969 }
970
971 static HRESULT WINAPI MimeBody_GetTransmitInfo(
972                                       IMimeBody* iface,
973                                       LPTRANSMITINFO pTransmitInfo)
974 {
975     FIXME("stub\n");
976     return E_NOTIMPL;
977 }
978
979 static HRESULT WINAPI MimeBody_SaveToFile(
980                                  IMimeBody* iface,
981                                  ENCODINGTYPE ietEncoding,
982                                  LPCSTR pszFilePath)
983 {
984     FIXME("stub\n");
985     return E_NOTIMPL;
986 }
987
988 static HRESULT WINAPI MimeBody_GetHandle(
989                                 IMimeBody* iface,
990                                 LPHBODY phBody)
991 {
992     MimeBody *This = impl_from_IMimeBody(iface);
993     TRACE("(%p)->(%p)\n", iface, phBody);
994
995     *phBody = This->handle;
996     return This->handle ? S_OK : MIME_E_NO_DATA;
997 }
998
999 static IMimeBodyVtbl body_vtbl =
1000 {
1001     MimeBody_QueryInterface,
1002     MimeBody_AddRef,
1003     MimeBody_Release,
1004     MimeBody_GetClassID,
1005     MimeBody_IsDirty,
1006     MimeBody_Load,
1007     MimeBody_Save,
1008     MimeBody_GetSizeMax,
1009     MimeBody_InitNew,
1010     MimeBody_GetPropInfo,
1011     MimeBody_SetPropInfo,
1012     MimeBody_GetProp,
1013     MimeBody_SetProp,
1014     MimeBody_AppendProp,
1015     MimeBody_DeleteProp,
1016     MimeBody_CopyProps,
1017     MimeBody_MoveProps,
1018     MimeBody_DeleteExcept,
1019     MimeBody_QueryProp,
1020     MimeBody_GetCharset,
1021     MimeBody_SetCharset,
1022     MimeBody_GetParameters,
1023     MimeBody_IsContentType,
1024     MimeBody_BindToObject,
1025     MimeBody_Clone,
1026     MimeBody_SetOption,
1027     MimeBody_GetOption,
1028     MimeBody_EnumProps,
1029     MimeBody_IsType,
1030     MimeBody_SetDisplayName,
1031     MimeBody_GetDisplayName,
1032     MimeBody_GetOffsets,
1033     MimeBody_GetCurrentEncoding,
1034     MimeBody_SetCurrentEncoding,
1035     MimeBody_GetEstimatedSize,
1036     MimeBody_GetDataHere,
1037     MimeBody_GetData,
1038     MimeBody_SetData,
1039     MimeBody_EmptyData,
1040     MimeBody_CopyTo,
1041     MimeBody_GetTransmitInfo,
1042     MimeBody_SaveToFile,
1043     MimeBody_GetHandle
1044 };
1045
1046 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1047 {
1048     TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1049           offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1050
1051     body->body_offsets = *offsets;
1052     return S_OK;
1053 }
1054
1055 #define FIRST_CUSTOM_PROP_ID 0x100
1056
1057 HRESULT MimeBody_create(IUnknown *outer, void **obj)
1058 {
1059     MimeBody *This;
1060     BODYOFFSETS body_offsets;
1061
1062     *obj = NULL;
1063
1064     if(outer) return CLASS_E_NOAGGREGATION;
1065
1066     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1067     if (!This) return E_OUTOFMEMORY;
1068
1069     This->lpVtbl = &body_vtbl;
1070     This->refs = 1;
1071     This->handle = NULL;
1072     list_init(&This->headers);
1073     list_init(&This->new_props);
1074     This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1075     This->content_pri_type = NULL;
1076     This->content_sub_type = NULL;
1077     This->encoding = IET_7BIT;
1078     This->data = NULL;
1079     This->data_iid = IID_NULL;
1080
1081     body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1082     body_offsets.cbBodyStart     = body_offsets.cbBodyEnd     = 0;
1083     MimeBody_set_offsets(This, &body_offsets);
1084
1085     *obj = (IMimeBody *)&This->lpVtbl;
1086     return S_OK;
1087 }
1088
1089 typedef struct MimeMessage
1090 {
1091     const IMimeMessageVtbl *lpVtbl;
1092
1093     LONG refs;
1094 } MimeMessage;
1095
1096 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1097 {
1098     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1099
1100     if (IsEqualIID(riid, &IID_IUnknown) ||
1101         IsEqualIID(riid, &IID_IPersist) ||
1102         IsEqualIID(riid, &IID_IPersistStreamInit) ||
1103         IsEqualIID(riid, &IID_IMimeMessageTree) ||
1104         IsEqualIID(riid, &IID_IMimeMessage))
1105     {
1106         *ppv = iface;
1107         IUnknown_AddRef(iface);
1108         return S_OK;
1109     }
1110
1111     FIXME("no interface for %s\n", debugstr_guid(riid));
1112     *ppv = NULL;
1113     return E_NOINTERFACE;
1114 }
1115
1116 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1117 {
1118     MimeMessage *This = (MimeMessage *)iface;
1119     TRACE("(%p)->()\n", iface);
1120     return InterlockedIncrement(&This->refs);
1121 }
1122
1123 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1124 {
1125     MimeMessage *This = (MimeMessage *)iface;
1126     ULONG refs;
1127
1128     TRACE("(%p)->()\n", iface);
1129
1130     refs = InterlockedDecrement(&This->refs);
1131     if (!refs)
1132     {
1133         HeapFree(GetProcessHeap(), 0, This);
1134     }
1135
1136     return refs;
1137 }
1138
1139 /*** IPersist methods ***/
1140 static HRESULT WINAPI MimeMessage_GetClassID(
1141     IMimeMessage *iface,
1142     CLSID *pClassID)
1143 {
1144     FIXME("(%p)->(%p)\n", iface, pClassID);
1145     return E_NOTIMPL;
1146 }
1147
1148 /*** IPersistStreamInit methods ***/
1149 static HRESULT WINAPI MimeMessage_IsDirty(
1150     IMimeMessage *iface)
1151 {
1152     FIXME("(%p)->()\n", iface);
1153     return E_NOTIMPL;
1154 }
1155
1156 static HRESULT WINAPI MimeMessage_Load(
1157     IMimeMessage *iface,
1158     LPSTREAM pStm){
1159     FIXME("(%p)->(%p)\n", iface, pStm);
1160     return E_NOTIMPL;
1161 }
1162
1163 static HRESULT WINAPI MimeMessage_Save(
1164     IMimeMessage *iface,
1165     LPSTREAM pStm,
1166     BOOL fClearDirty)
1167 {
1168     FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
1169     return E_NOTIMPL;
1170 }
1171
1172 static HRESULT WINAPI MimeMessage_GetSizeMax(
1173     IMimeMessage *iface,
1174     ULARGE_INTEGER *pcbSize)
1175 {
1176     FIXME("(%p)->(%p)\n", iface, pcbSize);
1177     return E_NOTIMPL;
1178 }
1179
1180 static HRESULT WINAPI MimeMessage_InitNew(
1181     IMimeMessage *iface)
1182 {
1183     FIXME("(%p)->()\n", iface);
1184     return E_NOTIMPL;
1185 }
1186
1187 /*** IMimeMessageTree methods ***/
1188 static HRESULT WINAPI MimeMessage_GetMessageSource(
1189     IMimeMessage *iface,
1190     IStream **ppStream,
1191     DWORD dwFlags)
1192 {
1193     FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
1194     return E_NOTIMPL;
1195 }
1196
1197 static HRESULT WINAPI MimeMessage_GetMessageSize(
1198     IMimeMessage *iface,
1199     ULONG *pcbSize,
1200     DWORD dwFlags)
1201 {
1202     FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
1203     return E_NOTIMPL;
1204 }
1205
1206 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
1207     IMimeMessage *iface,
1208     IStream *pStream)
1209 {
1210     FIXME("(%p)->(%p)\n", iface, pStream);
1211     return E_NOTIMPL;
1212 }
1213
1214 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
1215     IMimeMessage *iface,
1216     IStream *pStream,
1217     DWORD dwFlags)
1218 {
1219     FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
1220     return E_NOTIMPL;
1221 }
1222
1223
1224 static HRESULT WINAPI MimeMessage_GetFlags(
1225     IMimeMessage *iface,
1226     DWORD *pdwFlags)
1227 {
1228     FIXME("(%p)->(%p)\n", iface, pdwFlags);
1229     return E_NOTIMPL;
1230 }
1231
1232 static HRESULT WINAPI MimeMessage_Commit(
1233     IMimeMessage *iface,
1234     DWORD dwFlags)
1235 {
1236     FIXME("(%p)->(0x%x)\n", iface, dwFlags);
1237     return E_NOTIMPL;
1238 }
1239
1240
1241 static HRESULT WINAPI MimeMessage_HandsOffStorage(
1242     IMimeMessage *iface)
1243 {
1244     FIXME("(%p)->()\n", iface);
1245     return E_NOTIMPL;
1246 }
1247
1248 static HRESULT WINAPI MimeMessage_BindToObject(
1249     IMimeMessage *iface,
1250     const HBODY hBody,
1251     REFIID riid,
1252     void **ppvObject)
1253 {
1254     FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
1255     return E_NOTIMPL;
1256 }
1257
1258 static HRESULT WINAPI MimeMessage_SaveBody(
1259     IMimeMessage *iface,
1260     HBODY hBody,
1261     DWORD dwFlags,
1262     IStream *pStream)
1263 {
1264     FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
1265     return E_NOTIMPL;
1266 }
1267
1268 static HRESULT WINAPI MimeMessage_InsertBody(
1269     IMimeMessage *iface,
1270     BODYLOCATION location,
1271     HBODY hPivot,
1272     LPHBODY phBody)
1273 {
1274     FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1275     return E_NOTIMPL;
1276 }
1277
1278 static HRESULT WINAPI MimeMessage_GetBody(
1279     IMimeMessage *iface,
1280     BODYLOCATION location,
1281     HBODY hPivot,
1282     LPHBODY phBody)
1283 {
1284     FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1285     return E_NOTIMPL;
1286 }
1287
1288 static HRESULT WINAPI MimeMessage_DeleteBody(
1289     IMimeMessage *iface,
1290     HBODY hBody,
1291     DWORD dwFlags)
1292 {
1293     FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
1294     return E_NOTIMPL;
1295 }
1296
1297 static HRESULT WINAPI MimeMessage_MoveBody(
1298     IMimeMessage *iface,
1299     HBODY hBody,
1300     BODYLOCATION location)
1301 {
1302     FIXME("(%p)->(%d)\n", iface, location);
1303     return E_NOTIMPL;
1304 }
1305
1306 static HRESULT WINAPI MimeMessage_CountBodies(
1307     IMimeMessage *iface,
1308     HBODY hParent,
1309     boolean fRecurse,
1310     ULONG *pcBodies)
1311 {
1312     FIXME("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
1313     return E_NOTIMPL;
1314 }
1315
1316 static HRESULT WINAPI MimeMessage_FindFirst(
1317     IMimeMessage *iface,
1318     LPFINDBODY pFindBody,
1319     LPHBODY phBody)
1320 {
1321     FIXME("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
1322     return E_NOTIMPL;
1323 }
1324
1325 static HRESULT WINAPI MimeMessage_FindNext(
1326     IMimeMessage *iface,
1327     LPFINDBODY pFindBody,
1328     LPHBODY phBody)
1329 {
1330     FIXME("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
1331     return E_NOTIMPL;
1332 }
1333
1334 static HRESULT WINAPI MimeMessage_ResolveURL(
1335     IMimeMessage *iface,
1336     HBODY hRelated,
1337     LPCSTR pszBase,
1338     LPCSTR pszURL,
1339     DWORD dwFlags,
1340     LPHBODY phBody)
1341 {
1342     FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
1343     return E_NOTIMPL;
1344 }
1345
1346 static HRESULT WINAPI MimeMessage_ToMultipart(
1347     IMimeMessage *iface,
1348     HBODY hBody,
1349     LPCSTR pszSubType,
1350     LPHBODY phMultipart)
1351 {
1352     FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
1353     return E_NOTIMPL;
1354 }
1355
1356 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
1357     IMimeMessage *iface,
1358     HBODY hBody,
1359     LPBODYOFFSETS pOffsets)
1360 {
1361     FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
1362     return E_NOTIMPL;
1363 }
1364
1365 static HRESULT WINAPI MimeMessage_GetCharset(
1366     IMimeMessage *iface,
1367     LPHCHARSET phCharset)
1368 {
1369     FIXME("(%p)->(%p)\n", iface, phCharset);
1370     return E_NOTIMPL;
1371 }
1372
1373 static HRESULT WINAPI MimeMessage_SetCharset(
1374     IMimeMessage *iface,
1375     HCHARSET hCharset,
1376     CSETAPPLYTYPE applytype)
1377 {
1378     FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
1379     return E_NOTIMPL;
1380 }
1381
1382 static HRESULT WINAPI MimeMessage_IsBodyType(
1383     IMimeMessage *iface,
1384     HBODY hBody,
1385     IMSGBODYTYPE bodytype)
1386 {
1387     FIXME("(%p)->(%p, %d)\n", iface, hBody, bodytype);
1388     return E_NOTIMPL;
1389 }
1390
1391 static HRESULT WINAPI MimeMessage_IsContentType(
1392     IMimeMessage *iface,
1393     HBODY hBody,
1394     LPCSTR pszPriType,
1395     LPCSTR pszSubType)
1396 {
1397     FIXME("(%p)->(%p, %s, %s)\n", iface, hBody, pszPriType, pszSubType);
1398     return E_NOTIMPL;
1399 }
1400
1401 static HRESULT WINAPI MimeMessage_QueryBodyProp(
1402     IMimeMessage *iface,
1403     HBODY hBody,
1404     LPCSTR pszName,
1405     LPCSTR pszCriteria,
1406     boolean fSubString,
1407     boolean fCaseSensitive)
1408 {
1409     FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
1410     return E_NOTIMPL;
1411 }
1412
1413 static HRESULT WINAPI MimeMessage_GetBodyProp(
1414     IMimeMessage *iface,
1415     HBODY hBody,
1416     LPCSTR pszName,
1417     DWORD dwFlags,
1418     LPPROPVARIANT pValue)
1419 {
1420     FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
1421     return E_NOTIMPL;
1422 }
1423
1424 static HRESULT WINAPI MimeMessage_SetBodyProp(
1425     IMimeMessage *iface,
1426     HBODY hBody,
1427     LPCSTR pszName,
1428     DWORD dwFlags,
1429     LPCPROPVARIANT pValue)
1430 {
1431     FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
1432     return E_NOTIMPL;
1433 }
1434
1435 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
1436     IMimeMessage *iface,
1437     HBODY hBody,
1438     LPCSTR pszName)
1439 {
1440     FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
1441     return E_NOTIMPL;
1442 }
1443
1444 static HRESULT WINAPI MimeMessage_SetOption(
1445     IMimeMessage *iface,
1446     const TYPEDID oid,
1447     LPCPROPVARIANT pValue)
1448 {
1449     FIXME("(%p)->(%d, %p)\n", iface, oid, pValue);
1450     return E_NOTIMPL;
1451 }
1452
1453 static HRESULT WINAPI MimeMessage_GetOption(
1454     IMimeMessage *iface,
1455     const TYPEDID oid,
1456     LPPROPVARIANT pValue)
1457 {
1458     FIXME("(%p)->(%d, %p)\n", iface, oid, pValue);
1459     return E_NOTIMPL;
1460 }
1461
1462 /*** IMimeMessage methods ***/
1463 static HRESULT WINAPI MimeMessage_CreateWebPage(
1464     IMimeMessage *iface,
1465     IStream *pRootStm,
1466     LPWEBPAGEOPTIONS pOptions,
1467     IMimeMessageCallback *pCallback,
1468     IMoniker **ppMoniker)
1469 {
1470     FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
1471     *ppMoniker = NULL;
1472     return E_NOTIMPL;
1473 }
1474
1475 static HRESULT WINAPI MimeMessage_GetProp(
1476     IMimeMessage *iface,
1477     LPCSTR pszName,
1478     DWORD dwFlags,
1479     LPPROPVARIANT pValue)
1480 {
1481     FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
1482     return E_NOTIMPL;
1483 }
1484
1485 static HRESULT WINAPI MimeMessage_SetProp(
1486     IMimeMessage *iface,
1487     LPCSTR pszName,
1488     DWORD dwFlags,
1489     LPCPROPVARIANT pValue)
1490 {
1491     FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
1492     return E_NOTIMPL;
1493 }
1494
1495 static HRESULT WINAPI MimeMessage_DeleteProp(
1496     IMimeMessage *iface,
1497     LPCSTR pszName)
1498 {
1499     FIXME("(%p)->(%s)\n", iface, pszName);
1500     return E_NOTIMPL;
1501 }
1502
1503 static HRESULT WINAPI MimeMessage_QueryProp(
1504     IMimeMessage *iface,
1505     LPCSTR pszName,
1506     LPCSTR pszCriteria,
1507     boolean fSubString,
1508     boolean fCaseSensitive)
1509 {
1510     FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
1511     return E_NOTIMPL;
1512 }
1513
1514 static HRESULT WINAPI MimeMessage_GetTextBody(
1515     IMimeMessage *iface,
1516     DWORD dwTxtType,
1517     ENCODINGTYPE ietEncoding,
1518     IStream **pStream,
1519     LPHBODY phBody)
1520 {
1521     FIXME("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
1522     return E_NOTIMPL;
1523 }
1524
1525 static HRESULT WINAPI MimeMessage_SetTextBody(
1526     IMimeMessage *iface,
1527     DWORD dwTxtType,
1528     ENCODINGTYPE ietEncoding,
1529     HBODY hAlternative,
1530     IStream *pStream,
1531     LPHBODY phBody)
1532 {
1533     FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
1534     return E_NOTIMPL;
1535 }
1536
1537 static HRESULT WINAPI MimeMessage_AttachObject(
1538     IMimeMessage *iface,
1539     REFIID riid,
1540     void *pvObject,
1541     LPHBODY phBody)
1542 {
1543     FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
1544     return E_NOTIMPL;
1545 }
1546
1547 static HRESULT WINAPI MimeMessage_AttachFile(
1548     IMimeMessage *iface,
1549     LPCSTR pszFilePath,
1550     IStream *pstmFile,
1551     LPHBODY phBody)
1552 {
1553     FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
1554     return E_NOTIMPL;
1555 }
1556
1557 static HRESULT WINAPI MimeMessage_AttachURL(
1558     IMimeMessage *iface,
1559     LPCSTR pszBase,
1560     LPCSTR pszURL,
1561     DWORD dwFlags,
1562     IStream *pstmURL,
1563     LPSTR *ppszCIDURL,
1564     LPHBODY phBody)
1565 {
1566     FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
1567     return E_NOTIMPL;
1568 }
1569
1570 static HRESULT WINAPI MimeMessage_GetAttachments(
1571     IMimeMessage *iface,
1572     ULONG *pcAttach,
1573     LPHBODY *pprghAttach)
1574 {
1575     FIXME("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
1576     return E_NOTIMPL;
1577 }
1578
1579 static HRESULT WINAPI MimeMessage_GetAddressTable(
1580     IMimeMessage *iface,
1581     IMimeAddressTable **ppTable)
1582 {
1583     FIXME("(%p)->(%p)\n", iface, ppTable);
1584     return E_NOTIMPL;
1585 }
1586
1587 static HRESULT WINAPI MimeMessage_GetSender(
1588     IMimeMessage *iface,
1589     LPADDRESSPROPS pAddress)
1590 {
1591     FIXME("(%p)->(%p)\n", iface, pAddress);
1592     return E_NOTIMPL;
1593 }
1594
1595 static HRESULT WINAPI MimeMessage_GetAddressTypes(
1596     IMimeMessage *iface,
1597     DWORD dwAdrTypes,
1598     DWORD dwProps,
1599     LPADDRESSLIST pList)
1600 {
1601     FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
1602     return E_NOTIMPL;
1603 }
1604
1605 static HRESULT WINAPI MimeMessage_GetAddressFormat(
1606     IMimeMessage *iface,
1607     DWORD dwAdrTypes,
1608     ADDRESSFORMAT format,
1609     LPSTR *ppszFormat)
1610 {
1611     FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
1612     return E_NOTIMPL;
1613 }
1614
1615 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
1616     IMimeMessage *iface,
1617     DWORD dwAdrTypes,
1618     DWORD dwProps,
1619     IMimeEnumAddressTypes **ppEnum)
1620 {
1621     FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
1622     return E_NOTIMPL;
1623 }
1624
1625 static HRESULT WINAPI MimeMessage_SplitMessage(
1626     IMimeMessage *iface,
1627     ULONG cbMaxPart,
1628     IMimeMessageParts **ppParts)
1629 {
1630     FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
1631     return E_NOTIMPL;
1632 }
1633
1634 static HRESULT WINAPI MimeMessage_GetRootMoniker(
1635     IMimeMessage *iface,
1636     IMoniker **ppMoniker)
1637 {
1638     FIXME("(%p)->(%p)\n", iface, ppMoniker);
1639     return E_NOTIMPL;
1640 }
1641
1642 static const IMimeMessageVtbl MimeMessageVtbl =
1643 {
1644     MimeMessage_QueryInterface,
1645     MimeMessage_AddRef,
1646     MimeMessage_Release,
1647     MimeMessage_GetClassID,
1648     MimeMessage_IsDirty,
1649     MimeMessage_Load,
1650     MimeMessage_Save,
1651     MimeMessage_GetSizeMax,
1652     MimeMessage_InitNew,
1653     MimeMessage_GetMessageSource,
1654     MimeMessage_GetMessageSize,
1655     MimeMessage_LoadOffsetTable,
1656     MimeMessage_SaveOffsetTable,
1657     MimeMessage_GetFlags,
1658     MimeMessage_Commit,
1659     MimeMessage_HandsOffStorage,
1660     MimeMessage_BindToObject,
1661     MimeMessage_SaveBody,
1662     MimeMessage_InsertBody,
1663     MimeMessage_GetBody,
1664     MimeMessage_DeleteBody,
1665     MimeMessage_MoveBody,
1666     MimeMessage_CountBodies,
1667     MimeMessage_FindFirst,
1668     MimeMessage_FindNext,
1669     MimeMessage_ResolveURL,
1670     MimeMessage_ToMultipart,
1671     MimeMessage_GetBodyOffsets,
1672     MimeMessage_GetCharset,
1673     MimeMessage_SetCharset,
1674     MimeMessage_IsBodyType,
1675     MimeMessage_IsContentType,
1676     MimeMessage_QueryBodyProp,
1677     MimeMessage_GetBodyProp,
1678     MimeMessage_SetBodyProp,
1679     MimeMessage_DeleteBodyProp,
1680     MimeMessage_SetOption,
1681     MimeMessage_GetOption,
1682     MimeMessage_CreateWebPage,
1683     MimeMessage_GetProp,
1684     MimeMessage_SetProp,
1685     MimeMessage_DeleteProp,
1686     MimeMessage_QueryProp,
1687     MimeMessage_GetTextBody,
1688     MimeMessage_SetTextBody,
1689     MimeMessage_AttachObject,
1690     MimeMessage_AttachFile,
1691     MimeMessage_AttachURL,
1692     MimeMessage_GetAttachments,
1693     MimeMessage_GetAddressTable,
1694     MimeMessage_GetSender,
1695     MimeMessage_GetAddressTypes,
1696     MimeMessage_GetAddressFormat,
1697     MimeMessage_EnumAddressTypes,
1698     MimeMessage_SplitMessage,
1699     MimeMessage_GetRootMoniker,
1700 };
1701
1702 /***********************************************************************
1703  *              MimeOleCreateMessage (INETCOMM.@)
1704  */
1705 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
1706 {
1707     MimeMessage *This;
1708
1709     TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
1710
1711     if (pUnkOuter)
1712     {
1713         FIXME("outer unknown not supported yet\n");
1714         return E_NOTIMPL;
1715     }
1716
1717     *ppMessage = NULL;
1718
1719     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1720     if (!This) return E_OUTOFMEMORY;
1721
1722     This->lpVtbl = &MimeMessageVtbl;
1723     This->refs = 1;
1724
1725     *ppMessage = (IMimeMessage *)&This->lpVtbl;
1726     return S_OK;
1727 }
1728
1729 /***********************************************************************
1730  *              MimeOleSetCompatMode (INETCOMM.@)
1731  */
1732 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
1733 {
1734     FIXME("(0x%x)\n", dwMode);
1735     return S_OK;
1736 }
1737
1738 /***********************************************************************
1739  *              MimeOleCreateVirtualStream (INETCOMM.@)
1740  */
1741 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
1742 {
1743     HRESULT hr;
1744     FIXME("(%p)\n", ppStream);
1745
1746     hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
1747     return hr;
1748 }
1749
1750 typedef struct MimeSecurity
1751 {
1752     const IMimeSecurityVtbl *lpVtbl;
1753
1754     LONG refs;
1755 } MimeSecurity;
1756
1757 static HRESULT WINAPI MimeSecurity_QueryInterface(
1758         IMimeSecurity* iface,
1759         REFIID riid,
1760         void** obj)
1761 {
1762     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
1763
1764     if (IsEqualIID(riid, &IID_IUnknown) ||
1765         IsEqualIID(riid, &IID_IMimeSecurity))
1766     {
1767         *obj = iface;
1768         IUnknown_AddRef(iface);
1769         return S_OK;
1770     }
1771
1772     FIXME("no interface for %s\n", debugstr_guid(riid));
1773     *obj = NULL;
1774     return E_NOINTERFACE;
1775 }
1776
1777 static ULONG WINAPI MimeSecurity_AddRef(
1778         IMimeSecurity* iface)
1779 {
1780     MimeSecurity *This = (MimeSecurity *)iface;
1781     TRACE("(%p)->()\n", iface);
1782     return InterlockedIncrement(&This->refs);
1783 }
1784
1785 static ULONG WINAPI MimeSecurity_Release(
1786         IMimeSecurity* iface)
1787 {
1788     MimeSecurity *This = (MimeSecurity *)iface;
1789     ULONG refs;
1790
1791     TRACE("(%p)->()\n", iface);
1792
1793     refs = InterlockedDecrement(&This->refs);
1794     if (!refs)
1795     {
1796         HeapFree(GetProcessHeap(), 0, This);
1797     }
1798
1799     return refs;
1800 }
1801
1802 static HRESULT WINAPI MimeSecurity_InitNew(
1803         IMimeSecurity* iface)
1804 {
1805     FIXME("(%p)->(): stub\n", iface);
1806     return S_OK;
1807 }
1808
1809 static HRESULT WINAPI MimeSecurity_CheckInit(
1810         IMimeSecurity* iface)
1811 {
1812     FIXME("(%p)->(): stub\n", iface);
1813     return E_NOTIMPL;
1814 }
1815
1816 static HRESULT WINAPI MimeSecurity_EncodeMessage(
1817         IMimeSecurity* iface,
1818         IMimeMessageTree* pTree,
1819         DWORD dwFlags)
1820 {
1821     FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
1822     return E_NOTIMPL;
1823 }
1824
1825 static HRESULT WINAPI MimeSecurity_EncodeBody(
1826         IMimeSecurity* iface,
1827         IMimeMessageTree* pTree,
1828         HBODY hEncodeRoot,
1829         DWORD dwFlags)
1830 {
1831     FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
1832     return E_NOTIMPL;
1833 }
1834
1835 static HRESULT WINAPI MimeSecurity_DecodeMessage(
1836         IMimeSecurity* iface,
1837         IMimeMessageTree* pTree,
1838         DWORD dwFlags)
1839 {
1840     FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
1841     return E_NOTIMPL;
1842 }
1843
1844 static HRESULT WINAPI MimeSecurity_DecodeBody(
1845         IMimeSecurity* iface,
1846         IMimeMessageTree* pTree,
1847         HBODY hDecodeRoot,
1848         DWORD dwFlags)
1849 {
1850     FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
1851     return E_NOTIMPL;
1852 }
1853
1854 static HRESULT WINAPI MimeSecurity_EnumCertificates(
1855         IMimeSecurity* iface,
1856         HCAPICERTSTORE hc,
1857         DWORD dwUsage,
1858         PCX509CERT pPrev,
1859         PCX509CERT* ppCert)
1860 {
1861     FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
1862     return E_NOTIMPL;
1863 }
1864
1865 static HRESULT WINAPI MimeSecurity_GetCertificateName(
1866         IMimeSecurity* iface,
1867         const PCX509CERT pX509Cert,
1868         const CERTNAMETYPE cn,
1869         LPSTR* ppszName)
1870 {
1871     FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
1872     return E_NOTIMPL;
1873 }
1874
1875 static HRESULT WINAPI MimeSecurity_GetMessageType(
1876         IMimeSecurity* iface,
1877         const HWND hwndParent,
1878         IMimeBody* pBody,
1879         DWORD* pdwSecType)
1880 {
1881     FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
1882     return E_NOTIMPL;
1883 }
1884
1885 static HRESULT WINAPI MimeSecurity_GetCertData(
1886         IMimeSecurity* iface,
1887         const PCX509CERT pX509Cert,
1888         const CERTDATAID dataid,
1889         LPPROPVARIANT pValue)
1890 {
1891     FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
1892     return E_NOTIMPL;
1893 }
1894
1895
1896 static const IMimeSecurityVtbl MimeSecurityVtbl =
1897 {
1898     MimeSecurity_QueryInterface,
1899     MimeSecurity_AddRef,
1900     MimeSecurity_Release,
1901     MimeSecurity_InitNew,
1902     MimeSecurity_CheckInit,
1903     MimeSecurity_EncodeMessage,
1904     MimeSecurity_EncodeBody,
1905     MimeSecurity_DecodeMessage,
1906     MimeSecurity_DecodeBody,
1907     MimeSecurity_EnumCertificates,
1908     MimeSecurity_GetCertificateName,
1909     MimeSecurity_GetMessageType,
1910     MimeSecurity_GetCertData
1911 };
1912
1913 /***********************************************************************
1914  *              MimeOleCreateSecurity (INETCOMM.@)
1915  */
1916 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
1917 {
1918     MimeSecurity *This;
1919
1920     TRACE("(%p)\n", ppSecurity);
1921
1922     *ppSecurity = NULL;
1923
1924     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1925     if (!This) return E_OUTOFMEMORY;
1926
1927     This->lpVtbl = &MimeSecurityVtbl;
1928     This->refs = 1;
1929
1930     *ppSecurity = (IMimeSecurity *)&This->lpVtbl;
1931     return S_OK;
1932 }
1933
1934
1935 typedef struct
1936 {
1937     IMimeAllocatorVtbl *lpVtbl;
1938 } MimeAllocator;
1939
1940 static HRESULT WINAPI MimeAlloc_QueryInterface(
1941         IMimeAllocator* iface,
1942         REFIID riid,
1943         void **obj)
1944 {
1945     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
1946
1947     if (IsEqualIID(riid, &IID_IUnknown) ||
1948         IsEqualIID(riid, &IID_IMalloc) ||
1949         IsEqualIID(riid, &IID_IMimeAllocator))
1950     {
1951         *obj = iface;
1952         IUnknown_AddRef(iface);
1953         return S_OK;
1954     }
1955
1956     FIXME("no interface for %s\n", debugstr_guid(riid));
1957     *obj = NULL;
1958     return E_NOINTERFACE;
1959 }
1960
1961 static ULONG WINAPI MimeAlloc_AddRef(
1962         IMimeAllocator* iface)
1963 {
1964     return 2;
1965 }
1966
1967 static ULONG WINAPI MimeAlloc_Release(
1968         IMimeAllocator* iface)
1969 {
1970     return 1;
1971 }
1972
1973 static LPVOID WINAPI MimeAlloc_Alloc(
1974         IMimeAllocator* iface,
1975         ULONG cb)
1976 {
1977     return CoTaskMemAlloc(cb);
1978 }
1979
1980 static LPVOID WINAPI MimeAlloc_Realloc(
1981         IMimeAllocator* iface,
1982         LPVOID pv,
1983         ULONG cb)
1984 {
1985     return CoTaskMemRealloc(pv, cb);
1986 }
1987
1988 static void WINAPI MimeAlloc_Free(
1989         IMimeAllocator* iface,
1990         LPVOID pv)
1991 {
1992     return CoTaskMemFree(pv);
1993 }
1994
1995 static ULONG WINAPI MimeAlloc_GetSize(
1996         IMimeAllocator* iface,
1997         LPVOID pv)
1998 {
1999     FIXME("stub\n");
2000     return 0;
2001 }
2002
2003 static int WINAPI MimeAlloc_DidAlloc(
2004         IMimeAllocator* iface,
2005         LPVOID pv)
2006 {
2007     FIXME("stub\n");
2008     return 0;
2009 }
2010
2011 static void WINAPI MimeAlloc_HeapMinimize(
2012         IMimeAllocator* iface)
2013 {
2014     FIXME("stub\n");
2015     return;
2016 }
2017
2018 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
2019         IMimeAllocator* iface,
2020         ULONG cParams,
2021         LPMIMEPARAMINFO prgParam,
2022         boolean fFreeArray)
2023 {
2024     ULONG i;
2025     TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
2026
2027     for(i = 0; i < cParams; i++)
2028     {
2029         IMimeAllocator_Free(iface, prgParam[i].pszName);
2030         IMimeAllocator_Free(iface, prgParam[i].pszData);
2031     }
2032     if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
2033     return S_OK;
2034 }
2035
2036 static HRESULT WINAPI MimeAlloc_FreeAddressList(
2037         IMimeAllocator* iface,
2038         LPADDRESSLIST pList)
2039 {
2040     FIXME("stub\n");
2041     return E_NOTIMPL;
2042 }
2043
2044 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
2045         IMimeAllocator* iface,
2046         LPADDRESSPROPS pAddress)
2047 {
2048     FIXME("stub\n");
2049     return E_NOTIMPL;
2050 }
2051
2052 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
2053         IMimeAllocator* iface,
2054         ULONG cObjects,
2055         IUnknown **prgpUnknown,
2056         boolean fFreeArray)
2057 {
2058     FIXME("stub\n");
2059     return E_NOTIMPL;
2060 }
2061
2062
2063 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
2064         IMimeAllocator* iface,
2065         ULONG cRows,
2066         LPENUMHEADERROW prgRow,
2067         boolean fFreeArray)
2068 {
2069     FIXME("stub\n");
2070     return E_NOTIMPL;
2071 }
2072
2073 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
2074         IMimeAllocator* iface,
2075         ULONG cProps,
2076         LPENUMPROPERTY prgProp,
2077         boolean fFreeArray)
2078 {
2079     FIXME("stub\n");
2080     return E_NOTIMPL;
2081 }
2082
2083 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
2084         IMimeAllocator* iface,
2085         THUMBBLOB *pthumbprint)
2086 {
2087     FIXME("stub\n");
2088     return E_NOTIMPL;
2089 }
2090
2091
2092 static HRESULT WINAPI MimeAlloc_PropVariantClear(
2093         IMimeAllocator* iface,
2094         LPPROPVARIANT pProp)
2095 {
2096     FIXME("stub\n");
2097     return E_NOTIMPL;
2098 }
2099
2100 static IMimeAllocatorVtbl mime_alloc_vtbl =
2101 {
2102     MimeAlloc_QueryInterface,
2103     MimeAlloc_AddRef,
2104     MimeAlloc_Release,
2105     MimeAlloc_Alloc,
2106     MimeAlloc_Realloc,
2107     MimeAlloc_Free,
2108     MimeAlloc_GetSize,
2109     MimeAlloc_DidAlloc,
2110     MimeAlloc_HeapMinimize,
2111     MimeAlloc_FreeParamInfoArray,
2112     MimeAlloc_FreeAddressList,
2113     MimeAlloc_FreeAddressProps,
2114     MimeAlloc_ReleaseObjects,
2115     MimeAlloc_FreeEnumHeaderRowArray,
2116     MimeAlloc_FreeEnumPropertyArray,
2117     MimeAlloc_FreeThumbprint,
2118     MimeAlloc_PropVariantClear
2119 };
2120
2121 static MimeAllocator mime_allocator =
2122 {
2123     &mime_alloc_vtbl
2124 };
2125
2126 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
2127 {
2128     if(outer) return CLASS_E_NOAGGREGATION;
2129
2130     *obj = &mime_allocator;
2131     return S_OK;
2132 }
2133
2134 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
2135 {
2136     return MimeAllocator_create(NULL, (void**)alloc);
2137 }