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