inetcomm: Added support for decoding base64 in IMimeBody::GetData.
[wine.git] / dlls / inetcomm / mimeole.c
blob90a5dd41032bc84a87f3f83921e487d423b4c66f
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 typedef struct
171 IStream IStream_iface;
172 LONG ref;
173 IStream *base;
174 ULARGE_INTEGER pos, start, length;
175 } sub_stream_t;
177 static inline sub_stream_t *impl_from_IStream(IStream *iface)
179 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
182 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
184 sub_stream_t *This = impl_from_IStream(iface);
186 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
187 *ppv = NULL;
189 if(IsEqualIID(riid, &IID_IUnknown) ||
190 IsEqualIID(riid, &IID_ISequentialStream) ||
191 IsEqualIID(riid, &IID_IStream))
193 IStream_AddRef(iface);
194 *ppv = iface;
195 return S_OK;
197 return E_NOINTERFACE;
200 static ULONG WINAPI sub_stream_AddRef(IStream *iface)
202 sub_stream_t *This = impl_from_IStream(iface);
203 LONG ref = InterlockedIncrement(&This->ref);
205 TRACE("(%p) ref=%d\n", This, ref);
207 return ref;
210 static ULONG WINAPI sub_stream_Release(IStream *iface)
212 sub_stream_t *This = impl_from_IStream(iface);
213 LONG ref = InterlockedDecrement(&This->ref);
215 TRACE("(%p) ref=%d\n", This, ref);
217 if(!ref)
219 IStream_Release(This->base);
220 HeapFree(GetProcessHeap(), 0, This);
222 return ref;
225 static HRESULT WINAPI sub_stream_Read(
226 IStream* iface,
227 void *pv,
228 ULONG cb,
229 ULONG *pcbRead)
231 sub_stream_t *This = impl_from_IStream(iface);
232 HRESULT hr;
233 LARGE_INTEGER tmp_pos;
235 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
237 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
238 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
240 if(This->pos.QuadPart + cb > This->length.QuadPart)
241 cb = This->length.QuadPart - This->pos.QuadPart;
243 hr = IStream_Read(This->base, pv, cb, pcbRead);
245 This->pos.QuadPart += *pcbRead;
247 return hr;
250 static HRESULT WINAPI sub_stream_Write(
251 IStream* iface,
252 const void *pv,
253 ULONG cb,
254 ULONG *pcbWritten)
256 FIXME("stub\n");
257 return E_NOTIMPL;
260 static HRESULT WINAPI sub_stream_Seek(
261 IStream* iface,
262 LARGE_INTEGER dlibMove,
263 DWORD dwOrigin,
264 ULARGE_INTEGER *plibNewPosition)
266 sub_stream_t *This = impl_from_IStream(iface);
267 LARGE_INTEGER new_pos;
269 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
271 switch(dwOrigin)
273 case STREAM_SEEK_SET:
274 new_pos = dlibMove;
275 break;
276 case STREAM_SEEK_CUR:
277 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
278 break;
279 case STREAM_SEEK_END:
280 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
281 break;
282 default:
283 return STG_E_INVALIDFUNCTION;
286 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
287 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
289 This->pos.QuadPart = new_pos.QuadPart;
291 if(plibNewPosition) *plibNewPosition = This->pos;
292 return S_OK;
295 static HRESULT WINAPI sub_stream_SetSize(
296 IStream* iface,
297 ULARGE_INTEGER libNewSize)
299 FIXME("stub\n");
300 return E_NOTIMPL;
303 static HRESULT WINAPI sub_stream_CopyTo(
304 IStream* iface,
305 IStream *pstm,
306 ULARGE_INTEGER cb,
307 ULARGE_INTEGER *pcbRead,
308 ULARGE_INTEGER *pcbWritten)
310 HRESULT hr = S_OK;
311 BYTE tmpBuffer[128];
312 ULONG bytesRead, bytesWritten, copySize;
313 ULARGE_INTEGER totalBytesRead;
314 ULARGE_INTEGER totalBytesWritten;
316 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
318 totalBytesRead.QuadPart = 0;
319 totalBytesWritten.QuadPart = 0;
321 while ( cb.QuadPart > 0 )
323 if ( cb.QuadPart >= sizeof(tmpBuffer) )
324 copySize = sizeof(tmpBuffer);
325 else
326 copySize = cb.u.LowPart;
328 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
329 if (FAILED(hr)) break;
331 totalBytesRead.QuadPart += bytesRead;
333 if (bytesRead)
335 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
336 if (FAILED(hr)) break;
337 totalBytesWritten.QuadPart += bytesWritten;
340 if (bytesRead != copySize)
341 cb.QuadPart = 0;
342 else
343 cb.QuadPart -= bytesRead;
346 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
347 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
349 return hr;
352 static HRESULT WINAPI sub_stream_Commit(
353 IStream* iface,
354 DWORD grfCommitFlags)
356 FIXME("stub\n");
357 return E_NOTIMPL;
360 static HRESULT WINAPI sub_stream_Revert(
361 IStream* iface)
363 FIXME("stub\n");
364 return E_NOTIMPL;
367 static HRESULT WINAPI sub_stream_LockRegion(
368 IStream* iface,
369 ULARGE_INTEGER libOffset,
370 ULARGE_INTEGER cb,
371 DWORD dwLockType)
373 FIXME("stub\n");
374 return E_NOTIMPL;
377 static HRESULT WINAPI sub_stream_UnlockRegion(
378 IStream* iface,
379 ULARGE_INTEGER libOffset,
380 ULARGE_INTEGER cb,
381 DWORD dwLockType)
383 FIXME("stub\n");
384 return E_NOTIMPL;
387 static HRESULT WINAPI sub_stream_Stat(
388 IStream* iface,
389 STATSTG *pstatstg,
390 DWORD grfStatFlag)
392 sub_stream_t *This = impl_from_IStream(iface);
393 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
394 memset(pstatstg, 0, sizeof(*pstatstg));
395 pstatstg->cbSize = This->length;
396 return S_OK;
399 static HRESULT WINAPI sub_stream_Clone(
400 IStream* iface,
401 IStream **ppstm)
403 FIXME("stub\n");
404 return E_NOTIMPL;
407 static struct IStreamVtbl sub_stream_vtbl =
409 sub_stream_QueryInterface,
410 sub_stream_AddRef,
411 sub_stream_Release,
412 sub_stream_Read,
413 sub_stream_Write,
414 sub_stream_Seek,
415 sub_stream_SetSize,
416 sub_stream_CopyTo,
417 sub_stream_Commit,
418 sub_stream_Revert,
419 sub_stream_LockRegion,
420 sub_stream_UnlockRegion,
421 sub_stream_Stat,
422 sub_stream_Clone
425 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
427 sub_stream_t *This;
429 *out = NULL;
430 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
431 if(!This) return E_OUTOFMEMORY;
433 This->IStream_iface.lpVtbl = &sub_stream_vtbl;
434 This->ref = 1;
435 This->start = start;
436 This->length = length;
437 This->pos.QuadPart = 0;
438 IStream_AddRef(stream);
439 This->base = stream;
441 *out = &This->IStream_iface;
442 return S_OK;
445 static HRESULT get_stream_size(IStream *stream, ULARGE_INTEGER *size)
447 STATSTG statstg = {NULL};
448 LARGE_INTEGER zero;
449 HRESULT hres;
451 hres = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
452 if(SUCCEEDED(hres)) {
453 *size = statstg.cbSize;
454 return S_OK;
457 zero.QuadPart = 0;
458 return IStream_Seek(stream, zero, STREAM_SEEK_END, size);
461 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
463 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
466 typedef struct propschema
468 IMimePropertySchema IMimePropertySchema_iface;
469 LONG ref;
470 } propschema;
472 static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
474 return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
477 static LPSTR strdupA(LPCSTR str)
479 char *ret;
480 int len = strlen(str);
481 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
482 memcpy(ret, str, len + 1);
483 return ret;
486 #define PARSER_BUF_SIZE 1024
488 /*****************************************************
489 * copy_headers_to_buf [internal]
491 * Copies the headers into a '\0' terminated memory block and leave
492 * the stream's current position set to after the blank line.
494 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
496 char *buf = NULL;
497 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
498 HRESULT hr;
499 BOOL done = FALSE;
501 *ptr = NULL;
505 char *end;
506 DWORD read;
508 if(!buf)
509 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
510 else
512 size *= 2;
513 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
515 if(!buf)
517 hr = E_OUTOFMEMORY;
518 goto fail;
521 hr = IStream_Read(stm, buf + offset, size - offset, &read);
522 if(FAILED(hr)) goto fail;
524 offset += read;
525 buf[offset] = '\0';
527 if(read == 0) done = TRUE;
529 while(!done && (end = strstr(buf + last_end, "\r\n")))
531 DWORD new_end = end - buf + 2;
532 if(new_end - last_end == 2)
534 LARGE_INTEGER off;
535 off.QuadPart = new_end;
536 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
537 buf[new_end] = '\0';
538 done = TRUE;
540 else
541 last_end = new_end;
543 } while(!done);
545 *ptr = buf;
546 return S_OK;
548 fail:
549 HeapFree(GetProcessHeap(), 0, buf);
550 return hr;
553 static header_t *read_prop(MimeBody *body, char **ptr)
555 char *colon = strchr(*ptr, ':');
556 const property_t *prop;
557 header_t *ret;
559 if(!colon) return NULL;
561 *colon = '\0';
563 for(prop = default_props; prop->name; prop++)
565 if(!lstrcmpiA(*ptr, prop->name))
567 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
568 break;
572 if(!prop->name)
574 property_list_entry_t *prop_entry;
575 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
577 if(!lstrcmpiA(*ptr, prop_entry->prop.name))
579 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
580 prop = &prop_entry->prop;
581 break;
584 if(!prop->name)
586 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
587 prop_entry->prop.name = strdupA(*ptr);
588 prop_entry->prop.id = body->next_prop_id++;
589 prop_entry->prop.flags = 0;
590 prop_entry->prop.default_vt = VT_LPSTR;
591 list_add_tail(&body->new_props, &prop_entry->entry);
592 prop = &prop_entry->prop;
593 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
597 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
598 ret->prop = prop;
599 PropVariantInit(&ret->value);
600 list_init(&ret->params);
601 *ptr = colon + 1;
603 return ret;
606 static void unfold_header(char *header, int len)
608 char *start = header, *cp = header;
610 do {
611 while(*cp == ' ' || *cp == '\t')
613 cp++;
614 len--;
616 if(cp != start)
617 memmove(start, cp, len + 1);
619 cp = strstr(start, "\r\n");
620 len -= (cp - start);
621 start = cp;
622 *start = ' ';
623 start++;
624 len--;
625 cp += 2;
626 } while(*cp == ' ' || *cp == '\t');
628 *(start - 1) = '\0';
631 static char *unquote_string(const char *str)
633 BOOL quoted = FALSE;
634 char *ret, *cp;
636 while(*str == ' ' || *str == '\t') str++;
638 if(*str == '"')
640 quoted = TRUE;
641 str++;
643 ret = strdupA(str);
644 for(cp = ret; *cp; cp++)
646 if(*cp == '\\')
647 memmove(cp, cp + 1, strlen(cp + 1) + 1);
648 else if(*cp == '"')
650 if(!quoted)
652 WARN("quote in unquoted string\n");
654 else
656 *cp = '\0';
657 break;
661 return ret;
664 static void add_param(header_t *header, const char *p)
666 const char *key = p, *value, *cp = p;
667 param_t *param;
668 char *name;
670 TRACE("got param %s\n", p);
672 while (*key == ' ' || *key == '\t' ) key++;
674 cp = strchr(key, '=');
675 if(!cp)
677 WARN("malformed parameter - skipping\n");
678 return;
681 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
682 memcpy(name, key, cp - key);
683 name[cp - key] = '\0';
685 value = cp + 1;
687 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
688 param->name = name;
689 param->value = unquote_string(value);
690 list_add_tail(&header->params, &param->entry);
693 static void split_params(header_t *header, char *value)
695 char *cp = value, *start = value;
696 BOOL in_quotes = FALSE, done_value = FALSE;
698 while(*cp)
700 if(!in_quotes && *cp == ';')
702 *cp = '\0';
703 if(done_value) add_param(header, start);
704 done_value = TRUE;
705 start = cp + 1;
707 else if(*cp == '"')
708 in_quotes = !in_quotes;
709 cp++;
711 if(done_value) add_param(header, start);
714 static void read_value(header_t *header, char **cur)
716 char *end = *cur, *value;
717 DWORD len;
719 do {
720 end = strstr(end, "\r\n");
721 end += 2;
722 } while(*end == ' ' || *end == '\t');
724 len = end - *cur;
725 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
726 memcpy(value, *cur, len);
727 value[len] = '\0';
729 unfold_header(value, len);
730 TRACE("value %s\n", debugstr_a(value));
732 if(header->prop->flags & MPF_HASPARAMS)
734 split_params(header, value);
735 TRACE("value w/o params %s\n", debugstr_a(value));
738 header->value.vt = VT_LPSTR;
739 header->value.u.pszVal = value;
741 *cur = end;
744 static void init_content_type(MimeBody *body, header_t *header)
746 char *slash;
747 DWORD len;
749 if(header->prop->id != PID_HDR_CNTTYPE)
751 ERR("called with header %s\n", header->prop->name);
752 return;
755 slash = strchr(header->value.u.pszVal, '/');
756 if(!slash)
758 WARN("malformed context type value\n");
759 return;
761 len = slash - header->value.u.pszVal;
762 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
763 memcpy(body->content_pri_type, header->value.u.pszVal, len);
764 body->content_pri_type[len] = '\0';
765 body->content_sub_type = strdupA(slash + 1);
768 static HRESULT parse_headers(MimeBody *body, IStream *stm)
770 char *header_buf, *cur_header_ptr;
771 HRESULT hr;
772 header_t *header;
774 hr = copy_headers_to_buf(stm, &header_buf);
775 if(FAILED(hr)) return hr;
777 cur_header_ptr = header_buf;
778 while((header = read_prop(body, &cur_header_ptr)))
780 read_value(header, &cur_header_ptr);
781 list_add_tail(&body->headers, &header->entry);
783 if(header->prop->id == PID_HDR_CNTTYPE)
784 init_content_type(body, header);
787 HeapFree(GetProcessHeap(), 0, header_buf);
788 return hr;
791 static void empty_param_list(struct list *list)
793 param_t *param, *cursor2;
795 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
797 list_remove(&param->entry);
798 HeapFree(GetProcessHeap(), 0, param->name);
799 HeapFree(GetProcessHeap(), 0, param->value);
800 HeapFree(GetProcessHeap(), 0, param);
804 static void empty_header_list(struct list *list)
806 header_t *header, *cursor2;
808 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
810 list_remove(&header->entry);
811 PropVariantClear(&header->value);
812 empty_param_list(&header->params);
813 HeapFree(GetProcessHeap(), 0, header);
817 static void empty_new_prop_list(struct list *list)
819 property_list_entry_t *prop, *cursor2;
821 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
823 list_remove(&prop->entry);
824 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
825 HeapFree(GetProcessHeap(), 0, prop);
829 static void release_data(REFIID riid, void *data)
831 if(!data) return;
833 if(IsEqualIID(riid, &IID_IStream))
834 IStream_Release((IStream *)data);
835 else
836 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
839 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
841 header_t *header;
843 *prop = NULL;
845 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
847 if(ISPIDSTR(name))
849 if(STRTOPID(name) == header->prop->id)
851 *prop = header;
852 return S_OK;
855 else if(!lstrcmpiA(name, header->prop->name))
857 *prop = header;
858 return S_OK;
862 return MIME_E_NOT_FOUND;
865 static const property_t *find_default_prop(const char *name)
867 const property_t *prop_def = NULL;
869 for(prop_def = default_props; prop_def->name; prop_def++)
871 if(ISPIDSTR(name))
873 if(STRTOPID(name) == prop_def->id)
875 break;
878 else if(!lstrcmpiA(name, prop_def->name))
880 break;
884 if(prop_def->id)
885 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
886 else
887 prop_def = NULL;
889 return prop_def;
892 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
893 REFIID riid,
894 void** ppvObject)
896 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
898 *ppvObject = NULL;
900 if (IsEqualIID(riid, &IID_IUnknown) ||
901 IsEqualIID(riid, &IID_IPersist) ||
902 IsEqualIID(riid, &IID_IPersistStreamInit) ||
903 IsEqualIID(riid, &IID_IMimePropertySet) ||
904 IsEqualIID(riid, &IID_IMimeBody))
906 *ppvObject = iface;
909 if(*ppvObject)
911 IUnknown_AddRef((IUnknown*)*ppvObject);
912 return S_OK;
915 FIXME("no interface for %s\n", debugstr_guid(riid));
916 return E_NOINTERFACE;
919 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
921 MimeBody *This = impl_from_IMimeBody(iface);
922 LONG ref = InterlockedIncrement(&This->ref);
924 TRACE("(%p) ref=%d\n", This, ref);
926 return ref;
929 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
931 MimeBody *This = impl_from_IMimeBody(iface);
932 LONG ref = InterlockedDecrement(&This->ref);
934 TRACE("(%p) ref=%d\n", This, ref);
936 if (!ref)
938 empty_header_list(&This->headers);
939 empty_new_prop_list(&This->new_props);
941 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
942 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
944 release_data(&This->data_iid, This->data);
946 HeapFree(GetProcessHeap(), 0, This);
949 return ref;
952 static HRESULT WINAPI MimeBody_GetClassID(
953 IMimeBody* iface,
954 CLSID* pClassID)
956 MimeBody *This = impl_from_IMimeBody(iface);
957 FIXME("(%p)->(%p) stub\n", This, pClassID);
958 return E_NOTIMPL;
962 static HRESULT WINAPI MimeBody_IsDirty(
963 IMimeBody* iface)
965 MimeBody *This = impl_from_IMimeBody(iface);
966 FIXME("(%p)->() stub\n", This);
967 return E_NOTIMPL;
970 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
972 MimeBody *This = impl_from_IMimeBody(iface);
973 TRACE("(%p)->(%p)\n", This, pStm);
974 return parse_headers(This, pStm);
977 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
979 MimeBody *This = impl_from_IMimeBody(iface);
980 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
981 return E_NOTIMPL;
984 static HRESULT WINAPI MimeBody_GetSizeMax(
985 IMimeBody* iface,
986 ULARGE_INTEGER* pcbSize)
988 MimeBody *This = impl_from_IMimeBody(iface);
989 FIXME("(%p)->(%p) stub\n", This, pcbSize);
990 return E_NOTIMPL;
993 static HRESULT WINAPI MimeBody_InitNew(
994 IMimeBody* iface)
996 MimeBody *This = impl_from_IMimeBody(iface);
997 TRACE("(%p)->()\n", This);
998 return S_OK;
1001 static HRESULT WINAPI MimeBody_GetPropInfo(
1002 IMimeBody* iface,
1003 LPCSTR pszName,
1004 LPMIMEPROPINFO pInfo)
1006 MimeBody *This = impl_from_IMimeBody(iface);
1007 header_t *header;
1008 HRESULT hr;
1009 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1011 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1013 if(!pszName || !pInfo)
1014 return E_INVALIDARG;
1016 TRACE("mask 0x%04x\n", pInfo->dwMask);
1018 if(pInfo->dwMask & ~supported)
1019 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
1021 hr = find_prop(This, pszName, &header);
1022 if(hr == S_OK)
1024 if(pInfo->dwMask & PIM_CHARSET)
1025 pInfo->hCharset = 0;
1026 if(pInfo->dwMask & PIM_FLAGS)
1027 pInfo->dwFlags = 0x00000000;
1028 if(pInfo->dwMask & PIM_ROWNUMBER)
1029 pInfo->dwRowNumber = 0;
1030 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1031 pInfo->ietEncoding = 0;
1032 if(pInfo->dwMask & PIM_VALUES)
1033 pInfo->cValues = 0;
1034 if(pInfo->dwMask & PIM_PROPID)
1035 pInfo->dwPropId = header->prop->id;
1036 if(pInfo->dwMask & PIM_VTDEFAULT)
1037 pInfo->vtDefault = header->prop->default_vt;
1038 if(pInfo->dwMask & PIM_VTCURRENT)
1039 pInfo->vtCurrent = 0;
1042 return hr;
1045 static HRESULT WINAPI MimeBody_SetPropInfo(
1046 IMimeBody* iface,
1047 LPCSTR pszName,
1048 LPCMIMEPROPINFO pInfo)
1050 MimeBody *This = impl_from_IMimeBody(iface);
1051 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1052 return E_NOTIMPL;
1055 static HRESULT WINAPI MimeBody_GetProp(
1056 IMimeBody* iface,
1057 LPCSTR pszName,
1058 DWORD dwFlags,
1059 LPPROPVARIANT pValue)
1061 MimeBody *This = impl_from_IMimeBody(iface);
1062 header_t *header;
1063 HRESULT hr;
1065 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1067 if(!pszName || !pValue)
1068 return E_INVALIDARG;
1070 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1072 PropVariantClear(pValue);
1073 pValue->vt = VT_LPSTR;
1074 pValue->u.pszVal = strdupA(This->content_pri_type);
1075 return S_OK;
1078 hr = find_prop(This, pszName, &header);
1079 if(hr == S_OK)
1081 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1083 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1084 if(FAILED(hr))
1085 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1088 return hr;
1091 static HRESULT WINAPI MimeBody_SetProp(
1092 IMimeBody* iface,
1093 LPCSTR pszName,
1094 DWORD dwFlags,
1095 LPCPROPVARIANT pValue)
1097 MimeBody *This = impl_from_IMimeBody(iface);
1098 header_t *header;
1099 HRESULT hr;
1101 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1103 if(!pszName || !pValue)
1104 return E_INVALIDARG;
1106 hr = find_prop(This, pszName, &header);
1107 if(hr != S_OK)
1109 property_list_entry_t *prop_entry;
1110 const property_t *prop = NULL;
1112 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1114 if(ISPIDSTR(pszName))
1116 if(STRTOPID(pszName) == prop_entry->prop.id)
1118 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1119 prop = &prop_entry->prop;
1120 break;
1123 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1125 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1126 prop = &prop_entry->prop;
1127 break;
1131 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
1132 if(!header)
1133 return E_OUTOFMEMORY;
1135 if(!prop)
1137 const property_t *prop_def = NULL;
1138 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
1139 if(!prop_entry)
1141 HeapFree(GetProcessHeap(), 0, header);
1142 return E_OUTOFMEMORY;
1145 prop_def = find_default_prop(pszName);
1146 if(prop_def)
1148 prop_entry->prop.name = strdupA(prop_def->name);
1149 prop_entry->prop.id = prop_def->id;
1151 else
1153 if(ISPIDSTR(pszName))
1155 HeapFree(GetProcessHeap(), 0, prop_entry);
1156 HeapFree(GetProcessHeap(), 0, header);
1157 return MIME_E_NOT_FOUND;
1160 prop_entry->prop.name = strdupA(pszName);
1161 prop_entry->prop.id = This->next_prop_id++;
1164 prop_entry->prop.flags = 0;
1165 prop_entry->prop.default_vt = pValue->vt;
1166 list_add_tail(&This->new_props, &prop_entry->entry);
1167 prop = &prop_entry->prop;
1168 TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
1171 header->prop = prop;
1172 PropVariantInit(&header->value);
1173 list_init(&header->params);
1174 list_add_tail(&This->headers, &header->entry);
1177 PropVariantCopy(&header->value, pValue);
1179 return S_OK;
1182 static HRESULT WINAPI MimeBody_AppendProp(
1183 IMimeBody* iface,
1184 LPCSTR pszName,
1185 DWORD dwFlags,
1186 LPPROPVARIANT pValue)
1188 MimeBody *This = impl_from_IMimeBody(iface);
1189 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1190 return E_NOTIMPL;
1193 static HRESULT WINAPI MimeBody_DeleteProp(
1194 IMimeBody* iface,
1195 LPCSTR pszName)
1197 MimeBody *This = impl_from_IMimeBody(iface);
1198 header_t *cursor;
1199 BOOL found;
1201 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1203 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1205 if(ISPIDSTR(pszName))
1206 found = STRTOPID(pszName) == cursor->prop->id;
1207 else
1208 found = !lstrcmpiA(pszName, cursor->prop->name);
1210 if(found)
1212 list_remove(&cursor->entry);
1213 HeapFree(GetProcessHeap(), 0, cursor);
1214 return S_OK;
1218 return MIME_E_NOT_FOUND;
1221 static HRESULT WINAPI MimeBody_CopyProps(
1222 IMimeBody* iface,
1223 ULONG cNames,
1224 LPCSTR* prgszName,
1225 IMimePropertySet* pPropertySet)
1227 MimeBody *This = impl_from_IMimeBody(iface);
1228 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1229 return E_NOTIMPL;
1232 static HRESULT WINAPI MimeBody_MoveProps(
1233 IMimeBody* iface,
1234 ULONG cNames,
1235 LPCSTR* prgszName,
1236 IMimePropertySet* pPropertySet)
1238 MimeBody *This = impl_from_IMimeBody(iface);
1239 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1240 return E_NOTIMPL;
1243 static HRESULT WINAPI MimeBody_DeleteExcept(
1244 IMimeBody* iface,
1245 ULONG cNames,
1246 LPCSTR* prgszName)
1248 MimeBody *This = impl_from_IMimeBody(iface);
1249 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
1250 return E_NOTIMPL;
1253 static HRESULT WINAPI MimeBody_QueryProp(
1254 IMimeBody* iface,
1255 LPCSTR pszName,
1256 LPCSTR pszCriteria,
1257 boolean fSubString,
1258 boolean fCaseSensitive)
1260 MimeBody *This = impl_from_IMimeBody(iface);
1261 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1262 return E_NOTIMPL;
1265 static HRESULT WINAPI MimeBody_GetCharset(
1266 IMimeBody* iface,
1267 LPHCHARSET phCharset)
1269 MimeBody *This = impl_from_IMimeBody(iface);
1270 FIXME("(%p)->(%p) stub\n", This, phCharset);
1271 *phCharset = NULL;
1272 return S_OK;
1275 static HRESULT WINAPI MimeBody_SetCharset(
1276 IMimeBody* iface,
1277 HCHARSET hCharset,
1278 CSETAPPLYTYPE applytype)
1280 MimeBody *This = impl_from_IMimeBody(iface);
1281 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1282 return E_NOTIMPL;
1285 static HRESULT WINAPI MimeBody_GetParameters(
1286 IMimeBody* iface,
1287 LPCSTR pszName,
1288 ULONG* pcParams,
1289 LPMIMEPARAMINFO* pprgParam)
1291 MimeBody *This = impl_from_IMimeBody(iface);
1292 HRESULT hr;
1293 header_t *header;
1295 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1297 *pprgParam = NULL;
1298 *pcParams = 0;
1300 hr = find_prop(This, pszName, &header);
1301 if(hr != S_OK) return hr;
1303 *pcParams = list_count(&header->params);
1304 if(*pcParams)
1306 IMimeAllocator *alloc;
1307 param_t *param;
1308 MIMEPARAMINFO *info;
1310 MimeOleGetAllocator(&alloc);
1312 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1313 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1315 int len;
1317 len = strlen(param->name) + 1;
1318 info->pszName = IMimeAllocator_Alloc(alloc, len);
1319 memcpy(info->pszName, param->name, len);
1320 len = strlen(param->value) + 1;
1321 info->pszData = IMimeAllocator_Alloc(alloc, len);
1322 memcpy(info->pszData, param->value, len);
1323 info++;
1325 IMimeAllocator_Release(alloc);
1327 return S_OK;
1330 static HRESULT WINAPI MimeBody_IsContentType(
1331 IMimeBody* iface,
1332 LPCSTR pszPriType,
1333 LPCSTR pszSubType)
1335 MimeBody *This = impl_from_IMimeBody(iface);
1337 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1338 if(pszPriType)
1340 const char *pri = This->content_pri_type;
1341 if(!pri) pri = "text";
1342 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1345 if(pszSubType)
1347 const char *sub = This->content_sub_type;
1348 if(!sub) sub = "plain";
1349 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1352 return S_OK;
1355 static HRESULT WINAPI MimeBody_BindToObject(
1356 IMimeBody* iface,
1357 REFIID riid,
1358 void** ppvObject)
1360 MimeBody *This = impl_from_IMimeBody(iface);
1361 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1362 return E_NOTIMPL;
1365 static HRESULT WINAPI MimeBody_Clone(
1366 IMimeBody* iface,
1367 IMimePropertySet** ppPropertySet)
1369 MimeBody *This = impl_from_IMimeBody(iface);
1370 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1371 return E_NOTIMPL;
1374 static HRESULT WINAPI MimeBody_SetOption(
1375 IMimeBody* iface,
1376 const TYPEDID oid,
1377 LPCPROPVARIANT pValue)
1379 MimeBody *This = impl_from_IMimeBody(iface);
1380 HRESULT hr = E_NOTIMPL;
1381 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
1383 if(pValue->vt != TYPEDID_TYPE(oid))
1385 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
1386 return E_INVALIDARG;
1389 switch(oid)
1391 case OID_SECURITY_HWND_OWNER:
1392 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
1393 hr = S_OK;
1394 break;
1395 case OID_TRANSMIT_BODY_ENCODING:
1396 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
1397 hr = S_OK;
1398 break;
1399 default:
1400 FIXME("Unhandled oid %08x\n", oid);
1403 return hr;
1406 static HRESULT WINAPI MimeBody_GetOption(
1407 IMimeBody* iface,
1408 const TYPEDID oid,
1409 LPPROPVARIANT pValue)
1411 MimeBody *This = impl_from_IMimeBody(iface);
1412 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
1413 return E_NOTIMPL;
1416 static HRESULT WINAPI MimeBody_EnumProps(
1417 IMimeBody* iface,
1418 DWORD dwFlags,
1419 IMimeEnumProperties** ppEnum)
1421 MimeBody *This = impl_from_IMimeBody(iface);
1422 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
1423 return E_NOTIMPL;
1426 static HRESULT WINAPI MimeBody_IsType(
1427 IMimeBody* iface,
1428 IMSGBODYTYPE bodytype)
1430 MimeBody *This = impl_from_IMimeBody(iface);
1432 TRACE("(%p)->(%d)\n", This, bodytype);
1433 switch(bodytype)
1435 case IBT_EMPTY:
1436 return This->data ? S_FALSE : S_OK;
1437 default:
1438 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1440 return S_OK;
1443 static HRESULT WINAPI MimeBody_SetDisplayName(
1444 IMimeBody* iface,
1445 LPCSTR pszDisplay)
1447 MimeBody *This = impl_from_IMimeBody(iface);
1448 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1449 return E_NOTIMPL;
1452 static HRESULT WINAPI MimeBody_GetDisplayName(
1453 IMimeBody* iface,
1454 LPSTR* ppszDisplay)
1456 MimeBody *This = impl_from_IMimeBody(iface);
1457 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1458 return E_NOTIMPL;
1461 static HRESULT WINAPI MimeBody_GetOffsets(
1462 IMimeBody* iface,
1463 LPBODYOFFSETS pOffsets)
1465 MimeBody *This = impl_from_IMimeBody(iface);
1466 TRACE("(%p)->(%p)\n", This, pOffsets);
1468 *pOffsets = This->body_offsets;
1470 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1471 return S_OK;
1474 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1475 IMimeBody* iface,
1476 ENCODINGTYPE* pietEncoding)
1478 MimeBody *This = impl_from_IMimeBody(iface);
1480 TRACE("(%p)->(%p)\n", This, pietEncoding);
1482 *pietEncoding = This->encoding;
1483 return S_OK;
1486 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1487 IMimeBody* iface,
1488 ENCODINGTYPE ietEncoding)
1490 MimeBody *This = impl_from_IMimeBody(iface);
1492 TRACE("(%p)->(%d)\n", This, ietEncoding);
1494 This->encoding = ietEncoding;
1495 return S_OK;
1498 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1499 IMimeBody* iface,
1500 ENCODINGTYPE ietEncoding,
1501 ULONG* pcbSize)
1503 MimeBody *This = impl_from_IMimeBody(iface);
1504 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1505 return E_NOTIMPL;
1508 static HRESULT WINAPI MimeBody_GetDataHere(
1509 IMimeBody* iface,
1510 ENCODINGTYPE ietEncoding,
1511 IStream* pStream)
1513 MimeBody *This = impl_from_IMimeBody(iface);
1514 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1515 return E_NOTIMPL;
1518 static const signed char base64_decode_table[] =
1520 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1521 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1522 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1523 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1524 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1525 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1526 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1527 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1530 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1532 const unsigned char *ptr, *end;
1533 unsigned char buf[1024];
1534 LARGE_INTEGER pos;
1535 unsigned char *ret;
1536 unsigned char in[4];
1537 IStream *output;
1538 DWORD size;
1539 int n = 0;
1540 HRESULT hres;
1542 pos.QuadPart = 0;
1543 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1544 if(FAILED(hres))
1545 return hres;
1547 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1548 if(FAILED(hres))
1549 return hres;
1551 while(1) {
1552 hres = IStream_Read(input, buf, sizeof(buf), &size);
1553 if(FAILED(hres) || !size)
1554 break;
1556 ptr = ret = buf;
1557 end = buf + size;
1559 while(1) {
1560 /* skip invalid chars */
1561 while(ptr < end &&
1562 (*ptr >= sizeof(base64_decode_table)/sizeof(*base64_decode_table)
1563 || base64_decode_table[*ptr] == -1))
1564 ptr++;
1565 if(ptr == end)
1566 break;
1568 in[n++] = base64_decode_table[*ptr++];
1569 switch(n) {
1570 case 2:
1571 *ret++ = in[0] << 2 | in[1] >> 4;
1572 continue;
1573 case 3:
1574 *ret++ = in[1] << 4 | in[2] >> 2;
1575 continue;
1576 case 4:
1577 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1578 n = 0;
1582 if(ret > buf) {
1583 hres = IStream_Write(output, buf, ret - buf, NULL);
1584 if(FAILED(hres))
1585 break;
1589 if(SUCCEEDED(hres))
1590 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1591 if(FAILED(hres)) {
1592 IStream_Release(output);
1593 return hres;
1596 *ret_stream = output;
1597 return S_OK;
1600 static HRESULT WINAPI MimeBody_GetData(
1601 IMimeBody* iface,
1602 ENCODINGTYPE ietEncoding,
1603 IStream** ppStream)
1605 MimeBody *This = impl_from_IMimeBody(iface);
1606 ULARGE_INTEGER start, size;
1607 HRESULT hres;
1609 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1611 if(This->encoding != ietEncoding) {
1612 switch(This->encoding) {
1613 case IET_BASE64:
1614 if(ietEncoding != IET_BINARY)
1615 FIXME("Encofing %d is not supported.\n", ietEncoding);
1616 return decode_base64(This->data, ppStream);
1617 default:
1618 FIXME("Decoding %d is not supported.\n", This->encoding);
1622 start.QuadPart = 0;
1623 hres = get_stream_size(This->data, &size);
1624 if(SUCCEEDED(hres))
1625 hres = create_sub_stream(This->data, start, size, ppStream);
1626 return hres;
1629 static HRESULT WINAPI MimeBody_SetData(
1630 IMimeBody* iface,
1631 ENCODINGTYPE ietEncoding,
1632 LPCSTR pszPriType,
1633 LPCSTR pszSubType,
1634 REFIID riid,
1635 LPVOID pvObject)
1637 MimeBody *This = impl_from_IMimeBody(iface);
1638 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1639 debugstr_guid(riid), pvObject);
1641 if(IsEqualIID(riid, &IID_IStream))
1642 IStream_AddRef((IStream *)pvObject);
1643 else
1645 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1646 return E_INVALIDARG;
1649 if(This->data)
1650 FIXME("release old data\n");
1652 This->data_iid = *riid;
1653 This->data = pvObject;
1655 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1657 /* FIXME: Update the content type.
1658 If pszPriType == NULL use 'application'
1659 If pszSubType == NULL use 'octet-stream' */
1661 return S_OK;
1664 static HRESULT WINAPI MimeBody_EmptyData(
1665 IMimeBody* iface)
1667 MimeBody *This = impl_from_IMimeBody(iface);
1668 FIXME("(%p)->() stub\n", This);
1669 return E_NOTIMPL;
1672 static HRESULT WINAPI MimeBody_CopyTo(
1673 IMimeBody* iface,
1674 IMimeBody* pBody)
1676 MimeBody *This = impl_from_IMimeBody(iface);
1677 FIXME("(%p)->(%p) stub\n", This, pBody);
1678 return E_NOTIMPL;
1681 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1682 IMimeBody* iface,
1683 LPTRANSMITINFO pTransmitInfo)
1685 MimeBody *This = impl_from_IMimeBody(iface);
1686 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1687 return E_NOTIMPL;
1690 static HRESULT WINAPI MimeBody_SaveToFile(
1691 IMimeBody* iface,
1692 ENCODINGTYPE ietEncoding,
1693 LPCSTR pszFilePath)
1695 MimeBody *This = impl_from_IMimeBody(iface);
1696 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1697 return E_NOTIMPL;
1700 static HRESULT WINAPI MimeBody_GetHandle(
1701 IMimeBody* iface,
1702 LPHBODY phBody)
1704 MimeBody *This = impl_from_IMimeBody(iface);
1705 TRACE("(%p)->(%p)\n", iface, phBody);
1707 if(!phBody)
1708 return E_INVALIDARG;
1710 *phBody = This->handle;
1711 return This->handle ? S_OK : MIME_E_NO_DATA;
1714 static IMimeBodyVtbl body_vtbl =
1716 MimeBody_QueryInterface,
1717 MimeBody_AddRef,
1718 MimeBody_Release,
1719 MimeBody_GetClassID,
1720 MimeBody_IsDirty,
1721 MimeBody_Load,
1722 MimeBody_Save,
1723 MimeBody_GetSizeMax,
1724 MimeBody_InitNew,
1725 MimeBody_GetPropInfo,
1726 MimeBody_SetPropInfo,
1727 MimeBody_GetProp,
1728 MimeBody_SetProp,
1729 MimeBody_AppendProp,
1730 MimeBody_DeleteProp,
1731 MimeBody_CopyProps,
1732 MimeBody_MoveProps,
1733 MimeBody_DeleteExcept,
1734 MimeBody_QueryProp,
1735 MimeBody_GetCharset,
1736 MimeBody_SetCharset,
1737 MimeBody_GetParameters,
1738 MimeBody_IsContentType,
1739 MimeBody_BindToObject,
1740 MimeBody_Clone,
1741 MimeBody_SetOption,
1742 MimeBody_GetOption,
1743 MimeBody_EnumProps,
1744 MimeBody_IsType,
1745 MimeBody_SetDisplayName,
1746 MimeBody_GetDisplayName,
1747 MimeBody_GetOffsets,
1748 MimeBody_GetCurrentEncoding,
1749 MimeBody_SetCurrentEncoding,
1750 MimeBody_GetEstimatedSize,
1751 MimeBody_GetDataHere,
1752 MimeBody_GetData,
1753 MimeBody_SetData,
1754 MimeBody_EmptyData,
1755 MimeBody_CopyTo,
1756 MimeBody_GetTransmitInfo,
1757 MimeBody_SaveToFile,
1758 MimeBody_GetHandle
1761 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1763 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1764 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1766 body->body_offsets = *offsets;
1767 return S_OK;
1770 #define FIRST_CUSTOM_PROP_ID 0x100
1772 static MimeBody *mimebody_create(void)
1774 MimeBody *This;
1775 BODYOFFSETS body_offsets;
1777 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1778 if (!This)
1779 return NULL;
1781 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1782 This->ref = 1;
1783 This->handle = NULL;
1784 list_init(&This->headers);
1785 list_init(&This->new_props);
1786 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1787 This->content_pri_type = NULL;
1788 This->content_sub_type = NULL;
1789 This->encoding = IET_7BIT;
1790 This->data = NULL;
1791 This->data_iid = IID_NULL;
1793 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1794 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1795 MimeBody_set_offsets(This, &body_offsets);
1797 return This;
1800 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1802 MimeBody *mb;
1804 if(outer)
1805 return CLASS_E_NOAGGREGATION;
1807 if ((mb = mimebody_create()))
1809 *ppv = &mb->IMimeBody_iface;
1810 return S_OK;
1812 else
1814 *ppv = NULL;
1815 return E_OUTOFMEMORY;
1819 typedef struct body_t
1821 struct list entry;
1822 DWORD index;
1823 MimeBody *mime_body;
1825 struct body_t *parent;
1826 struct list children;
1827 } body_t;
1829 typedef struct MimeMessage
1831 IMimeMessage IMimeMessage_iface;
1832 LONG ref;
1833 IStream *stream;
1835 struct list body_tree;
1836 DWORD next_index;
1837 } MimeMessage;
1839 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1841 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1844 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1846 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1848 if (IsEqualIID(riid, &IID_IUnknown) ||
1849 IsEqualIID(riid, &IID_IPersist) ||
1850 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1851 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1852 IsEqualIID(riid, &IID_IMimeMessage))
1854 *ppv = iface;
1855 IMimeMessage_AddRef(iface);
1856 return S_OK;
1859 FIXME("no interface for %s\n", debugstr_guid(riid));
1860 *ppv = NULL;
1861 return E_NOINTERFACE;
1864 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1866 MimeMessage *This = impl_from_IMimeMessage(iface);
1867 ULONG ref = InterlockedIncrement(&This->ref);
1869 TRACE("(%p) ref=%d\n", This, ref);
1871 return ref;
1874 static void empty_body_list(struct list *list)
1876 body_t *body, *cursor2;
1877 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1879 empty_body_list(&body->children);
1880 list_remove(&body->entry);
1881 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1882 HeapFree(GetProcessHeap(), 0, body);
1886 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1888 MimeMessage *This = impl_from_IMimeMessage(iface);
1889 ULONG ref = InterlockedDecrement(&This->ref);
1891 TRACE("(%p) ref=%d\n", This, ref);
1893 if (!ref)
1895 empty_body_list(&This->body_tree);
1897 if(This->stream) IStream_Release(This->stream);
1898 HeapFree(GetProcessHeap(), 0, This);
1901 return ref;
1904 /*** IPersist methods ***/
1905 static HRESULT WINAPI MimeMessage_GetClassID(
1906 IMimeMessage *iface,
1907 CLSID *pClassID)
1909 FIXME("(%p)->(%p)\n", iface, pClassID);
1910 return E_NOTIMPL;
1913 /*** IPersistStreamInit methods ***/
1914 static HRESULT WINAPI MimeMessage_IsDirty(
1915 IMimeMessage *iface)
1917 FIXME("(%p)->()\n", iface);
1918 return E_NOTIMPL;
1921 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
1923 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
1924 if(body)
1926 body->mime_body = mime_body;
1927 body->index = index;
1928 list_init(&body->children);
1929 body->parent = parent;
1931 mime_body->handle = UlongToHandle(body->index);
1933 return body;
1936 typedef struct
1938 struct list entry;
1939 BODYOFFSETS offsets;
1940 } offset_entry_t;
1942 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
1944 HRESULT hr;
1945 DWORD read;
1946 int boundary_len = strlen(boundary);
1947 char *buf, *nl_boundary, *ptr, *overlap;
1948 DWORD start = 0, overlap_no;
1949 offset_entry_t *cur_body = NULL;
1950 ULARGE_INTEGER cur;
1951 LARGE_INTEGER zero;
1953 list_init(body_offsets);
1954 nl_boundary = HeapAlloc(GetProcessHeap(), 0, 4 + boundary_len + 1);
1955 memcpy(nl_boundary, "\r\n--", 4);
1956 memcpy(nl_boundary + 4, boundary, boundary_len + 1);
1958 overlap_no = boundary_len + 5;
1960 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
1962 zero.QuadPart = 0;
1963 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
1964 start = cur.u.LowPart;
1966 do {
1967 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
1968 if(FAILED(hr)) goto end;
1969 if(read == 0) break;
1970 overlap[read] = '\0';
1972 ptr = buf;
1973 do {
1974 ptr = strstr(ptr, nl_boundary);
1975 if(ptr)
1977 DWORD boundary_start = start + ptr - buf;
1978 char *end = ptr + boundary_len + 4;
1980 if(*end == '\0' || *(end + 1) == '\0')
1981 break;
1983 if(*end == '\r' && *(end + 1) == '\n')
1985 if(cur_body)
1987 cur_body->offsets.cbBodyEnd = boundary_start;
1988 list_add_tail(body_offsets, &cur_body->entry);
1990 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
1991 cur_body->offsets.cbBoundaryStart = boundary_start + 2; /* doesn't including the leading \r\n */
1992 cur_body->offsets.cbHeaderStart = boundary_start + boundary_len + 6;
1994 else if(*end == '-' && *(end + 1) == '-')
1996 if(cur_body)
1998 cur_body->offsets.cbBodyEnd = boundary_start;
1999 list_add_tail(body_offsets, &cur_body->entry);
2000 goto end;
2003 ptr = end + 2;
2005 } while(ptr);
2007 if(overlap == buf) /* 1st iteration */
2009 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2010 overlap = buf + overlap_no;
2011 start += read - overlap_no;
2013 else
2015 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2016 start += read;
2018 } while(1);
2020 end:
2021 HeapFree(GetProcessHeap(), 0, nl_boundary);
2022 HeapFree(GetProcessHeap(), 0, buf);
2023 return hr;
2026 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2028 MimeBody *mime_body;
2029 HRESULT hr;
2030 body_t *body;
2031 ULARGE_INTEGER cur;
2032 LARGE_INTEGER zero;
2034 mime_body = mimebody_create();
2035 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2036 zero.QuadPart = 0;
2037 hr = IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &cur);
2038 offset->cbBodyStart = cur.u.LowPart + offset->cbHeaderStart;
2039 if (parent) MimeBody_set_offsets(mime_body, offset);
2040 IMimeBody_SetData(&mime_body->IMimeBody_iface, IET_BINARY, NULL, NULL, &IID_IStream, pStm);
2041 body = new_body_entry(mime_body, msg->next_index++, parent);
2043 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2045 MIMEPARAMINFO *param_info;
2046 ULONG count, i;
2047 IMimeAllocator *alloc;
2049 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2050 &param_info);
2051 if(hr != S_OK || count == 0) return body;
2053 MimeOleGetAllocator(&alloc);
2055 for(i = 0; i < count; i++)
2057 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2059 struct list offset_list;
2060 offset_entry_t *cur, *cursor2;
2061 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2062 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2064 body_t *sub_body;
2065 IStream *sub_stream;
2066 ULARGE_INTEGER start, length;
2068 start.QuadPart = cur->offsets.cbHeaderStart;
2069 length.QuadPart = cur->offsets.cbBodyEnd - cur->offsets.cbHeaderStart;
2070 create_sub_stream(pStm, start, length, &sub_stream);
2071 sub_body = create_sub_body(msg, sub_stream, &cur->offsets, body);
2072 IStream_Release(sub_stream);
2073 list_add_tail(&body->children, &sub_body->entry);
2074 list_remove(&cur->entry);
2075 HeapFree(GetProcessHeap(), 0, cur);
2077 break;
2080 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2081 IMimeAllocator_Release(alloc);
2083 return body;
2086 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2088 MimeMessage *This = impl_from_IMimeMessage(iface);
2089 body_t *root_body;
2090 BODYOFFSETS offsets;
2091 ULARGE_INTEGER cur;
2092 LARGE_INTEGER zero;
2094 TRACE("(%p)->(%p)\n", iface, pStm);
2096 if(This->stream)
2098 FIXME("already loaded a message\n");
2099 return E_FAIL;
2102 empty_body_list(&This->body_tree);
2104 IStream_AddRef(pStm);
2105 This->stream = pStm;
2106 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2107 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2109 root_body = create_sub_body(This, pStm, &offsets, NULL);
2111 zero.QuadPart = 0;
2112 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2113 offsets.cbBodyEnd = cur.u.LowPart;
2114 MimeBody_set_offsets(root_body->mime_body, &offsets);
2116 list_add_head(&This->body_tree, &root_body->entry);
2118 return S_OK;
2121 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2123 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2124 return E_NOTIMPL;
2127 static HRESULT WINAPI MimeMessage_GetSizeMax(
2128 IMimeMessage *iface,
2129 ULARGE_INTEGER *pcbSize)
2131 FIXME("(%p)->(%p)\n", iface, pcbSize);
2132 return E_NOTIMPL;
2135 static HRESULT WINAPI MimeMessage_InitNew(
2136 IMimeMessage *iface)
2138 FIXME("(%p)->()\n", iface);
2139 return E_NOTIMPL;
2142 /*** IMimeMessageTree methods ***/
2143 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2144 DWORD dwFlags)
2146 MimeMessage *This = impl_from_IMimeMessage(iface);
2148 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
2150 IStream_AddRef(This->stream);
2151 *ppStream = This->stream;
2152 return S_OK;
2155 static HRESULT WINAPI MimeMessage_GetMessageSize(
2156 IMimeMessage *iface,
2157 ULONG *pcbSize,
2158 DWORD dwFlags)
2160 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
2161 return E_NOTIMPL;
2164 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2165 IMimeMessage *iface,
2166 IStream *pStream)
2168 FIXME("(%p)->(%p)\n", iface, pStream);
2169 return E_NOTIMPL;
2172 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2173 IMimeMessage *iface,
2174 IStream *pStream,
2175 DWORD dwFlags)
2177 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
2178 return E_NOTIMPL;
2182 static HRESULT WINAPI MimeMessage_GetFlags(
2183 IMimeMessage *iface,
2184 DWORD *pdwFlags)
2186 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2187 return E_NOTIMPL;
2190 static HRESULT WINAPI MimeMessage_Commit(
2191 IMimeMessage *iface,
2192 DWORD dwFlags)
2194 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
2195 return S_OK;
2199 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2200 IMimeMessage *iface)
2202 FIXME("(%p)->()\n", iface);
2203 return E_NOTIMPL;
2206 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2208 body_t *cur;
2209 HRESULT hr;
2211 if(hbody == HBODY_ROOT)
2213 *body = LIST_ENTRY(list_head(list), body_t, entry);
2214 return S_OK;
2217 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2219 if(cur->index == HandleToUlong(hbody))
2221 *body = cur;
2222 return S_OK;
2224 hr = find_body(&cur->children, hbody, body);
2225 if(hr == S_OK) return S_OK;
2227 return S_FALSE;
2230 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2231 void **ppvObject)
2233 MimeMessage *This = impl_from_IMimeMessage(iface);
2234 HRESULT hr;
2235 body_t *body;
2237 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2239 hr = find_body(&This->body_tree, hBody, &body);
2241 if(hr != S_OK) return hr;
2243 if(IsEqualIID(riid, &IID_IMimeBody))
2245 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2246 *ppvObject = &body->mime_body->IMimeBody_iface;
2247 return S_OK;
2250 return E_NOINTERFACE;
2253 static HRESULT WINAPI MimeMessage_SaveBody(
2254 IMimeMessage *iface,
2255 HBODY hBody,
2256 DWORD dwFlags,
2257 IStream *pStream)
2259 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
2260 return E_NOTIMPL;
2263 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2265 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2266 body_t *body;
2267 HRESULT hr;
2268 struct list *list;
2270 if(location == IBL_ROOT)
2272 *out = root;
2273 return S_OK;
2276 hr = find_body(&msg->body_tree, pivot, &body);
2278 if(hr == S_OK)
2280 switch(location)
2282 case IBL_PARENT:
2283 if(body->parent)
2284 *out = body->parent;
2285 else
2286 hr = MIME_E_NOT_FOUND;
2287 break;
2289 case IBL_FIRST:
2290 list = list_head(&body->children);
2291 if(list)
2292 *out = LIST_ENTRY(list, body_t, entry);
2293 else
2294 hr = MIME_E_NOT_FOUND;
2295 break;
2297 case IBL_LAST:
2298 list = list_tail(&body->children);
2299 if(list)
2300 *out = LIST_ENTRY(list, body_t, entry);
2301 else
2302 hr = MIME_E_NOT_FOUND;
2303 break;
2305 case IBL_NEXT:
2306 list = list_next(&body->parent->children, &body->entry);
2307 if(list)
2308 *out = LIST_ENTRY(list, body_t, entry);
2309 else
2310 hr = MIME_E_NOT_FOUND;
2311 break;
2313 case IBL_PREVIOUS:
2314 list = list_prev(&body->parent->children, &body->entry);
2315 if(list)
2316 *out = LIST_ENTRY(list, body_t, entry);
2317 else
2318 hr = MIME_E_NOT_FOUND;
2319 break;
2321 default:
2322 hr = E_FAIL;
2323 break;
2327 return hr;
2331 static HRESULT WINAPI MimeMessage_InsertBody(
2332 IMimeMessage *iface,
2333 BODYLOCATION location,
2334 HBODY hPivot,
2335 LPHBODY phBody)
2337 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2338 return E_NOTIMPL;
2341 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2342 HBODY *phBody)
2344 MimeMessage *This = impl_from_IMimeMessage(iface);
2345 body_t *body;
2346 HRESULT hr;
2348 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2350 if(!phBody)
2351 return E_INVALIDARG;
2353 *phBody = NULL;
2355 hr = get_body(This, location, hPivot, &body);
2357 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2359 return hr;
2362 static HRESULT WINAPI MimeMessage_DeleteBody(
2363 IMimeMessage *iface,
2364 HBODY hBody,
2365 DWORD dwFlags)
2367 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
2368 return E_NOTIMPL;
2371 static HRESULT WINAPI MimeMessage_MoveBody(
2372 IMimeMessage *iface,
2373 HBODY hBody,
2374 BODYLOCATION location)
2376 FIXME("(%p)->(%d)\n", iface, location);
2377 return E_NOTIMPL;
2380 static void count_children(body_t *body, boolean recurse, ULONG *count)
2382 body_t *child;
2384 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2386 (*count)++;
2387 if(recurse) count_children(child, recurse, count);
2391 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2392 ULONG *pcBodies)
2394 HRESULT hr;
2395 MimeMessage *This = impl_from_IMimeMessage(iface);
2396 body_t *body;
2398 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2400 hr = find_body(&This->body_tree, hParent, &body);
2401 if(hr != S_OK) return hr;
2403 *pcBodies = 1;
2404 count_children(body, fRecurse, pcBodies);
2406 return S_OK;
2409 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2411 struct list *ptr;
2412 HBODY next;
2414 for (;;)
2416 if (!body) ptr = list_head( &This->body_tree );
2417 else
2419 ptr = list_head( &body->children );
2420 while (!ptr)
2422 if (!body->parent) return MIME_E_NOT_FOUND;
2423 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2427 body = LIST_ENTRY( ptr, body_t, entry );
2428 next = UlongToHandle( body->index );
2429 find->dwReserved = body->index;
2430 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2431 find->pszSubType) == S_OK)
2433 *out = next;
2434 return S_OK;
2437 return MIME_E_NOT_FOUND;
2440 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2442 MimeMessage *This = impl_from_IMimeMessage(iface);
2444 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2446 pFindBody->dwReserved = 0;
2447 return find_next(This, NULL, pFindBody, phBody);
2450 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2452 MimeMessage *This = impl_from_IMimeMessage(iface);
2453 body_t *body;
2454 HRESULT hr;
2456 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2458 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2459 if (hr != S_OK) return MIME_E_NOT_FOUND;
2460 return find_next(This, body, pFindBody, phBody);
2463 static HRESULT WINAPI MimeMessage_ResolveURL(
2464 IMimeMessage *iface,
2465 HBODY hRelated,
2466 LPCSTR pszBase,
2467 LPCSTR pszURL,
2468 DWORD dwFlags,
2469 LPHBODY phBody)
2471 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2472 return E_NOTIMPL;
2475 static HRESULT WINAPI MimeMessage_ToMultipart(
2476 IMimeMessage *iface,
2477 HBODY hBody,
2478 LPCSTR pszSubType,
2479 LPHBODY phMultipart)
2481 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2482 return E_NOTIMPL;
2485 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2486 IMimeMessage *iface,
2487 HBODY hBody,
2488 LPBODYOFFSETS pOffsets)
2490 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2491 return E_NOTIMPL;
2494 static HRESULT WINAPI MimeMessage_GetCharset(
2495 IMimeMessage *iface,
2496 LPHCHARSET phCharset)
2498 FIXME("(%p)->(%p)\n", iface, phCharset);
2499 *phCharset = NULL;
2500 return S_OK;
2503 static HRESULT WINAPI MimeMessage_SetCharset(
2504 IMimeMessage *iface,
2505 HCHARSET hCharset,
2506 CSETAPPLYTYPE applytype)
2508 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2509 return E_NOTIMPL;
2512 static HRESULT WINAPI MimeMessage_IsBodyType(
2513 IMimeMessage *iface,
2514 HBODY hBody,
2515 IMSGBODYTYPE bodytype)
2517 HRESULT hr;
2518 IMimeBody *mime_body;
2519 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2521 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2522 if(hr != S_OK) return hr;
2524 hr = IMimeBody_IsType(mime_body, bodytype);
2525 MimeBody_Release(mime_body);
2526 return hr;
2529 static HRESULT WINAPI MimeMessage_IsContentType(
2530 IMimeMessage *iface,
2531 HBODY hBody,
2532 LPCSTR pszPriType,
2533 LPCSTR pszSubType)
2535 HRESULT hr;
2536 IMimeBody *mime_body;
2537 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2538 debugstr_a(pszSubType));
2540 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2541 if(FAILED(hr)) return hr;
2543 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2544 IMimeBody_Release(mime_body);
2545 return hr;
2548 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2549 IMimeMessage *iface,
2550 HBODY hBody,
2551 LPCSTR pszName,
2552 LPCSTR pszCriteria,
2553 boolean fSubString,
2554 boolean fCaseSensitive)
2556 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2557 return E_NOTIMPL;
2560 static HRESULT WINAPI MimeMessage_GetBodyProp(
2561 IMimeMessage *iface,
2562 HBODY hBody,
2563 LPCSTR pszName,
2564 DWORD dwFlags,
2565 LPPROPVARIANT pValue)
2567 HRESULT hr;
2568 IMimeBody *mime_body;
2570 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2572 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2573 if(hr != S_OK) return hr;
2575 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2576 IMimeBody_Release(mime_body);
2578 return hr;
2581 static HRESULT WINAPI MimeMessage_SetBodyProp(
2582 IMimeMessage *iface,
2583 HBODY hBody,
2584 LPCSTR pszName,
2585 DWORD dwFlags,
2586 LPCPROPVARIANT pValue)
2588 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2589 return E_NOTIMPL;
2592 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2593 IMimeMessage *iface,
2594 HBODY hBody,
2595 LPCSTR pszName)
2597 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2598 return E_NOTIMPL;
2601 static HRESULT WINAPI MimeMessage_SetOption(
2602 IMimeMessage *iface,
2603 const TYPEDID oid,
2604 LPCPROPVARIANT pValue)
2606 HRESULT hr = S_OK;
2607 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2609 /* Message ID is checked before type.
2610 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2612 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2614 WARN("oid (%08x) out of range\n", oid);
2615 return MIME_E_INVALID_OPTION_ID;
2618 if(pValue->vt != TYPEDID_TYPE(oid))
2620 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2621 return S_OK;
2624 switch(oid)
2626 case OID_HIDE_TNEF_ATTACHMENTS:
2627 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2628 break;
2629 case OID_SHOW_MACBINARY:
2630 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2631 break;
2632 case OID_SAVEBODY_KEEPBOUNDARY:
2633 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal);
2634 break;
2635 case OID_CLEANUP_TREE_ON_SAVE:
2636 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal);
2637 break;
2638 default:
2639 FIXME("Unhandled oid %08x\n", oid);
2640 hr = MIME_E_INVALID_OPTION_ID;
2643 return hr;
2646 static HRESULT WINAPI MimeMessage_GetOption(
2647 IMimeMessage *iface,
2648 const TYPEDID oid,
2649 LPPROPVARIANT pValue)
2651 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2652 return E_NOTIMPL;
2655 /*** IMimeMessage methods ***/
2656 static HRESULT WINAPI MimeMessage_CreateWebPage(
2657 IMimeMessage *iface,
2658 IStream *pRootStm,
2659 LPWEBPAGEOPTIONS pOptions,
2660 IMimeMessageCallback *pCallback,
2661 IMoniker **ppMoniker)
2663 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2664 *ppMoniker = NULL;
2665 return E_NOTIMPL;
2668 static HRESULT WINAPI MimeMessage_GetProp(
2669 IMimeMessage *iface,
2670 LPCSTR pszName,
2671 DWORD dwFlags,
2672 LPPROPVARIANT pValue)
2674 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2675 return E_NOTIMPL;
2678 static HRESULT WINAPI MimeMessage_SetProp(
2679 IMimeMessage *iface,
2680 LPCSTR pszName,
2681 DWORD dwFlags,
2682 LPCPROPVARIANT pValue)
2684 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2685 return E_NOTIMPL;
2688 static HRESULT WINAPI MimeMessage_DeleteProp(
2689 IMimeMessage *iface,
2690 LPCSTR pszName)
2692 FIXME("(%p)->(%s)\n", iface, pszName);
2693 return E_NOTIMPL;
2696 static HRESULT WINAPI MimeMessage_QueryProp(
2697 IMimeMessage *iface,
2698 LPCSTR pszName,
2699 LPCSTR pszCriteria,
2700 boolean fSubString,
2701 boolean fCaseSensitive)
2703 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2704 return E_NOTIMPL;
2707 static HRESULT WINAPI MimeMessage_GetTextBody(
2708 IMimeMessage *iface,
2709 DWORD dwTxtType,
2710 ENCODINGTYPE ietEncoding,
2711 IStream **pStream,
2712 LPHBODY phBody)
2714 HRESULT hr;
2715 HBODY hbody;
2716 FINDBODY find_struct;
2717 IMimeBody *mime_body;
2718 static char text[] = "text";
2719 static char plain[] = "plain";
2720 static char html[] = "html";
2722 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2724 find_struct.pszPriType = text;
2726 switch(dwTxtType)
2728 case TXT_PLAIN:
2729 find_struct.pszSubType = plain;
2730 break;
2731 case TXT_HTML:
2732 find_struct.pszSubType = html;
2733 break;
2734 default:
2735 return MIME_E_INVALID_TEXT_TYPE;
2738 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2739 if(hr != S_OK)
2741 TRACE("not found hr %08x\n", hr);
2742 *phBody = NULL;
2743 return hr;
2746 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2748 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2749 *phBody = hbody;
2750 IMimeBody_Release(mime_body);
2751 return hr;
2754 static HRESULT WINAPI MimeMessage_SetTextBody(
2755 IMimeMessage *iface,
2756 DWORD dwTxtType,
2757 ENCODINGTYPE ietEncoding,
2758 HBODY hAlternative,
2759 IStream *pStream,
2760 LPHBODY phBody)
2762 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2763 return E_NOTIMPL;
2766 static HRESULT WINAPI MimeMessage_AttachObject(
2767 IMimeMessage *iface,
2768 REFIID riid,
2769 void *pvObject,
2770 LPHBODY phBody)
2772 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2773 return E_NOTIMPL;
2776 static HRESULT WINAPI MimeMessage_AttachFile(
2777 IMimeMessage *iface,
2778 LPCSTR pszFilePath,
2779 IStream *pstmFile,
2780 LPHBODY phBody)
2782 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2783 return E_NOTIMPL;
2786 static HRESULT WINAPI MimeMessage_AttachURL(
2787 IMimeMessage *iface,
2788 LPCSTR pszBase,
2789 LPCSTR pszURL,
2790 DWORD dwFlags,
2791 IStream *pstmURL,
2792 LPSTR *ppszCIDURL,
2793 LPHBODY phBody)
2795 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2796 return E_NOTIMPL;
2799 static HRESULT WINAPI MimeMessage_GetAttachments(
2800 IMimeMessage *iface,
2801 ULONG *pcAttach,
2802 LPHBODY *pprghAttach)
2804 HRESULT hr;
2805 FINDBODY find_struct;
2806 HBODY hbody;
2807 LPHBODY array;
2808 ULONG size = 10;
2810 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2812 *pcAttach = 0;
2813 array = CoTaskMemAlloc(size * sizeof(HBODY));
2815 find_struct.pszPriType = find_struct.pszSubType = NULL;
2816 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2817 while(hr == S_OK)
2819 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2820 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2821 if(hr != S_OK)
2823 if(*pcAttach + 1 > size)
2825 size *= 2;
2826 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2828 array[*pcAttach] = hbody;
2829 (*pcAttach)++;
2831 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2834 *pprghAttach = array;
2835 return S_OK;
2838 static HRESULT WINAPI MimeMessage_GetAddressTable(
2839 IMimeMessage *iface,
2840 IMimeAddressTable **ppTable)
2842 FIXME("(%p)->(%p)\n", iface, ppTable);
2843 return E_NOTIMPL;
2846 static HRESULT WINAPI MimeMessage_GetSender(
2847 IMimeMessage *iface,
2848 LPADDRESSPROPS pAddress)
2850 FIXME("(%p)->(%p)\n", iface, pAddress);
2851 return E_NOTIMPL;
2854 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2855 IMimeMessage *iface,
2856 DWORD dwAdrTypes,
2857 DWORD dwProps,
2858 LPADDRESSLIST pList)
2860 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2861 return E_NOTIMPL;
2864 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2865 IMimeMessage *iface,
2866 DWORD dwAdrTypes,
2867 ADDRESSFORMAT format,
2868 LPSTR *ppszFormat)
2870 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2871 return E_NOTIMPL;
2874 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2875 IMimeMessage *iface,
2876 DWORD dwAdrTypes,
2877 DWORD dwProps,
2878 IMimeEnumAddressTypes **ppEnum)
2880 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2881 return E_NOTIMPL;
2884 static HRESULT WINAPI MimeMessage_SplitMessage(
2885 IMimeMessage *iface,
2886 ULONG cbMaxPart,
2887 IMimeMessageParts **ppParts)
2889 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
2890 return E_NOTIMPL;
2893 static HRESULT WINAPI MimeMessage_GetRootMoniker(
2894 IMimeMessage *iface,
2895 IMoniker **ppMoniker)
2897 FIXME("(%p)->(%p)\n", iface, ppMoniker);
2898 return E_NOTIMPL;
2901 static const IMimeMessageVtbl MimeMessageVtbl =
2903 MimeMessage_QueryInterface,
2904 MimeMessage_AddRef,
2905 MimeMessage_Release,
2906 MimeMessage_GetClassID,
2907 MimeMessage_IsDirty,
2908 MimeMessage_Load,
2909 MimeMessage_Save,
2910 MimeMessage_GetSizeMax,
2911 MimeMessage_InitNew,
2912 MimeMessage_GetMessageSource,
2913 MimeMessage_GetMessageSize,
2914 MimeMessage_LoadOffsetTable,
2915 MimeMessage_SaveOffsetTable,
2916 MimeMessage_GetFlags,
2917 MimeMessage_Commit,
2918 MimeMessage_HandsOffStorage,
2919 MimeMessage_BindToObject,
2920 MimeMessage_SaveBody,
2921 MimeMessage_InsertBody,
2922 MimeMessage_GetBody,
2923 MimeMessage_DeleteBody,
2924 MimeMessage_MoveBody,
2925 MimeMessage_CountBodies,
2926 MimeMessage_FindFirst,
2927 MimeMessage_FindNext,
2928 MimeMessage_ResolveURL,
2929 MimeMessage_ToMultipart,
2930 MimeMessage_GetBodyOffsets,
2931 MimeMessage_GetCharset,
2932 MimeMessage_SetCharset,
2933 MimeMessage_IsBodyType,
2934 MimeMessage_IsContentType,
2935 MimeMessage_QueryBodyProp,
2936 MimeMessage_GetBodyProp,
2937 MimeMessage_SetBodyProp,
2938 MimeMessage_DeleteBodyProp,
2939 MimeMessage_SetOption,
2940 MimeMessage_GetOption,
2941 MimeMessage_CreateWebPage,
2942 MimeMessage_GetProp,
2943 MimeMessage_SetProp,
2944 MimeMessage_DeleteProp,
2945 MimeMessage_QueryProp,
2946 MimeMessage_GetTextBody,
2947 MimeMessage_SetTextBody,
2948 MimeMessage_AttachObject,
2949 MimeMessage_AttachFile,
2950 MimeMessage_AttachURL,
2951 MimeMessage_GetAttachments,
2952 MimeMessage_GetAddressTable,
2953 MimeMessage_GetSender,
2954 MimeMessage_GetAddressTypes,
2955 MimeMessage_GetAddressFormat,
2956 MimeMessage_EnumAddressTypes,
2957 MimeMessage_SplitMessage,
2958 MimeMessage_GetRootMoniker,
2961 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
2963 MimeMessage *This;
2964 MimeBody *mime_body;
2965 body_t *root_body;
2967 TRACE("(%p, %p)\n", outer, obj);
2969 if (outer)
2971 FIXME("outer unknown not supported yet\n");
2972 return E_NOTIMPL;
2975 *obj = NULL;
2977 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2978 if (!This) return E_OUTOFMEMORY;
2980 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
2981 This->ref = 1;
2982 This->stream = NULL;
2983 list_init(&This->body_tree);
2984 This->next_index = 1;
2986 mime_body = mimebody_create();
2987 root_body = new_body_entry(mime_body, This->next_index++, NULL);
2988 list_add_head(&This->body_tree, &root_body->entry);
2990 *obj = &This->IMimeMessage_iface;
2991 return S_OK;
2994 /***********************************************************************
2995 * MimeOleCreateMessage (INETCOMM.@)
2997 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
2999 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3000 return MimeMessage_create(NULL, (void **)ppMessage);
3003 /***********************************************************************
3004 * MimeOleSetCompatMode (INETCOMM.@)
3006 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3008 FIXME("(0x%x)\n", dwMode);
3009 return S_OK;
3012 /***********************************************************************
3013 * MimeOleCreateVirtualStream (INETCOMM.@)
3015 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3017 HRESULT hr;
3018 FIXME("(%p)\n", ppStream);
3020 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3021 return hr;
3024 typedef struct MimeSecurity
3026 IMimeSecurity IMimeSecurity_iface;
3027 LONG ref;
3028 } MimeSecurity;
3030 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3032 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3035 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3037 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3039 if (IsEqualIID(riid, &IID_IUnknown) ||
3040 IsEqualIID(riid, &IID_IMimeSecurity))
3042 *ppv = iface;
3043 IMimeSecurity_AddRef(iface);
3044 return S_OK;
3047 FIXME("no interface for %s\n", debugstr_guid(riid));
3048 *ppv = NULL;
3049 return E_NOINTERFACE;
3052 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3054 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3055 LONG ref = InterlockedIncrement(&This->ref);
3057 TRACE("(%p) ref=%d\n", This, ref);
3059 return ref;
3062 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3064 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3065 LONG ref = InterlockedDecrement(&This->ref);
3067 TRACE("(%p) ref=%d\n", This, ref);
3069 if (!ref)
3070 HeapFree(GetProcessHeap(), 0, This);
3072 return ref;
3075 static HRESULT WINAPI MimeSecurity_InitNew(
3076 IMimeSecurity* iface)
3078 FIXME("(%p)->(): stub\n", iface);
3079 return S_OK;
3082 static HRESULT WINAPI MimeSecurity_CheckInit(
3083 IMimeSecurity* iface)
3085 FIXME("(%p)->(): stub\n", iface);
3086 return E_NOTIMPL;
3089 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3090 IMimeSecurity* iface,
3091 IMimeMessageTree* pTree,
3092 DWORD dwFlags)
3094 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3095 return E_NOTIMPL;
3098 static HRESULT WINAPI MimeSecurity_EncodeBody(
3099 IMimeSecurity* iface,
3100 IMimeMessageTree* pTree,
3101 HBODY hEncodeRoot,
3102 DWORD dwFlags)
3104 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3105 return E_NOTIMPL;
3108 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3109 IMimeSecurity* iface,
3110 IMimeMessageTree* pTree,
3111 DWORD dwFlags)
3113 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3114 return E_NOTIMPL;
3117 static HRESULT WINAPI MimeSecurity_DecodeBody(
3118 IMimeSecurity* iface,
3119 IMimeMessageTree* pTree,
3120 HBODY hDecodeRoot,
3121 DWORD dwFlags)
3123 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3124 return E_NOTIMPL;
3127 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3128 IMimeSecurity* iface,
3129 HCAPICERTSTORE hc,
3130 DWORD dwUsage,
3131 PCX509CERT pPrev,
3132 PCX509CERT* ppCert)
3134 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3135 return E_NOTIMPL;
3138 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3139 IMimeSecurity* iface,
3140 const PCX509CERT pX509Cert,
3141 const CERTNAMETYPE cn,
3142 LPSTR* ppszName)
3144 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3145 return E_NOTIMPL;
3148 static HRESULT WINAPI MimeSecurity_GetMessageType(
3149 IMimeSecurity* iface,
3150 const HWND hwndParent,
3151 IMimeBody* pBody,
3152 DWORD* pdwSecType)
3154 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3155 return E_NOTIMPL;
3158 static HRESULT WINAPI MimeSecurity_GetCertData(
3159 IMimeSecurity* iface,
3160 const PCX509CERT pX509Cert,
3161 const CERTDATAID dataid,
3162 LPPROPVARIANT pValue)
3164 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3165 return E_NOTIMPL;
3169 static const IMimeSecurityVtbl MimeSecurityVtbl =
3171 MimeSecurity_QueryInterface,
3172 MimeSecurity_AddRef,
3173 MimeSecurity_Release,
3174 MimeSecurity_InitNew,
3175 MimeSecurity_CheckInit,
3176 MimeSecurity_EncodeMessage,
3177 MimeSecurity_EncodeBody,
3178 MimeSecurity_DecodeMessage,
3179 MimeSecurity_DecodeBody,
3180 MimeSecurity_EnumCertificates,
3181 MimeSecurity_GetCertificateName,
3182 MimeSecurity_GetMessageType,
3183 MimeSecurity_GetCertData
3186 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3188 MimeSecurity *This;
3190 *obj = NULL;
3192 if (outer) return CLASS_E_NOAGGREGATION;
3194 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3195 if (!This) return E_OUTOFMEMORY;
3197 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3198 This->ref = 1;
3200 *obj = &This->IMimeSecurity_iface;
3201 return S_OK;
3204 /***********************************************************************
3205 * MimeOleCreateSecurity (INETCOMM.@)
3207 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3209 return MimeSecurity_create(NULL, (void **)ppSecurity);
3212 static HRESULT WINAPI MimeAlloc_QueryInterface(
3213 IMimeAllocator* iface,
3214 REFIID riid,
3215 void **obj)
3217 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3219 if (IsEqualIID(riid, &IID_IUnknown) ||
3220 IsEqualIID(riid, &IID_IMalloc) ||
3221 IsEqualIID(riid, &IID_IMimeAllocator))
3223 *obj = iface;
3224 IMimeAllocator_AddRef(iface);
3225 return S_OK;
3228 FIXME("no interface for %s\n", debugstr_guid(riid));
3229 *obj = NULL;
3230 return E_NOINTERFACE;
3233 static ULONG WINAPI MimeAlloc_AddRef(
3234 IMimeAllocator* iface)
3236 return 2;
3239 static ULONG WINAPI MimeAlloc_Release(
3240 IMimeAllocator* iface)
3242 return 1;
3245 static LPVOID WINAPI MimeAlloc_Alloc(
3246 IMimeAllocator* iface,
3247 SIZE_T cb)
3249 return CoTaskMemAlloc(cb);
3252 static LPVOID WINAPI MimeAlloc_Realloc(
3253 IMimeAllocator* iface,
3254 LPVOID pv,
3255 SIZE_T cb)
3257 return CoTaskMemRealloc(pv, cb);
3260 static void WINAPI MimeAlloc_Free(
3261 IMimeAllocator* iface,
3262 LPVOID pv)
3264 CoTaskMemFree(pv);
3267 static SIZE_T WINAPI MimeAlloc_GetSize(
3268 IMimeAllocator* iface,
3269 LPVOID pv)
3271 FIXME("stub\n");
3272 return 0;
3275 static int WINAPI MimeAlloc_DidAlloc(
3276 IMimeAllocator* iface,
3277 LPVOID pv)
3279 FIXME("stub\n");
3280 return 0;
3283 static void WINAPI MimeAlloc_HeapMinimize(
3284 IMimeAllocator* iface)
3286 FIXME("stub\n");
3287 return;
3290 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3291 IMimeAllocator* iface,
3292 ULONG cParams,
3293 LPMIMEPARAMINFO prgParam,
3294 boolean fFreeArray)
3296 ULONG i;
3297 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3299 for(i = 0; i < cParams; i++)
3301 IMimeAllocator_Free(iface, prgParam[i].pszName);
3302 IMimeAllocator_Free(iface, prgParam[i].pszData);
3304 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3305 return S_OK;
3308 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3309 IMimeAllocator* iface,
3310 LPADDRESSLIST pList)
3312 FIXME("stub\n");
3313 return E_NOTIMPL;
3316 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3317 IMimeAllocator* iface,
3318 LPADDRESSPROPS pAddress)
3320 FIXME("stub\n");
3321 return E_NOTIMPL;
3324 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3325 IMimeAllocator* iface,
3326 ULONG cObjects,
3327 IUnknown **prgpUnknown,
3328 boolean fFreeArray)
3330 FIXME("stub\n");
3331 return E_NOTIMPL;
3335 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3336 IMimeAllocator* iface,
3337 ULONG cRows,
3338 LPENUMHEADERROW prgRow,
3339 boolean fFreeArray)
3341 FIXME("stub\n");
3342 return E_NOTIMPL;
3345 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3346 IMimeAllocator* iface,
3347 ULONG cProps,
3348 LPENUMPROPERTY prgProp,
3349 boolean fFreeArray)
3351 FIXME("stub\n");
3352 return E_NOTIMPL;
3355 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3356 IMimeAllocator* iface,
3357 THUMBBLOB *pthumbprint)
3359 FIXME("stub\n");
3360 return E_NOTIMPL;
3364 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3365 IMimeAllocator* iface,
3366 LPPROPVARIANT pProp)
3368 FIXME("stub\n");
3369 return E_NOTIMPL;
3372 static IMimeAllocatorVtbl mime_alloc_vtbl =
3374 MimeAlloc_QueryInterface,
3375 MimeAlloc_AddRef,
3376 MimeAlloc_Release,
3377 MimeAlloc_Alloc,
3378 MimeAlloc_Realloc,
3379 MimeAlloc_Free,
3380 MimeAlloc_GetSize,
3381 MimeAlloc_DidAlloc,
3382 MimeAlloc_HeapMinimize,
3383 MimeAlloc_FreeParamInfoArray,
3384 MimeAlloc_FreeAddressList,
3385 MimeAlloc_FreeAddressProps,
3386 MimeAlloc_ReleaseObjects,
3387 MimeAlloc_FreeEnumHeaderRowArray,
3388 MimeAlloc_FreeEnumPropertyArray,
3389 MimeAlloc_FreeThumbprint,
3390 MimeAlloc_PropVariantClear
3393 static IMimeAllocator mime_allocator =
3395 &mime_alloc_vtbl
3398 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3400 if(outer) return CLASS_E_NOAGGREGATION;
3402 *obj = &mime_allocator;
3403 return S_OK;
3406 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3408 return MimeAllocator_create(NULL, (void**)alloc);
3411 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3413 FIXME("(%p, %p)\n", outer, obj);
3415 *obj = NULL;
3416 if (outer) return CLASS_E_NOAGGREGATION;
3418 return MimeOleCreateVirtualStream((IStream **)obj);
3421 /* IMimePropertySchema Interface */
3422 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3424 propschema *This = impl_from_IMimePropertySchema(iface);
3425 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3427 *out = NULL;
3429 if (IsEqualIID(riid, &IID_IUnknown) ||
3430 IsEqualIID(riid, &IID_IMimePropertySchema))
3432 *out = iface;
3434 else
3436 FIXME("no interface for %s\n", debugstr_guid(riid));
3437 return E_NOINTERFACE;
3440 IMimePropertySchema_AddRef(iface);
3441 return S_OK;
3444 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3446 propschema *This = impl_from_IMimePropertySchema(iface);
3447 LONG ref = InterlockedIncrement(&This->ref);
3449 TRACE("(%p) ref=%d\n", This, ref);
3451 return ref;
3454 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3456 propschema *This = impl_from_IMimePropertySchema(iface);
3457 LONG ref = InterlockedDecrement(&This->ref);
3459 TRACE("(%p) ref=%d\n", This, ref);
3461 if (!ref)
3463 HeapFree(GetProcessHeap(), 0, This);
3466 return ref;
3469 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3470 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3472 propschema *This = impl_from_IMimePropertySchema(iface);
3473 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3474 return E_NOTIMPL;
3477 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3478 DWORD rownumber, VARTYPE vtdefault)
3480 propschema *This = impl_from_IMimePropertySchema(iface);
3481 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3482 return S_OK;
3485 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3487 propschema *This = impl_from_IMimePropertySchema(iface);
3488 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3489 return E_NOTIMPL;
3492 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3494 propschema *This = impl_from_IMimePropertySchema(iface);
3495 FIXME("(%p)->(%d, %p) stub\n", This, propid, name);
3496 return E_NOTIMPL;
3499 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3501 propschema *This = impl_from_IMimePropertySchema(iface);
3502 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3503 return E_NOTIMPL;
3506 static IMimePropertySchemaVtbl prop_schema_vtbl =
3508 propschema_QueryInterface,
3509 propschema_AddRef,
3510 propschema_Release,
3511 propschema_RegisterProperty,
3512 propschema_ModifyProperty,
3513 propschema_GetPropertyId,
3514 propschema_GetPropertyName,
3515 propschema_RegisterAddressType
3519 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3521 propschema *This;
3523 TRACE("(%p) stub\n", schema);
3525 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3526 if (!This)
3527 return E_OUTOFMEMORY;
3529 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3530 This->ref = 1;
3532 *schema = &This->IMimePropertySchema_iface;
3534 return S_OK;
3537 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3538 ADDRESSFORMAT addr_format, WCHAR **address)
3540 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3542 return E_NOTIMPL;
3545 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3546 REFIID riid, void **out, IMoniker **moniker_new)
3548 FIXME("(0x%08x, %p, %p, %s, %p, %p) stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3550 return E_NOTIMPL;