1 /*
2 * MIME OLE Interfaces
3 *
4 * Copyright 2006 Robert Shearman for CodeWeavers
5 * Copyright 2007 Huw Davies for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "ole2.h"
33 #include "mimeole.h"
34
35 #include "wine/list.h"
36 #include "wine/debug.h"
37
38 #include "inetcomm_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
41
42 typedef struct
43 {
44 LPCSTR name;
45 DWORD id;
46 DWORD flags; /* MIMEPROPFLAGS */
47 VARTYPE default_vt;
48 } property_t;
49
50 typedef struct
51 {
52 struct list entry;
53 property_t prop;
54 } property_list_entry_t;
55
56 static const property_t default_props[] =
57 {
58 {"References", PID_HDR_REFS, 0, VT_LPSTR},
59 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
60 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
61 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
62 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
63 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
64 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
65 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
66 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
67 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
68 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
69 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
70 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
71 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
72 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME, VT_LPSTR},
73 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
74 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
75 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
76 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
77 {NULL, 0, 0, 0}
78 };
79
80 typedef struct
81 {
82 struct list entry;
83 char *name;
84 char *value;
85 } param_t;
86
87 typedef struct
88 {
89 struct list entry;
90 const property_t *prop;
91 PROPVARIANT value;
92 struct list params;
93 } header_t;
94
95 typedef struct MimeBody
96 {
97 const IMimeBodyVtbl *lpVtbl;
98 LONG refs;
99
100 HBODY handle;
101
102 struct list headers;
103 struct list new_props; /* FIXME: This should be in a PropertySchema */
104 DWORD next_prop_id;
105 char *content_pri_type;
106 char *content_sub_type;
107 ENCODINGTYPE encoding;
108 void *data;
109 IID data_iid;
110 BODYOFFSETS body_offsets;
111 } MimeBody;
112
113 static inline MimeBody *impl_from_IMimeBody( IMimeBody *iface )
114 {
115 return (MimeBody *)((char*)iface - FIELD_OFFSET(MimeBody, lpVtbl));
116 }
117
118 static LPSTR strdupA(LPCSTR str)
119 {
120 char *ret;
121 int len = strlen(str);
122 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
123 memcpy(ret, str, len + 1);
124 return ret;
125 }
126
127 #define PARSER_BUF_SIZE 1024
128
129 /*****************************************************
130 * copy_headers_to_buf [internal]
131 *
132 * Copies the headers into a '\0' terminated memory block and leave
133 * the stream's current position set to after the blank line.
134 */
135 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
136 {
137 char *buf = NULL;
138 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
139 HRESULT hr;
140 int done = 0;
141
142 *ptr = NULL;
143
144 do
145 {
146 char *end;
147 DWORD read;
148
149 if(!buf)
150 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
151 else
152 {
153 size *= 2;
154 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
155 }
156 if(!buf)
157 {
158 hr = E_OUTOFMEMORY;
159 goto fail;
160 }
161
162 hr = IStream_Read(stm, buf + offset, size - offset, &read);
163 if(FAILED(hr)) goto fail;
164
165 offset += read;
166 buf[offset] = '\0';
167
168 if(read == 0) done = 1;
169
170 while(!done && (end = strstr(buf + last_end, "\r\n")))
171 {
172 DWORD new_end = end - buf + 2;
173 if(new_end - last_end == 2)
174 {
175 LARGE_INTEGER off;
176 off.QuadPart = new_end;
177 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
178 buf[new_end] = '\0';
179 done = 1;
180 }
181 else
182 last_end = new_end;
183 }
184 } while(!done);
185
186 *ptr = buf;
187 return S_OK;
188
189 fail:
190 HeapFree(GetProcessHeap(), 0, buf);
191 return hr;
192 }
193
194 static header_t *read_prop(MimeBody *body, char **ptr)
195 {
196 char *colon = strchr(*ptr, ':');
197 const property_t *prop;
198 header_t *ret;
199
200 if(!colon) return NULL;
201
202 *colon = '\0';
203
204 for(prop = default_props; prop->name; prop++)
205 {
206 if(!strcasecmp(*ptr, prop->name))
207 {
208 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
209 break;
210 }
211 }
212
213 if(!prop->name)
214 {
215 property_list_entry_t *prop_entry;
216 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
217 {
218 if(!strcasecmp(*ptr, prop_entry->prop.name))
219 {
220 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
221 prop = &prop_entry->prop;
222 break;
223 }
224 }
225 if(!prop->name)
226 {
227 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
228 prop_entry->prop.name = strdupA(*ptr);
229 prop_entry->prop.id = body->next_prop_id++;
230 prop_entry->prop.flags = 0;
231 prop_entry->prop.default_vt = VT_LPSTR;
232 list_add_tail(&body->new_props, &prop_entry->entry);
233 prop = &prop_entry->prop;
234 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
235 }
236 }
237
238 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
239 ret->prop = prop;
240 PropVariantInit(&ret->value);
241 list_init(&ret->params);
242 *ptr = colon + 1;
243
244 return ret;
245 }
246
247 static void unfold_header(char *header, int len)
248 {
249 char *start = header, *cp = header;
250
251 do {
252 while(*cp == ' ' || *cp == '\t')
253 {
254 cp++;
255 len--;
256 }
257 if(cp != start)
258 memmove(start, cp, len + 1);
259
260 cp = strstr(start, "\r\n");
261 len -= (cp - start);
262 start = cp;
263 *start = ' ';
264 start++;
265 len--;
266 cp += 2;
267 } while(*cp == ' ' || *cp == '\t');
268
269 *(start - 1) = '\0';
270 }
271
272 static char *unquote_string(const char *str)
273 {
274 int quoted = 0;
275 char *ret, *cp;
276
277 while(*str == ' ' || *str == '\t') str++;
278
279 if(*str == '"')
280 {
281 quoted = 1;
282 str++;
283 }
284 ret = strdupA(str);
285 for(cp = ret; *cp; cp++)
286 {
287 if(*cp == '\\')
288 memmove(cp, cp + 1, strlen(cp + 1) + 1);
289 else if(*cp == '"')
290 {
291 if(!quoted)
292 {
293 WARN("quote in unquoted string\n");
294 }
295 else
296 {
297 *cp = '\0';
298 break;
299 }
300 }
301 }
302 return ret;
303 }
304
305 static void add_param(header_t *header, const char *p)
306 {
307 const char *key = p, *value, *cp = p;
308 param_t *param;
309 char *name;
310
311 TRACE("got param %s\n", p);
312
313 while (*key == ' ' || *key == '\t' ) key++;
314
315 cp = strchr(key, '=');
316 if(!cp)
317 {
318 WARN("malformed parameter - skipping\n");
319 return;
320 }
321
322 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
323 memcpy(name, key, cp - key);
324 name[cp - key] = '\0';
325
326 value = cp + 1;
327
328 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
329 param->name = name;
330 param->value = unquote_string(value);
331 list_add_tail(&header->params, ¶m->entry);
332 }
333
334 static void split_params(header_t *header, char *value)
335 {
336 char *cp = value, *start = value;
337 int in_quote = 0;
338 int done_value = 0;
339
340 while(*cp)
341 {
342 if(!in_quote && *cp == ';')
343 {
344 *cp = '\0';
345 if(done_value) add_param(header, start);
346 done_value = 1;
347 start = cp + 1;
348 }
349 else if(*cp == '"')
350 in_quote = !in_quote;
351 cp++;
352 }
353 if(done_value) add_param(header, start);
354 }
355
356 static void read_value(header_t *header, char **cur)
357 {
358 char *end = *cur, *value;
359 DWORD len;
360
361 do {
362 end = strstr(end, "\r\n");
363 end += 2;
364 } while(*end == ' ' || *end == '\t');
365
366 len = end - *cur;
367 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
368 memcpy(value, *cur, len);
369 value[len] = '\0';
370
371 unfold_header(value, len);
372 TRACE("value %s\n", debugstr_a(value));
373
374 if(header->prop->flags & MPF_HASPARAMS)
375 {
376 split_params(header, value);
377 TRACE("value w/o params %s\n", debugstr_a(value));
378 }
379
380 header->value.vt = VT_LPSTR;
381 header->value.u.pszVal = value;
382
383 *cur = end;
384 }
385
386 static void init_content_type(MimeBody *body, header_t *header)
387 {
388 char *slash;
389 DWORD len;
390
391 if(header->prop->id != PID_HDR_CNTTYPE)
392 {
393 ERR("called with header %s\n", header->prop->name);
394 return;
395 }
396
397 slash = strchr(header->value.u.pszVal, '/');
398 if(!slash)
399 {
400 WARN("malformed context type value\n");
401 return;
402 }
403 len = slash - header->value.u.pszVal;
404 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
405 memcpy(body->content_pri_type, header->value.u.pszVal, len);
406 body->content_pri_type[len] = '\0';
407 body->content_sub_type = strdupA(slash + 1);
408 }
409
410 static HRESULT parse_headers(MimeBody *body, IStream *stm)
411 {
412 char *header_buf, *cur_header_ptr;
413 HRESULT hr;
414 header_t *header;
415
416 hr = copy_headers_to_buf(stm, &header_buf);
417 if(FAILED(hr)) return hr;
418
419 cur_header_ptr = header_buf;
420 while((header = read_prop(body, &cur_header_ptr)))
421 {
422 read_value(header, &cur_header_ptr);
423 list_add_tail(&body->headers, &header->entry);
424
425 if(header->prop->id == PID_HDR_CNTTYPE)
426 init_content_type(body, header);
427 }
428
429 HeapFree(GetProcessHeap(), 0, header_buf);
430 return hr;
431 }
432
433 static void empty_param_list(struct list *list)
434 {
435 param_t *param, *cursor2;
436
437 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
438 {
439 list_remove(¶m->entry);
440 HeapFree(GetProcessHeap(), 0, param->name);
441 HeapFree(GetProcessHeap(), 0, param->value);
442 HeapFree(GetProcessHeap(), 0, param);
443 }
444 }
445
446 static void empty_header_list(struct list *list)
447 {
448 header_t *header, *cursor2;
449
450 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
451 {
452 list_remove(&header->entry);
453 PropVariantClear(&header->value);
454 empty_param_list(&header->params);
455 HeapFree(GetProcessHeap(), 0, header);
456 }
457 }
458
459 static void empty_new_prop_list(struct list *list)
460 {
461 property_list_entry_t *prop, *cursor2;
462
463 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
464 {
465 list_remove(&prop->entry);
466 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
467 HeapFree(GetProcessHeap(), 0, prop);
468 }
469 }
470
471 static void release_data(REFIID riid, void *data)
472 {
473 if(!data) return;
474
475 if(IsEqualIID(riid, &IID_IStream))
476 IStream_Release((IStream *)data);
477 else
478 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
479 }
480
481 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
482 {
483 header_t *header;
484
485 *prop = NULL;
486
487 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
488 {
489 if(!strcasecmp(name, header->prop->name))
490 {
491 *prop = header;
492 return S_OK;
493 }
494 }
495
496 return MIME_E_NOT_FOUND;
497 }
498
499 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
500 REFIID riid,
501 void** ppvObject)
502 {
503 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
504
505 *ppvObject = NULL;
506
507 if (IsEqualIID(riid, &IID_IUnknown) ||
508 IsEqualIID(riid, &IID_IPersist) ||
509 IsEqualIID(riid, &IID_IPersistStreamInit) ||
510 IsEqualIID(riid, &IID_IMimePropertySet) ||
511 IsEqualIID(riid, &IID_IMimeBody))
512 {
513 *ppvObject = iface;
514 }
515
516 if(*ppvObject)
517 {
518 IUnknown_AddRef((IUnknown*)*ppvObject);
519 return S_OK;
520 }
521
522 FIXME("no interface for %s\n", debugstr_guid(riid));
523 return E_NOINTERFACE;
524 }
525
526 static ULONG WINAPI MimeBody_AddRef(IMimeBody* iface)
527 {
528 MimeBody *This = impl_from_IMimeBody(iface);
529 TRACE("(%p)->()\n", iface);
530 return InterlockedIncrement(&This->refs);
531 }
532
533 static ULONG WINAPI MimeBody_Release(IMimeBody* iface)
534 {
535 MimeBody *This = impl_from_IMimeBody(iface);
536 ULONG refs;
537
538 TRACE("(%p)->()\n", iface);
539
540 refs = InterlockedDecrement(&This->refs);
541 if (!refs)
542 {
543 empty_header_list(&This->headers);
544 empty_new_prop_list(&This->new_props);
545
546 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
547 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
548
549 release_data(&This->data_iid, This->data);
550
551 HeapFree(GetProcessHeap(), 0, This);
552 }
553
554 return refs;
555 }
556
557 static HRESULT WINAPI MimeBody_GetClassID(
558 IMimeBody* iface,
559 CLSID* pClassID)
560 {
561 FIXME("stub\n");
562 return E_NOTIMPL;
563 }
564
565
566 static HRESULT WINAPI MimeBody_IsDirty(
567 IMimeBody* iface)
568 {
569 FIXME("stub\n");
570 return E_NOTIMPL;
571 }
572
573 static HRESULT WINAPI MimeBody_Load(
574 IMimeBody* iface,
575 LPSTREAM pStm)
576 {
577 MimeBody *This = impl_from_IMimeBody(iface);
578 TRACE("(%p)->(%p)\n", iface, pStm);
579 return parse_headers(This, pStm);
580 }
581
582 static HRESULT WINAPI MimeBody_Save(
583 IMimeBody* iface,
584 LPSTREAM pStm,
585 BOOL fClearDirty)
586 {
587 FIXME("stub\n");
588 return E_NOTIMPL;
589 }
590
591 static HRESULT WINAPI MimeBody_GetSizeMax(
592 IMimeBody* iface,
593 ULARGE_INTEGER* pcbSize)
594 {
595 FIXME("stub\n");
596 return E_NOTIMPL;
597 }
598
599 static HRESULT WINAPI MimeBody_InitNew(
600 IMimeBody* iface)
601 {
602 TRACE("%p->()\n", iface);
603 return S_OK;
604 }
605
606 static HRESULT WINAPI MimeBody_GetPropInfo(
607 IMimeBody* iface,
608 LPCSTR pszName,
609 LPMIMEPROPINFO pInfo)
610 {
611 FIXME("stub\n");
612 return E_NOTIMPL;
613 }
614
615 static HRESULT WINAPI MimeBody_SetPropInfo(
616 IMimeBody* iface,
617 LPCSTR pszName,
618 LPCMIMEPROPINFO pInfo)
619 {
620 FIXME("stub\n");
621 return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI MimeBody_GetProp(
625 IMimeBody* iface,
626 LPCSTR pszName,
627 DWORD dwFlags,
628 LPPROPVARIANT pValue)
629 {
630 MimeBody *This = impl_from_IMimeBody(iface);
631 TRACE("(%p)->(%s, %d, %p)\n", This, pszName, dwFlags, pValue);
632
633 if(!strcasecmp(pszName, "att:pri-content-type"))
634 {
635 PropVariantClear(pValue);
636 pValue->vt = VT_LPSTR;
637 pValue->u.pszVal = strdupA(This->content_pri_type);
638 return S_OK;
639 }
640
641 FIXME("stub!\n");
642 return E_FAIL;
643 }
644
645 static HRESULT WINAPI MimeBody_SetProp(
646 IMimeBody* iface,
647 LPCSTR pszName,
648 DWORD dwFlags,
649 LPCPROPVARIANT pValue)
650 {
651 FIXME("stub\n");
652 return E_NOTIMPL;
653 }
654
655 static HRESULT WINAPI MimeBody_AppendProp(
656 IMimeBody* iface,
657 LPCSTR pszName,
658 DWORD dwFlags,
659 LPPROPVARIANT pValue)
660 {
661 FIXME("stub\n");
662 return E_NOTIMPL;
663 }
664
665 static HRESULT WINAPI MimeBody_DeleteProp(
666 IMimeBody* iface,
667 LPCSTR pszName)
668 {
669 FIXME("stub\n");
670 return E_NOTIMPL;
671 }
672
673 static HRESULT WINAPI MimeBody_CopyProps(
674 IMimeBody* iface,
675 ULONG cNames,
676 LPCSTR* prgszName,
677 IMimePropertySet* pPropertySet)
678 {
679 FIXME("stub\n");
680 return E_NOTIMPL;
681 }
682
683 static HRESULT WINAPI MimeBody_MoveProps(
684 IMimeBody* iface,
685 ULONG cNames,
686 LPCSTR* prgszName,
687 IMimePropertySet* pPropertySet)
688 {
689 FIXME("stub\n");
690 return E_NOTIMPL;
691 }
692
693 static HRESULT WINAPI MimeBody_DeleteExcept(
694 IMimeBody* iface,
695 ULONG cNames,
696 LPCSTR* prgszName)
697 {
698 FIXME("stub\n");
699 return E_NOTIMPL;
700 }
701
702 static HRESULT WINAPI MimeBody_QueryProp(
703 IMimeBody* iface,
704 LPCSTR pszName,
705 LPCSTR pszCriteria,
706 boolean fSubString,
707 boolean fCaseSensitive)
708 {
709 FIXME("stub\n");
710 return E_NOTIMPL;
711 }
712
713 static HRESULT WINAPI MimeBody_GetCharset(
714 IMimeBody* iface,
715 LPHCHARSET phCharset)
716 {
717 FIXME("stub\n");
718 *phCharset = NULL;
719 return S_OK;
720 }
721
722 static HRESULT WINAPI MimeBody_SetCharset(
723 IMimeBody* iface,
724 HCHARSET hCharset,
725 CSETAPPLYTYPE applytype)
726 {
727 FIXME("stub\n");
728 return E_NOTIMPL;
729 }
730
731 static HRESULT WINAPI MimeBody_GetParameters(
732 IMimeBody* iface,
733 LPCSTR pszName,
734 ULONG* pcParams,
735 LPMIMEPARAMINFO* pprgParam)
736 {
737 MimeBody *This = impl_from_IMimeBody(iface);
738 HRESULT hr;
739 header_t *header;
740
741 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
742
743 *pprgParam = NULL;
744 *pcParams = 0;
745
746 hr = find_prop(This, pszName, &header);
747 if(hr != S_OK) return hr;
748
749 *pcParams = list_count(&header->params);
750 if(*pcParams)
751 {
752 IMimeAllocator *alloc;
753 param_t *param;
754 MIMEPARAMINFO *info;
755
756 MimeOleGetAllocator(&alloc);
757
758 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
759 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
760 {
761 int len;
762
763 len = strlen(param->name) + 1;
764 info->pszName = IMimeAllocator_Alloc(alloc, len);
765 memcpy(info->pszName, param->name, len);
766 len = strlen(param->value) + 1;
767 info->pszData = IMimeAllocator_Alloc(alloc, len);
768 memcpy(info->pszData, param->value, len);
769 info++;
770 }
771 IMimeAllocator_Release(alloc);
772 }
773 return S_OK;
774 }
775
776 static HRESULT WINAPI MimeBody_IsContentType(
777 IMimeBody* iface,
778 LPCSTR pszPriType,
779 LPCSTR pszSubType)
780 {
781 MimeBody *This = impl_from_IMimeBody(iface);
782
783 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
784 if(pszPriType)
785 {
786 const char *pri = This->content_pri_type;
787 if(!pri) pri = "text";
788 if(strcasecmp(pri, pszPriType)) return S_FALSE;
789 }
790
791 if(pszSubType)
792 {
793 const char *sub = This->content_sub_type;
794 if(!sub) sub = "plain";
795 if(strcasecmp(sub, pszSubType)) return S_FALSE;
796 }
797
798 return S_OK;
799 }
800
801 static HRESULT WINAPI MimeBody_BindToObject(
802 IMimeBody* iface,
803 REFIID riid,
804 void** ppvObject)
805 {
806 FIXME("stub\n");
807 return E_NOTIMPL;
808 }
809
810 static HRESULT WINAPI MimeBody_Clone(
811 IMimeBody* iface,
812 IMimePropertySet** ppPropertySet)
813 {
814 FIXME("stub\n");
815 return E_NOTIMPL;
816 }
817
818 static HRESULT WINAPI MimeBody_SetOption(
819 IMimeBody* iface,
820 const TYPEDID oid,
821 LPCPROPVARIANT pValue)
822 {
823 FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
824 return E_NOTIMPL;
825 }
826
827 static HRESULT WINAPI MimeBody_GetOption(
828 IMimeBody* iface,
829 const TYPEDID oid,
830 LPPROPVARIANT pValue)
831 {
832 FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
833 return E_NOTIMPL;
834 }
835
836 static HRESULT WINAPI MimeBody_EnumProps(
837 IMimeBody* iface,
838 DWORD dwFlags,
839 IMimeEnumProperties** ppEnum)
840 {
841 FIXME("stub\n");
842 return E_NOTIMPL;
843 }
844
845 static HRESULT WINAPI MimeBody_IsType(
846 IMimeBody* iface,
847 IMSGBODYTYPE bodytype)
848 {
849 FIXME("(%p)->(%d): stub\n", iface, bodytype);
850 return E_NOTIMPL;
851 }
852
853 static HRESULT WINAPI MimeBody_SetDisplayName(
854 IMimeBody* iface,
855 LPCSTR pszDisplay)
856 {
857 FIXME("stub\n");
858 return E_NOTIMPL;
859 }
860
861 static HRESULT WINAPI MimeBody_GetDisplayName(
862 IMimeBody* iface,
863 LPSTR* ppszDisplay)
864 {
865 FIXME("stub\n");
866 return E_NOTIMPL;
867 }
868
869 static HRESULT WINAPI MimeBody_GetOffsets(
870 IMimeBody* iface,
871 LPBODYOFFSETS pOffsets)
872 {
873 MimeBody *This = impl_from_IMimeBody(iface);
874 TRACE("(%p)->(%p)\n", This, pOffsets);
875
876 *pOffsets = This->body_offsets;
877
878 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
879 return S_OK;
880 }
881
882 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
883 IMimeBody* iface,
884 ENCODINGTYPE* pietEncoding)
885 {
886 MimeBody *This = impl_from_IMimeBody(iface);
887
888 TRACE("(%p)->(%p)\n", This, pietEncoding);
889
890 *pietEncoding = This->encoding;
891 return S_OK;
892 }
893
894 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
895 IMimeBody* iface,
896 ENCODINGTYPE ietEncoding)
897 {
898 MimeBody *This = impl_from_IMimeBody(iface);
899
900 TRACE("(%p)->(%d)\n", This, ietEncoding);
901
902 This->encoding = ietEncoding;
903 return S_OK;
904 }
905
906 static HRESULT WINAPI MimeBody_GetEstimatedSize(
907 IMimeBody* iface,
908 ENCODINGTYPE ietEncoding,
909 ULONG* pcbSize)
910 {
911 FIXME("stub\n");
912 return E_NOTIMPL;
913 }
914
915 static HRESULT WINAPI MimeBody_GetDataHere(
916 IMimeBody* iface,
917 ENCODINGTYPE ietEncoding,
918 IStream* pStream)
919 {
920 FIXME("stub\n");
921 return E_NOTIMPL;
922 }
923
924 static HRESULT WINAPI MimeBody_GetData(
925 IMimeBody* iface,
926 ENCODINGTYPE ietEncoding,
927 IStream** ppStream)
928 {
929 MimeBody *This = impl_from_IMimeBody(iface);
930 FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
931
932 *ppStream = This->data;
933 IStream_AddRef(*ppStream);
934 return S_OK;
935 }
936
937 static HRESULT WINAPI MimeBody_SetData(
938 IMimeBody* iface,
939 ENCODINGTYPE ietEncoding,
940 LPCSTR pszPriType,
941 LPCSTR pszSubType,
942 REFIID riid,
943 LPVOID pvObject)
944 {
945 MimeBody *This = impl_from_IMimeBody(iface);
946 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
947 debugstr_guid(riid), pvObject);
948
949 if(IsEqualIID(riid, &IID_IStream))
950 IStream_AddRef((IStream *)pvObject);
951 else
952 {
953 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
954 return E_INVALIDARG;
955 }
956
957 if(This->data)
958 FIXME("release old data\n");
959
960 This->data_iid = *riid;
961 This->data = pvObject;
962
963 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
964
965 /* FIXME: Update the content type.
966 If pszPriType == NULL use 'application'
967 If pszSubType == NULL use 'octet-stream' */
968
969 return S_OK;
970 }
971
972 static HRESULT WINAPI MimeBody_EmptyData(
973 IMimeBody* iface)
974 {
975 FIXME("stub\n");
976 return E_NOTIMPL;
977 }
978