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