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