inetcomm: Improve IMimeBody GetHandle return value.
[wine.git] / dlls / inetcomm / mimeole.c
blob23bd9309c0dac99834d07852a050948552605e14
1 /*
2 * MIME OLE Interfaces
4 * Copyright 2006 Robert Shearman for CodeWeavers
5 * Copyright 2007 Huw Davies for CodeWeavers
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.
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.
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
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include <stdarg.h>
26 #include <stdio.h>
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 #include "propvarutil.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
39 #include "inetcomm_private.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
43 typedef struct
45 LPCSTR name;
46 DWORD id;
47 DWORD flags; /* MIMEPROPFLAGS */
48 VARTYPE default_vt;
49 } property_t;
51 typedef struct
53 struct list entry;
54 property_t prop;
55 } property_list_entry_t;
57 static const property_t default_props[] =
59 {"X-Newsgroup", PID_HDR_NEWSGROUP, 0, VT_LPSTR},
60 {"Newsgroups", PID_HDR_NEWSGROUPS, 0, VT_LPSTR},
61 {"References", PID_HDR_REFS, 0, VT_LPSTR},
62 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
63 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
64 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
65 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
66 {"Rr", PID_HDR_RR, 0, VT_LPSTR},
67 {"Return-Receipt-To", PID_HDR_RETRCPTO, MPF_ADDRESS, VT_LPSTR},
68 {"Apparently-To", PID_HDR_APPARTO, MPF_ADDRESS, VT_LPSTR},
69 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
70 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
71 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
72 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
73 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
74 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
75 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
76 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
77 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
78 {"Content-Description", PID_HDR_CNTDESC, MPF_MIME, VT_LPSTR},
79 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
80 {"Content-Base", PID_HDR_CNTBASE, MPF_MIME, VT_LPSTR},
81 {"Content-Location", PID_HDR_CNTLOC, MPF_MIME, VT_LPSTR},
82 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
83 {"Path", PID_HDR_PATH, 0, VT_LPSTR},
84 {"Followup-To", PID_HDR_FOLLOWUPTO, 0, VT_LPSTR},
85 {"Expires", PID_HDR_EXPIRES, 0, VT_LPSTR},
86 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
87 {"Control", PID_HDR_CONTROL, 0, VT_LPSTR},
88 {"Distribution", PID_HDR_DISTRIB, 0, VT_LPSTR},
89 {"Keywords", PID_HDR_KEYWORDS, 0, VT_LPSTR},
90 {"Summary", PID_HDR_SUMMARY, 0, VT_LPSTR},
91 {"Approved", PID_HDR_APPROVED, 0, VT_LPSTR},
92 {"Lines", PID_HDR_LINES, 0, VT_LPSTR},
93 {"Xref", PID_HDR_XREF, 0, VT_LPSTR},
94 {"Organization", PID_HDR_ORG, 0, VT_LPSTR},
95 {"X-Newsreader", PID_HDR_XNEWSRDR, 0, VT_LPSTR},
96 {"X-Priority", PID_HDR_XPRI, 0, VT_LPSTR},
97 {"X-MSMail-Priority", PID_HDR_XMSPRI, 0, VT_LPSTR},
98 {"par:content-disposition:filename", PID_PAR_FILENAME, 0, VT_LPSTR},
99 {"par:content-type:boundary", PID_PAR_BOUNDARY, 0, VT_LPSTR},
100 {"par:content-type:charset", PID_PAR_CHARSET, 0, VT_LPSTR},
101 {"par:content-type:name", PID_PAR_NAME, 0, VT_LPSTR},
102 {"att:filename", PID_ATT_FILENAME, 0, VT_LPSTR},
103 {"att:pri-content-type", PID_ATT_PRITYPE, 0, VT_LPSTR},
104 {"att:sub-content-type", PID_ATT_SUBTYPE, 0, VT_LPSTR},
105 {"att:illegal-lines", PID_ATT_ILLEGAL, 0, VT_LPSTR},
106 {"att:rendered", PID_ATT_RENDERED, 0, VT_LPSTR},
107 {"att:sent-time", PID_ATT_SENTTIME, 0, VT_LPSTR},
108 {"att:priority", PID_ATT_PRIORITY, 0, VT_LPSTR},
109 {"Comment", PID_HDR_COMMENT, 0, VT_LPSTR},
110 {"Encoding", PID_HDR_ENCODING, 0, VT_LPSTR},
111 {"Encrypted", PID_HDR_ENCRYPTED, 0, VT_LPSTR},
112 {"X-Offsets", PID_HDR_OFFSETS, 0, VT_LPSTR},
113 {"X-Unsent", PID_HDR_XUNSENT, 0, VT_LPSTR},
114 {"X-ArticleId", PID_HDR_ARTICLEID, 0, VT_LPSTR},
115 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
116 {"att:athena-server", PID_ATT_SERVER, 0, VT_LPSTR},
117 {"att:athena-account-id", PID_ATT_ACCOUNT, 0, VT_LPSTR},
118 {"att:athena-pop3-uidl", PID_ATT_UIDL, 0, VT_LPSTR},
119 {"att:athena-store-msgid", PID_ATT_STOREMSGID, 0, VT_LPSTR},
120 {"att:athena-user-name", PID_ATT_USERNAME, 0, VT_LPSTR},
121 {"att:athena-forward-to", PID_ATT_FORWARDTO, 0, VT_LPSTR},
122 {"att:athena-store-fdrid", PID_ATT_STOREFOLDERID,0, VT_LPSTR},
123 {"att:athena-ghosted", PID_ATT_GHOSTED, 0, VT_LPSTR},
124 {"att:athena-uncachedsize", PID_ATT_UNCACHEDSIZE, 0, VT_LPSTR},
125 {"att:athena-combined", PID_ATT_COMBINED, 0, VT_LPSTR},
126 {"att:auto-inlined", PID_ATT_AUTOINLINED, 0, VT_LPSTR},
127 {"Disposition-Notification-To", PID_HDR_DISP_NOTIFICATION_TO, 0, VT_LPSTR},
128 {"par:Content-Type:reply-type", PID_PAR_REPLYTYPE, 0, VT_LPSTR},
129 {"par:Content-Type:format", PID_PAR_FORMAT , 0, VT_LPSTR},
130 {"att:format", PID_ATT_FORMAT , 0, VT_LPSTR},
131 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
132 {"att:athena-account-name", PID_ATT_ACCOUNTNAME, 0, VT_LPSTR},
133 {NULL, 0, 0, 0}
136 typedef struct
138 struct list entry;
139 char *name;
140 char *value;
141 } param_t;
143 typedef struct
145 struct list entry;
146 const property_t *prop;
147 PROPVARIANT value;
148 struct list params;
149 } header_t;
151 typedef struct MimeBody
153 IMimeBody IMimeBody_iface;
154 LONG ref;
156 HBODY handle;
158 struct list headers;
159 struct list new_props; /* FIXME: This should be in a PropertySchema */
160 DWORD next_prop_id;
161 char *content_pri_type;
162 char *content_sub_type;
163 ENCODINGTYPE encoding;
164 void *data;
165 IID data_iid;
166 BODYOFFSETS body_offsets;
167 } MimeBody;
169 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
171 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
174 typedef struct propschema
176 IMimePropertySchema IMimePropertySchema_iface;
177 LONG ref;
178 } propschema;
180 static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
182 return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
185 static LPSTR strdupA(LPCSTR str)
187 char *ret;
188 int len = strlen(str);
189 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
190 memcpy(ret, str, len + 1);
191 return ret;
194 #define PARSER_BUF_SIZE 1024
196 /*****************************************************
197 * copy_headers_to_buf [internal]
199 * Copies the headers into a '\0' terminated memory block and leave
200 * the stream's current position set to after the blank line.
202 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
204 char *buf = NULL;
205 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
206 HRESULT hr;
207 BOOL done = FALSE;
209 *ptr = NULL;
213 char *end;
214 DWORD read;
216 if(!buf)
217 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
218 else
220 size *= 2;
221 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
223 if(!buf)
225 hr = E_OUTOFMEMORY;
226 goto fail;
229 hr = IStream_Read(stm, buf + offset, size - offset, &read);
230 if(FAILED(hr)) goto fail;
232 offset += read;
233 buf[offset] = '\0';
235 if(read == 0) done = TRUE;
237 while(!done && (end = strstr(buf + last_end, "\r\n")))
239 DWORD new_end = end - buf + 2;
240 if(new_end - last_end == 2)
242 LARGE_INTEGER off;
243 off.QuadPart = new_end;
244 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
245 buf[new_end] = '\0';
246 done = TRUE;
248 else
249 last_end = new_end;
251 } while(!done);
253 *ptr = buf;
254 return S_OK;
256 fail:
257 HeapFree(GetProcessHeap(), 0, buf);
258 return hr;
261 static header_t *read_prop(MimeBody *body, char **ptr)
263 char *colon = strchr(*ptr, ':');
264 const property_t *prop;
265 header_t *ret;
267 if(!colon) return NULL;
269 *colon = '\0';
271 for(prop = default_props; prop->name; prop++)
273 if(!lstrcmpiA(*ptr, prop->name))
275 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
276 break;
280 if(!prop->name)
282 property_list_entry_t *prop_entry;
283 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
285 if(!lstrcmpiA(*ptr, prop_entry->prop.name))
287 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
288 prop = &prop_entry->prop;
289 break;
292 if(!prop->name)
294 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
295 prop_entry->prop.name = strdupA(*ptr);
296 prop_entry->prop.id = body->next_prop_id++;
297 prop_entry->prop.flags = 0;
298 prop_entry->prop.default_vt = VT_LPSTR;
299 list_add_tail(&body->new_props, &prop_entry->entry);
300 prop = &prop_entry->prop;
301 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
305 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
306 ret->prop = prop;
307 PropVariantInit(&ret->value);
308 list_init(&ret->params);
309 *ptr = colon + 1;
311 return ret;
314 static void unfold_header(char *header, int len)
316 char *start = header, *cp = header;
318 do {
319 while(*cp == ' ' || *cp == '\t')
321 cp++;
322 len--;
324 if(cp != start)
325 memmove(start, cp, len + 1);
327 cp = strstr(start, "\r\n");
328 len -= (cp - start);
329 start = cp;
330 *start = ' ';
331 start++;
332 len--;
333 cp += 2;
334 } while(*cp == ' ' || *cp == '\t');
336 *(start - 1) = '\0';
339 static char *unquote_string(const char *str)
341 BOOL quoted = FALSE;
342 char *ret, *cp;
344 while(*str == ' ' || *str == '\t') str++;
346 if(*str == '"')
348 quoted = TRUE;
349 str++;
351 ret = strdupA(str);
352 for(cp = ret; *cp; cp++)
354 if(*cp == '\\')
355 memmove(cp, cp + 1, strlen(cp + 1) + 1);
356 else if(*cp == '"')
358 if(!quoted)
360 WARN("quote in unquoted string\n");
362 else
364 *cp = '\0';
365 break;
369 return ret;
372 static void add_param(header_t *header, const char *p)
374 const char *key = p, *value, *cp = p;
375 param_t *param;
376 char *name;
378 TRACE("got param %s\n", p);
380 while (*key == ' ' || *key == '\t' ) key++;
382 cp = strchr(key, '=');
383 if(!cp)
385 WARN("malformed parameter - skipping\n");
386 return;
389 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
390 memcpy(name, key, cp - key);
391 name[cp - key] = '\0';
393 value = cp + 1;
395 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
396 param->name = name;
397 param->value = unquote_string(value);
398 list_add_tail(&header->params, &param->entry);
401 static void split_params(header_t *header, char *value)
403 char *cp = value, *start = value;
404 BOOL in_quotes = FALSE, done_value = FALSE;
406 while(*cp)
408 if(!in_quotes && *cp == ';')
410 *cp = '\0';
411 if(done_value) add_param(header, start);
412 done_value = TRUE;
413 start = cp + 1;
415 else if(*cp == '"')
416 in_quotes = !in_quotes;
417 cp++;
419 if(done_value) add_param(header, start);
422 static void read_value(header_t *header, char **cur)
424 char *end = *cur, *value;
425 DWORD len;
427 do {
428 end = strstr(end, "\r\n");
429 end += 2;
430 } while(*end == ' ' || *end == '\t');
432 len = end - *cur;
433 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
434 memcpy(value, *cur, len);
435 value[len] = '\0';
437 unfold_header(value, len);
438 TRACE("value %s\n", debugstr_a(value));
440 if(header->prop->flags & MPF_HASPARAMS)
442 split_params(header, value);
443 TRACE("value w/o params %s\n", debugstr_a(value));
446 header->value.vt = VT_LPSTR;
447 header->value.u.pszVal = value;
449 *cur = end;
452 static void init_content_type(MimeBody *body, header_t *header)
454 char *slash;
455 DWORD len;
457 if(header->prop->id != PID_HDR_CNTTYPE)
459 ERR("called with header %s\n", header->prop->name);
460 return;
463 slash = strchr(header->value.u.pszVal, '/');
464 if(!slash)
466 WARN("malformed context type value\n");
467 return;
469 len = slash - header->value.u.pszVal;
470 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
471 memcpy(body->content_pri_type, header->value.u.pszVal, len);
472 body->content_pri_type[len] = '\0';
473 body->content_sub_type = strdupA(slash + 1);
476 static HRESULT parse_headers(MimeBody *body, IStream *stm)
478 char *header_buf, *cur_header_ptr;
479 HRESULT hr;
480 header_t *header;
482 hr = copy_headers_to_buf(stm, &header_buf);
483 if(FAILED(hr)) return hr;
485 cur_header_ptr = header_buf;
486 while((header = read_prop(body, &cur_header_ptr)))
488 read_value(header, &cur_header_ptr);
489 list_add_tail(&body->headers, &header->entry);
491 if(header->prop->id == PID_HDR_CNTTYPE)
492 init_content_type(body, header);
495 HeapFree(GetProcessHeap(), 0, header_buf);
496 return hr;
499 static void empty_param_list(struct list *list)
501 param_t *param, *cursor2;
503 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
505 list_remove(&param->entry);
506 HeapFree(GetProcessHeap(), 0, param->name);
507 HeapFree(GetProcessHeap(), 0, param->value);
508 HeapFree(GetProcessHeap(), 0, param);
512 static void empty_header_list(struct list *list)
514 header_t *header, *cursor2;
516 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
518 list_remove(&header->entry);
519 PropVariantClear(&header->value);
520 empty_param_list(&header->params);
521 HeapFree(GetProcessHeap(), 0, header);
525 static void empty_new_prop_list(struct list *list)
527 property_list_entry_t *prop, *cursor2;
529 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
531 list_remove(&prop->entry);
532 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
533 HeapFree(GetProcessHeap(), 0, prop);
537 static void release_data(REFIID riid, void *data)
539 if(!data) return;
541 if(IsEqualIID(riid, &IID_IStream))
542 IStream_Release((IStream *)data);
543 else
544 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
547 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
549 header_t *header;
551 *prop = NULL;
553 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
555 if(ISPIDSTR(name))
557 if(STRTOPID(name) == header->prop->id)
559 *prop = header;
560 return S_OK;
563 else if(!lstrcmpiA(name, header->prop->name))
565 *prop = header;
566 return S_OK;
570 return MIME_E_NOT_FOUND;
573 static const property_t *find_default_prop(const char *name)
575 const property_t *prop_def = NULL;
577 for(prop_def = default_props; prop_def->name; prop_def++)
579 if(ISPIDSTR(name))
581 if(STRTOPID(name) == prop_def->id)
583 break;
586 else if(!lstrcmpiA(name, prop_def->name))
588 break;
592 if(prop_def->id)
593 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
594 else
595 prop_def = NULL;
597 return prop_def;
600 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
601 REFIID riid,
602 void** ppvObject)
604 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
606 *ppvObject = NULL;
608 if (IsEqualIID(riid, &IID_IUnknown) ||
609 IsEqualIID(riid, &IID_IPersist) ||
610 IsEqualIID(riid, &IID_IPersistStreamInit) ||
611 IsEqualIID(riid, &IID_IMimePropertySet) ||
612 IsEqualIID(riid, &IID_IMimeBody))
614 *ppvObject = iface;
617 if(*ppvObject)
619 IUnknown_AddRef((IUnknown*)*ppvObject);
620 return S_OK;
623 FIXME("no interface for %s\n", debugstr_guid(riid));
624 return E_NOINTERFACE;
627 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
629 MimeBody *This = impl_from_IMimeBody(iface);
630 LONG ref = InterlockedIncrement(&This->ref);
632 TRACE("(%p) ref=%d\n", This, ref);
634 return ref;
637 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
639 MimeBody *This = impl_from_IMimeBody(iface);
640 LONG ref = InterlockedDecrement(&This->ref);
642 TRACE("(%p) ref=%d\n", This, ref);
644 if (!ref)
646 empty_header_list(&This->headers);
647 empty_new_prop_list(&This->new_props);
649 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
650 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
652 release_data(&This->data_iid, This->data);
654 HeapFree(GetProcessHeap(), 0, This);
657 return ref;
660 static HRESULT WINAPI MimeBody_GetClassID(
661 IMimeBody* iface,
662 CLSID* pClassID)
664 MimeBody *This = impl_from_IMimeBody(iface);
665 FIXME("(%p)->(%p) stub\n", This, pClassID);
666 return E_NOTIMPL;
670 static HRESULT WINAPI MimeBody_IsDirty(
671 IMimeBody* iface)
673 MimeBody *This = impl_from_IMimeBody(iface);
674 FIXME("(%p)->() stub\n", This);
675 return E_NOTIMPL;
678 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
680 MimeBody *This = impl_from_IMimeBody(iface);
681 TRACE("(%p)->(%p)\n", This, pStm);
682 return parse_headers(This, pStm);
685 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
687 MimeBody *This = impl_from_IMimeBody(iface);
688 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
689 return E_NOTIMPL;
692 static HRESULT WINAPI MimeBody_GetSizeMax(
693 IMimeBody* iface,
694 ULARGE_INTEGER* pcbSize)
696 MimeBody *This = impl_from_IMimeBody(iface);
697 FIXME("(%p)->(%p) stub\n", This, pcbSize);
698 return E_NOTIMPL;
701 static HRESULT WINAPI MimeBody_InitNew(
702 IMimeBody* iface)
704 MimeBody *This = impl_from_IMimeBody(iface);
705 TRACE("(%p)->()\n", This);
706 return S_OK;
709 static HRESULT WINAPI MimeBody_GetPropInfo(
710 IMimeBody* iface,
711 LPCSTR pszName,
712 LPMIMEPROPINFO pInfo)
714 MimeBody *This = impl_from_IMimeBody(iface);
715 header_t *header;
716 HRESULT hr;
717 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
719 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
721 if(!pszName || !pInfo)
722 return E_INVALIDARG;
724 TRACE("mask 0x%04x\n", pInfo->dwMask);
726 if(pInfo->dwMask & ~supported)
727 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
729 hr = find_prop(This, pszName, &header);
730 if(hr == S_OK)
732 if(pInfo->dwMask & PIM_CHARSET)
733 pInfo->hCharset = 0;
734 if(pInfo->dwMask & PIM_FLAGS)
735 pInfo->dwFlags = 0x00000000;
736 if(pInfo->dwMask & PIM_ROWNUMBER)
737 pInfo->dwRowNumber = 0;
738 if(pInfo->dwMask & PIM_ENCODINGTYPE)
739 pInfo->ietEncoding = 0;
740 if(pInfo->dwMask & PIM_VALUES)
741 pInfo->cValues = 0;
742 if(pInfo->dwMask & PIM_PROPID)
743 pInfo->dwPropId = header->prop->id;
744 if(pInfo->dwMask & PIM_VTDEFAULT)
745 pInfo->vtDefault = header->prop->default_vt;
746 if(pInfo->dwMask & PIM_VTCURRENT)
747 pInfo->vtCurrent = 0;
750 return hr;
753 static HRESULT WINAPI MimeBody_SetPropInfo(
754 IMimeBody* iface,
755 LPCSTR pszName,
756 LPCMIMEPROPINFO pInfo)
758 MimeBody *This = impl_from_IMimeBody(iface);
759 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
760 return E_NOTIMPL;
763 static HRESULT WINAPI MimeBody_GetProp(
764 IMimeBody* iface,
765 LPCSTR pszName,
766 DWORD dwFlags,
767 LPPROPVARIANT pValue)
769 MimeBody *This = impl_from_IMimeBody(iface);
770 header_t *header;
771 HRESULT hr;
773 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
775 if(!pszName || !pValue)
776 return E_INVALIDARG;
778 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
780 PropVariantClear(pValue);
781 pValue->vt = VT_LPSTR;
782 pValue->u.pszVal = strdupA(This->content_pri_type);
783 return S_OK;
786 hr = find_prop(This, pszName, &header);
787 if(hr == S_OK)
789 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
791 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
792 if(FAILED(hr))
793 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
796 return hr;
799 static HRESULT WINAPI MimeBody_SetProp(
800 IMimeBody* iface,
801 LPCSTR pszName,
802 DWORD dwFlags,
803 LPCPROPVARIANT pValue)
805 MimeBody *This = impl_from_IMimeBody(iface);
806 header_t *header;
807 HRESULT hr;
809 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
811 if(!pszName || !pValue)
812 return E_INVALIDARG;
814 hr = find_prop(This, pszName, &header);
815 if(hr != S_OK)
817 property_list_entry_t *prop_entry;
818 const property_t *prop = NULL;
820 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
822 if(ISPIDSTR(pszName))
824 if(STRTOPID(pszName) == prop_entry->prop.id)
826 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
827 prop = &prop_entry->prop;
828 break;
831 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
833 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
834 prop = &prop_entry->prop;
835 break;
839 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
840 if(!header)
841 return E_OUTOFMEMORY;
843 if(!prop)
845 const property_t *prop_def = NULL;
846 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
847 if(!prop_entry)
849 HeapFree(GetProcessHeap(), 0, header);
850 return E_OUTOFMEMORY;
853 prop_def = find_default_prop(pszName);
854 if(prop_def)
856 prop_entry->prop.name = strdupA(prop_def->name);
857 prop_entry->prop.id = prop_def->id;
859 else
861 if(ISPIDSTR(pszName))
863 HeapFree(GetProcessHeap(), 0, prop_entry);
864 HeapFree(GetProcessHeap(), 0, header);
865 return MIME_E_NOT_FOUND;
868 prop_entry->prop.name = strdupA(pszName);
869 prop_entry->prop.id = This->next_prop_id++;
872 prop_entry->prop.flags = 0;
873 prop_entry->prop.default_vt = pValue->vt;
874 list_add_tail(&This->new_props, &prop_entry->entry);
875 prop = &prop_entry->prop;
876 TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
879 header->prop = prop;
880 PropVariantInit(&header->value);
881 list_init(&header->params);
882 list_add_tail(&This->headers, &header->entry);
885 PropVariantCopy(&header->value, pValue);
887 return S_OK;
890 static HRESULT WINAPI MimeBody_AppendProp(
891 IMimeBody* iface,
892 LPCSTR pszName,
893 DWORD dwFlags,
894 LPPROPVARIANT pValue)
896 MimeBody *This = impl_from_IMimeBody(iface);
897 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
898 return E_NOTIMPL;
901 static HRESULT WINAPI MimeBody_DeleteProp(
902 IMimeBody* iface,
903 LPCSTR pszName)
905 MimeBody *This = impl_from_IMimeBody(iface);
906 header_t *cursor;
907 BOOL found;
909 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
911 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
913 if(ISPIDSTR(pszName))
914 found = STRTOPID(pszName) == cursor->prop->id;
915 else
916 found = !lstrcmpiA(pszName, cursor->prop->name);
918 if(found)
920 list_remove(&cursor->entry);
921 HeapFree(GetProcessHeap(), 0, cursor);
922 return S_OK;
926 return MIME_E_NOT_FOUND;
929 static HRESULT WINAPI MimeBody_CopyProps(
930 IMimeBody* iface,
931 ULONG cNames,
932 LPCSTR* prgszName,
933 IMimePropertySet* pPropertySet)
935 MimeBody *This = impl_from_IMimeBody(iface);
936 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
937 return E_NOTIMPL;
940 static HRESULT WINAPI MimeBody_MoveProps(
941 IMimeBody* iface,
942 ULONG cNames,
943 LPCSTR* prgszName,
944 IMimePropertySet* pPropertySet)
946 MimeBody *This = impl_from_IMimeBody(iface);
947 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
948 return E_NOTIMPL;
951 static HRESULT WINAPI MimeBody_DeleteExcept(
952 IMimeBody* iface,
953 ULONG cNames,
954 LPCSTR* prgszName)
956 MimeBody *This = impl_from_IMimeBody(iface);
957 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
958 return E_NOTIMPL;
961 static HRESULT WINAPI MimeBody_QueryProp(
962 IMimeBody* iface,
963 LPCSTR pszName,
964 LPCSTR pszCriteria,
965 boolean fSubString,
966 boolean fCaseSensitive)
968 MimeBody *This = impl_from_IMimeBody(iface);
969 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
970 return E_NOTIMPL;
973 static HRESULT WINAPI MimeBody_GetCharset(
974 IMimeBody* iface,
975 LPHCHARSET phCharset)
977 MimeBody *This = impl_from_IMimeBody(iface);
978 FIXME("(%p)->(%p) stub\n", This, phCharset);
979 *phCharset = NULL;
980 return S_OK;
983 static HRESULT WINAPI MimeBody_SetCharset(
984 IMimeBody* iface,
985 HCHARSET hCharset,
986 CSETAPPLYTYPE applytype)
988 MimeBody *This = impl_from_IMimeBody(iface);
989 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
990 return E_NOTIMPL;
993 static HRESULT WINAPI MimeBody_GetParameters(
994 IMimeBody* iface,
995 LPCSTR pszName,
996 ULONG* pcParams,
997 LPMIMEPARAMINFO* pprgParam)
999 MimeBody *This = impl_from_IMimeBody(iface);
1000 HRESULT hr;
1001 header_t *header;
1003 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1005 *pprgParam = NULL;
1006 *pcParams = 0;
1008 hr = find_prop(This, pszName, &header);
1009 if(hr != S_OK) return hr;
1011 *pcParams = list_count(&header->params);
1012 if(*pcParams)
1014 IMimeAllocator *alloc;
1015 param_t *param;
1016 MIMEPARAMINFO *info;
1018 MimeOleGetAllocator(&alloc);
1020 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1021 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1023 int len;
1025 len = strlen(param->name) + 1;
1026 info->pszName = IMimeAllocator_Alloc(alloc, len);
1027 memcpy(info->pszName, param->name, len);
1028 len = strlen(param->value) + 1;
1029 info->pszData = IMimeAllocator_Alloc(alloc, len);
1030 memcpy(info->pszData, param->value, len);
1031 info++;
1033 IMimeAllocator_Release(alloc);
1035 return S_OK;
1038 static HRESULT WINAPI MimeBody_IsContentType(
1039 IMimeBody* iface,
1040 LPCSTR pszPriType,
1041 LPCSTR pszSubType)
1043 MimeBody *This = impl_from_IMimeBody(iface);
1045 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1046 if(pszPriType)
1048 const char *pri = This->content_pri_type;
1049 if(!pri) pri = "text";
1050 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1053 if(pszSubType)
1055 const char *sub = This->content_sub_type;
1056 if(!sub) sub = "plain";
1057 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1060 return S_OK;
1063 static HRESULT WINAPI MimeBody_BindToObject(
1064 IMimeBody* iface,
1065 REFIID riid,
1066 void** ppvObject)
1068 MimeBody *This = impl_from_IMimeBody(iface);
1069 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1070 return E_NOTIMPL;
1073 static HRESULT WINAPI MimeBody_Clone(
1074 IMimeBody* iface,
1075 IMimePropertySet** ppPropertySet)
1077 MimeBody *This = impl_from_IMimeBody(iface);
1078 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1079 return E_NOTIMPL;
1082 static HRESULT WINAPI MimeBody_SetOption(
1083 IMimeBody* iface,
1084 const TYPEDID oid,
1085 LPCPROPVARIANT pValue)
1087 MimeBody *This = impl_from_IMimeBody(iface);
1088 HRESULT hr = E_NOTIMPL;
1089 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
1091 if(pValue->vt != TYPEDID_TYPE(oid))
1093 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
1094 return E_INVALIDARG;
1097 switch(oid)
1099 case OID_SECURITY_HWND_OWNER:
1100 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
1101 hr = S_OK;
1102 break;
1103 case OID_TRANSMIT_BODY_ENCODING:
1104 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
1105 hr = S_OK;
1106 break;
1107 default:
1108 FIXME("Unhandled oid %08x\n", oid);
1111 return hr;
1114 static HRESULT WINAPI MimeBody_GetOption(
1115 IMimeBody* iface,
1116 const TYPEDID oid,
1117 LPPROPVARIANT pValue)
1119 MimeBody *This = impl_from_IMimeBody(iface);
1120 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
1121 return E_NOTIMPL;
1124 static HRESULT WINAPI MimeBody_EnumProps(
1125 IMimeBody* iface,
1126 DWORD dwFlags,
1127 IMimeEnumProperties** ppEnum)
1129 MimeBody *This = impl_from_IMimeBody(iface);
1130 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
1131 return E_NOTIMPL;
1134 static HRESULT WINAPI MimeBody_IsType(
1135 IMimeBody* iface,
1136 IMSGBODYTYPE bodytype)
1138 MimeBody *This = impl_from_IMimeBody(iface);
1140 TRACE("(%p)->(%d)\n", This, bodytype);
1141 switch(bodytype)
1143 case IBT_EMPTY:
1144 return This->data ? S_FALSE : S_OK;
1145 default:
1146 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1148 return S_OK;
1151 static HRESULT WINAPI MimeBody_SetDisplayName(
1152 IMimeBody* iface,
1153 LPCSTR pszDisplay)
1155 MimeBody *This = impl_from_IMimeBody(iface);
1156 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1157 return E_NOTIMPL;
1160 static HRESULT WINAPI MimeBody_GetDisplayName(
1161 IMimeBody* iface,
1162 LPSTR* ppszDisplay)
1164 MimeBody *This = impl_from_IMimeBody(iface);
1165 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1166 return E_NOTIMPL;
1169 static HRESULT WINAPI MimeBody_GetOffsets(
1170 IMimeBody* iface,
1171 LPBODYOFFSETS pOffsets)
1173 MimeBody *This = impl_from_IMimeBody(iface);
1174 TRACE("(%p)->(%p)\n", This, pOffsets);
1176 *pOffsets = This->body_offsets;
1178 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1179 return S_OK;
1182 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1183 IMimeBody* iface,
1184 ENCODINGTYPE* pietEncoding)
1186 MimeBody *This = impl_from_IMimeBody(iface);
1188 TRACE("(%p)->(%p)\n", This, pietEncoding);
1190 *pietEncoding = This->encoding;
1191 return S_OK;
1194 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1195 IMimeBody* iface,
1196 ENCODINGTYPE ietEncoding)
1198 MimeBody *This = impl_from_IMimeBody(iface);
1200 TRACE("(%p)->(%d)\n", This, ietEncoding);
1202 This->encoding = ietEncoding;
1203 return S_OK;
1206 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1207 IMimeBody* iface,
1208 ENCODINGTYPE ietEncoding,
1209 ULONG* pcbSize)
1211 MimeBody *This = impl_from_IMimeBody(iface);
1212 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1213 return E_NOTIMPL;
1216 static HRESULT WINAPI MimeBody_GetDataHere(
1217 IMimeBody* iface,
1218 ENCODINGTYPE ietEncoding,
1219 IStream* pStream)
1221 MimeBody *This = impl_from_IMimeBody(iface);
1222 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1223 return E_NOTIMPL;
1226 static HRESULT WINAPI MimeBody_GetData(
1227 IMimeBody* iface,
1228 ENCODINGTYPE ietEncoding,
1229 IStream** ppStream)
1231 MimeBody *This = impl_from_IMimeBody(iface);
1232 FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
1234 *ppStream = This->data;
1235 IStream_AddRef(*ppStream);
1236 return S_OK;
1239 static HRESULT WINAPI MimeBody_SetData(
1240 IMimeBody* iface,
1241 ENCODINGTYPE ietEncoding,
1242 LPCSTR pszPriType,
1243 LPCSTR pszSubType,
1244 REFIID riid,
1245 LPVOID pvObject)
1247 MimeBody *This = impl_from_IMimeBody(iface);
1248 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1249 debugstr_guid(riid), pvObject);
1251 if(IsEqualIID(riid, &IID_IStream))
1252 IStream_AddRef((IStream *)pvObject);
1253 else
1255 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1256 return E_INVALIDARG;
1259 if(This->data)
1260 FIXME("release old data\n");
1262 This->data_iid = *riid;
1263 This->data = pvObject;
1265 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1267 /* FIXME: Update the content type.
1268 If pszPriType == NULL use 'application'
1269 If pszSubType == NULL use 'octet-stream' */
1271 return S_OK;
1274 static HRESULT WINAPI MimeBody_EmptyData(
1275 IMimeBody* iface)
1277 MimeBody *This = impl_from_IMimeBody(iface);
1278 FIXME("(%p)->() stub\n", This);
1279 return E_NOTIMPL;
1282 static HRESULT WINAPI MimeBody_CopyTo(
1283 IMimeBody* iface,
1284 IMimeBody* pBody)
1286 MimeBody *This = impl_from_IMimeBody(iface);
1287 FIXME("(%p)->(%p) stub\n", This, pBody);
1288 return E_NOTIMPL;
1291 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1292 IMimeBody* iface,
1293 LPTRANSMITINFO pTransmitInfo)
1295 MimeBody *This = impl_from_IMimeBody(iface);
1296 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1297 return E_NOTIMPL;
1300 static HRESULT WINAPI MimeBody_SaveToFile(
1301 IMimeBody* iface,
1302 ENCODINGTYPE ietEncoding,
1303 LPCSTR pszFilePath)
1305 MimeBody *This = impl_from_IMimeBody(iface);
1306 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1307 return E_NOTIMPL;
1310 static HRESULT WINAPI MimeBody_GetHandle(
1311 IMimeBody* iface,
1312 LPHBODY phBody)
1314 MimeBody *This = impl_from_IMimeBody(iface);
1315 TRACE("(%p)->(%p)\n", iface, phBody);
1317 if(!phBody)
1318 return E_INVALIDARG;
1320 *phBody = This->handle;
1321 return This->handle ? S_OK : MIME_E_NO_DATA;
1324 static IMimeBodyVtbl body_vtbl =
1326 MimeBody_QueryInterface,
1327 MimeBody_AddRef,
1328 MimeBody_Release,
1329 MimeBody_GetClassID,
1330 MimeBody_IsDirty,
1331 MimeBody_Load,
1332 MimeBody_Save,
1333 MimeBody_GetSizeMax,
1334 MimeBody_InitNew,
1335 MimeBody_GetPropInfo,
1336 MimeBody_SetPropInfo,
1337 MimeBody_GetProp,
1338 MimeBody_SetProp,
1339 MimeBody_AppendProp,
1340 MimeBody_DeleteProp,
1341 MimeBody_CopyProps,
1342 MimeBody_MoveProps,
1343 MimeBody_DeleteExcept,
1344 MimeBody_QueryProp,
1345 MimeBody_GetCharset,
1346 MimeBody_SetCharset,
1347 MimeBody_GetParameters,
1348 MimeBody_IsContentType,
1349 MimeBody_BindToObject,
1350 MimeBody_Clone,
1351 MimeBody_SetOption,
1352 MimeBody_GetOption,
1353 MimeBody_EnumProps,
1354 MimeBody_IsType,
1355 MimeBody_SetDisplayName,
1356 MimeBody_GetDisplayName,
1357 MimeBody_GetOffsets,
1358 MimeBody_GetCurrentEncoding,
1359 MimeBody_SetCurrentEncoding,
1360 MimeBody_GetEstimatedSize,
1361 MimeBody_GetDataHere,
1362 MimeBody_GetData,
1363 MimeBody_SetData,
1364 MimeBody_EmptyData,
1365 MimeBody_CopyTo,
1366 MimeBody_GetTransmitInfo,
1367 MimeBody_SaveToFile,
1368 MimeBody_GetHandle
1371 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1373 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1374 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1376 body->body_offsets = *offsets;
1377 return S_OK;
1380 #define FIRST_CUSTOM_PROP_ID 0x100
1382 static MimeBody *mimebody_create(void)
1384 MimeBody *This;
1385 BODYOFFSETS body_offsets;
1387 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1388 if (!This)
1389 return NULL;
1391 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1392 This->ref = 1;
1393 This->handle = NULL;
1394 list_init(&This->headers);
1395 list_init(&This->new_props);
1396 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1397 This->content_pri_type = NULL;
1398 This->content_sub_type = NULL;
1399 This->encoding = IET_7BIT;
1400 This->data = NULL;
1401 This->data_iid = IID_NULL;
1403 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1404 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1405 MimeBody_set_offsets(This, &body_offsets);
1407 return This;
1410 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1412 MimeBody *mb;
1414 if(outer)
1415 return CLASS_E_NOAGGREGATION;
1417 if ((mb = mimebody_create()))
1419 *ppv = &mb->IMimeBody_iface;
1420 return S_OK;
1422 else
1424 *ppv = NULL;
1425 return E_OUTOFMEMORY;
1431 typedef struct
1433 IStream IStream_iface;
1434 LONG ref;
1435 IStream *base;
1436 ULARGE_INTEGER pos, start, length;
1437 } sub_stream_t;
1439 static inline sub_stream_t *impl_from_IStream(IStream *iface)
1441 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
1444 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
1446 sub_stream_t *This = impl_from_IStream(iface);
1448 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1449 *ppv = NULL;
1451 if(IsEqualIID(riid, &IID_IUnknown) ||
1452 IsEqualIID(riid, &IID_ISequentialStream) ||
1453 IsEqualIID(riid, &IID_IStream))
1455 IStream_AddRef(iface);
1456 *ppv = iface;
1457 return S_OK;
1459 return E_NOINTERFACE;
1462 static ULONG WINAPI sub_stream_AddRef(IStream *iface)
1464 sub_stream_t *This = impl_from_IStream(iface);
1465 LONG ref = InterlockedIncrement(&This->ref);
1467 TRACE("(%p) ref=%d\n", This, ref);
1469 return ref;
1472 static ULONG WINAPI sub_stream_Release(IStream *iface)
1474 sub_stream_t *This = impl_from_IStream(iface);
1475 LONG ref = InterlockedDecrement(&This->ref);
1477 TRACE("(%p) ref=%d\n", This, ref);
1479 if(!ref)
1481 IStream_Release(This->base);
1482 HeapFree(GetProcessHeap(), 0, This);
1484 return ref;
1487 static HRESULT WINAPI sub_stream_Read(
1488 IStream* iface,
1489 void *pv,
1490 ULONG cb,
1491 ULONG *pcbRead)
1493 sub_stream_t *This = impl_from_IStream(iface);
1494 HRESULT hr;
1495 ULARGE_INTEGER base_pos;
1496 LARGE_INTEGER tmp_pos;
1498 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
1500 tmp_pos.QuadPart = 0;
1501 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_CUR, &base_pos);
1502 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
1503 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1505 if(This->pos.QuadPart + cb > This->length.QuadPart)
1506 cb = This->length.QuadPart - This->pos.QuadPart;
1508 hr = IStream_Read(This->base, pv, cb, pcbRead);
1510 This->pos.QuadPart += *pcbRead;
1512 tmp_pos.QuadPart = base_pos.QuadPart;
1513 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
1515 return hr;
1518 static HRESULT WINAPI sub_stream_Write(
1519 IStream* iface,
1520 const void *pv,
1521 ULONG cb,
1522 ULONG *pcbWritten)
1524 FIXME("stub\n");
1525 return E_NOTIMPL;
1528 static HRESULT WINAPI sub_stream_Seek(
1529 IStream* iface,
1530 LARGE_INTEGER dlibMove,
1531 DWORD dwOrigin,
1532 ULARGE_INTEGER *plibNewPosition)
1534 sub_stream_t *This = impl_from_IStream(iface);
1535 LARGE_INTEGER new_pos;
1537 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
1539 switch(dwOrigin)
1541 case STREAM_SEEK_SET:
1542 new_pos = dlibMove;
1543 break;
1544 case STREAM_SEEK_CUR:
1545 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
1546 break;
1547 case STREAM_SEEK_END:
1548 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
1549 break;
1550 default:
1551 return STG_E_INVALIDFUNCTION;
1554 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
1555 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
1557 This->pos.QuadPart = new_pos.QuadPart;
1559 if(plibNewPosition) *plibNewPosition = This->pos;
1560 return S_OK;
1563 static HRESULT WINAPI sub_stream_SetSize(
1564 IStream* iface,
1565 ULARGE_INTEGER libNewSize)
1567 FIXME("stub\n");
1568 return E_NOTIMPL;
1571 static HRESULT WINAPI sub_stream_CopyTo(
1572 IStream* iface,
1573 IStream *pstm,
1574 ULARGE_INTEGER cb,
1575 ULARGE_INTEGER *pcbRead,
1576 ULARGE_INTEGER *pcbWritten)
1578 HRESULT hr = S_OK;
1579 BYTE tmpBuffer[128];
1580 ULONG bytesRead, bytesWritten, copySize;
1581 ULARGE_INTEGER totalBytesRead;
1582 ULARGE_INTEGER totalBytesWritten;
1584 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
1586 totalBytesRead.QuadPart = 0;
1587 totalBytesWritten.QuadPart = 0;
1589 while ( cb.QuadPart > 0 )
1591 if ( cb.QuadPart >= sizeof(tmpBuffer) )
1592 copySize = sizeof(tmpBuffer);
1593 else
1594 copySize = cb.u.LowPart;
1596 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1597 if (FAILED(hr)) break;
1599 totalBytesRead.QuadPart += bytesRead;
1601 if (bytesRead)
1603 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1604 if (FAILED(hr)) break;
1605 totalBytesWritten.QuadPart += bytesWritten;
1608 if (bytesRead != copySize)
1609 cb.QuadPart = 0;
1610 else
1611 cb.QuadPart -= bytesRead;
1614 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
1615 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
1617 return hr;
1620 static HRESULT WINAPI sub_stream_Commit(
1621 IStream* iface,
1622 DWORD grfCommitFlags)
1624 FIXME("stub\n");
1625 return E_NOTIMPL;
1628 static HRESULT WINAPI sub_stream_Revert(
1629 IStream* iface)
1631 FIXME("stub\n");
1632 return E_NOTIMPL;
1635 static HRESULT WINAPI sub_stream_LockRegion(
1636 IStream* iface,
1637 ULARGE_INTEGER libOffset,
1638 ULARGE_INTEGER cb,
1639 DWORD dwLockType)
1641 FIXME("stub\n");
1642 return E_NOTIMPL;
1645 static HRESULT WINAPI sub_stream_UnlockRegion(
1646 IStream* iface,
1647 ULARGE_INTEGER libOffset,
1648 ULARGE_INTEGER cb,
1649 DWORD dwLockType)
1651 FIXME("stub\n");
1652 return E_NOTIMPL;
1655 static HRESULT WINAPI sub_stream_Stat(
1656 IStream* iface,
1657 STATSTG *pstatstg,
1658 DWORD grfStatFlag)
1660 sub_stream_t *This = impl_from_IStream(iface);
1661 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
1662 memset(pstatstg, 0, sizeof(*pstatstg));
1663 pstatstg->cbSize = This->length;
1664 return S_OK;
1667 static HRESULT WINAPI sub_stream_Clone(
1668 IStream* iface,
1669 IStream **ppstm)
1671 FIXME("stub\n");
1672 return E_NOTIMPL;
1675 static struct IStreamVtbl sub_stream_vtbl =
1677 sub_stream_QueryInterface,
1678 sub_stream_AddRef,
1679 sub_stream_Release,
1680 sub_stream_Read,
1681 sub_stream_Write,
1682 sub_stream_Seek,
1683 sub_stream_SetSize,
1684 sub_stream_CopyTo,
1685 sub_stream_Commit,
1686 sub_stream_Revert,
1687 sub_stream_LockRegion,
1688 sub_stream_UnlockRegion,
1689 sub_stream_Stat,
1690 sub_stream_Clone
1693 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
1695 sub_stream_t *This;
1697 *out = NULL;
1698 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1699 if(!This) return E_OUTOFMEMORY;
1701 This->IStream_iface.lpVtbl = &sub_stream_vtbl;
1702 This->ref = 1;
1703 This->start = start;
1704 This->length = length;
1705 This->pos.QuadPart = 0;
1706 IStream_AddRef(stream);
1707 This->base = stream;
1709 *out = &This->IStream_iface;
1710 return S_OK;
1714 typedef struct body_t
1716 struct list entry;
1717 DWORD index;
1718 MimeBody *mime_body;
1720 struct body_t *parent;
1721 struct list children;
1722 } body_t;
1724 typedef struct MimeMessage
1726 IMimeMessage IMimeMessage_iface;
1727 LONG ref;
1728 IStream *stream;
1730 struct list body_tree;
1731 DWORD next_index;
1732 } MimeMessage;
1734 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1736 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1739 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1741 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1743 if (IsEqualIID(riid, &IID_IUnknown) ||
1744 IsEqualIID(riid, &IID_IPersist) ||
1745 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1746 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1747 IsEqualIID(riid, &IID_IMimeMessage))
1749 *ppv = iface;
1750 IMimeMessage_AddRef(iface);
1751 return S_OK;
1754 FIXME("no interface for %s\n", debugstr_guid(riid));
1755 *ppv = NULL;
1756 return E_NOINTERFACE;
1759 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1761 MimeMessage *This = impl_from_IMimeMessage(iface);
1762 ULONG ref = InterlockedIncrement(&This->ref);
1764 TRACE("(%p) ref=%d\n", This, ref);
1766 return ref;
1769 static void empty_body_list(struct list *list)
1771 body_t *body, *cursor2;
1772 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1774 empty_body_list(&body->children);
1775 list_remove(&body->entry);
1776 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1777 HeapFree(GetProcessHeap(), 0, body);
1781 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1783 MimeMessage *This = impl_from_IMimeMessage(iface);
1784 ULONG ref = InterlockedDecrement(&This->ref);
1786 TRACE("(%p) ref=%d\n", This, ref);
1788 if (!ref)
1790 empty_body_list(&This->body_tree);
1792 if(This->stream) IStream_Release(This->stream);
1793 HeapFree(GetProcessHeap(), 0, This);
1796 return ref;
1799 /*** IPersist methods ***/
1800 static HRESULT WINAPI MimeMessage_GetClassID(
1801 IMimeMessage *iface,
1802 CLSID *pClassID)
1804 FIXME("(%p)->(%p)\n", iface, pClassID);
1805 return E_NOTIMPL;
1808 /*** IPersistStreamInit methods ***/
1809 static HRESULT WINAPI MimeMessage_IsDirty(
1810 IMimeMessage *iface)
1812 FIXME("(%p)->()\n", iface);
1813 return E_NOTIMPL;
1816 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
1818 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
1819 if(body)
1821 body->mime_body = mime_body;
1822 body->index = index;
1823 list_init(&body->children);
1824 body->parent = parent;
1826 mime_body->handle = UlongToHandle(body->index);
1828 return body;
1831 typedef struct
1833 struct list entry;
1834 BODYOFFSETS offsets;
1835 } offset_entry_t;
1837 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
1839 HRESULT hr;
1840 DWORD read;
1841 int boundary_len = strlen(boundary);
1842 char *buf, *nl_boundary, *ptr, *overlap;
1843 DWORD start = 0, overlap_no;
1844 offset_entry_t *cur_body = NULL;
1845 ULARGE_INTEGER cur;
1846 LARGE_INTEGER zero;
1848 list_init(body_offsets);
1849 nl_boundary = HeapAlloc(GetProcessHeap(), 0, 4 + boundary_len + 1);
1850 memcpy(nl_boundary, "\r\n--", 4);
1851 memcpy(nl_boundary + 4, boundary, boundary_len + 1);
1853 overlap_no = boundary_len + 5;
1855 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
1857 zero.QuadPart = 0;
1858 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
1859 start = cur.u.LowPart;
1861 do {
1862 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
1863 if(FAILED(hr)) goto end;
1864 if(read == 0) break;
1865 overlap[read] = '\0';
1867 ptr = buf;
1868 do {
1869 ptr = strstr(ptr, nl_boundary);
1870 if(ptr)
1872 DWORD boundary_start = start + ptr - buf;
1873 char *end = ptr + boundary_len + 4;
1875 if(*end == '\0' || *(end + 1) == '\0')
1876 break;
1878 if(*end == '\r' && *(end + 1) == '\n')
1880 if(cur_body)
1882 cur_body->offsets.cbBodyEnd = boundary_start;
1883 list_add_tail(body_offsets, &cur_body->entry);
1885 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
1886 cur_body->offsets.cbBoundaryStart = boundary_start + 2; /* doesn't including the leading \r\n */
1887 cur_body->offsets.cbHeaderStart = boundary_start + boundary_len + 6;
1889 else if(*end == '-' && *(end + 1) == '-')
1891 if(cur_body)
1893 cur_body->offsets.cbBodyEnd = boundary_start;
1894 list_add_tail(body_offsets, &cur_body->entry);
1895 goto end;
1898 ptr = end + 2;
1900 } while(ptr);
1902 if(overlap == buf) /* 1st iteration */
1904 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
1905 overlap = buf + overlap_no;
1906 start += read - overlap_no;
1908 else
1910 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
1911 start += read;
1913 } while(1);
1915 end:
1916 HeapFree(GetProcessHeap(), 0, nl_boundary);
1917 HeapFree(GetProcessHeap(), 0, buf);
1918 return hr;
1921 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
1923 MimeBody *mime_body;
1924 HRESULT hr;
1925 body_t *body;
1926 ULARGE_INTEGER cur;
1927 LARGE_INTEGER zero;
1929 mime_body = mimebody_create();
1930 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
1931 zero.QuadPart = 0;
1932 hr = IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &cur);
1933 offset->cbBodyStart = cur.u.LowPart + offset->cbHeaderStart;
1934 if (parent) MimeBody_set_offsets(mime_body, offset);
1935 IMimeBody_SetData(&mime_body->IMimeBody_iface, IET_BINARY, NULL, NULL, &IID_IStream, pStm);
1936 body = new_body_entry(mime_body, msg->next_index++, parent);
1938 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
1940 MIMEPARAMINFO *param_info;
1941 ULONG count, i;
1942 IMimeAllocator *alloc;
1944 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
1945 &param_info);
1946 if(hr != S_OK || count == 0) return body;
1948 MimeOleGetAllocator(&alloc);
1950 for(i = 0; i < count; i++)
1952 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
1954 struct list offset_list;
1955 offset_entry_t *cur, *cursor2;
1956 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
1957 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
1959 body_t *sub_body;
1960 IStream *sub_stream;
1961 ULARGE_INTEGER start, length;
1963 start.QuadPart = cur->offsets.cbHeaderStart;
1964 length.QuadPart = cur->offsets.cbBodyEnd - cur->offsets.cbHeaderStart;
1965 create_sub_stream(pStm, start, length, &sub_stream);
1966 sub_body = create_sub_body(msg, sub_stream, &cur->offsets, body);
1967 IStream_Release(sub_stream);
1968 list_add_tail(&body->children, &sub_body->entry);
1969 list_remove(&cur->entry);
1970 HeapFree(GetProcessHeap(), 0, cur);
1972 break;
1975 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
1976 IMimeAllocator_Release(alloc);
1978 return body;
1981 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
1983 MimeMessage *This = impl_from_IMimeMessage(iface);
1984 body_t *root_body;
1985 BODYOFFSETS offsets;
1986 ULARGE_INTEGER cur;
1987 LARGE_INTEGER zero;
1989 TRACE("(%p)->(%p)\n", iface, pStm);
1991 if(This->stream)
1993 FIXME("already loaded a message\n");
1994 return E_FAIL;
1997 empty_body_list(&This->body_tree);
1999 IStream_AddRef(pStm);
2000 This->stream = pStm;
2001 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2002 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2004 root_body = create_sub_body(This, pStm, &offsets, NULL);
2006 zero.QuadPart = 0;
2007 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2008 offsets.cbBodyEnd = cur.u.LowPart;
2009 MimeBody_set_offsets(root_body->mime_body, &offsets);
2011 list_add_head(&This->body_tree, &root_body->entry);
2013 return S_OK;
2016 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2018 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2019 return E_NOTIMPL;
2022 static HRESULT WINAPI MimeMessage_GetSizeMax(
2023 IMimeMessage *iface,
2024 ULARGE_INTEGER *pcbSize)
2026 FIXME("(%p)->(%p)\n", iface, pcbSize);
2027 return E_NOTIMPL;
2030 static HRESULT WINAPI MimeMessage_InitNew(
2031 IMimeMessage *iface)
2033 FIXME("(%p)->()\n", iface);
2034 return E_NOTIMPL;
2037 /*** IMimeMessageTree methods ***/
2038 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2039 DWORD dwFlags)
2041 MimeMessage *This = impl_from_IMimeMessage(iface);
2043 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
2045 IStream_AddRef(This->stream);
2046 *ppStream = This->stream;
2047 return S_OK;
2050 static HRESULT WINAPI MimeMessage_GetMessageSize(
2051 IMimeMessage *iface,
2052 ULONG *pcbSize,
2053 DWORD dwFlags)
2055 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
2056 return E_NOTIMPL;
2059 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2060 IMimeMessage *iface,
2061 IStream *pStream)
2063 FIXME("(%p)->(%p)\n", iface, pStream);
2064 return E_NOTIMPL;
2067 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2068 IMimeMessage *iface,
2069 IStream *pStream,
2070 DWORD dwFlags)
2072 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
2073 return E_NOTIMPL;
2077 static HRESULT WINAPI MimeMessage_GetFlags(
2078 IMimeMessage *iface,
2079 DWORD *pdwFlags)
2081 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2082 return E_NOTIMPL;
2085 static HRESULT WINAPI MimeMessage_Commit(
2086 IMimeMessage *iface,
2087 DWORD dwFlags)
2089 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
2090 return S_OK;
2094 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2095 IMimeMessage *iface)
2097 FIXME("(%p)->()\n", iface);
2098 return E_NOTIMPL;
2101 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2103 body_t *cur;
2104 HRESULT hr;
2106 if(hbody == HBODY_ROOT)
2108 *body = LIST_ENTRY(list_head(list), body_t, entry);
2109 return S_OK;
2112 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2114 if(cur->index == HandleToUlong(hbody))
2116 *body = cur;
2117 return S_OK;
2119 hr = find_body(&cur->children, hbody, body);
2120 if(hr == S_OK) return S_OK;
2122 return S_FALSE;
2125 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2126 void **ppvObject)
2128 MimeMessage *This = impl_from_IMimeMessage(iface);
2129 HRESULT hr;
2130 body_t *body;
2132 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2134 hr = find_body(&This->body_tree, hBody, &body);
2136 if(hr != S_OK) return hr;
2138 if(IsEqualIID(riid, &IID_IMimeBody))
2140 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2141 *ppvObject = &body->mime_body->IMimeBody_iface;
2142 return S_OK;
2145 return E_NOINTERFACE;
2148 static HRESULT WINAPI MimeMessage_SaveBody(
2149 IMimeMessage *iface,
2150 HBODY hBody,
2151 DWORD dwFlags,
2152 IStream *pStream)
2154 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
2155 return E_NOTIMPL;
2158 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2160 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2161 body_t *body;
2162 HRESULT hr;
2163 struct list *list;
2165 if(location == IBL_ROOT)
2167 *out = root;
2168 return S_OK;
2171 hr = find_body(&msg->body_tree, pivot, &body);
2173 if(hr == S_OK)
2175 switch(location)
2177 case IBL_PARENT:
2178 *out = body->parent;
2179 break;
2181 case IBL_FIRST:
2182 list = list_head(&body->children);
2183 if(list)
2184 *out = LIST_ENTRY(list, body_t, entry);
2185 else
2186 hr = MIME_E_NOT_FOUND;
2187 break;
2189 case IBL_LAST:
2190 list = list_tail(&body->children);
2191 if(list)
2192 *out = LIST_ENTRY(list, body_t, entry);
2193 else
2194 hr = MIME_E_NOT_FOUND;
2195 break;
2197 case IBL_NEXT:
2198 list = list_next(&body->parent->children, &body->entry);
2199 if(list)
2200 *out = LIST_ENTRY(list, body_t, entry);
2201 else
2202 hr = MIME_E_NOT_FOUND;
2203 break;
2205 case IBL_PREVIOUS:
2206 list = list_prev(&body->parent->children, &body->entry);
2207 if(list)
2208 *out = LIST_ENTRY(list, body_t, entry);
2209 else
2210 hr = MIME_E_NOT_FOUND;
2211 break;
2213 default:
2214 hr = E_FAIL;
2215 break;
2219 return hr;
2223 static HRESULT WINAPI MimeMessage_InsertBody(
2224 IMimeMessage *iface,
2225 BODYLOCATION location,
2226 HBODY hPivot,
2227 LPHBODY phBody)
2229 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2230 return E_NOTIMPL;
2233 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2234 HBODY *phBody)
2236 MimeMessage *This = impl_from_IMimeMessage(iface);
2237 body_t *body;
2238 HRESULT hr;
2240 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2242 hr = get_body(This, location, hPivot, &body);
2244 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2246 return hr;
2249 static HRESULT WINAPI MimeMessage_DeleteBody(
2250 IMimeMessage *iface,
2251 HBODY hBody,
2252 DWORD dwFlags)
2254 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
2255 return E_NOTIMPL;
2258 static HRESULT WINAPI MimeMessage_MoveBody(
2259 IMimeMessage *iface,
2260 HBODY hBody,
2261 BODYLOCATION location)
2263 FIXME("(%p)->(%d)\n", iface, location);
2264 return E_NOTIMPL;
2267 static void count_children(body_t *body, boolean recurse, ULONG *count)
2269 body_t *child;
2271 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2273 (*count)++;
2274 if(recurse) count_children(child, recurse, count);
2278 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2279 ULONG *pcBodies)
2281 HRESULT hr;
2282 MimeMessage *This = impl_from_IMimeMessage(iface);
2283 body_t *body;
2285 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2287 hr = find_body(&This->body_tree, hParent, &body);
2288 if(hr != S_OK) return hr;
2290 *pcBodies = 1;
2291 count_children(body, fRecurse, pcBodies);
2293 return S_OK;
2296 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2298 struct list *ptr;
2299 HBODY next;
2301 for (;;)
2303 if (!body) ptr = list_head( &This->body_tree );
2304 else
2306 ptr = list_head( &body->children );
2307 while (!ptr)
2309 if (!body->parent) return MIME_E_NOT_FOUND;
2310 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2314 body = LIST_ENTRY( ptr, body_t, entry );
2315 next = UlongToHandle( body->index );
2316 find->dwReserved = body->index;
2317 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2318 find->pszSubType) == S_OK)
2320 *out = next;
2321 return S_OK;
2324 return MIME_E_NOT_FOUND;
2327 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2329 MimeMessage *This = impl_from_IMimeMessage(iface);
2331 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2333 pFindBody->dwReserved = 0;
2334 return find_next(This, NULL, pFindBody, phBody);
2337 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2339 MimeMessage *This = impl_from_IMimeMessage(iface);
2340 body_t *body;
2341 HRESULT hr;
2343 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2345 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2346 if (hr != S_OK) return MIME_E_NOT_FOUND;
2347 return find_next(This, body, pFindBody, phBody);
2350 static HRESULT WINAPI MimeMessage_ResolveURL(
2351 IMimeMessage *iface,
2352 HBODY hRelated,
2353 LPCSTR pszBase,
2354 LPCSTR pszURL,
2355 DWORD dwFlags,
2356 LPHBODY phBody)
2358 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2359 return E_NOTIMPL;
2362 static HRESULT WINAPI MimeMessage_ToMultipart(
2363 IMimeMessage *iface,
2364 HBODY hBody,
2365 LPCSTR pszSubType,
2366 LPHBODY phMultipart)
2368 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2369 return E_NOTIMPL;
2372 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2373 IMimeMessage *iface,
2374 HBODY hBody,
2375 LPBODYOFFSETS pOffsets)
2377 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2378 return E_NOTIMPL;
2381 static HRESULT WINAPI MimeMessage_GetCharset(
2382 IMimeMessage *iface,
2383 LPHCHARSET phCharset)
2385 FIXME("(%p)->(%p)\n", iface, phCharset);
2386 *phCharset = NULL;
2387 return S_OK;
2390 static HRESULT WINAPI MimeMessage_SetCharset(
2391 IMimeMessage *iface,
2392 HCHARSET hCharset,
2393 CSETAPPLYTYPE applytype)
2395 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2396 return E_NOTIMPL;
2399 static HRESULT WINAPI MimeMessage_IsBodyType(
2400 IMimeMessage *iface,
2401 HBODY hBody,
2402 IMSGBODYTYPE bodytype)
2404 HRESULT hr;
2405 IMimeBody *mime_body;
2406 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2408 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2409 if(hr != S_OK) return hr;
2411 hr = IMimeBody_IsType(mime_body, bodytype);
2412 MimeBody_Release(mime_body);
2413 return hr;
2416 static HRESULT WINAPI MimeMessage_IsContentType(
2417 IMimeMessage *iface,
2418 HBODY hBody,
2419 LPCSTR pszPriType,
2420 LPCSTR pszSubType)
2422 HRESULT hr;
2423 IMimeBody *mime_body;
2424 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2425 debugstr_a(pszSubType));
2427 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2428 if(FAILED(hr)) return hr;
2430 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2431 IMimeBody_Release(mime_body);
2432 return hr;
2435 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2436 IMimeMessage *iface,
2437 HBODY hBody,
2438 LPCSTR pszName,
2439 LPCSTR pszCriteria,
2440 boolean fSubString,
2441 boolean fCaseSensitive)
2443 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2444 return E_NOTIMPL;
2447 static HRESULT WINAPI MimeMessage_GetBodyProp(
2448 IMimeMessage *iface,
2449 HBODY hBody,
2450 LPCSTR pszName,
2451 DWORD dwFlags,
2452 LPPROPVARIANT pValue)
2454 HRESULT hr;
2455 IMimeBody *mime_body;
2457 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2459 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2460 if(hr != S_OK) return hr;
2462 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2463 IMimeBody_Release(mime_body);
2465 return hr;
2468 static HRESULT WINAPI MimeMessage_SetBodyProp(
2469 IMimeMessage *iface,
2470 HBODY hBody,
2471 LPCSTR pszName,
2472 DWORD dwFlags,
2473 LPCPROPVARIANT pValue)
2475 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2476 return E_NOTIMPL;
2479 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2480 IMimeMessage *iface,
2481 HBODY hBody,
2482 LPCSTR pszName)
2484 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2485 return E_NOTIMPL;
2488 static HRESULT WINAPI MimeMessage_SetOption(
2489 IMimeMessage *iface,
2490 const TYPEDID oid,
2491 LPCPROPVARIANT pValue)
2493 HRESULT hr = S_OK;
2494 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2496 /* Message ID is checked before type.
2497 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2499 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2501 WARN("oid (%08x) out of range\n", oid);
2502 return MIME_E_INVALID_OPTION_ID;
2505 if(pValue->vt != TYPEDID_TYPE(oid))
2507 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2508 return S_OK;
2511 switch(oid)
2513 case OID_HIDE_TNEF_ATTACHMENTS:
2514 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2515 break;
2516 case OID_SHOW_MACBINARY:
2517 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2518 break;
2519 case OID_SAVEBODY_KEEPBOUNDARY:
2520 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal);
2521 break;
2522 case OID_CLEANUP_TREE_ON_SAVE:
2523 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal);
2524 break;
2525 default:
2526 FIXME("Unhandled oid %08x\n", oid);
2527 hr = MIME_E_INVALID_OPTION_ID;
2530 return hr;
2533 static HRESULT WINAPI MimeMessage_GetOption(
2534 IMimeMessage *iface,
2535 const TYPEDID oid,
2536 LPPROPVARIANT pValue)
2538 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2539 return E_NOTIMPL;
2542 /*** IMimeMessage methods ***/
2543 static HRESULT WINAPI MimeMessage_CreateWebPage(
2544 IMimeMessage *iface,
2545 IStream *pRootStm,
2546 LPWEBPAGEOPTIONS pOptions,
2547 IMimeMessageCallback *pCallback,
2548 IMoniker **ppMoniker)
2550 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2551 *ppMoniker = NULL;
2552 return E_NOTIMPL;
2555 static HRESULT WINAPI MimeMessage_GetProp(
2556 IMimeMessage *iface,
2557 LPCSTR pszName,
2558 DWORD dwFlags,
2559 LPPROPVARIANT pValue)
2561 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2562 return E_NOTIMPL;
2565 static HRESULT WINAPI MimeMessage_SetProp(
2566 IMimeMessage *iface,
2567 LPCSTR pszName,
2568 DWORD dwFlags,
2569 LPCPROPVARIANT pValue)
2571 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2572 return E_NOTIMPL;
2575 static HRESULT WINAPI MimeMessage_DeleteProp(
2576 IMimeMessage *iface,
2577 LPCSTR pszName)
2579 FIXME("(%p)->(%s)\n", iface, pszName);
2580 return E_NOTIMPL;
2583 static HRESULT WINAPI MimeMessage_QueryProp(
2584 IMimeMessage *iface,
2585 LPCSTR pszName,
2586 LPCSTR pszCriteria,
2587 boolean fSubString,
2588 boolean fCaseSensitive)
2590 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2591 return E_NOTIMPL;
2594 static HRESULT WINAPI MimeMessage_GetTextBody(
2595 IMimeMessage *iface,
2596 DWORD dwTxtType,
2597 ENCODINGTYPE ietEncoding,
2598 IStream **pStream,
2599 LPHBODY phBody)
2601 HRESULT hr;
2602 HBODY hbody;
2603 FINDBODY find_struct;
2604 IMimeBody *mime_body;
2605 static char text[] = "text";
2606 static char plain[] = "plain";
2607 static char html[] = "html";
2609 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2611 find_struct.pszPriType = text;
2613 switch(dwTxtType)
2615 case TXT_PLAIN:
2616 find_struct.pszSubType = plain;
2617 break;
2618 case TXT_HTML:
2619 find_struct.pszSubType = html;
2620 break;
2621 default:
2622 return MIME_E_INVALID_TEXT_TYPE;
2625 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2626 if(hr != S_OK)
2628 TRACE("not found hr %08x\n", hr);
2629 *phBody = NULL;
2630 return hr;
2633 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2635 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2636 *phBody = hbody;
2637 IMimeBody_Release(mime_body);
2638 return hr;
2641 static HRESULT WINAPI MimeMessage_SetTextBody(
2642 IMimeMessage *iface,
2643 DWORD dwTxtType,
2644 ENCODINGTYPE ietEncoding,
2645 HBODY hAlternative,
2646 IStream *pStream,
2647 LPHBODY phBody)
2649 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2650 return E_NOTIMPL;
2653 static HRESULT WINAPI MimeMessage_AttachObject(
2654 IMimeMessage *iface,
2655 REFIID riid,
2656 void *pvObject,
2657 LPHBODY phBody)
2659 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2660 return E_NOTIMPL;
2663 static HRESULT WINAPI MimeMessage_AttachFile(
2664 IMimeMessage *iface,
2665 LPCSTR pszFilePath,
2666 IStream *pstmFile,
2667 LPHBODY phBody)
2669 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2670 return E_NOTIMPL;
2673 static HRESULT WINAPI MimeMessage_AttachURL(
2674 IMimeMessage *iface,
2675 LPCSTR pszBase,
2676 LPCSTR pszURL,
2677 DWORD dwFlags,
2678 IStream *pstmURL,
2679 LPSTR *ppszCIDURL,
2680 LPHBODY phBody)
2682 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2683 return E_NOTIMPL;
2686 static HRESULT WINAPI MimeMessage_GetAttachments(
2687 IMimeMessage *iface,
2688 ULONG *pcAttach,
2689 LPHBODY *pprghAttach)
2691 HRESULT hr;
2692 FINDBODY find_struct;
2693 HBODY hbody;
2694 LPHBODY array;
2695 ULONG size = 10;
2697 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2699 *pcAttach = 0;
2700 array = CoTaskMemAlloc(size * sizeof(HBODY));
2702 find_struct.pszPriType = find_struct.pszSubType = NULL;
2703 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2704 while(hr == S_OK)
2706 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2707 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2708 if(hr != S_OK)
2710 if(*pcAttach + 1 > size)
2712 size *= 2;
2713 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2715 array[*pcAttach] = hbody;
2716 (*pcAttach)++;
2718 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2721 *pprghAttach = array;
2722 return S_OK;
2725 static HRESULT WINAPI MimeMessage_GetAddressTable(
2726 IMimeMessage *iface,
2727 IMimeAddressTable **ppTable)
2729 FIXME("(%p)->(%p)\n", iface, ppTable);
2730 return E_NOTIMPL;
2733 static HRESULT WINAPI MimeMessage_GetSender(
2734 IMimeMessage *iface,
2735 LPADDRESSPROPS pAddress)
2737 FIXME("(%p)->(%p)\n", iface, pAddress);
2738 return E_NOTIMPL;
2741 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2742 IMimeMessage *iface,
2743 DWORD dwAdrTypes,
2744 DWORD dwProps,
2745 LPADDRESSLIST pList)
2747 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2748 return E_NOTIMPL;
2751 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2752 IMimeMessage *iface,
2753 DWORD dwAdrTypes,
2754 ADDRESSFORMAT format,
2755 LPSTR *ppszFormat)
2757 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2758 return E_NOTIMPL;
2761 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2762 IMimeMessage *iface,
2763 DWORD dwAdrTypes,
2764 DWORD dwProps,
2765 IMimeEnumAddressTypes **ppEnum)
2767 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2768 return E_NOTIMPL;
2771 static HRESULT WINAPI MimeMessage_SplitMessage(
2772 IMimeMessage *iface,
2773 ULONG cbMaxPart,
2774 IMimeMessageParts **ppParts)
2776 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
2777 return E_NOTIMPL;
2780 static HRESULT WINAPI MimeMessage_GetRootMoniker(
2781 IMimeMessage *iface,
2782 IMoniker **ppMoniker)
2784 FIXME("(%p)->(%p)\n", iface, ppMoniker);
2785 return E_NOTIMPL;
2788 static const IMimeMessageVtbl MimeMessageVtbl =
2790 MimeMessage_QueryInterface,
2791 MimeMessage_AddRef,
2792 MimeMessage_Release,
2793 MimeMessage_GetClassID,
2794 MimeMessage_IsDirty,
2795 MimeMessage_Load,
2796 MimeMessage_Save,
2797 MimeMessage_GetSizeMax,
2798 MimeMessage_InitNew,
2799 MimeMessage_GetMessageSource,
2800 MimeMessage_GetMessageSize,
2801 MimeMessage_LoadOffsetTable,
2802 MimeMessage_SaveOffsetTable,
2803 MimeMessage_GetFlags,
2804 MimeMessage_Commit,
2805 MimeMessage_HandsOffStorage,
2806 MimeMessage_BindToObject,
2807 MimeMessage_SaveBody,
2808 MimeMessage_InsertBody,
2809 MimeMessage_GetBody,
2810 MimeMessage_DeleteBody,
2811 MimeMessage_MoveBody,
2812 MimeMessage_CountBodies,
2813 MimeMessage_FindFirst,
2814 MimeMessage_FindNext,
2815 MimeMessage_ResolveURL,
2816 MimeMessage_ToMultipart,
2817 MimeMessage_GetBodyOffsets,
2818 MimeMessage_GetCharset,
2819 MimeMessage_SetCharset,
2820 MimeMessage_IsBodyType,
2821 MimeMessage_IsContentType,
2822 MimeMessage_QueryBodyProp,
2823 MimeMessage_GetBodyProp,
2824 MimeMessage_SetBodyProp,
2825 MimeMessage_DeleteBodyProp,
2826 MimeMessage_SetOption,
2827 MimeMessage_GetOption,
2828 MimeMessage_CreateWebPage,
2829 MimeMessage_GetProp,
2830 MimeMessage_SetProp,
2831 MimeMessage_DeleteProp,
2832 MimeMessage_QueryProp,
2833 MimeMessage_GetTextBody,
2834 MimeMessage_SetTextBody,
2835 MimeMessage_AttachObject,
2836 MimeMessage_AttachFile,
2837 MimeMessage_AttachURL,
2838 MimeMessage_GetAttachments,
2839 MimeMessage_GetAddressTable,
2840 MimeMessage_GetSender,
2841 MimeMessage_GetAddressTypes,
2842 MimeMessage_GetAddressFormat,
2843 MimeMessage_EnumAddressTypes,
2844 MimeMessage_SplitMessage,
2845 MimeMessage_GetRootMoniker,
2848 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
2850 MimeMessage *This;
2851 MimeBody *mime_body;
2852 body_t *root_body;
2854 TRACE("(%p, %p)\n", outer, obj);
2856 if (outer)
2858 FIXME("outer unknown not supported yet\n");
2859 return E_NOTIMPL;
2862 *obj = NULL;
2864 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2865 if (!This) return E_OUTOFMEMORY;
2867 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
2868 This->ref = 1;
2869 This->stream = NULL;
2870 list_init(&This->body_tree);
2871 This->next_index = 1;
2873 mime_body = mimebody_create();
2874 root_body = new_body_entry(mime_body, This->next_index++, NULL);
2875 list_add_head(&This->body_tree, &root_body->entry);
2877 *obj = &This->IMimeMessage_iface;
2878 return S_OK;
2881 /***********************************************************************
2882 * MimeOleCreateMessage (INETCOMM.@)
2884 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
2886 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
2887 return MimeMessage_create(NULL, (void **)ppMessage);
2890 /***********************************************************************
2891 * MimeOleSetCompatMode (INETCOMM.@)
2893 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
2895 FIXME("(0x%x)\n", dwMode);
2896 return S_OK;
2899 /***********************************************************************
2900 * MimeOleCreateVirtualStream (INETCOMM.@)
2902 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
2904 HRESULT hr;
2905 FIXME("(%p)\n", ppStream);
2907 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
2908 return hr;
2911 typedef struct MimeSecurity
2913 IMimeSecurity IMimeSecurity_iface;
2914 LONG ref;
2915 } MimeSecurity;
2917 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
2919 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
2922 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
2924 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2926 if (IsEqualIID(riid, &IID_IUnknown) ||
2927 IsEqualIID(riid, &IID_IMimeSecurity))
2929 *ppv = iface;
2930 IMimeSecurity_AddRef(iface);
2931 return S_OK;
2934 FIXME("no interface for %s\n", debugstr_guid(riid));
2935 *ppv = NULL;
2936 return E_NOINTERFACE;
2939 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
2941 MimeSecurity *This = impl_from_IMimeSecurity(iface);
2942 LONG ref = InterlockedIncrement(&This->ref);
2944 TRACE("(%p) ref=%d\n", This, ref);
2946 return ref;
2949 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
2951 MimeSecurity *This = impl_from_IMimeSecurity(iface);
2952 LONG ref = InterlockedDecrement(&This->ref);
2954 TRACE("(%p) ref=%d\n", This, ref);
2956 if (!ref)
2957 HeapFree(GetProcessHeap(), 0, This);
2959 return ref;
2962 static HRESULT WINAPI MimeSecurity_InitNew(
2963 IMimeSecurity* iface)
2965 FIXME("(%p)->(): stub\n", iface);
2966 return S_OK;
2969 static HRESULT WINAPI MimeSecurity_CheckInit(
2970 IMimeSecurity* iface)
2972 FIXME("(%p)->(): stub\n", iface);
2973 return E_NOTIMPL;
2976 static HRESULT WINAPI MimeSecurity_EncodeMessage(
2977 IMimeSecurity* iface,
2978 IMimeMessageTree* pTree,
2979 DWORD dwFlags)
2981 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
2982 return E_NOTIMPL;
2985 static HRESULT WINAPI MimeSecurity_EncodeBody(
2986 IMimeSecurity* iface,
2987 IMimeMessageTree* pTree,
2988 HBODY hEncodeRoot,
2989 DWORD dwFlags)
2991 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
2992 return E_NOTIMPL;
2995 static HRESULT WINAPI MimeSecurity_DecodeMessage(
2996 IMimeSecurity* iface,
2997 IMimeMessageTree* pTree,
2998 DWORD dwFlags)
3000 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3001 return E_NOTIMPL;
3004 static HRESULT WINAPI MimeSecurity_DecodeBody(
3005 IMimeSecurity* iface,
3006 IMimeMessageTree* pTree,
3007 HBODY hDecodeRoot,
3008 DWORD dwFlags)
3010 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3011 return E_NOTIMPL;
3014 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3015 IMimeSecurity* iface,
3016 HCAPICERTSTORE hc,
3017 DWORD dwUsage,
3018 PCX509CERT pPrev,
3019 PCX509CERT* ppCert)
3021 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3022 return E_NOTIMPL;
3025 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3026 IMimeSecurity* iface,
3027 const PCX509CERT pX509Cert,
3028 const CERTNAMETYPE cn,
3029 LPSTR* ppszName)
3031 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3032 return E_NOTIMPL;
3035 static HRESULT WINAPI MimeSecurity_GetMessageType(
3036 IMimeSecurity* iface,
3037 const HWND hwndParent,
3038 IMimeBody* pBody,
3039 DWORD* pdwSecType)
3041 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3042 return E_NOTIMPL;
3045 static HRESULT WINAPI MimeSecurity_GetCertData(
3046 IMimeSecurity* iface,
3047 const PCX509CERT pX509Cert,
3048 const CERTDATAID dataid,
3049 LPPROPVARIANT pValue)
3051 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3052 return E_NOTIMPL;
3056 static const IMimeSecurityVtbl MimeSecurityVtbl =
3058 MimeSecurity_QueryInterface,
3059 MimeSecurity_AddRef,
3060 MimeSecurity_Release,
3061 MimeSecurity_InitNew,
3062 MimeSecurity_CheckInit,
3063 MimeSecurity_EncodeMessage,
3064 MimeSecurity_EncodeBody,
3065 MimeSecurity_DecodeMessage,
3066 MimeSecurity_DecodeBody,
3067 MimeSecurity_EnumCertificates,
3068 MimeSecurity_GetCertificateName,
3069 MimeSecurity_GetMessageType,
3070 MimeSecurity_GetCertData
3073 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3075 MimeSecurity *This;
3077 *obj = NULL;
3079 if (outer) return CLASS_E_NOAGGREGATION;
3081 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3082 if (!This) return E_OUTOFMEMORY;
3084 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3085 This->ref = 1;
3087 *obj = &This->IMimeSecurity_iface;
3088 return S_OK;
3091 /***********************************************************************
3092 * MimeOleCreateSecurity (INETCOMM.@)
3094 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3096 return MimeSecurity_create(NULL, (void **)ppSecurity);
3099 static HRESULT WINAPI MimeAlloc_QueryInterface(
3100 IMimeAllocator* iface,
3101 REFIID riid,
3102 void **obj)
3104 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3106 if (IsEqualIID(riid, &IID_IUnknown) ||
3107 IsEqualIID(riid, &IID_IMalloc) ||
3108 IsEqualIID(riid, &IID_IMimeAllocator))
3110 *obj = iface;
3111 IMimeAllocator_AddRef(iface);
3112 return S_OK;
3115 FIXME("no interface for %s\n", debugstr_guid(riid));
3116 *obj = NULL;
3117 return E_NOINTERFACE;
3120 static ULONG WINAPI MimeAlloc_AddRef(
3121 IMimeAllocator* iface)
3123 return 2;
3126 static ULONG WINAPI MimeAlloc_Release(
3127 IMimeAllocator* iface)
3129 return 1;
3132 static LPVOID WINAPI MimeAlloc_Alloc(
3133 IMimeAllocator* iface,
3134 SIZE_T cb)
3136 return CoTaskMemAlloc(cb);
3139 static LPVOID WINAPI MimeAlloc_Realloc(
3140 IMimeAllocator* iface,
3141 LPVOID pv,
3142 SIZE_T cb)
3144 return CoTaskMemRealloc(pv, cb);
3147 static void WINAPI MimeAlloc_Free(
3148 IMimeAllocator* iface,
3149 LPVOID pv)
3151 CoTaskMemFree(pv);
3154 static SIZE_T WINAPI MimeAlloc_GetSize(
3155 IMimeAllocator* iface,
3156 LPVOID pv)
3158 FIXME("stub\n");
3159 return 0;
3162 static int WINAPI MimeAlloc_DidAlloc(
3163 IMimeAllocator* iface,
3164 LPVOID pv)
3166 FIXME("stub\n");
3167 return 0;
3170 static void WINAPI MimeAlloc_HeapMinimize(
3171 IMimeAllocator* iface)
3173 FIXME("stub\n");
3174 return;
3177 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3178 IMimeAllocator* iface,
3179 ULONG cParams,
3180 LPMIMEPARAMINFO prgParam,
3181 boolean fFreeArray)
3183 ULONG i;
3184 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3186 for(i = 0; i < cParams; i++)
3188 IMimeAllocator_Free(iface, prgParam[i].pszName);
3189 IMimeAllocator_Free(iface, prgParam[i].pszData);
3191 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3192 return S_OK;
3195 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3196 IMimeAllocator* iface,
3197 LPADDRESSLIST pList)
3199 FIXME("stub\n");
3200 return E_NOTIMPL;
3203 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3204 IMimeAllocator* iface,
3205 LPADDRESSPROPS pAddress)
3207 FIXME("stub\n");
3208 return E_NOTIMPL;
3211 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3212 IMimeAllocator* iface,
3213 ULONG cObjects,
3214 IUnknown **prgpUnknown,
3215 boolean fFreeArray)
3217 FIXME("stub\n");
3218 return E_NOTIMPL;
3222 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3223 IMimeAllocator* iface,
3224 ULONG cRows,
3225 LPENUMHEADERROW prgRow,
3226 boolean fFreeArray)
3228 FIXME("stub\n");
3229 return E_NOTIMPL;
3232 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3233 IMimeAllocator* iface,
3234 ULONG cProps,
3235 LPENUMPROPERTY prgProp,
3236 boolean fFreeArray)
3238 FIXME("stub\n");
3239 return E_NOTIMPL;
3242 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3243 IMimeAllocator* iface,
3244 THUMBBLOB *pthumbprint)
3246 FIXME("stub\n");
3247 return E_NOTIMPL;
3251 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3252 IMimeAllocator* iface,
3253 LPPROPVARIANT pProp)
3255 FIXME("stub\n");
3256 return E_NOTIMPL;
3259 static IMimeAllocatorVtbl mime_alloc_vtbl =
3261 MimeAlloc_QueryInterface,
3262 MimeAlloc_AddRef,
3263 MimeAlloc_Release,
3264 MimeAlloc_Alloc,
3265 MimeAlloc_Realloc,
3266 MimeAlloc_Free,
3267 MimeAlloc_GetSize,
3268 MimeAlloc_DidAlloc,
3269 MimeAlloc_HeapMinimize,
3270 MimeAlloc_FreeParamInfoArray,
3271 MimeAlloc_FreeAddressList,
3272 MimeAlloc_FreeAddressProps,
3273 MimeAlloc_ReleaseObjects,
3274 MimeAlloc_FreeEnumHeaderRowArray,
3275 MimeAlloc_FreeEnumPropertyArray,
3276 MimeAlloc_FreeThumbprint,
3277 MimeAlloc_PropVariantClear
3280 static IMimeAllocator mime_allocator =
3282 &mime_alloc_vtbl
3285 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3287 if(outer) return CLASS_E_NOAGGREGATION;
3289 *obj = &mime_allocator;
3290 return S_OK;
3293 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3295 return MimeAllocator_create(NULL, (void**)alloc);
3298 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3300 FIXME("(%p, %p)\n", outer, obj);
3302 *obj = NULL;
3303 if (outer) return CLASS_E_NOAGGREGATION;
3305 return MimeOleCreateVirtualStream((IStream **)obj);
3308 /* IMimePropertySchema Interface */
3309 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3311 propschema *This = impl_from_IMimePropertySchema(iface);
3312 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3314 *out = NULL;
3316 if (IsEqualIID(riid, &IID_IUnknown) ||
3317 IsEqualIID(riid, &IID_IMimePropertySchema))
3319 *out = iface;
3321 else
3323 FIXME("no interface for %s\n", debugstr_guid(riid));
3324 return E_NOINTERFACE;
3327 IMimePropertySchema_AddRef(iface);
3328 return S_OK;
3331 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3333 propschema *This = impl_from_IMimePropertySchema(iface);
3334 LONG ref = InterlockedIncrement(&This->ref);
3336 TRACE("(%p) ref=%d\n", This, ref);
3338 return ref;
3341 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3343 propschema *This = impl_from_IMimePropertySchema(iface);
3344 LONG ref = InterlockedDecrement(&This->ref);
3346 TRACE("(%p) ref=%d\n", This, ref);
3348 if (!ref)
3350 HeapFree(GetProcessHeap(), 0, This);
3353 return ref;
3356 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3357 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3359 propschema *This = impl_from_IMimePropertySchema(iface);
3360 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3361 return E_NOTIMPL;
3364 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3365 DWORD rownumber, VARTYPE vtdefault)
3367 propschema *This = impl_from_IMimePropertySchema(iface);
3368 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3369 return S_OK;
3372 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3374 propschema *This = impl_from_IMimePropertySchema(iface);
3375 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3376 return E_NOTIMPL;
3379 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3381 propschema *This = impl_from_IMimePropertySchema(iface);
3382 FIXME("(%p)->(%d, %p) stub\n", This, propid, name);
3383 return E_NOTIMPL;
3386 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3388 propschema *This = impl_from_IMimePropertySchema(iface);
3389 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3390 return E_NOTIMPL;
3393 static IMimePropertySchemaVtbl prop_schema_vtbl =
3395 propschema_QueryInterface,
3396 propschema_AddRef,
3397 propschema_Release,
3398 propschema_RegisterProperty,
3399 propschema_ModifyProperty,
3400 propschema_GetPropertyId,
3401 propschema_GetPropertyName,
3402 propschema_RegisterAddressType
3406 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3408 propschema *This;
3410 TRACE("(%p) stub\n", schema);
3412 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3413 if (!This)
3414 return E_OUTOFMEMORY;
3416 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3417 This->ref = 1;
3419 *schema = &This->IMimePropertySchema_iface;
3421 return S_OK;
3424 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3425 ADDRESSFORMAT addr_format, WCHAR **address)
3427 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3429 return E_NOTIMPL;