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