* Slap *some* sense into our header inclusions.
[reactos.git] / reactos / dll / win32 / 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 WIN32_NO_STATUS
23 #define _INC_WINDOWS
24 #define COM_NO_WINDOWS_H
25
26 #define COBJMACROS
27 #define NONAMELESSUNION
28
29 #include <stdarg.h>
30 //#include <stdio.h>
31
32 #include <windef.h>
33 #include <winbase.h>
34 //#include "winuser.h"
35 //#include "objbase.h"
36 #include <ole2.h>
37 #include <mimeole.h>
38
39 #include <wine/list.h>
40 #include <wine/debug.h>
41
42 #include "inetcomm_private.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
45
46 typedef struct
47 {
48 LPCSTR name;
49 DWORD id;
50 DWORD flags; /* MIMEPROPFLAGS */
51 VARTYPE default_vt;
52 } property_t;
53
54 typedef struct
55 {
56 struct list entry;
57 property_t prop;
58 } property_list_entry_t;
59
60 static const property_t default_props[] =
61 {
62 {"References", PID_HDR_REFS, 0, VT_LPSTR},
63 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
64 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
65 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
66 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
67 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
68 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
69 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
70 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
71 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
72 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
73 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
74 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
75 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
76 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
77 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
78 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
79 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
80 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
81 {NULL, 0, 0, 0}
82 };
83
84 typedef struct
85 {
86 struct list entry;
87 char *name;
88 char *value;
89 } param_t;
90
91 typedef struct
92 {
93 struct list entry;
94 const property_t *prop;
95 PROPVARIANT value;
96 struct list params;
97 } header_t;
98
99 typedef struct MimeBody
100 {
101 const IMimeBodyVtbl *lpVtbl;
102 LONG refs;
103
104 HBODY handle;
105
106 struct list headers;
107 struct list new_props; /* FIXME: This should be in a PropertySchema */
108 DWORD next_prop_id;
109 char *content_pri_type;
110 char *content_sub_type;
111 ENCODINGTYPE encoding;
112 void *data;
113 IID data_iid;
114 BODYOFFSETS body_offsets;
115 } MimeBody;
116
117 static inline MimeBody *impl_from_IMimeBody( IMimeBody *iface )
118 {
119 return (MimeBody *)((char*)iface - FIELD_OFFSET(MimeBody, lpVtbl));
120 }
121
122 static LPSTR strdupA(LPCSTR str)
123 {
124 char *ret;
125 int len = strlen(str);
126 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
127 memcpy(ret, str, len + 1);
128 return ret;
129 }
130
131 #define PARSER_BUF_SIZE 1024
132
133 /*****************************************************
134 * copy_headers_to_buf [internal]
135 *
136 * Copies the headers into a '\0' terminated memory block and leave
137 * the stream's current position set to after the blank line.
138 */
139 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
140 {
141 char *buf = NULL;
142 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
143 HRESULT hr;
144 int done = 0;
145
146 *ptr = NULL;
147
148 do
149 {
150 char *end;
151 DWORD read;
152
153 if(!buf)
154 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
155 else
156 {
157 size *= 2;
158 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
159 }
160 if(!buf)
161 {
162 hr = E_OUTOFMEMORY;
163 goto fail;
164 }
165
166 hr = IStream_Read(stm, buf + offset, size - offset, &read);
167 if(FAILED(hr)) goto fail;
168
169 offset += read;
170 buf[offset] = '\0';
171
172 if(read == 0) done = 1;
173
174 while(!done && (end = strstr(buf + last_end, "\r\n")))
175 {
176 DWORD new_end = end - buf + 2;
177 if(new_end - last_end == 2)
178 {
179 LARGE_INTEGER off;
180 off.QuadPart = new_end;
181 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
182 buf[new_end] = '\0';
183 done = 1;
184 }
185 else
186 last_end = new_end;
187 }
188 } while(!done);
189
190 *ptr = buf;
191 return S_OK;
192
193 fail:
194 HeapFree(GetProcessHeap(), 0, buf);
195 return hr;
196 }
197
198 static header_t *read_prop(MimeBody *body, char **ptr)
199 {
200 char *colon = strchr(*ptr, ':');
201 const property_t *prop;
202 header_t *ret;
203
204 if(!colon) return NULL;
205
206 *colon = '\0';
207
208 for(prop = default_props; prop->name; prop++)
209 {
210 if(!strcasecmp(*ptr, prop->name))
211 {
212 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
213 break;
214 }
215 }
216
217 if(!prop->name)
218 {
219 property_list_entry_t *prop_entry;
220 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
221 {
222 if(!strcasecmp(*ptr, prop_entry->prop.name))
223 {
224 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
225 prop = &prop_entry->prop;
226 break;
227 }
228 }
229 if(!prop->name)
230 {
231 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
232 prop_entry->prop.name = strdupA(*ptr);
233 prop_entry->prop.id = body->next_prop_id++;
234 prop_entry->prop.flags = 0;
235 prop_entry->prop.default_vt = VT_LPSTR;
236 list_add_tail(&body->new_props, &prop_entry->entry);
237 prop = &prop_entry->prop;
238 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
239 }
240 }
241
242 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
243 ret->prop = prop;
244 PropVariantInit(&ret->value);
245 list_init(&ret->params);
246 *ptr = colon + 1;
247
248 return ret;
249 }
250
251 static void unfold_header(char *header, int len)
252 {
253 char *start = header, *cp = header;
254
255 do {
256 while(*cp == ' ' || *cp == '\t')
257 {
258 cp++;
259 len--;
260 }
261 if(cp != start)
262 memmove(start, cp, len + 1);
263
264 cp = strstr(start, "\r\n");
265 len -= (cp - start);
266 start = cp;
267 *start = ' ';
268 start++;
269 len--;
270 cp += 2;
271 } while(*cp == ' ' || *cp == '\t');
272
273 *(start - 1) = '\0';
274 }
275
276 static char *unquote_string(const char *str)
277 {
278 int quoted = 0;
279 char *ret, *cp;
280
281 while(*str == ' ' || *str == '\t') str++;
282
283 if(*str == '"')
284 {
285 quoted = 1;
286 str++;
287 }
288 ret = strdupA(str);
289 for(cp = ret; *cp; cp++)
290 {
291 if(*cp == '\\')
292 memmove(cp, cp + 1, strlen(cp + 1) + 1);
293 else if(*cp == '"')
294 {
295 if(!quoted)
296 {
297 WARN("quote in unquoted string\n");
298 }
299 else
300 {
301 *cp = '\0';
302 break;
303 }
304 }
305 }
306 return ret;
307 }
308
309 static void add_param(header_t *header, const char *p)
310 {
311 const char *key = p, *value, *cp = p;
312 param_t *param;
313 char *name;
314
315 TRACE("got param %s\n", p);
316
317 while (*key == ' ' || *key == '\t' ) key++;
318
319 cp = strchr(key, '=');
320 if(!cp)
321 {
322 WARN("malformed parameter - skipping\n");
323 return;
324 }
325
326 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
327 memcpy(name, key, cp - key);
328 name[cp - key] = '\0';
329
330 value = cp + 1;
331
332 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
333 param->name = name;
334 param->value = unquote_string(value);
335 list_add_tail(&header->params, &param->entry);
336 }
337
338 static void split_params(header_t *header, char *value)
339 {
340 char *cp = value, *start = value;
341 int in_quote = 0;
342 int done_value = 0;
343
344 while(*cp)
345 {
346 if(!in_quote && *cp == ';')
347 {
348 *cp = '\0';
349 if(done_value) add_param(header, start);
350 done_value = 1;
351 start = cp + 1;
352 }
353 else if(*cp == '"')
354 in_quote = !in_quote;
355 cp++;
356 }
357 if(done_value) add_param(header, start);
358 }
359
360 static void read_value(header_t *header, char **cur)
361 {
362 char *end = *cur, *value;
363 DWORD len;
364
365 do {
366 end = strstr(end, "\r\n");
367 end += 2;
368 } while(*end == ' ' || *end == '\t');
369
370 len = end - *cur;
371 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
372 memcpy(value, *cur, len);
373 value[len] = '\0';
374
375 unfold_header(value, len);
376 TRACE("value %s\n", debugstr_a(value));
377
378 if(header->prop->flags & MPF_HASPARAMS)
379 {
380 split_params(header, value);
381 TRACE("value w/o params %s\n", debugstr_a(value));
382 }
383
384 header->value.vt = VT_LPSTR;
385 header->value.u.pszVal = value;
386
387 *cur = end;
388 }
389
390 static void init_content_type(MimeBody *body, header_t *header)
391 {
392 char *slash;
393 DWORD len;
394
395 if(header->prop->id != PID_HDR_CNTTYPE)
396 {
397 ERR("called with header %s\n", header->prop->name);
398 return;
399 }
400
401 slash = strchr(header->value.u.pszVal, '/');
402 if(!slash)
403 {
404 WARN("malformed context type value\n");
405 return;
406 }
407 len = slash - header->value.u.pszVal;
408 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
409 memcpy(body->content_pri_type, header->value.u.pszVal, len);
410 body->content_pri_type[len] = '\0';
411 body->content_sub_type = strdupA(slash + 1);
412 }
413
414 static HRESULT parse_headers(MimeBody *body, IStream *stm)
415 {
416 char *header_buf, *cur_header_ptr;
417 HRESULT hr;
418 header_t *header;
419
420 hr = copy_headers_to_buf(stm, &header_buf);
421 if(FAILED(hr)) return hr;
422
423 cur_header_ptr = header_buf;
424 while((header = read_prop(body, &cur_header_ptr)))
425 {
426 read_value(header, &cur_header_ptr);
427 list_add_tail(&body->headers, &header->entry);
428
429 if(header->prop->id == PID_HDR_CNTTYPE)
430 init_content_type(body, header);
431 }
432
433 HeapFree(GetProcessHeap(), 0, header_buf);
434 return hr;
435 }
436
437 static void empty_param_list(struct list *list)
438 {
439 param_t *param, *cursor2;
440
441 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
442 {
443 list_remove(&param->entry);
444 HeapFree(GetProcessHeap(), 0, param->name);
445 HeapFree(GetProcessHeap(), 0, param->value);
446 HeapFree(GetProcessHeap(), 0, param);
447 }
448 }
449
450 static void empty_header_list(struct list *list)
451 {
452 header_t *header, *cursor2;
453
454 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
455 {
456 list_remove(&header->entry);
457 PropVariantClear(&header->value);
458 empty_param_list(&header->params);
459 HeapFree(GetProcessHeap(), 0, header);
460 }
461 }
462
463 static void empty_new_prop_list(struct list *list)
464 {
465 property_list_entry_t *prop, *cursor2;
466
467 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
468 {
469 list_remove(&prop->entry);
470 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
471 HeapFree(GetProcessHeap(), 0, prop);
472 }
473 }
474
475 static void release_data(REFIID riid, void *data)
476 {
477 if(!data) return;
478
479 if(IsEqualIID(riid, &IID_IStream))
480 IStream_Release((IStream *)data);
481 else
482 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
483 }
484
485 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
486 {
487 header_t *header;
488
489 *prop = NULL;
490
491 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
492 {
493 if(!strcasecmp(name, header->prop->name))
494 {
495 *prop = header;
496 return S_OK;
497 }
498 }
499
500 return MIME_E_NOT_FOUND;
501 }
502
503 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
504 REFIID riid,
505 void** ppvObject)
506 {
507 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
508
509 *ppvObject = NULL;
510
511 if (IsEqualIID(riid, &IID_IUnknown) ||
512 IsEqualIID(riid, &IID_IPersist) ||
513 IsEqualIID(riid, &IID_IPersistStreamInit) ||
514 IsEqualIID(riid, &IID_IMimePropertySet) ||
515 IsEqualIID(riid, &IID_IMimeBody))
516 {
517 *ppvObject = iface;
518 }
519
520 if(*ppvObject)
521 {
522 IUnknown_AddRef((IUnknown*)*ppvObject);
523 return S_OK;
524 }
525
526 FIXME("no interface for %s\n", debugstr_guid(riid));
527 return E_NOINTERFACE;
528 }
529
530 static ULONG WINAPI MimeBody_AddRef(IMimeBody* iface)
531 {
532 MimeBody *This = impl_from_IMimeBody(iface);
533 TRACE("(%p)->()\n", iface);
534 return InterlockedIncrement(&This->refs);
535 }
536
537 static ULONG WINAPI MimeBody_Release(IMimeBody* iface)
538 {
539 MimeBody *This = impl_from_IMimeBody(iface);
540 ULONG refs;
541
542 TRACE("(%p)->()\n", iface);
543
544 refs = InterlockedDecrement(&This->refs);
545 if (!refs)
546 {
547 empty_header_list(&This->headers);
548 empty_new_prop_list(&This->new_props);
549
550 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
551 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
552
553 release_data(&This->data_iid, This->data);
554
555 HeapFree(GetProcessHeap(), 0, This);
556 }
557
558 return refs;
559 }
560
561 static HRESULT WINAPI MimeBody_GetClassID(
562 IMimeBody* iface,
563 CLSID* pClassID)
564 {
565 FIXME("stub\n");
566 return E_NOTIMPL;
567 }
568
569
570 static HRESULT WINAPI MimeBody_IsDirty(
571 IMimeBody* iface)
572 {
573 FIXME("stub\n");
574 return E_NOTIMPL;
575 }
576
577 static HRESULT WINAPI MimeBody_Load(
578 IMimeBody* iface,
579 LPSTREAM pStm)
580 {
581 MimeBody *This = impl_from_IMimeBody(iface);
582 TRACE("(%p)->(%p)\n", iface, pStm);
583 return parse_headers(This, pStm);
584 }
585
586 static HRESULT WINAPI MimeBody_Save(
587 IMimeBody* iface,
588 LPSTREAM pStm,
589 BOOL fClearDirty)
590 {
591 FIXME("stub\n");
592 return E_NOTIMPL;
593 }
594
595 static HRESULT WINAPI MimeBody_GetSizeMax(
596 IMimeBody* iface,
597 ULARGE_INTEGER* pcbSize)
598 {
599 FIXME("stub\n");
600 return E_NOTIMPL;
601 }
602
603 static HRESULT WINAPI MimeBody_InitNew(
604 IMimeBody* iface)
605 {
606 TRACE("%p->()\n", iface);
607 return S_OK;
608 }
609
610 static HRESULT WINAPI MimeBody_GetPropInfo(
611 IMimeBody* iface,
612 LPCSTR pszName,
613 LPMIMEPROPINFO pInfo)
614 {
615 FIXME("stub\n");
616 return E_NOTIMPL;
617 }
618
619 static HRESULT WINAPI MimeBody_SetPropInfo(
620 IMimeBody* iface,
621 LPCSTR pszName,
622 LPCMIMEPROPINFO pInfo)
623 {
624 FIXME("stub\n");
625 return E_NOTIMPL;
626 }
627
628 static HRESULT WINAPI MimeBody_GetProp(
629 IMimeBody* iface,
630 LPCSTR pszName,
631 DWORD dwFlags,
632 LPPROPVARIANT pValue)
633 {
634 MimeBody *This = impl_from_IMimeBody(iface);
635 TRACE("(%p)->(%s, %d, %p)\n", This, pszName, dwFlags, pValue);
636
637 if(!strcasecmp(pszName, "att:pri-content-type"))
638 {
639 PropVariantClear(pValue);
640 pValue->vt = VT_LPSTR;
641 pValue->u.pszVal = strdupA(This->content_pri_type);
642 return S_OK;
643 }
644
645 FIXME("stub!\n");
646 return E_FAIL;
647 }
648
649 static HRESULT WINAPI MimeBody_SetProp(
650 IMimeBody* iface,
651 LPCSTR pszName,
652 DWORD dwFlags,
653 LPCPROPVARIANT pValue)
654 {
655 FIXME("stub\n");
656 return E_NOTIMPL;
657 }
658
659 static HRESULT WINAPI MimeBody_AppendProp(
660 IMimeBody* iface,
661 LPCSTR pszName,
662 DWORD dwFlags,
663 LPPROPVARIANT pValue)
664 {
665 FIXME("stub\n");
666 return E_NOTIMPL;
667 }
668
669 static HRESULT WINAPI MimeBody_DeleteProp(
670 IMimeBody* iface,
671 LPCSTR pszName)
672 {
673 FIXME("stub\n");
674 return E_NOTIMPL;
675 }
676
677 static HRESULT WINAPI MimeBody_CopyProps(
678 IMimeBody* iface,
679 ULONG cNames,
680 LPCSTR* prgszName,
681 IMimePropertySet* pPropertySet)
682 {
683 FIXME("stub\n");
684 return E_NOTIMPL;
685 }
686
687 static HRESULT WINAPI MimeBody_MoveProps(
688 IMimeBody* iface,
689 ULONG cNames,
690 LPCSTR* prgszName,
691 IMimePropertySet* pPropertySet)
692 {
693 FIXME("stub\n");
694 return E_NOTIMPL;
695 }
696
697 static HRESULT WINAPI MimeBody_DeleteExcept(
698 IMimeBody* iface,
699 ULONG cNames,
700 LPCSTR* prgszName)
701 {
702 FIXME("stub\n");
703 return E_NOTIMPL;
704 }
705
706 static HRESULT WINAPI MimeBody_QueryProp(
707 IMimeBody* iface,
708 LPCSTR pszName,
709 LPCSTR pszCriteria,
710 boolean fSubString,
711 boolean fCaseSensitive)
712 {
713 FIXME("stub\n");
714 return E_NOTIMPL;
715 }
716
717 static HRESULT WINAPI MimeBody_GetCharset(
718 IMimeBody* iface,
719 LPHCHARSET phCharset)
720 {
721 FIXME("stub\n");
722 *phCharset = NULL;
723 return S_OK;
724 }
725
726 static HRESULT WINAPI MimeBody_SetCharset(
727 IMimeBody* iface,
728 HCHARSET hCharset,
729 CSETAPPLYTYPE applytype)
730 {
731 FIXME("stub\n");
732 return E_NOTIMPL;
733 }
734
735 static HRESULT WINAPI MimeBody_GetParameters(
736 IMimeBody* iface,
737 LPCSTR pszName,
738 ULONG* pcParams,
739 LPMIMEPARAMINFO* pprgParam)
740 {
741 MimeBody *This = impl_from_IMimeBody(iface);
742 HRESULT hr;
743 header_t *header;
744
745 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
746
747 *pprgParam = NULL;
748 *pcParams = 0;
749
750 hr = find_prop(This, pszName, &header);
751 if(hr != S_OK) return hr;
752
753 *pcParams = list_count(&header->params);
754 if(*pcParams)
755 {
756 IMimeAllocator *alloc;
757 param_t *param;
758 MIMEPARAMINFO *info;
759
760 MimeOleGetAllocator(&alloc);
761
762 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
763 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
764 {
765 int len;
766
767 len = strlen(param->name) + 1;
768 info->pszName = IMimeAllocator_Alloc(alloc, len);
769 memcpy(info->pszName, param->name, len);
770 len = strlen(param->value) + 1;
771 info->pszData = IMimeAllocator_Alloc(alloc, len);
772 memcpy(info->pszData, param->value, len);
773 info++;
774 }
775 IMimeAllocator_Release(alloc);
776 }
777 return S_OK;
778 }
779
780 static HRESULT WINAPI MimeBody_IsContentType(
781 IMimeBody* iface,
782 LPCSTR pszPriType,
783 LPCSTR pszSubType)
784 {
785 MimeBody *This = impl_from_IMimeBody(iface);
786
787 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
788 if(pszPriType)
789 {
790 const char *pri = This->content_pri_type;
791 if(!pri) pri = "text";
792 if(strcasecmp(pri, pszPriType)) return S_FALSE;
793 }
794
795 if(pszSubType)
796 {
797 const char *sub = This->content_sub_type;
798 if(!sub) sub = "plain";
799 if(strcasecmp(sub, pszSubType)) return S_FALSE;
800 }
801
802 return S_OK;
803 }
804
805 static HRESULT WINAPI MimeBody_BindToObject(
806 IMimeBody* iface,
807 REFIID riid,
808 void** ppvObject)
809 {
810 FIXME("stub\n");
811 return E_NOTIMPL;
812 }
813
814 static HRESULT WINAPI MimeBody_Clone(
815 IMimeBody* iface,
816 IMimePropertySet** ppPropertySet)
817 {
818 FIXME("stub\n");
819 return E_NOTIMPL;
820 }
821
822 static HRESULT WINAPI MimeBody_SetOption(
823 IMimeBody* iface,
824 const TYPEDID oid,
825 LPCPROPVARIANT pValue)
826 {
827 HRESULT hr = E_NOTIMPL;
828 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
829
830 if(pValue->vt != TYPEDID_TYPE(oid))
831 {
832 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
833 return E_INVALIDARG;
834 }
835
836 switch(oid)
837 {
838 case OID_SECURITY_HWND_OWNER:
839 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
840 hr = S_OK;
841 break;
842 default:
843 FIXME("Unhandled oid %08x\n", oid);
844 }
845
846 return hr;
847 }
848
849 static HRESULT WINAPI MimeBody_GetOption(
850 IMimeBody* iface,
851 const TYPEDID oid,
852 LPPROPVARIANT pValue)
853 {
854 FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
855 return E_NOTIMPL;
856 }
857
858 static HRESULT WINAPI MimeBody_EnumProps(
859 IMimeBody* iface,
860 DWORD dwFlags,
861 IMimeEnumProperties** ppEnum)
862 {
863 FIXME("stub\n");
864 return E_NOTIMPL;
865 }
866
867 static HRESULT WINAPI MimeBody_IsType(
868 IMimeBody* iface,
869 IMSGBODYTYPE bodytype)
870 {
871 MimeBody *This = impl_from_IMimeBody(iface);
872
873 TRACE("(%p)->(%d)\n", iface, bodytype);
874 switch(bodytype)
875 {
876 case IBT_EMPTY:
877 return This->data ? S_FALSE : S_OK;
878 default:
879 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
880 }
881 return S_OK;
882 }
883
884 static HRESULT WINAPI MimeBody_SetDisplayName(
885 IMimeBody* iface,
886 LPCSTR pszDisplay)
887 {
888 FIXME("stub\n");
889 return E_NOTIMPL;
890 }
891
892 static HRESULT WINAPI MimeBody_GetDisplayName(
893 IMimeBody* iface,
894 LPSTR* ppszDisplay)
895 {
896 FIXME("stub\n");
897 return E_NOTIMPL;
898 }
899
900 static HRESULT WINAPI MimeBody_GetOffsets(
901 IMimeBody* iface,
902 LPBODYOFFSETS pOffsets)
903 {
904 MimeBody *This = impl_from_IMimeBody(iface);
905 TRACE("(%p)->(%p)\n", This, pOffsets);
906
907 *pOffsets = This->body_offsets;
908
909 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
910 return S_OK;
911 }
912
913 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
914 IMimeBody* iface,
915 ENCODINGTYPE* pietEncoding)
916 {
917 MimeBody *This = impl_from_IMimeBody(iface);
918
919 TRACE("(%p)->(%p)\n", This, pietEncoding);
920
921 *pietEncoding = This->encoding;
922 return S_OK;
923 }
924
925 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
926 IMimeBody* iface,
927 ENCODINGTYPE ietEncoding)
928 {
929 MimeBody *This = impl_from_IMimeBody(iface);
930
931 TRACE("(%p)->(%d)\n", This, ietEncoding);
932
933 This->encoding = ietEncoding;
934 return S_OK;
935 }
936
937 static HRESULT WINAPI MimeBody_GetEstimatedSize(
938 IMimeBody* iface,
939 ENCODINGTYPE ietEncoding,
940 ULONG* pcbSize)
941 {
942 FIXME("stub\n");
943 return E_NOTIMPL;
944 }
945
946 static HRESULT WINAPI MimeBody_GetDataHere(
947 IMimeBody* iface,
948 ENCODINGTYPE ietEncoding,
949 IStream* pStream)
950 {
951 FIXME("stub\n");
952 return E_NOTIMPL;
953 }
954
955 static HRESULT WINAPI MimeBody_GetData(
956 IMimeBody* iface,
957 ENCODINGTYPE ietEncoding,
958 IStream** ppStream)
959 {
960 MimeBody *This = impl_from_IMimeBody(iface);
961 FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
962
963 *ppStream = This->data;
964 IStream_AddRef(*ppStream);
965 return S_OK;
966 }
967
968 static HRESULT WINAPI MimeBody_SetData(
969 IMimeBody* iface,
970 ENCODINGTYPE ietEncoding,
971 LPCSTR pszPriType,
972 LPCSTR pszSubType,
973 REFIID riid,
974 LPVOID pvObject)
975 {
976 MimeBody *This = impl_from_IMimeBody(iface);
977 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
978 debugstr_guid(riid), pvObject);
979
980 if(IsEqualIID(riid, &IID_IStream))
981 IStream_AddRef((IStream *)pvObject);
982 else
983 {
984 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
985 return E_INVALIDARG;
986 }
987
988 if(This->data)
989 FIXME("release old data\n");
990
991 This->data_iid = *riid;
992 This->data = pvObject;
993
994 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
995
996 /* FIXME: Update the content type.
997 If pszPriType == NULL use 'application'
998 If pszSubType == NULL use 'octet-stream' */
999
1000 return S_OK;
1001 }
1002
1003 static HRESULT WINAPI MimeBody_EmptyData(
1004 IMimeBody* iface)
1005 {
1006 FIXME("stub\n");
1007 return E_NOTIMPL;
1008 }
1009
1010 static HRESULT WINAPI MimeBody_CopyTo(
1011 IMimeBody* iface,
1012 IMimeBody* pBody)
1013 {
1014 FIXME("stub\n");
1015 return E_NOTIMPL;
1016 }
1017
1018 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1019 IMimeBody* iface,
1020 LPTRANSMITINFO pTransmitInfo)
1021 {
1022 FIXME("stub\n");
1023 return E_NOTIMPL;
1024 }
1025
1026 static HRESULT WINAPI MimeBody_SaveToFile(
1027 IMimeBody* iface,
1028 ENCODINGTYPE ietEncoding,
1029 LPCSTR pszFilePath)
1030 {
1031 FIXME("stub\n");
1032 return E_NOTIMPL;
1033 }
1034
1035 static HRESULT WINAPI MimeBody_GetHandle(
1036 IMimeBody* iface,
1037 LPHBODY phBody)
1038 {
1039 MimeBody *This = impl_from_IMimeBody(iface);
1040 TRACE("(%p)->(%p)\n", iface, phBody);
1041
1042 *phBody = This->handle;
1043 return This->handle ? S_OK : MIME_E_NO_DATA;
1044 }
1045
1046 static IMimeBodyVtbl body_vtbl =
1047 {
1048 MimeBody_QueryInterface,
1049 MimeBody_AddRef,
1050 MimeBody_Release,
1051 MimeBody_GetClassID,
1052 MimeBody_IsDirty,
1053 MimeBody_Load,
1054 MimeBody_Save,
1055 MimeBody_GetSizeMax,
1056 MimeBody_InitNew,
1057 MimeBody_GetPropInfo,
1058 MimeBody_SetPropInfo,
1059 MimeBody_GetProp,
1060 MimeBody_SetProp,
1061 MimeBody_AppendProp,
1062 MimeBody_DeleteProp,
1063 MimeBody_CopyProps,
1064 MimeBody_MoveProps,
1065 MimeBody_DeleteExcept,
1066 MimeBody_QueryProp,
1067 MimeBody_GetCharset,
1068 MimeBody_SetCharset,
1069 MimeBody_GetParameters,
1070 MimeBody_IsContentType,
1071 MimeBody_BindToObject,
1072 MimeBody_Clone,
1073 MimeBody_SetOption,
1074 MimeBody_GetOption,
1075 MimeBody_EnumProps,
1076 MimeBody_IsType,
1077 MimeBody_SetDisplayName,
1078 MimeBody_GetDisplayName,
1079 MimeBody_GetOffsets,
1080 MimeBody_GetCurrentEncoding,
1081 MimeBody_SetCurrentEncoding,
1082 MimeBody_GetEstimatedSize,
1083 MimeBody_GetDataHere,
1084 MimeBody_GetData,
1085 MimeBody_SetData,
1086 MimeBody_EmptyData,
1087 MimeBody_CopyTo,
1088 MimeBody_GetTransmitInfo,
1089 MimeBody_SaveToFile,
1090 MimeBody_GetHandle
1091 };
1092
1093 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1094 {
1095 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1096 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1097
1098 body->body_offsets = *offsets;
1099 return S_OK;
1100 }
1101
1102 #define FIRST_CUSTOM_PROP_ID 0x100
1103
1104 HRESULT MimeBody_create(IUnknown *outer, void **obj)
1105 {
1106 MimeBody *This;
1107 BODYOFFSETS body_offsets;
1108
1109 *obj = NULL;
1110
1111 if(outer) return CLASS_E_NOAGGREGATION;
1112
1113 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1114 if (!This) return E_OUTOFMEMORY;
1115
1116 This->lpVtbl = &body_vtbl;
1117 This->refs = 1;
1118 This->handle = NULL;
1119 list_init(&This->headers);
1120 list_init(&This->new_props);
1121 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1122 This->content_pri_type = NULL;
1123 This->content_sub_type = NULL;
1124 This->encoding = IET_7BIT;
1125 This->data = NULL;
1126 This->data_iid = IID_NULL;
1127
1128 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1129 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1130 MimeBody_set_offsets(This, &body_offsets);
1131
1132 *obj = &This->lpVtbl;
1133 return S_OK;
1134 }
1135
1136 typedef struct
1137 {
1138 IStreamVtbl *lpVtbl;
1139 LONG refs;
1140
1141 IStream *base;
1142 ULARGE_INTEGER pos, start, length;
1143 } sub_stream_t;
1144
1145 static inline sub_stream_t *impl_from_IStream( IStream *iface )
1146 {
1147 return (sub_stream_t *)((char*)iface - FIELD_OFFSET(sub_stream_t, lpVtbl));
1148 }
1149
1150 static HRESULT WINAPI sub_stream_QueryInterface(
1151 IStream* iface,
1152 REFIID riid,
1153 void **ppvObject)
1154 {
1155 sub_stream_t *This = impl_from_IStream(iface);
1156
1157 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1158 *ppvObject = NULL;
1159
1160 if(IsEqualIID(riid, &IID_IUnknown) ||
1161 IsEqualIID(riid, &IID_ISequentialStream) ||
1162 IsEqualIID(riid, &IID_IStream))
1163 {
1164 IStream_AddRef(iface);
1165 *ppvObject = iface;
1166 return S_OK;
1167 }
1168 return E_NOINTERFACE;
1169 }
1170
1171 static ULONG WINAPI sub_stream_AddRef(
1172 IStream* iface)
1173 {
1174 sub_stream_t *This = impl_from_IStream(iface);
1175
1176 TRACE("(%p)\n", This);
1177 return InterlockedIncrement(&This->refs);
1178 }
1179
1180 static ULONG WINAPI sub_stream_Release(
1181 IStream* iface)
1182 {
1183 sub_stream_t *This = impl_from_IStream(iface);
1184 LONG refs;
1185
1186 TRACE("(%p)\n", This);
1187 refs = InterlockedDecrement(&This->refs);
1188 if(!refs)
1189 {
1190 IStream_Release(This->base);
1191 HeapFree(GetProcessHeap(), 0, This);
1192 }
1193 return refs;
1194 }
1195
1196 static HRESULT WINAPI sub_stream_Read(
1197 IStream* iface,
1198 void *pv,
1199 ULONG cb,
1200 ULONG *pcbRead)
1201 {
1202 sub_stream_t *This = impl_from_IStream(iface);
1203 HRESULT hr;
1204 ULARGE_INTEGER base_pos;
1205 LARGE_INTEGER tmp_pos;
1206
1207 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
1208
1209 tmp_pos.QuadPart = 0;
1210 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_CUR, &base_pos);
1211 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
1212 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1213
1214 if(This->pos.QuadPart + cb > This->length.QuadPart)
1215 cb = This->length.QuadPart - This->pos.QuadPart;
1216
1217 hr = IStream_Read(This->base, pv, cb, pcbRead);
1218
1219 This->pos.QuadPart += *pcbRead;
1220
1221 tmp_pos.QuadPart = base_pos.QuadPart;
1222 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1223
1224 return hr;
1225 }
1226
1227 static HRESULT WINAPI sub_stream_Write(
1228 IStream* iface,
1229 const void *pv,
1230 ULONG cb,
1231 ULONG *pcbWritten)
1232 {
1233 FIXME("stub\n");
1234 return E_NOTIMPL;
1235 }
1236
1237 static HRESULT WINAPI sub_stream_Seek(
1238 IStream* iface,
1239 LARGE_INTEGER dlibMove,
1240 DWORD dwOrigin,
1241 ULARGE_INTEGER *plibNewPosition)
1242 {
1243 sub_stream_t *This = impl_from_IStream(iface);
1244 LARGE_INTEGER new_pos;
1245
1246 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
1247
1248 switch(dwOrigin)
1249 {
1250 case STREAM_SEEK_SET:
1251 new_pos = dlibMove;
1252 break;
1253 case STREAM_SEEK_CUR:
1254 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
1255 break;
1256 case STREAM_SEEK_END:
1257 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
1258 break;
1259 default:
1260 return STG_E_INVALIDFUNCTION;
1261 }
1262
1263 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
1264 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
1265
1266 This->pos.QuadPart = new_pos.QuadPart;
1267
1268 if(plibNewPosition) *plibNewPosition = This->pos;
1269 return S_OK;
1270 }
1271
1272 static HRESULT WINAPI sub_stream_SetSize(
1273 IStream* iface,
1274 ULARGE_INTEGER libNewSize)
1275 {
1276 FIXME("stub\n");
1277 return E_NOTIMPL;
1278 }
1279
1280 static HRESULT WINAPI sub_stream_CopyTo(
1281 IStream* iface,
1282 IStream *pstm,
1283 ULARGE_INTEGER cb,
1284 ULARGE_INTEGER *pcbRead,
1285 ULARGE_INTEGER *pcbWritten)
1286 {
1287 HRESULT hr = S_OK;
1288 BYTE tmpBuffer[128];
1289 ULONG bytesRead, bytesWritten, copySize;
1290 ULARGE_INTEGER totalBytesRead;
1291 ULARGE_INTEGER totalBytesWritten;
1292
1293 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
1294
1295 totalBytesRead.QuadPart = 0;
1296 totalBytesWritten.QuadPart = 0;
1297
1298 while ( cb.QuadPart > 0 )
1299 {
1300 if ( cb.QuadPart >= sizeof(tmpBuffer) )
1301 copySize = sizeof(tmpBuffer);
1302 else
1303 copySize = cb.u.LowPart;
1304
1305 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1306 if (FAILED(hr)) break;
1307
1308 totalBytesRead.QuadPart += bytesRead;
1309
1310 if (bytesRead)
1311 {
1312 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1313 if (FAILED(hr)) break;
1314 totalBytesWritten.QuadPart += bytesWritten;
1315 }
1316
1317 if (bytesRead != copySize)
1318 cb.QuadPart = 0;
1319 else
1320 cb.QuadPart -= bytesRead;
1321 }
1322
1323 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
1324 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
1325
1326 return hr;
1327 }
1328
1329 static HRESULT WINAPI sub_stream_Commit(
1330 IStream* iface,
1331 DWORD grfCommitFlags)
1332 {
1333 FIXME("stub\n");
1334 return E_NOTIMPL;
1335 }
1336
1337 static HRESULT WINAPI sub_stream_Revert(
1338 IStream* iface)
1339 {
1340 FIXME("stub\n");
1341 return E_NOTIMPL;
1342 }
1343
1344 static HRESULT WINAPI sub_stream_LockRegion(
1345 IStream* iface,
1346 ULARGE_INTEGER libOffset,
1347 ULARGE_INTEGER cb,
1348 DWORD dwLockType)
1349 {
1350 FIXME("stub\n");
1351 return E_NOTIMPL;
1352 }
1353
1354 static HRESULT WINAPI sub_stream_UnlockRegion(
1355 IStream* iface,
1356 ULARGE_INTEGER libOffset,
1357 ULARGE_INTEGER cb,
1358 DWORD dwLockType)
1359 {
1360 FIXME("stub\n");
1361 return E_NOTIMPL;
1362 }
1363
1364 static HRESULT WINAPI sub_stream_Stat(
1365 IStream* iface,
1366 STATSTG *pstatstg,
1367 DWORD grfStatFlag)
1368 {
1369 sub_stream_t *This = impl_from_IStream(iface);
1370 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
1371 memset(pstatstg, 0, sizeof(*pstatstg));
1372 pstatstg->cbSize = This->length;
1373 return S_OK;
1374 }
1375
1376 static HRESULT WINAPI sub_stream_Clone(
1377 IStream* iface,
1378 IStream **ppstm)
1379 {
1380 FIXME("stub\n");
1381 return E_NOTIMPL;
1382 }
1383
1384 static struct IStreamVtbl sub_stream_vtbl =
1385 {
1386 sub_stream_QueryInterface,
1387 sub_stream_AddRef,
1388 sub_stream_Release,
1389 sub_stream_Read,
1390 sub_stream_Write,
1391 sub_stream_Seek,
1392 sub_stream_SetSize,
1393 sub_stream_CopyTo,
1394 sub_stream_Commit,
1395 sub_stream_Revert,
1396 sub_stream_LockRegion,
1397 sub_stream_UnlockRegion,
1398 sub_stream_Stat,
1399 sub_stream_Clone
1400 };
1401
1402 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
1403 {
1404 sub_stream_t *This;
1405
1406 *out = NULL;
1407 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1408 if(!This) return E_OUTOFMEMORY;
1409
1410 This->lpVtbl = &sub_stream_vtbl;
1411 This->refs = 1;
1412 This->start = start;
1413 This->length = length;
1414 This->pos.QuadPart = 0;
1415 IStream_AddRef(stream);
1416 This->base = stream;
1417
1418 *out = (IStream*)&This->lpVtbl;
1419 return S_OK;
1420 }
1421
1422
1423 typedef struct body_t
1424 {
1425 struct list entry;
1426 DWORD index;
1427 IMimeBody *mime_body;
1428
1429 struct body_t *parent;
1430 struct list children;
1431 } body_t;
1432
1433 typedef struct MimeMessage
1434 {
1435 const IMimeMessageVtbl *lpVtbl;
1436
1437 LONG refs;
1438 IStream *stream;
1439
1440 struct list body_tree;
1441 DWORD next_index;
1442 } MimeMessage;
1443
1444 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1445 {
1446 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1447
1448 if (IsEqualIID(riid, &IID_IUnknown) ||
1449 IsEqualIID(riid, &IID_IPersist) ||
1450 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1451 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1452 IsEqualIID(riid, &IID_IMimeMessage))
1453 {
1454 *ppv = iface;
1455 IUnknown_AddRef(iface);
1456 return S_OK;
1457 }
1458
1459 FIXME("no interface for %s\n", debugstr_guid(riid));
1460 *ppv = NULL;
1461 return E_NOINTERFACE;
1462 }
1463
1464 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1465 {
1466 MimeMessage *This = (MimeMessage *)iface;
1467 TRACE("(%p)->()\n", iface);
1468 return InterlockedIncrement(&This->refs);
1469 }
1470
1471 static void empty_body_list(struct list *list)
1472 {
1473 body_t *body, *cursor2;
1474 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1475 {
1476 empty_body_list(&body->children);
1477 list_remove(&body->entry);
1478 IMimeBody_Release(body->mime_body);
1479 HeapFree(GetProcessHeap(), 0, body);
1480 }
1481 }
1482
1483 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1484 {
1485 MimeMessage *This = (MimeMessage *)iface;
1486 ULONG refs;
1487
1488 TRACE("(%p)->()\n", iface);
1489
1490 refs = InterlockedDecrement(&This->refs);
1491 if (!refs)
1492 {
1493 empty_body_list(&This->body_tree);
1494
1495 if(This->stream) IStream_Release(This->stream);
1496 HeapFree(GetProcessHeap(), 0, This);
1497 }
1498
1499 return refs;
1500 }
1501
1502 /*** IPersist methods ***/
1503 static HRESULT WINAPI MimeMessage_GetClassID(
1504 IMimeMessage *iface,
1505 CLSID *pClassID)
1506 {
1507 FIXME("(%p)->(%p)\n", iface, pClassID);
1508 return E_NOTIMPL;
1509 }
1510
1511 /*** IPersistStreamInit methods ***/
1512 static HRESULT WINAPI MimeMessage_IsDirty(
1513 IMimeMessage *iface)
1514 {
1515 FIXME("(%p)->()\n", iface);
1516 return E_NOTIMPL;
1517 }
1518
1519 static body_t *new_body_entry(IMimeBody *mime_body, DWORD index, body_t *parent)
1520 {
1521 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
1522 if(body)
1523 {
1524 body->mime_body = mime_body;
1525 body->index = index;
1526 list_init(&body->children);
1527 body->parent = parent;
1528 }
1529 return body;
1530 }
1531
1532 typedef struct
1533 {
1534 struct list entry;
1535 BODYOFFSETS offsets;
1536 } offset_entry_t;
1537
1538 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
1539 {
1540 HRESULT hr;
1541 DWORD read;
1542 int boundary_len = strlen(boundary);
1543 char *buf, *nl_boundary, *ptr, *overlap;
1544 DWORD start = 0, overlap_no;
1545 offset_entry_t *cur_body = NULL;
1546 ULARGE_INTEGER cur;
1547 LARGE_INTEGER zero;
1548
1549 list_init(body_offsets);
1550 nl_boundary = HeapAlloc(GetProcessHeap(), 0, 4 + boundary_len + 1);
1551 memcpy(nl_boundary, "\r\n--", 4);
1552 memcpy(nl_boundary + 4, boundary, boundary_len + 1);
1553
1554 overlap_no = boundary_len + 5;
1555
1556 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
1557
1558 zero.QuadPart = 0;
1559 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
1560 start = cur.u.LowPart;
1561
1562 do {
1563 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
1564 if(FAILED(hr)) goto end;
1565 if(read == 0) break;
1566 overlap[read] = '\0';
1567
1568 ptr = buf;
1569 do {
1570 ptr = strstr(ptr, nl_boundary);
1571 if(ptr)
1572 {
1573 DWORD boundary_start = start + ptr - buf;
1574 char *end = ptr + boundary_len + 4;
1575
1576 if(*end == '\0' || *(end + 1) == '\0')
1577 break;
1578
1579 if(*end == '\r' && *(end + 1) == '\n')
1580 {
1581 if(cur_body)
1582 {
1583 cur_body->offsets.cbBodyEnd = boundary_start;
1584 list_add_tail(body_offsets, &cur_body->entry);
1585 }
1586 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
1587 cur_body->offsets.cbBoundaryStart = boundary_start + 2; /* doesn't including the leading \r\n */
1588 cur_body->offsets.cbHeaderStart = boundary_start + boundary_len + 6;
1589 }
1590 else if(*end == '-' && *(end + 1) == '-')
1591 {
1592 if(cur_body)
1593 {
1594 cur_body->offsets.cbBodyEnd = boundary_start;
1595 list_add_tail(body_offsets, &cur_body->entry);
1596 goto end;
1597 }
1598 }
1599 ptr = end + 2;
1600 }
1601 } while(ptr);
1602
1603 if(overlap == buf) /* 1st iteration */
1604 {
1605 memcpy(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
1606 overlap = buf + overlap_no;
1607 start += read - overlap_no;
1608 }
1609 else
1610 {
1611 memcpy(buf, buf + PARSER_BUF_SIZE, overlap_no);
1612 start += read;
1613 }
1614 } while(1);
1615
1616 end:
1617 HeapFree(GetProcessHeap(), 0, nl_boundary);
1618 HeapFree(GetProcessHeap(), 0, buf);
1619 return hr;
1620 }
1621
1622 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
1623 {
1624 IMimeBody *mime_body;
1625 HRESULT hr;
1626 body_t *body;
1627 ULARGE_INTEGER cur;
1628 LARGE_INTEGER zero;
1629
1630 MimeBody_create(NULL, (void**)&mime_body);
1631 IMimeBody_Load(mime_body, pStm);
1632 zero.QuadPart = 0;
1633 hr = IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &cur);
1634 offset->cbBodyStart = cur.u.LowPart + offset->cbHeaderStart;
1635 if(parent) MimeBody_set_offsets(impl_from_IMimeBody(mime_body), offset);
1636 IMimeBody_SetData(mime_body, IET_BINARY, NULL, NULL, &IID_IStream, pStm);
1637 body = new_body_entry(mime_body, msg->next_index++, parent);
1638
1639 if(IMimeBody_IsContentType(mime_body, "multipart", NULL) == S_OK)
1640 {
1641 MIMEPARAMINFO *param_info;
1642 ULONG count, i;
1643 IMimeAllocator *alloc;
1644
1645 hr = IMimeBody_GetParameters(mime_body, "Content-Type", &count, &param_info);
1646 if(hr != S_OK || count == 0) return body;
1647
1648 MimeOleGetAllocator(&alloc);
1649
1650 for(i = 0; i < count; i++)
1651 {
1652 if(!strcasecmp(param_info[i].pszName, "boundary"))
1653 {
1654 struct list offset_list;
1655 offset_entry_t *cur, *cursor2;
1656 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
1657 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
1658 {
1659 body_t *sub_body;
1660 IStream *sub_stream;
1661 ULARGE_INTEGER start, length;
1662
1663 start.QuadPart = cur->offsets.cbHeaderStart;
1664 length.QuadPart = cur->offsets.cbBodyEnd - cur->offsets.cbHeaderStart;
1665 create_sub_stream(pStm, start, length, &sub_stream);
1666 sub_body = create_sub_body(msg, sub_stream, &cur->offsets, body);
1667 IStream_Release(sub_stream);
1668 list_add_tail(&body->children, &sub_body->entry);
1669 list_remove(&cur->entry);
1670 HeapFree(GetProcessHeap(), 0, cur);
1671 }
1672 break;
1673 }
1674 }
1675 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
1676 IMimeAllocator_Release(alloc);
1677 }
1678 return body;
1679 }
1680
1681 static HRESULT WINAPI MimeMessage_Load(
1682 IMimeMessage *iface,
1683 LPSTREAM pStm)
1684 {
1685 MimeMessage *This = (MimeMessage *)iface;
1686 body_t *root_body;
1687 BODYOFFSETS offsets;
1688 ULARGE_INTEGER cur;
1689 LARGE_INTEGER zero;
1690
1691 TRACE("(%p)->(%p)\n", iface, pStm);
1692
1693 if(This->stream)
1694 {
1695 FIXME("already loaded a message\n");
1696 return E_FAIL;
1697 }
1698
1699 IStream_AddRef(pStm);
1700 This->stream = pStm;
1701 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
1702 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
1703
1704 root_body = create_sub_body(This, pStm, &offsets, NULL);
1705
1706 zero.QuadPart = 0;
1707 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
1708 offsets.cbBodyEnd = cur.u.LowPart;
1709 MimeBody_set_offsets(impl_from_IMimeBody(root_body->mime_body), &offsets);
1710
1711 list_add_head(&This->body_tree, &root_body->entry);
1712
1713 return S_OK;
1714 }
1715
1716 static HRESULT WINAPI MimeMessage_Save(
1717 IMimeMessage *iface,
1718 LPSTREAM pStm,
1719 BOOL fClearDirty)
1720 {
1721 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
1722 return E_NOTIMPL;
1723 }
1724
1725 static HRESULT WINAPI MimeMessage_GetSizeMax(
1726 IMimeMessage *iface,
1727 ULARGE_INTEGER *pcbSize)
1728 {
1729 FIXME("(%p)->(%p)\n", iface, pcbSize);
1730 return E_NOTIMPL;
1731 }
1732
1733 static HRESULT WINAPI MimeMessage_InitNew(
1734 IMimeMessage *iface)
1735 {
1736 FIXME("(%p)->()\n", iface);
1737 return E_NOTIMPL;
1738 }
1739
1740 /*** IMimeMessageTree methods ***/
1741 static HRESULT WINAPI MimeMessage_GetMessageSource(
1742 IMimeMessage *iface,
1743 IStream **ppStream,
1744 DWORD dwFlags)
1745 {
1746 MimeMessage *This = (MimeMessage *)iface;
1747 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
1748
1749 IStream_AddRef(This->stream);
1750 *ppStream = This->stream;
1751 return S_OK;
1752 }
1753
1754 static HRESULT WINAPI MimeMessage_GetMessageSize(
1755 IMimeMessage *iface,
1756 ULONG *pcbSize,
1757 DWORD dwFlags)
1758 {
1759 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
1760 return E_NOTIMPL;
1761 }
1762
1763 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
1764 IMimeMessage *iface,
1765 IStream *pStream)
1766 {
1767 FIXME("(%p)->(%p)\n", iface, pStream);
1768 return E_NOTIMPL;
1769 }
1770
1771 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
1772 IMimeMessage *iface,
1773 IStream *pStream,
1774 DWORD dwFlags)
1775 {
1776 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
1777 return E_NOTIMPL;
1778 }
1779
1780
1781 static HRESULT WINAPI MimeMessage_GetFlags(
1782 IMimeMessage *iface,
1783 DWORD *pdwFlags)
1784 {
1785 FIXME("(%p)->(%p)\n", iface, pdwFlags);
1786 return E_NOTIMPL;
1787 }
1788
1789 static HRESULT WINAPI MimeMessage_Commit(
1790 IMimeMessage *iface,
1791 DWORD dwFlags)
1792 {
1793 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
1794 return E_NOTIMPL;
1795 }
1796
1797
1798 static HRESULT WINAPI MimeMessage_HandsOffStorage(
1799 IMimeMessage *iface)
1800 {
1801 FIXME("(%p)->()\n", iface);
1802 return E_NOTIMPL;
1803 }
1804
1805 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
1806 {
1807 body_t *cur;
1808 HRESULT hr;
1809
1810 if(hbody == HBODY_ROOT)
1811 {
1812 *body = LIST_ENTRY(list_head(list), body_t, entry);
1813 return S_OK;
1814 }
1815
1816 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
1817 {
1818 if(cur->index == HandleToUlong(hbody))
1819 {
1820 *body = cur;
1821 return S_OK;
1822 }
1823 hr = find_body(&cur->children, hbody, body);
1824 if(hr == S_OK) return S_OK;
1825 }
1826 return S_FALSE;
1827 }
1828
1829 static HRESULT WINAPI MimeMessage_BindToObject(
1830 IMimeMessage *iface,
1831 const HBODY hBody,
1832 REFIID riid,
1833 void **ppvObject)
1834 {
1835 MimeMessage *This = (MimeMessage *)iface;
1836 HRESULT hr;
1837 body_t *body;
1838
1839 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
1840
1841 hr = find_body(&This->body_tree, hBody, &body);
1842
1843 if(hr != S_OK) return hr;
1844
1845 if(IsEqualIID(riid, &IID_IMimeBody))
1846 {
1847 IMimeBody_AddRef(body->mime_body);
1848 *ppvObject = body->mime_body;
1849 return S_OK;
1850 }
1851
1852 return E_NOINTERFACE;
1853 }
1854
1855 static HRESULT WINAPI MimeMessage_SaveBody(
1856 IMimeMessage *iface,
1857 HBODY hBody,
1858 DWORD dwFlags,
1859 IStream *pStream)
1860 {
1861 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
1862 return E_NOTIMPL;
1863 }
1864
1865 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
1866 {
1867 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
1868 body_t *body;
1869 HRESULT hr;
1870 struct list *list;
1871
1872 if(location == IBL_ROOT)
1873 {
1874 *out = root;
1875 return S_OK;
1876 }
1877
1878 hr = find_body(&msg->body_tree, pivot, &body);
1879
1880 if(hr == S_OK)
1881 {
1882 switch(location)
1883 {
1884 case IBL_PARENT:
1885 *out = body->parent;
1886 break;
1887
1888 case IBL_FIRST:
1889 list = list_head(&body->children);
1890 if(list)
1891 *out = LIST_ENTRY(list, body_t, entry);
1892 else
1893 hr = MIME_E_NOT_FOUND;
1894 break;
1895
1896 case IBL_LAST:
1897 list = list_tail(&body->children);
1898 if(list)
1899 *out = LIST_ENTRY(list, body_t, entry);
1900 else
1901 hr = MIME_E_NOT_FOUND;
1902 break;
1903
1904 case IBL_NEXT:
1905 list = list_next(&body->parent->children, &body->entry);
1906 if(list)
1907 *out = LIST_ENTRY(list, body_t, entry);
1908 else
1909 hr = MIME_E_NOT_FOUND;
1910 break;
1911
1912 case IBL_PREVIOUS:
1913 list = list_prev(&body->parent->children, &body->entry);
1914 if(list)
1915 *out = LIST_ENTRY(list, body_t, entry);
1916 else
1917 hr = MIME_E_NOT_FOUND;
1918 break;
1919
1920 default:
1921 hr = E_FAIL;
1922 break;
1923 }
1924 }
1925
1926 return hr;
1927 }
1928
1929
1930 static HRESULT WINAPI MimeMessage_InsertBody(
1931 IMimeMessage *iface,
1932 BODYLOCATION location,
1933 HBODY hPivot,
1934 LPHBODY phBody)
1935 {
1936 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1937 return E_NOTIMPL;
1938 }
1939
1940 static HRESULT WINAPI MimeMessage_GetBody(
1941 IMimeMessage *iface,
1942 BODYLOCATION location,
1943 HBODY hPivot,
1944 LPHBODY phBody)
1945 {
1946 MimeMessage *This = (MimeMessage *)iface;
1947 body_t *body;
1948 HRESULT hr;
1949
1950 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
1951
1952 hr = get_body(This, location, hPivot, &body);
1953
1954 if(hr == S_OK) *phBody = UlongToHandle(body->index);
1955
1956 return hr;
1957 }
1958
1959 static HRESULT WINAPI MimeMessage_DeleteBody(
1960 IMimeMessage *iface,
1961 HBODY hBody,
1962 DWORD dwFlags)
1963 {
1964 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
1965 return E_NOTIMPL;
1966 }
1967
1968 static HRESULT WINAPI MimeMessage_MoveBody(
1969 IMimeMessage *iface,
1970 HBODY hBody,
1971 BODYLOCATION location)
1972 {
1973 FIXME("(%p)->(%d)\n", iface, location);
1974 return E_NOTIMPL;
1975 }
1976
1977 static void count_children(body_t *body, boolean recurse, ULONG *count)
1978 {
1979 body_t *child;
1980
1981 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
1982 {
1983 (*count)++;
1984 if(recurse) count_children(child, recurse, count);
1985 }
1986 }
1987
1988 static HRESULT WINAPI MimeMessage_CountBodies(
1989 IMimeMessage *iface,
1990 HBODY hParent,
1991 boolean fRecurse,
1992 ULONG *pcBodies)
1993 {
1994 HRESULT hr;
1995 MimeMessage *This = (MimeMessage *)iface;
1996 body_t *body;
1997
1998 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
1999
2000 hr = find_body(&This->body_tree, hParent, &body);
2001 if(hr != S_OK) return hr;
2002
2003 *pcBodies = 1;
2004 count_children(body, fRecurse, pcBodies);
2005
2006 return S_OK;
2007 }
2008
2009 static HRESULT find_next(IMimeMessage *msg, body_t *body, LPFINDBODY find, HBODY *out)
2010 {
2011 MimeMessage *This = (MimeMessage *)msg;
2012 struct list *ptr;
2013 HBODY next;
2014
2015 for (;;)
2016 {
2017 if (!body) ptr = list_head( &This->body_tree );
2018 else
2019 {
2020 ptr = list_head( &body->children );
2021 while (!ptr)
2022 {
2023 if (!body->parent) return MIME_E_NOT_FOUND;
2024 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2025 }
2026 }
2027
2028 body = LIST_ENTRY( ptr, body_t, entry );
2029 next = UlongToHandle( body->index );
2030 find->dwReserved = body->index;
2031 if (IMimeBody_IsContentType(body->mime_body, find->pszPriType, find->pszSubType) == S_OK)
2032 {
2033 *out = next;
2034 return S_OK;
2035 }
2036 }
2037 return MIME_E_NOT_FOUND;
2038 }
2039
2040 static HRESULT WINAPI MimeMessage_FindFirst(
2041 IMimeMessage *iface,
2042 LPFINDBODY pFindBody,
2043 LPHBODY phBody)
2044 {
2045 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2046
2047 pFindBody->dwReserved = 0;
2048 return find_next( iface, NULL, pFindBody, phBody );
2049 }
2050
2051 static HRESULT WINAPI MimeMessage_FindNext(
2052 IMimeMessage *iface,
2053 LPFINDBODY pFindBody,
2054 LPHBODY phBody)
2055 {
2056 MimeMessage *This = (MimeMessage *)iface;
2057 body_t *body;
2058 HRESULT hr;
2059
2060 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2061
2062 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2063 if (hr != S_OK) return MIME_E_NOT_FOUND;
2064 return find_next( iface, body, pFindBody, phBody );
2065 }
2066
2067 static HRESULT WINAPI MimeMessage_ResolveURL(
2068 IMimeMessage *iface,
2069 HBODY hRelated,
2070 LPCSTR pszBase,
2071 LPCSTR pszURL,
2072 DWORD dwFlags,
2073 LPHBODY phBody)
2074 {
2075 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2076 return E_NOTIMPL;
2077 }
2078
2079 static HRESULT WINAPI MimeMessage_ToMultipart(
2080 IMimeMessage *iface,
2081 HBODY hBody,
2082 LPCSTR pszSubType,
2083 LPHBODY phMultipart)
2084 {
2085 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2086 return E_NOTIMPL;
2087 }
2088
2089 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2090 IMimeMessage *iface,
2091 HBODY hBody,
2092 LPBODYOFFSETS pOffsets)
2093 {
2094 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2095 return E_NOTIMPL;
2096 }
2097
2098 static HRESULT WINAPI MimeMessage_GetCharset(
2099 IMimeMessage *iface,
2100 LPHCHARSET phCharset)
2101 {
2102 FIXME("(%p)->(%p)\n", iface, phCharset);
2103 *phCharset = NULL;
2104 return S_OK;
2105 }
2106
2107 static HRESULT WINAPI MimeMessage_SetCharset(
2108 IMimeMessage *iface,
2109 HCHARSET hCharset,
2110 CSETAPPLYTYPE applytype)
2111 {
2112 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2113 return E_NOTIMPL;
2114 }
2115
2116 static HRESULT WINAPI MimeMessage_IsBodyType(
2117 IMimeMessage *iface,
2118 HBODY hBody,
2119 IMSGBODYTYPE bodytype)
2120 {
2121 HRESULT hr;
2122 IMimeBody *mime_body;
2123 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2124
2125 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2126 if(hr != S_OK) return hr;
2127
2128 hr = IMimeBody_IsType(mime_body, bodytype);
2129 MimeBody_Release(mime_body);
2130 return hr;
2131 }
2132
2133 static HRESULT WINAPI MimeMessage_IsContentType(
2134 IMimeMessage *iface,
2135 HBODY hBody,
2136 LPCSTR pszPriType,
2137 LPCSTR pszSubType)
2138 {
2139 HRESULT hr;
2140 IMimeBody *mime_body;
2141 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2142 debugstr_a(pszSubType));
2143
2144 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2145 if(FAILED(hr)) return hr;
2146
2147 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2148 IMimeBody_Release(mime_body);
2149 return hr;
2150 }
2151
2152 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2153 IMimeMessage *iface,
2154 HBODY hBody,
2155 LPCSTR pszName,
2156 LPCSTR pszCriteria,
2157 boolean fSubString,
2158 boolean fCaseSensitive)
2159 {
2160 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2161 return E_NOTIMPL;
2162 }
2163
2164 static HRESULT WINAPI MimeMessage_GetBodyProp(
2165 IMimeMessage *iface,
2166 HBODY hBody,
2167 LPCSTR pszName,
2168 DWORD dwFlags,
2169 LPPROPVARIANT pValue)
2170 {
2171 HRESULT hr;
2172 IMimeBody *mime_body;
2173
2174 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2175
2176 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2177 if(hr != S_OK) return hr;
2178
2179 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2180 IMimeBody_Release(mime_body);
2181
2182 return hr;
2183 }
2184
2185 static HRESULT WINAPI MimeMessage_SetBodyProp(
2186 IMimeMessage *iface,
2187 HBODY hBody,
2188 LPCSTR pszName,
2189 DWORD dwFlags,
2190 LPCPROPVARIANT pValue)
2191 {
2192 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2193 return E_NOTIMPL;
2194 }
2195
2196 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2197 IMimeMessage *iface,
2198 HBODY hBody,
2199 LPCSTR pszName)
2200 {
2201 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2202 return E_NOTIMPL;
2203 }
2204
2205 static HRESULT WINAPI MimeMessage_SetOption(
2206 IMimeMessage *iface,
2207 const TYPEDID oid,
2208 LPCPROPVARIANT pValue)
2209 {
2210 HRESULT hr = E_NOTIMPL;
2211 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2212
2213 if(pValue->vt != TYPEDID_TYPE(oid))
2214 {
2215 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2216 return E_INVALIDARG;
2217 }
2218
2219 switch(oid)
2220 {
2221 case OID_HIDE_TNEF_ATTACHMENTS:
2222 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2223 hr = S_OK;
2224 break;
2225 case OID_SHOW_MACBINARY:
2226 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2227 hr = S_OK;
2228 break;
2229 default:
2230 FIXME("Unhandled oid %08x\n", oid);
2231 }
2232
2233 return hr;
2234 }
2235
2236 static HRESULT WINAPI MimeMessage_GetOption(
2237 IMimeMessage *iface,
2238 const TYPEDID oid,
2239 LPPROPVARIANT pValue)
2240 {
2241 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2242 return E_NOTIMPL;
2243 }
2244
2245 /*** IMimeMessage methods ***/
2246 static HRESULT WINAPI MimeMessage_CreateWebPage(
2247 IMimeMessage *iface,
2248 IStream *pRootStm,
2249 LPWEBPAGEOPTIONS pOptions,
2250 IMimeMessageCallback *pCallback,
2251 IMoniker **ppMoniker)
2252 {
2253 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2254 *ppMoniker = NULL;
2255 return E_NOTIMPL;
2256 }
2257
2258 static HRESULT WINAPI MimeMessage_GetProp(
2259 IMimeMessage *iface,
2260 LPCSTR pszName,
2261 DWORD dwFlags,
2262 LPPROPVARIANT pValue)
2263 {
2264 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2265 return E_NOTIMPL;
2266 }
2267
2268 static HRESULT WINAPI MimeMessage_SetProp(
2269 IMimeMessage *iface,
2270 LPCSTR pszName,
2271 DWORD dwFlags,
2272 LPCPROPVARIANT pValue)
2273 {
2274 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2275 return E_NOTIMPL;
2276 }
2277
2278 static HRESULT WINAPI MimeMessage_DeleteProp(
2279 IMimeMessage *iface,
2280 LPCSTR pszName)
2281 {
2282 FIXME("(%p)->(%s)\n", iface, pszName);
2283 return E_NOTIMPL;
2284 }
2285
2286 static HRESULT WINAPI MimeMessage_QueryProp(
2287 IMimeMessage *iface,
2288 LPCSTR pszName,
2289 LPCSTR pszCriteria,
2290 boolean fSubString,
2291 boolean fCaseSensitive)
2292 {
2293 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2294 return E_NOTIMPL;
2295 }
2296
2297 static HRESULT WINAPI MimeMessage_GetTextBody(
2298 IMimeMessage *iface,
2299 DWORD dwTxtType,
2300 ENCODINGTYPE ietEncoding,
2301 IStream **pStream,
2302 LPHBODY phBody)
2303 {
2304 HRESULT hr;
2305 HBODY hbody;
2306 FINDBODY find_struct;
2307 IMimeBody *mime_body;
2308 static char text[] = "text";
2309 static char plain[] = "plain";
2310 static char html[] = "html";
2311
2312 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2313
2314 find_struct.pszPriType = text;
2315
2316 switch(dwTxtType)
2317 {
2318 case TXT_PLAIN:
2319 find_struct.pszSubType = plain;
2320 break;
2321 case TXT_HTML:
2322 find_struct.pszSubType = html;
2323 break;
2324 default:
2325 return MIME_E_INVALID_TEXT_TYPE;
2326 }
2327
2328 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2329 if(hr != S_OK)
2330 {
2331 TRACE("not found hr %08x\n", hr);
2332 *phBody = NULL;
2333 return hr;
2334 }
2335
2336 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2337
2338 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2339 *phBody = hbody;
2340 IMimeBody_Release(mime_body);
2341 return hr;
2342 }
2343
2344 static HRESULT WINAPI MimeMessage_SetTextBody(
2345 IMimeMessage *iface,
2346 DWORD dwTxtType,
2347 ENCODINGTYPE ietEncoding,
2348 HBODY hAlternative,
2349 IStream *pStream,
2350 LPHBODY phBody)
2351 {
2352 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2353 return E_NOTIMPL;
2354 }
2355
2356 static HRESULT WINAPI MimeMessage_AttachObject(
2357 IMimeMessage *iface,
2358 REFIID riid,
2359 void *pvObject,
2360 LPHBODY phBody)
2361 {
2362 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2363 return E_NOTIMPL;
2364 }
2365
2366 static HRESULT WINAPI MimeMessage_AttachFile(
2367 IMimeMessage *iface,
2368 LPCSTR pszFilePath,
2369 IStream *pstmFile,
2370 LPHBODY phBody)
2371 {
2372 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2373 return E_NOTIMPL;
2374 }
2375
2376 static HRESULT WINAPI MimeMessage_AttachURL(
2377 IMimeMessage *iface,
2378 LPCSTR pszBase,
2379 LPCSTR pszURL,
2380 DWORD dwFlags,
2381 IStream *pstmURL,
2382 LPSTR *ppszCIDURL,
2383 LPHBODY phBody)
2384 {
2385 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2386 return E_NOTIMPL;
2387 }
2388
2389 static HRESULT WINAPI MimeMessage_GetAttachments(
2390 IMimeMessage *iface,
2391 ULONG *pcAttach,
2392 LPHBODY *pprghAttach)
2393 {
2394 HRESULT hr;
2395 FINDBODY find_struct;
2396 HBODY hbody;
2397 LPHBODY array;
2398 ULONG size = 10;
2399
2400 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2401
2402 *pcAttach = 0;
2403 array = CoTaskMemAlloc(size * sizeof(HBODY));
2404
2405 find_struct.pszPriType = find_struct.pszSubType = NULL;
2406 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2407 while(hr == S_OK)
2408 {
2409 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2410 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2411 if(hr != S_OK)
2412 {
2413 if(*pcAttach + 1 > size)
2414 {
2415 size *= 2;
2416 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2417 }
2418 array[*pcAttach] = hbody;
2419 (*pcAttach)++;
2420 }
2421 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2422 }
2423
2424 *pprghAttach = array;
2425 return S_OK;
2426 }
2427
2428 static HRESULT WINAPI MimeMessage_GetAddressTable(
2429 IMimeMessage *iface,
2430 IMimeAddressTable **ppTable)
2431 {
2432 FIXME("(%p)->(%p)\n", iface, ppTable);
2433 return E_NOTIMPL;
2434 }
2435
2436 static HRESULT WINAPI MimeMessage_GetSender(
2437 IMimeMessage *iface,
2438 LPADDRESSPROPS pAddress)
2439 {
2440 FIXME("(%p)->(%p)\n", iface, pAddress);
2441 return E_NOTIMPL;
2442 }
2443
2444 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2445 IMimeMessage *iface,
2446 DWORD dwAdrTypes,
2447 DWORD dwProps,
2448 LPADDRESSLIST pList)
2449 {
2450 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2451 return E_NOTIMPL;
2452 }
2453
2454 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2455 IMimeMessage *iface,
2456 DWORD dwAdrTypes,
2457 ADDRESSFORMAT format,
2458 LPSTR *ppszFormat)
2459 {
2460 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2461 return E_NOTIMPL;
2462 }
2463
2464 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2465 IMimeMessage *iface,
2466 DWORD dwAdrTypes,
2467 DWORD dwProps,
2468 IMimeEnumAddressTypes **ppEnum)
2469 {
2470 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2471 return E_NOTIMPL;
2472 }
2473
2474 static HRESULT WINAPI MimeMessage_SplitMessage(
2475 IMimeMessage *iface,
2476 ULONG cbMaxPart,
2477 IMimeMessageParts **ppParts)
2478 {
2479 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
2480 return E_NOTIMPL;
2481 }
2482
2483 static HRESULT WINAPI MimeMessage_GetRootMoniker(
2484 IMimeMessage *iface,
2485 IMoniker **ppMoniker)
2486 {
2487 FIXME("(%p)->(%p)\n", iface, ppMoniker);
2488 return E_NOTIMPL;
2489 }
2490
2491 static const IMimeMessageVtbl MimeMessageVtbl =
2492 {
2493 MimeMessage_QueryInterface,
2494 MimeMessage_AddRef,
2495 MimeMessage_Release,
2496 MimeMessage_GetClassID,
2497 MimeMessage_IsDirty,
2498 MimeMessage_Load,
2499 MimeMessage_Save,
2500 MimeMessage_GetSizeMax,
2501 MimeMessage_InitNew,
2502 MimeMessage_GetMessageSource,
2503 MimeMessage_GetMessageSize,
2504 MimeMessage_LoadOffsetTable,
2505 MimeMessage_SaveOffsetTable,
2506 MimeMessage_GetFlags,
2507 MimeMessage_Commit,
2508 MimeMessage_HandsOffStorage,
2509 MimeMessage_BindToObject,
2510 MimeMessage_SaveBody,
2511 MimeMessage_InsertBody,
2512 MimeMessage_GetBody,
2513 MimeMessage_DeleteBody,
2514 MimeMessage_MoveBody,
2515 MimeMessage_CountBodies,
2516 MimeMessage_FindFirst,
2517 MimeMessage_FindNext,
2518 MimeMessage_ResolveURL,
2519 MimeMessage_ToMultipart,
2520 MimeMessage_GetBodyOffsets,
2521 MimeMessage_GetCharset,
2522 MimeMessage_SetCharset,
2523 MimeMessage_IsBodyType,
2524 MimeMessage_IsContentType,
2525 MimeMessage_QueryBodyProp,
2526 MimeMessage_GetBodyProp,
2527 MimeMessage_SetBodyProp,
2528 MimeMessage_DeleteBodyProp,
2529 MimeMessage_SetOption,
2530 MimeMessage_GetOption,
2531 MimeMessage_CreateWebPage,
2532 MimeMessage_GetProp,
2533 MimeMessage_SetProp,
2534 MimeMessage_DeleteProp,
2535 MimeMessage_QueryProp,
2536 MimeMessage_GetTextBody,
2537 MimeMessage_SetTextBody,
2538 MimeMessage_AttachObject,
2539 MimeMessage_AttachFile,
2540 MimeMessage_AttachURL,
2541 MimeMessage_GetAttachments,
2542 MimeMessage_GetAddressTable,
2543 MimeMessage_GetSender,
2544 MimeMessage_GetAddressTypes,
2545 MimeMessage_GetAddressFormat,
2546 MimeMessage_EnumAddressTypes,
2547 MimeMessage_SplitMessage,
2548 MimeMessage_GetRootMoniker,
2549 };
2550
2551 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
2552 {
2553 MimeMessage *This;
2554
2555 TRACE("(%p, %p)\n", outer, obj);
2556
2557 if (outer)
2558 {
2559 FIXME("outer unknown not supported yet\n");
2560 return E_NOTIMPL;
2561 }
2562
2563 *obj = NULL;
2564
2565 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2566 if (!This) return E_OUTOFMEMORY;
2567
2568 This->lpVtbl = &MimeMessageVtbl;
2569 This->refs = 1;
2570 This->stream = NULL;
2571 list_init(&This->body_tree);
2572 This->next_index = 1;
2573
2574 *obj = &This->lpVtbl;
2575 return S_OK;
2576 }
2577
2578 /***********************************************************************
2579 * MimeOleCreateMessage (INETCOMM.@)
2580 */
2581 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
2582 {
2583 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
2584 return MimeMessage_create(NULL, (void **)ppMessage);
2585 }
2586
2587 /***********************************************************************
2588 * MimeOleSetCompatMode (INETCOMM.@)
2589 */
2590 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
2591 {
2592 FIXME("(0x%x)\n", dwMode);
2593 return S_OK;
2594 }
2595
2596 /***********************************************************************
2597 * MimeOleCreateVirtualStream (INETCOMM.@)
2598 */
2599 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
2600 {
2601 HRESULT hr;
2602 FIXME("(%p)\n", ppStream);
2603
2604 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
2605 return hr;
2606 }
2607
2608 typedef struct MimeSecurity
2609 {
2610 const IMimeSecurityVtbl *lpVtbl;
2611
2612 LONG refs;
2613 } MimeSecurity;
2614
2615 static HRESULT WINAPI MimeSecurity_QueryInterface(
2616 IMimeSecurity* iface,
2617 REFIID riid,
2618 void** obj)
2619 {
2620 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
2621
2622 if (IsEqualIID(riid, &IID_IUnknown) ||
2623 IsEqualIID(riid, &IID_IMimeSecurity))
2624 {
2625 *obj = iface;
2626 IUnknown_AddRef(iface);
2627 return S_OK;
2628 }
2629
2630 FIXME("no interface for %s\n", debugstr_guid(riid));
2631 *obj = NULL;
2632 return E_NOINTERFACE;
2633 }
2634
2635 static ULONG WINAPI MimeSecurity_AddRef(
2636 IMimeSecurity* iface)
2637 {
2638 MimeSecurity *This = (MimeSecurity *)iface;
2639 TRACE("(%p)->()\n", iface);
2640 return InterlockedIncrement(&This->refs);
2641 }
2642
2643 static ULONG WINAPI MimeSecurity_Release(
2644 IMimeSecurity* iface)
2645 {
2646 MimeSecurity *This = (MimeSecurity *)iface;
2647 ULONG refs;
2648
2649 TRACE("(%p)->()\n", iface);
2650
2651 refs = InterlockedDecrement(&This->refs);
2652 if (!refs)
2653 {
2654 HeapFree(GetProcessHeap(), 0, This);
2655 }
2656
2657 return refs;
2658 }
2659
2660 static HRESULT WINAPI MimeSecurity_InitNew(
2661 IMimeSecurity* iface)
2662 {
2663 FIXME("(%p)->(): stub\n", iface);
2664 return S_OK;
2665 }
2666
2667 static HRESULT WINAPI MimeSecurity_CheckInit(
2668 IMimeSecurity* iface)
2669 {
2670 FIXME("(%p)->(): stub\n", iface);
2671 return E_NOTIMPL;
2672 }
2673
2674 static HRESULT WINAPI MimeSecurity_EncodeMessage(
2675 IMimeSecurity* iface,
2676 IMimeMessageTree* pTree,
2677 DWORD dwFlags)
2678 {
2679 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
2680 return E_NOTIMPL;
2681 }
2682
2683 static HRESULT WINAPI MimeSecurity_EncodeBody(
2684 IMimeSecurity* iface,
2685 IMimeMessageTree* pTree,
2686 HBODY hEncodeRoot,
2687 DWORD dwFlags)
2688 {
2689 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
2690 return E_NOTIMPL;
2691 }
2692
2693 static HRESULT WINAPI MimeSecurity_DecodeMessage(
2694 IMimeSecurity* iface,
2695 IMimeMessageTree* pTree,
2696 DWORD dwFlags)
2697 {
2698 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
2699 return E_NOTIMPL;
2700 }
2701
2702 static HRESULT WINAPI MimeSecurity_DecodeBody(
2703 IMimeSecurity* iface,
2704 IMimeMessageTree* pTree,
2705 HBODY hDecodeRoot,
2706 DWORD dwFlags)
2707 {
2708 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
2709 return E_NOTIMPL;
2710 }
2711
2712 static HRESULT WINAPI MimeSecurity_EnumCertificates(
2713 IMimeSecurity* iface,
2714 HCAPICERTSTORE hc,
2715 DWORD dwUsage,
2716 PCX509CERT pPrev,
2717 PCX509CERT* ppCert)
2718 {
2719 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
2720 return E_NOTIMPL;
2721 }
2722
2723 static HRESULT WINAPI MimeSecurity_GetCertificateName(
2724 IMimeSecurity* iface,
2725 const PCX509CERT pX509Cert,
2726 const CERTNAMETYPE cn,
2727 LPSTR* ppszName)
2728 {
2729 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
2730 return E_NOTIMPL;
2731 }
2732
2733 static HRESULT WINAPI MimeSecurity_GetMessageType(
2734 IMimeSecurity* iface,
2735 const HWND hwndParent,
2736 IMimeBody* pBody,
2737 DWORD* pdwSecType)
2738 {
2739 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
2740 return E_NOTIMPL;
2741 }
2742
2743 static HRESULT WINAPI MimeSecurity_GetCertData(
2744 IMimeSecurity* iface,
2745 const PCX509CERT pX509Cert,
2746 const CERTDATAID dataid,
2747 LPPROPVARIANT pValue)
2748 {
2749 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
2750 return E_NOTIMPL;
2751 }
2752
2753
2754 static const IMimeSecurityVtbl MimeSecurityVtbl =
2755 {
2756 MimeSecurity_QueryInterface,
2757 MimeSecurity_AddRef,
2758 MimeSecurity_Release,
2759 MimeSecurity_InitNew,
2760 MimeSecurity_CheckInit,
2761 MimeSecurity_EncodeMessage,
2762 MimeSecurity_EncodeBody,
2763 MimeSecurity_DecodeMessage,
2764 MimeSecurity_DecodeBody,
2765 MimeSecurity_EnumCertificates,
2766 MimeSecurity_GetCertificateName,
2767 MimeSecurity_GetMessageType,
2768 MimeSecurity_GetCertData
2769 };
2770
2771 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
2772 {
2773 MimeSecurity *This;
2774
2775 *obj = NULL;
2776
2777 if (outer) return CLASS_E_NOAGGREGATION;
2778
2779 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2780 if (!This) return E_OUTOFMEMORY;
2781
2782 This->lpVtbl = &MimeSecurityVtbl;
2783 This->refs = 1;
2784
2785 *obj = &This->lpVtbl;
2786 return S_OK;
2787 }
2788
2789 /***********************************************************************
2790 * MimeOleCreateSecurity (INETCOMM.@)
2791 */
2792 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
2793 {
2794 return MimeSecurity_create(NULL, (void **)ppSecurity);
2795 }
2796
2797 typedef struct
2798 {
2799 IMimeAllocatorVtbl *lpVtbl;
2800 } MimeAllocator;
2801
2802 static HRESULT WINAPI MimeAlloc_QueryInterface(
2803 IMimeAllocator* iface,
2804 REFIID riid,
2805 void **obj)
2806 {
2807 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
2808
2809 if (IsEqualIID(riid, &IID_IUnknown) ||
2810 IsEqualIID(riid, &IID_IMalloc) ||
2811 IsEqualIID(riid, &IID_IMimeAllocator))
2812 {
2813 *obj = iface;
2814 IUnknown_AddRef(iface);
2815 return S_OK;
2816 }
2817
2818 FIXME("no interface for %s\n", debugstr_guid(riid));
2819 *obj = NULL;
2820 return E_NOINTERFACE;
2821 }
2822
2823 static ULONG WINAPI MimeAlloc_AddRef(
2824 IMimeAllocator* iface)
2825 {
2826 return 2;
2827 }
2828
2829 static ULONG WINAPI MimeAlloc_Release(
2830 IMimeAllocator* iface)
2831 {
2832 return 1;
2833 }
2834
2835 static LPVOID WINAPI MimeAlloc_Alloc(
2836 IMimeAllocator* iface,
2837 ULONG cb)
2838 {
2839 return CoTaskMemAlloc(cb);
2840 }
2841
2842 static LPVOID WINAPI MimeAlloc_Realloc(
2843 IMimeAllocator* iface,
2844 LPVOID pv,
2845 ULONG cb)
2846 {
2847 return CoTaskMemRealloc(pv, cb);
2848 }
2849
2850 static void WINAPI MimeAlloc_Free(
2851 IMimeAllocator* iface,
2852 LPVOID pv)
2853 {
2854 CoTaskMemFree(pv);
2855 }
2856
2857 static ULONG WINAPI MimeAlloc_GetSize(
2858 IMimeAllocator* iface,
2859 LPVOID pv)
2860 {
2861 FIXME("stub\n");
2862 return 0;
2863 }
2864
2865 static int WINAPI MimeAlloc_DidAlloc(
2866 IMimeAllocator* iface,
2867 LPVOID pv)
2868 {
2869 FIXME("stub\n");
2870 return 0;
2871 }
2872
2873 static void WINAPI MimeAlloc_HeapMinimize(
2874 IMimeAllocator* iface)
2875 {
2876 FIXME("stub\n");
2877 return;
2878 }
2879
2880 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
2881 IMimeAllocator* iface,
2882 ULONG cParams,
2883 LPMIMEPARAMINFO prgParam,
2884 boolean fFreeArray)
2885 {
2886 ULONG i;
2887 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
2888
2889 for(i = 0; i < cParams; i++)
2890 {
2891 IMimeAllocator_Free(iface, prgParam[i].pszName);
2892 IMimeAllocator_Free(iface, prgParam[i].pszData);
2893 }
2894 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
2895 return S_OK;
2896 }
2897
2898 static HRESULT WINAPI MimeAlloc_FreeAddressList(
2899 IMimeAllocator* iface,
2900 LPADDRESSLIST pList)
2901 {
2902 FIXME("stub\n");
2903 return E_NOTIMPL;
2904 }
2905
2906 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
2907 IMimeAllocator* iface,
2908 LPADDRESSPROPS pAddress)
2909 {
2910 FIXME("stub\n");
2911 return E_NOTIMPL;
2912 }
2913
2914 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
2915 IMimeAllocator* iface,
2916 ULONG cObjects,
2917 IUnknown **prgpUnknown,
2918 boolean fFreeArray)
2919 {
2920 FIXME("stub\n");
2921 return E_NOTIMPL;
2922 }
2923
2924
2925 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
2926 IMimeAllocator* iface,
2927 ULONG cRows,
2928 LPENUMHEADERROW prgRow,
2929 boolean fFreeArray)
2930 {
2931 FIXME("stub\n");
2932 return E_NOTIMPL;
2933 }
2934
2935 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
2936 IMimeAllocator* iface,
2937 ULONG cProps,
2938 LPENUMPROPERTY prgProp,
2939 boolean fFreeArray)
2940 {
2941 FIXME("stub\n");
2942 return E_NOTIMPL;
2943 }
2944
2945 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
2946 IMimeAllocator* iface,
2947 THUMBBLOB *pthumbprint)
2948 {
2949 FIXME("stub\n");
2950 return E_NOTIMPL;
2951 }
2952
2953
2954 static HRESULT WINAPI MimeAlloc_PropVariantClear(
2955 IMimeAllocator* iface,
2956 LPPROPVARIANT pProp)
2957 {
2958 FIXME("stub\n");
2959 return E_NOTIMPL;
2960 }
2961
2962 static IMimeAllocatorVtbl mime_alloc_vtbl =
2963 {
2964 MimeAlloc_QueryInterface,
2965 MimeAlloc_AddRef,
2966 MimeAlloc_Release,
2967 MimeAlloc_Alloc,
2968 MimeAlloc_Realloc,
2969 MimeAlloc_Free,
2970 MimeAlloc_GetSize,
2971 MimeAlloc_DidAlloc,
2972 MimeAlloc_HeapMinimize,
2973 MimeAlloc_FreeParamInfoArray,
2974 MimeAlloc_FreeAddressList,
2975 MimeAlloc_FreeAddressProps,
2976 MimeAlloc_ReleaseObjects,
2977 MimeAlloc_FreeEnumHeaderRowArray,
2978 MimeAlloc_FreeEnumPropertyArray,
2979 MimeAlloc_FreeThumbprint,
2980 MimeAlloc_PropVariantClear
2981 };
2982
2983 static MimeAllocator mime_allocator =
2984 {
2985 &mime_alloc_vtbl
2986 };
2987
2988 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
2989 {
2990 if(outer) return CLASS_E_NOAGGREGATION;
2991
2992 *obj = &mime_allocator;
2993 return S_OK;
2994 }
2995
2996 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
2997 {
2998 return MimeAllocator_create(NULL, (void**)alloc);
2999 }
3000
3001 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3002 {
3003 FIXME("(%p, %p)\n", outer, obj);
3004
3005 *obj = NULL;
3006 if (outer) return CLASS_E_NOAGGREGATION;
3007
3008 return MimeOleCreateVirtualStream((IStream **)obj);
3009 }