inetcomm: Removed unneeded type check in init_content_type.
[wine.git] / dlls / inetcomm / mimeole.c
blobde37f090c07d9d7b1b4304b03f7f28471de76da2
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 = (LONGLONG)new_end - offset;
536 IStream_Seek(stm, off, STREAM_SEEK_CUR, 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 slash = strchr(header->value.u.pszVal, '/');
750 if(!slash)
752 WARN("malformed context type value\n");
753 return;
755 len = slash - header->value.u.pszVal;
756 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
757 memcpy(body->content_pri_type, header->value.u.pszVal, len);
758 body->content_pri_type[len] = '\0';
759 body->content_sub_type = strdupA(slash + 1);
762 static void init_content_encoding(MimeBody *body, header_t *header)
764 const char *encoding = header->value.u.pszVal;
766 if(!strcasecmp(encoding, "base64"))
767 body->encoding = IET_BASE64;
768 else if(!strcasecmp(encoding, "quoted-printable"))
769 body->encoding = IET_QP;
770 else if(!strcasecmp(encoding, "7bit"))
771 body->encoding = IET_7BIT;
772 else if(!strcasecmp(encoding, "8bit"))
773 body->encoding = IET_8BIT;
774 else
775 FIXME("unknown encoding %s\n", debugstr_a(encoding));
778 static HRESULT parse_headers(MimeBody *body, IStream *stm)
780 char *header_buf, *cur_header_ptr;
781 HRESULT hr;
782 header_t *header;
784 hr = copy_headers_to_buf(stm, &header_buf);
785 if(FAILED(hr)) return hr;
787 cur_header_ptr = header_buf;
788 while((header = read_prop(body, &cur_header_ptr)))
790 read_value(header, &cur_header_ptr);
791 list_add_tail(&body->headers, &header->entry);
793 switch(header->prop->id) {
794 case PID_HDR_CNTTYPE:
795 init_content_type(body, header);
796 break;
797 case PID_HDR_CNTXFER:
798 init_content_encoding(body, header);
799 break;
803 HeapFree(GetProcessHeap(), 0, header_buf);
804 return hr;
807 static void empty_param_list(struct list *list)
809 param_t *param, *cursor2;
811 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
813 list_remove(&param->entry);
814 HeapFree(GetProcessHeap(), 0, param->name);
815 HeapFree(GetProcessHeap(), 0, param->value);
816 HeapFree(GetProcessHeap(), 0, param);
820 static void empty_header_list(struct list *list)
822 header_t *header, *cursor2;
824 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
826 list_remove(&header->entry);
827 PropVariantClear(&header->value);
828 empty_param_list(&header->params);
829 HeapFree(GetProcessHeap(), 0, header);
833 static void empty_new_prop_list(struct list *list)
835 property_list_entry_t *prop, *cursor2;
837 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
839 list_remove(&prop->entry);
840 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
841 HeapFree(GetProcessHeap(), 0, prop);
845 static void release_data(REFIID riid, void *data)
847 if(!data) return;
849 if(IsEqualIID(riid, &IID_IStream))
850 IStream_Release((IStream *)data);
851 else
852 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
855 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
857 header_t *header;
859 *prop = NULL;
861 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
863 if(ISPIDSTR(name))
865 if(STRTOPID(name) == header->prop->id)
867 *prop = header;
868 return S_OK;
871 else if(!lstrcmpiA(name, header->prop->name))
873 *prop = header;
874 return S_OK;
878 return MIME_E_NOT_FOUND;
881 static const property_t *find_default_prop(const char *name)
883 const property_t *prop_def = NULL;
885 for(prop_def = default_props; prop_def->name; prop_def++)
887 if(ISPIDSTR(name))
889 if(STRTOPID(name) == prop_def->id)
891 break;
894 else if(!lstrcmpiA(name, prop_def->name))
896 break;
900 if(prop_def->id)
901 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
902 else
903 prop_def = NULL;
905 return prop_def;
908 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
909 REFIID riid,
910 void** ppvObject)
912 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
914 *ppvObject = NULL;
916 if (IsEqualIID(riid, &IID_IUnknown) ||
917 IsEqualIID(riid, &IID_IPersist) ||
918 IsEqualIID(riid, &IID_IPersistStreamInit) ||
919 IsEqualIID(riid, &IID_IMimePropertySet) ||
920 IsEqualIID(riid, &IID_IMimeBody))
922 *ppvObject = iface;
925 if(*ppvObject)
927 IUnknown_AddRef((IUnknown*)*ppvObject);
928 return S_OK;
931 FIXME("no interface for %s\n", debugstr_guid(riid));
932 return E_NOINTERFACE;
935 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
937 MimeBody *This = impl_from_IMimeBody(iface);
938 LONG ref = InterlockedIncrement(&This->ref);
940 TRACE("(%p) ref=%d\n", This, ref);
942 return ref;
945 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
947 MimeBody *This = impl_from_IMimeBody(iface);
948 LONG ref = InterlockedDecrement(&This->ref);
950 TRACE("(%p) ref=%d\n", This, ref);
952 if (!ref)
954 empty_header_list(&This->headers);
955 empty_new_prop_list(&This->new_props);
957 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
958 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
960 release_data(&This->data_iid, This->data);
962 HeapFree(GetProcessHeap(), 0, This);
965 return ref;
968 static HRESULT WINAPI MimeBody_GetClassID(
969 IMimeBody* iface,
970 CLSID* pClassID)
972 MimeBody *This = impl_from_IMimeBody(iface);
973 FIXME("(%p)->(%p) stub\n", This, pClassID);
974 return E_NOTIMPL;
978 static HRESULT WINAPI MimeBody_IsDirty(
979 IMimeBody* iface)
981 MimeBody *This = impl_from_IMimeBody(iface);
982 FIXME("(%p)->() stub\n", This);
983 return E_NOTIMPL;
986 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
988 MimeBody *This = impl_from_IMimeBody(iface);
989 TRACE("(%p)->(%p)\n", This, pStm);
990 return parse_headers(This, pStm);
993 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
995 MimeBody *This = impl_from_IMimeBody(iface);
996 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
997 return E_NOTIMPL;
1000 static HRESULT WINAPI MimeBody_GetSizeMax(
1001 IMimeBody* iface,
1002 ULARGE_INTEGER* pcbSize)
1004 MimeBody *This = impl_from_IMimeBody(iface);
1005 FIXME("(%p)->(%p) stub\n", This, pcbSize);
1006 return E_NOTIMPL;
1009 static HRESULT WINAPI MimeBody_InitNew(
1010 IMimeBody* iface)
1012 MimeBody *This = impl_from_IMimeBody(iface);
1013 TRACE("(%p)->()\n", This);
1014 return S_OK;
1017 static HRESULT WINAPI MimeBody_GetPropInfo(
1018 IMimeBody* iface,
1019 LPCSTR pszName,
1020 LPMIMEPROPINFO pInfo)
1022 MimeBody *This = impl_from_IMimeBody(iface);
1023 header_t *header;
1024 HRESULT hr;
1025 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1027 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1029 if(!pszName || !pInfo)
1030 return E_INVALIDARG;
1032 TRACE("mask 0x%04x\n", pInfo->dwMask);
1034 if(pInfo->dwMask & ~supported)
1035 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
1037 hr = find_prop(This, pszName, &header);
1038 if(hr == S_OK)
1040 if(pInfo->dwMask & PIM_CHARSET)
1041 pInfo->hCharset = 0;
1042 if(pInfo->dwMask & PIM_FLAGS)
1043 pInfo->dwFlags = 0x00000000;
1044 if(pInfo->dwMask & PIM_ROWNUMBER)
1045 pInfo->dwRowNumber = 0;
1046 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1047 pInfo->ietEncoding = 0;
1048 if(pInfo->dwMask & PIM_VALUES)
1049 pInfo->cValues = 0;
1050 if(pInfo->dwMask & PIM_PROPID)
1051 pInfo->dwPropId = header->prop->id;
1052 if(pInfo->dwMask & PIM_VTDEFAULT)
1053 pInfo->vtDefault = header->prop->default_vt;
1054 if(pInfo->dwMask & PIM_VTCURRENT)
1055 pInfo->vtCurrent = 0;
1058 return hr;
1061 static HRESULT WINAPI MimeBody_SetPropInfo(
1062 IMimeBody* iface,
1063 LPCSTR pszName,
1064 LPCMIMEPROPINFO pInfo)
1066 MimeBody *This = impl_from_IMimeBody(iface);
1067 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1068 return E_NOTIMPL;
1071 static HRESULT WINAPI MimeBody_GetProp(
1072 IMimeBody* iface,
1073 LPCSTR pszName,
1074 DWORD dwFlags,
1075 LPPROPVARIANT pValue)
1077 MimeBody *This = impl_from_IMimeBody(iface);
1078 header_t *header;
1079 HRESULT hr;
1081 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1083 if(!pszName || !pValue)
1084 return E_INVALIDARG;
1086 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1088 PropVariantClear(pValue);
1089 pValue->vt = VT_LPSTR;
1090 pValue->u.pszVal = strdupA(This->content_pri_type);
1091 return S_OK;
1094 hr = find_prop(This, pszName, &header);
1095 if(hr == S_OK)
1097 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1099 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1100 if(FAILED(hr))
1101 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1104 return hr;
1107 static HRESULT WINAPI MimeBody_SetProp(
1108 IMimeBody* iface,
1109 LPCSTR pszName,
1110 DWORD dwFlags,
1111 LPCPROPVARIANT pValue)
1113 MimeBody *This = impl_from_IMimeBody(iface);
1114 header_t *header;
1115 HRESULT hr;
1117 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1119 if(!pszName || !pValue)
1120 return E_INVALIDARG;
1122 hr = find_prop(This, pszName, &header);
1123 if(hr != S_OK)
1125 property_list_entry_t *prop_entry;
1126 const property_t *prop = NULL;
1128 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1130 if(ISPIDSTR(pszName))
1132 if(STRTOPID(pszName) == prop_entry->prop.id)
1134 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1135 prop = &prop_entry->prop;
1136 break;
1139 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1141 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1142 prop = &prop_entry->prop;
1143 break;
1147 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
1148 if(!header)
1149 return E_OUTOFMEMORY;
1151 if(!prop)
1153 const property_t *prop_def = NULL;
1154 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
1155 if(!prop_entry)
1157 HeapFree(GetProcessHeap(), 0, header);
1158 return E_OUTOFMEMORY;
1161 prop_def = find_default_prop(pszName);
1162 if(prop_def)
1164 prop_entry->prop.name = strdupA(prop_def->name);
1165 prop_entry->prop.id = prop_def->id;
1167 else
1169 if(ISPIDSTR(pszName))
1171 HeapFree(GetProcessHeap(), 0, prop_entry);
1172 HeapFree(GetProcessHeap(), 0, header);
1173 return MIME_E_NOT_FOUND;
1176 prop_entry->prop.name = strdupA(pszName);
1177 prop_entry->prop.id = This->next_prop_id++;
1180 prop_entry->prop.flags = 0;
1181 prop_entry->prop.default_vt = pValue->vt;
1182 list_add_tail(&This->new_props, &prop_entry->entry);
1183 prop = &prop_entry->prop;
1184 TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
1187 header->prop = prop;
1188 PropVariantInit(&header->value);
1189 list_init(&header->params);
1190 list_add_tail(&This->headers, &header->entry);
1193 PropVariantCopy(&header->value, pValue);
1195 return S_OK;
1198 static HRESULT WINAPI MimeBody_AppendProp(
1199 IMimeBody* iface,
1200 LPCSTR pszName,
1201 DWORD dwFlags,
1202 LPPROPVARIANT pValue)
1204 MimeBody *This = impl_from_IMimeBody(iface);
1205 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1206 return E_NOTIMPL;
1209 static HRESULT WINAPI MimeBody_DeleteProp(
1210 IMimeBody* iface,
1211 LPCSTR pszName)
1213 MimeBody *This = impl_from_IMimeBody(iface);
1214 header_t *cursor;
1215 BOOL found;
1217 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1219 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1221 if(ISPIDSTR(pszName))
1222 found = STRTOPID(pszName) == cursor->prop->id;
1223 else
1224 found = !lstrcmpiA(pszName, cursor->prop->name);
1226 if(found)
1228 list_remove(&cursor->entry);
1229 HeapFree(GetProcessHeap(), 0, cursor);
1230 return S_OK;
1234 return MIME_E_NOT_FOUND;
1237 static HRESULT WINAPI MimeBody_CopyProps(
1238 IMimeBody* iface,
1239 ULONG cNames,
1240 LPCSTR* prgszName,
1241 IMimePropertySet* pPropertySet)
1243 MimeBody *This = impl_from_IMimeBody(iface);
1244 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1245 return E_NOTIMPL;
1248 static HRESULT WINAPI MimeBody_MoveProps(
1249 IMimeBody* iface,
1250 ULONG cNames,
1251 LPCSTR* prgszName,
1252 IMimePropertySet* pPropertySet)
1254 MimeBody *This = impl_from_IMimeBody(iface);
1255 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1256 return E_NOTIMPL;
1259 static HRESULT WINAPI MimeBody_DeleteExcept(
1260 IMimeBody* iface,
1261 ULONG cNames,
1262 LPCSTR* prgszName)
1264 MimeBody *This = impl_from_IMimeBody(iface);
1265 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
1266 return E_NOTIMPL;
1269 static HRESULT WINAPI MimeBody_QueryProp(
1270 IMimeBody* iface,
1271 LPCSTR pszName,
1272 LPCSTR pszCriteria,
1273 boolean fSubString,
1274 boolean fCaseSensitive)
1276 MimeBody *This = impl_from_IMimeBody(iface);
1277 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1278 return E_NOTIMPL;
1281 static HRESULT WINAPI MimeBody_GetCharset(
1282 IMimeBody* iface,
1283 LPHCHARSET phCharset)
1285 MimeBody *This = impl_from_IMimeBody(iface);
1286 FIXME("(%p)->(%p) stub\n", This, phCharset);
1287 *phCharset = NULL;
1288 return S_OK;
1291 static HRESULT WINAPI MimeBody_SetCharset(
1292 IMimeBody* iface,
1293 HCHARSET hCharset,
1294 CSETAPPLYTYPE applytype)
1296 MimeBody *This = impl_from_IMimeBody(iface);
1297 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1298 return E_NOTIMPL;
1301 static HRESULT WINAPI MimeBody_GetParameters(
1302 IMimeBody* iface,
1303 LPCSTR pszName,
1304 ULONG* pcParams,
1305 LPMIMEPARAMINFO* pprgParam)
1307 MimeBody *This = impl_from_IMimeBody(iface);
1308 HRESULT hr;
1309 header_t *header;
1311 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1313 *pprgParam = NULL;
1314 *pcParams = 0;
1316 hr = find_prop(This, pszName, &header);
1317 if(hr != S_OK) return hr;
1319 *pcParams = list_count(&header->params);
1320 if(*pcParams)
1322 IMimeAllocator *alloc;
1323 param_t *param;
1324 MIMEPARAMINFO *info;
1326 MimeOleGetAllocator(&alloc);
1328 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1329 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1331 int len;
1333 len = strlen(param->name) + 1;
1334 info->pszName = IMimeAllocator_Alloc(alloc, len);
1335 memcpy(info->pszName, param->name, len);
1336 len = strlen(param->value) + 1;
1337 info->pszData = IMimeAllocator_Alloc(alloc, len);
1338 memcpy(info->pszData, param->value, len);
1339 info++;
1341 IMimeAllocator_Release(alloc);
1343 return S_OK;
1346 static HRESULT WINAPI MimeBody_IsContentType(
1347 IMimeBody* iface,
1348 LPCSTR pszPriType,
1349 LPCSTR pszSubType)
1351 MimeBody *This = impl_from_IMimeBody(iface);
1353 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1354 if(pszPriType)
1356 const char *pri = This->content_pri_type;
1357 if(!pri) pri = "text";
1358 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1361 if(pszSubType)
1363 const char *sub = This->content_sub_type;
1364 if(!sub) sub = "plain";
1365 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1368 return S_OK;
1371 static HRESULT WINAPI MimeBody_BindToObject(
1372 IMimeBody* iface,
1373 REFIID riid,
1374 void** ppvObject)
1376 MimeBody *This = impl_from_IMimeBody(iface);
1377 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1378 return E_NOTIMPL;
1381 static HRESULT WINAPI MimeBody_Clone(
1382 IMimeBody* iface,
1383 IMimePropertySet** ppPropertySet)
1385 MimeBody *This = impl_from_IMimeBody(iface);
1386 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1387 return E_NOTIMPL;
1390 static HRESULT WINAPI MimeBody_SetOption(
1391 IMimeBody* iface,
1392 const TYPEDID oid,
1393 LPCPROPVARIANT pValue)
1395 MimeBody *This = impl_from_IMimeBody(iface);
1396 HRESULT hr = E_NOTIMPL;
1397 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
1399 if(pValue->vt != TYPEDID_TYPE(oid))
1401 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
1402 return E_INVALIDARG;
1405 switch(oid)
1407 case OID_SECURITY_HWND_OWNER:
1408 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
1409 hr = S_OK;
1410 break;
1411 case OID_TRANSMIT_BODY_ENCODING:
1412 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
1413 hr = S_OK;
1414 break;
1415 default:
1416 FIXME("Unhandled oid %08x\n", oid);
1419 return hr;
1422 static HRESULT WINAPI MimeBody_GetOption(
1423 IMimeBody* iface,
1424 const TYPEDID oid,
1425 LPPROPVARIANT pValue)
1427 MimeBody *This = impl_from_IMimeBody(iface);
1428 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
1429 return E_NOTIMPL;
1432 static HRESULT WINAPI MimeBody_EnumProps(
1433 IMimeBody* iface,
1434 DWORD dwFlags,
1435 IMimeEnumProperties** ppEnum)
1437 MimeBody *This = impl_from_IMimeBody(iface);
1438 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
1439 return E_NOTIMPL;
1442 static HRESULT WINAPI MimeBody_IsType(
1443 IMimeBody* iface,
1444 IMSGBODYTYPE bodytype)
1446 MimeBody *This = impl_from_IMimeBody(iface);
1448 TRACE("(%p)->(%d)\n", This, bodytype);
1449 switch(bodytype)
1451 case IBT_EMPTY:
1452 return This->data ? S_FALSE : S_OK;
1453 default:
1454 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1456 return S_OK;
1459 static HRESULT WINAPI MimeBody_SetDisplayName(
1460 IMimeBody* iface,
1461 LPCSTR pszDisplay)
1463 MimeBody *This = impl_from_IMimeBody(iface);
1464 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1465 return E_NOTIMPL;
1468 static HRESULT WINAPI MimeBody_GetDisplayName(
1469 IMimeBody* iface,
1470 LPSTR* ppszDisplay)
1472 MimeBody *This = impl_from_IMimeBody(iface);
1473 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1474 return E_NOTIMPL;
1477 static HRESULT WINAPI MimeBody_GetOffsets(
1478 IMimeBody* iface,
1479 LPBODYOFFSETS pOffsets)
1481 MimeBody *This = impl_from_IMimeBody(iface);
1482 TRACE("(%p)->(%p)\n", This, pOffsets);
1484 *pOffsets = This->body_offsets;
1486 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1487 return S_OK;
1490 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1491 IMimeBody* iface,
1492 ENCODINGTYPE* pietEncoding)
1494 MimeBody *This = impl_from_IMimeBody(iface);
1496 TRACE("(%p)->(%p)\n", This, pietEncoding);
1498 *pietEncoding = This->encoding;
1499 return S_OK;
1502 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1503 IMimeBody* iface,
1504 ENCODINGTYPE ietEncoding)
1506 MimeBody *This = impl_from_IMimeBody(iface);
1508 TRACE("(%p)->(%d)\n", This, ietEncoding);
1510 This->encoding = ietEncoding;
1511 return S_OK;
1514 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1515 IMimeBody* iface,
1516 ENCODINGTYPE ietEncoding,
1517 ULONG* pcbSize)
1519 MimeBody *This = impl_from_IMimeBody(iface);
1520 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1521 return E_NOTIMPL;
1524 static HRESULT WINAPI MimeBody_GetDataHere(
1525 IMimeBody* iface,
1526 ENCODINGTYPE ietEncoding,
1527 IStream* pStream)
1529 MimeBody *This = impl_from_IMimeBody(iface);
1530 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1531 return E_NOTIMPL;
1534 static const signed char base64_decode_table[] =
1536 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1537 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1538 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1539 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1540 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1541 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1542 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1543 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1546 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1548 const unsigned char *ptr, *end;
1549 unsigned char buf[1024];
1550 LARGE_INTEGER pos;
1551 unsigned char *ret;
1552 unsigned char in[4];
1553 IStream *output;
1554 DWORD size;
1555 int n = 0;
1556 HRESULT hres;
1558 pos.QuadPart = 0;
1559 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1560 if(FAILED(hres))
1561 return hres;
1563 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1564 if(FAILED(hres))
1565 return hres;
1567 while(1) {
1568 hres = IStream_Read(input, buf, sizeof(buf), &size);
1569 if(FAILED(hres) || !size)
1570 break;
1572 ptr = ret = buf;
1573 end = buf + size;
1575 while(1) {
1576 /* skip invalid chars */
1577 while(ptr < end &&
1578 (*ptr >= sizeof(base64_decode_table)/sizeof(*base64_decode_table)
1579 || base64_decode_table[*ptr] == -1))
1580 ptr++;
1581 if(ptr == end)
1582 break;
1584 in[n++] = base64_decode_table[*ptr++];
1585 switch(n) {
1586 case 2:
1587 *ret++ = in[0] << 2 | in[1] >> 4;
1588 continue;
1589 case 3:
1590 *ret++ = in[1] << 4 | in[2] >> 2;
1591 continue;
1592 case 4:
1593 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1594 n = 0;
1598 if(ret > buf) {
1599 hres = IStream_Write(output, buf, ret - buf, NULL);
1600 if(FAILED(hres))
1601 break;
1605 if(SUCCEEDED(hres))
1606 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1607 if(FAILED(hres)) {
1608 IStream_Release(output);
1609 return hres;
1612 *ret_stream = output;
1613 return S_OK;
1616 static HRESULT WINAPI MimeBody_GetData(
1617 IMimeBody* iface,
1618 ENCODINGTYPE ietEncoding,
1619 IStream** ppStream)
1621 MimeBody *This = impl_from_IMimeBody(iface);
1622 ULARGE_INTEGER start, size;
1623 HRESULT hres;
1625 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1627 if(This->encoding != ietEncoding) {
1628 switch(This->encoding) {
1629 case IET_BASE64:
1630 if(ietEncoding != IET_BINARY)
1631 FIXME("Encofing %d is not supported.\n", ietEncoding);
1632 return decode_base64(This->data, ppStream);
1633 default:
1634 FIXME("Decoding %d is not supported.\n", This->encoding);
1638 start.QuadPart = 0;
1639 hres = get_stream_size(This->data, &size);
1640 if(SUCCEEDED(hres))
1641 hres = create_sub_stream(This->data, start, size, ppStream);
1642 return hres;
1645 static HRESULT WINAPI MimeBody_SetData(
1646 IMimeBody* iface,
1647 ENCODINGTYPE ietEncoding,
1648 LPCSTR pszPriType,
1649 LPCSTR pszSubType,
1650 REFIID riid,
1651 LPVOID pvObject)
1653 MimeBody *This = impl_from_IMimeBody(iface);
1654 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1655 debugstr_guid(riid), pvObject);
1657 if(IsEqualIID(riid, &IID_IStream))
1658 IStream_AddRef((IStream *)pvObject);
1659 else
1661 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1662 return E_INVALIDARG;
1665 if(This->data)
1666 FIXME("release old data\n");
1668 This->data_iid = *riid;
1669 This->data = pvObject;
1671 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1673 /* FIXME: Update the content type.
1674 If pszPriType == NULL use 'application'
1675 If pszSubType == NULL use 'octet-stream' */
1677 return S_OK;
1680 static HRESULT WINAPI MimeBody_EmptyData(
1681 IMimeBody* iface)
1683 MimeBody *This = impl_from_IMimeBody(iface);
1684 FIXME("(%p)->() stub\n", This);
1685 return E_NOTIMPL;
1688 static HRESULT WINAPI MimeBody_CopyTo(
1689 IMimeBody* iface,
1690 IMimeBody* pBody)
1692 MimeBody *This = impl_from_IMimeBody(iface);
1693 FIXME("(%p)->(%p) stub\n", This, pBody);
1694 return E_NOTIMPL;
1697 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1698 IMimeBody* iface,
1699 LPTRANSMITINFO pTransmitInfo)
1701 MimeBody *This = impl_from_IMimeBody(iface);
1702 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1703 return E_NOTIMPL;
1706 static HRESULT WINAPI MimeBody_SaveToFile(
1707 IMimeBody* iface,
1708 ENCODINGTYPE ietEncoding,
1709 LPCSTR pszFilePath)
1711 MimeBody *This = impl_from_IMimeBody(iface);
1712 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1713 return E_NOTIMPL;
1716 static HRESULT WINAPI MimeBody_GetHandle(
1717 IMimeBody* iface,
1718 LPHBODY phBody)
1720 MimeBody *This = impl_from_IMimeBody(iface);
1721 TRACE("(%p)->(%p)\n", iface, phBody);
1723 if(!phBody)
1724 return E_INVALIDARG;
1726 *phBody = This->handle;
1727 return This->handle ? S_OK : MIME_E_NO_DATA;
1730 static IMimeBodyVtbl body_vtbl =
1732 MimeBody_QueryInterface,
1733 MimeBody_AddRef,
1734 MimeBody_Release,
1735 MimeBody_GetClassID,
1736 MimeBody_IsDirty,
1737 MimeBody_Load,
1738 MimeBody_Save,
1739 MimeBody_GetSizeMax,
1740 MimeBody_InitNew,
1741 MimeBody_GetPropInfo,
1742 MimeBody_SetPropInfo,
1743 MimeBody_GetProp,
1744 MimeBody_SetProp,
1745 MimeBody_AppendProp,
1746 MimeBody_DeleteProp,
1747 MimeBody_CopyProps,
1748 MimeBody_MoveProps,
1749 MimeBody_DeleteExcept,
1750 MimeBody_QueryProp,
1751 MimeBody_GetCharset,
1752 MimeBody_SetCharset,
1753 MimeBody_GetParameters,
1754 MimeBody_IsContentType,
1755 MimeBody_BindToObject,
1756 MimeBody_Clone,
1757 MimeBody_SetOption,
1758 MimeBody_GetOption,
1759 MimeBody_EnumProps,
1760 MimeBody_IsType,
1761 MimeBody_SetDisplayName,
1762 MimeBody_GetDisplayName,
1763 MimeBody_GetOffsets,
1764 MimeBody_GetCurrentEncoding,
1765 MimeBody_SetCurrentEncoding,
1766 MimeBody_GetEstimatedSize,
1767 MimeBody_GetDataHere,
1768 MimeBody_GetData,
1769 MimeBody_SetData,
1770 MimeBody_EmptyData,
1771 MimeBody_CopyTo,
1772 MimeBody_GetTransmitInfo,
1773 MimeBody_SaveToFile,
1774 MimeBody_GetHandle
1777 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1779 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1780 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1782 body->body_offsets = *offsets;
1783 return S_OK;
1786 #define FIRST_CUSTOM_PROP_ID 0x100
1788 static MimeBody *mimebody_create(void)
1790 MimeBody *This;
1791 BODYOFFSETS body_offsets;
1793 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1794 if (!This)
1795 return NULL;
1797 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1798 This->ref = 1;
1799 This->handle = NULL;
1800 list_init(&This->headers);
1801 list_init(&This->new_props);
1802 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1803 This->content_pri_type = NULL;
1804 This->content_sub_type = NULL;
1805 This->encoding = IET_7BIT;
1806 This->data = NULL;
1807 This->data_iid = IID_NULL;
1809 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1810 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1811 MimeBody_set_offsets(This, &body_offsets);
1813 return This;
1816 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1818 MimeBody *mb;
1820 if(outer)
1821 return CLASS_E_NOAGGREGATION;
1823 if ((mb = mimebody_create()))
1825 *ppv = &mb->IMimeBody_iface;
1826 return S_OK;
1828 else
1830 *ppv = NULL;
1831 return E_OUTOFMEMORY;
1835 typedef struct body_t
1837 struct list entry;
1838 DWORD index;
1839 MimeBody *mime_body;
1841 struct body_t *parent;
1842 struct list children;
1843 } body_t;
1845 typedef struct MimeMessage
1847 IMimeMessage IMimeMessage_iface;
1848 LONG ref;
1849 IStream *stream;
1851 struct list body_tree;
1852 DWORD next_index;
1853 } MimeMessage;
1855 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1857 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1860 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1862 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1864 if (IsEqualIID(riid, &IID_IUnknown) ||
1865 IsEqualIID(riid, &IID_IPersist) ||
1866 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1867 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1868 IsEqualIID(riid, &IID_IMimeMessage))
1870 *ppv = iface;
1871 IMimeMessage_AddRef(iface);
1872 return S_OK;
1875 FIXME("no interface for %s\n", debugstr_guid(riid));
1876 *ppv = NULL;
1877 return E_NOINTERFACE;
1880 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1882 MimeMessage *This = impl_from_IMimeMessage(iface);
1883 ULONG ref = InterlockedIncrement(&This->ref);
1885 TRACE("(%p) ref=%d\n", This, ref);
1887 return ref;
1890 static void empty_body_list(struct list *list)
1892 body_t *body, *cursor2;
1893 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1895 empty_body_list(&body->children);
1896 list_remove(&body->entry);
1897 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1898 HeapFree(GetProcessHeap(), 0, body);
1902 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1904 MimeMessage *This = impl_from_IMimeMessage(iface);
1905 ULONG ref = InterlockedDecrement(&This->ref);
1907 TRACE("(%p) ref=%d\n", This, ref);
1909 if (!ref)
1911 empty_body_list(&This->body_tree);
1913 if(This->stream) IStream_Release(This->stream);
1914 HeapFree(GetProcessHeap(), 0, This);
1917 return ref;
1920 /*** IPersist methods ***/
1921 static HRESULT WINAPI MimeMessage_GetClassID(
1922 IMimeMessage *iface,
1923 CLSID *pClassID)
1925 FIXME("(%p)->(%p)\n", iface, pClassID);
1926 return E_NOTIMPL;
1929 /*** IPersistStreamInit methods ***/
1930 static HRESULT WINAPI MimeMessage_IsDirty(
1931 IMimeMessage *iface)
1933 FIXME("(%p)->()\n", iface);
1934 return E_NOTIMPL;
1937 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
1939 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
1940 if(body)
1942 body->mime_body = mime_body;
1943 body->index = index;
1944 list_init(&body->children);
1945 body->parent = parent;
1947 mime_body->handle = UlongToHandle(body->index);
1949 return body;
1952 typedef struct
1954 struct list entry;
1955 BODYOFFSETS offsets;
1956 } offset_entry_t;
1958 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
1960 HRESULT hr;
1961 DWORD read, boundary_start;
1962 int boundary_len = strlen(boundary);
1963 char *buf, *ptr, *overlap;
1964 DWORD start = 0, overlap_no;
1965 offset_entry_t *cur_body = NULL;
1966 BOOL is_first_line = TRUE;
1967 ULARGE_INTEGER cur;
1968 LARGE_INTEGER zero;
1970 list_init(body_offsets);
1972 overlap_no = boundary_len + 5;
1974 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
1976 zero.QuadPart = 0;
1977 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
1978 start = cur.u.LowPart;
1980 do {
1981 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
1982 if(FAILED(hr)) goto end;
1983 if(read == 0) break;
1984 overlap[read] = '\0';
1986 ptr = buf;
1987 while(1) {
1988 if(is_first_line) {
1989 is_first_line = FALSE;
1990 }else {
1991 ptr = strstr(ptr, "\r\n");
1992 if(!ptr)
1993 break;
1994 ptr += 2;
1997 boundary_start = start + ptr - buf;
1999 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) {
2000 ptr += boundary_len + 2;
2002 if(*ptr == '\r' && *(ptr + 1) == '\n')
2004 ptr += 2;
2005 if(cur_body)
2007 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2008 list_add_tail(body_offsets, &cur_body->entry);
2010 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
2011 cur_body->offsets.cbBoundaryStart = boundary_start;
2012 cur_body->offsets.cbHeaderStart = start + ptr - buf;
2014 else if(*ptr == '-' && *(ptr + 1) == '-')
2016 if(cur_body)
2018 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2019 list_add_tail(body_offsets, &cur_body->entry);
2020 goto end;
2026 if(overlap == buf) /* 1st iteration */
2028 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2029 overlap = buf + overlap_no;
2030 start += read - overlap_no;
2032 else
2034 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2035 start += read;
2037 } while(1);
2039 end:
2040 HeapFree(GetProcessHeap(), 0, buf);
2041 return hr;
2044 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2046 ULARGE_INTEGER start, length;
2047 MimeBody *mime_body;
2048 HRESULT hr;
2049 body_t *body;
2050 LARGE_INTEGER pos;
2052 pos.QuadPart = offset->cbHeaderStart;
2053 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL);
2055 mime_body = mimebody_create();
2056 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2058 pos.QuadPart = 0;
2059 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start);
2060 offset->cbBodyStart = start.QuadPart;
2061 if (parent) MimeBody_set_offsets(mime_body, offset);
2063 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart;
2064 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data);
2065 mime_body->data_iid = IID_IStream;
2067 body = new_body_entry(mime_body, msg->next_index++, parent);
2069 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2071 MIMEPARAMINFO *param_info;
2072 ULONG count, i;
2073 IMimeAllocator *alloc;
2075 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2076 &param_info);
2077 if(hr != S_OK || count == 0) return body;
2079 MimeOleGetAllocator(&alloc);
2081 for(i = 0; i < count; i++)
2083 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2085 struct list offset_list;
2086 offset_entry_t *cur, *cursor2;
2087 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2088 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2090 body_t *sub_body;
2092 sub_body = create_sub_body(msg, pStm, &cur->offsets, body);
2093 list_add_tail(&body->children, &sub_body->entry);
2094 list_remove(&cur->entry);
2095 HeapFree(GetProcessHeap(), 0, cur);
2097 break;
2100 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2101 IMimeAllocator_Release(alloc);
2103 return body;
2106 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2108 MimeMessage *This = impl_from_IMimeMessage(iface);
2109 body_t *root_body;
2110 BODYOFFSETS offsets;
2111 ULARGE_INTEGER cur;
2112 LARGE_INTEGER zero;
2114 TRACE("(%p)->(%p)\n", iface, pStm);
2116 if(This->stream)
2118 FIXME("already loaded a message\n");
2119 return E_FAIL;
2122 empty_body_list(&This->body_tree);
2124 IStream_AddRef(pStm);
2125 This->stream = pStm;
2126 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2127 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2129 root_body = create_sub_body(This, pStm, &offsets, NULL);
2131 zero.QuadPart = 0;
2132 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2133 offsets.cbBodyEnd = cur.u.LowPart;
2134 MimeBody_set_offsets(root_body->mime_body, &offsets);
2136 list_add_head(&This->body_tree, &root_body->entry);
2138 return S_OK;
2141 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2143 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2144 return E_NOTIMPL;
2147 static HRESULT WINAPI MimeMessage_GetSizeMax(
2148 IMimeMessage *iface,
2149 ULARGE_INTEGER *pcbSize)
2151 FIXME("(%p)->(%p)\n", iface, pcbSize);
2152 return E_NOTIMPL;
2155 static HRESULT WINAPI MimeMessage_InitNew(
2156 IMimeMessage *iface)
2158 FIXME("(%p)->()\n", iface);
2159 return E_NOTIMPL;
2162 /*** IMimeMessageTree methods ***/
2163 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2164 DWORD dwFlags)
2166 MimeMessage *This = impl_from_IMimeMessage(iface);
2168 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
2170 IStream_AddRef(This->stream);
2171 *ppStream = This->stream;
2172 return S_OK;
2175 static HRESULT WINAPI MimeMessage_GetMessageSize(
2176 IMimeMessage *iface,
2177 ULONG *pcbSize,
2178 DWORD dwFlags)
2180 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
2181 return E_NOTIMPL;
2184 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2185 IMimeMessage *iface,
2186 IStream *pStream)
2188 FIXME("(%p)->(%p)\n", iface, pStream);
2189 return E_NOTIMPL;
2192 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2193 IMimeMessage *iface,
2194 IStream *pStream,
2195 DWORD dwFlags)
2197 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
2198 return E_NOTIMPL;
2202 static HRESULT WINAPI MimeMessage_GetFlags(
2203 IMimeMessage *iface,
2204 DWORD *pdwFlags)
2206 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2207 return E_NOTIMPL;
2210 static HRESULT WINAPI MimeMessage_Commit(
2211 IMimeMessage *iface,
2212 DWORD dwFlags)
2214 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
2215 return S_OK;
2219 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2220 IMimeMessage *iface)
2222 FIXME("(%p)->()\n", iface);
2223 return E_NOTIMPL;
2226 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2228 body_t *cur;
2229 HRESULT hr;
2231 if(hbody == HBODY_ROOT)
2233 *body = LIST_ENTRY(list_head(list), body_t, entry);
2234 return S_OK;
2237 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2239 if(cur->index == HandleToUlong(hbody))
2241 *body = cur;
2242 return S_OK;
2244 hr = find_body(&cur->children, hbody, body);
2245 if(hr == S_OK) return S_OK;
2247 return S_FALSE;
2250 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2251 void **ppvObject)
2253 MimeMessage *This = impl_from_IMimeMessage(iface);
2254 HRESULT hr;
2255 body_t *body;
2257 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2259 hr = find_body(&This->body_tree, hBody, &body);
2261 if(hr != S_OK) return hr;
2263 if(IsEqualIID(riid, &IID_IMimeBody))
2265 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2266 *ppvObject = &body->mime_body->IMimeBody_iface;
2267 return S_OK;
2270 return E_NOINTERFACE;
2273 static HRESULT WINAPI MimeMessage_SaveBody(
2274 IMimeMessage *iface,
2275 HBODY hBody,
2276 DWORD dwFlags,
2277 IStream *pStream)
2279 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
2280 return E_NOTIMPL;
2283 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2285 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2286 body_t *body;
2287 HRESULT hr;
2288 struct list *list;
2290 if(location == IBL_ROOT)
2292 *out = root;
2293 return S_OK;
2296 hr = find_body(&msg->body_tree, pivot, &body);
2298 if(hr == S_OK)
2300 switch(location)
2302 case IBL_PARENT:
2303 if(body->parent)
2304 *out = body->parent;
2305 else
2306 hr = MIME_E_NOT_FOUND;
2307 break;
2309 case IBL_FIRST:
2310 list = list_head(&body->children);
2311 if(list)
2312 *out = LIST_ENTRY(list, body_t, entry);
2313 else
2314 hr = MIME_E_NOT_FOUND;
2315 break;
2317 case IBL_LAST:
2318 list = list_tail(&body->children);
2319 if(list)
2320 *out = LIST_ENTRY(list, body_t, entry);
2321 else
2322 hr = MIME_E_NOT_FOUND;
2323 break;
2325 case IBL_NEXT:
2326 list = list_next(&body->parent->children, &body->entry);
2327 if(list)
2328 *out = LIST_ENTRY(list, body_t, entry);
2329 else
2330 hr = MIME_E_NOT_FOUND;
2331 break;
2333 case IBL_PREVIOUS:
2334 list = list_prev(&body->parent->children, &body->entry);
2335 if(list)
2336 *out = LIST_ENTRY(list, body_t, entry);
2337 else
2338 hr = MIME_E_NOT_FOUND;
2339 break;
2341 default:
2342 hr = E_FAIL;
2343 break;
2347 return hr;
2351 static HRESULT WINAPI MimeMessage_InsertBody(
2352 IMimeMessage *iface,
2353 BODYLOCATION location,
2354 HBODY hPivot,
2355 LPHBODY phBody)
2357 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2358 return E_NOTIMPL;
2361 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2362 HBODY *phBody)
2364 MimeMessage *This = impl_from_IMimeMessage(iface);
2365 body_t *body;
2366 HRESULT hr;
2368 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2370 if(!phBody)
2371 return E_INVALIDARG;
2373 *phBody = NULL;
2375 hr = get_body(This, location, hPivot, &body);
2377 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2379 return hr;
2382 static HRESULT WINAPI MimeMessage_DeleteBody(
2383 IMimeMessage *iface,
2384 HBODY hBody,
2385 DWORD dwFlags)
2387 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
2388 return E_NOTIMPL;
2391 static HRESULT WINAPI MimeMessage_MoveBody(
2392 IMimeMessage *iface,
2393 HBODY hBody,
2394 BODYLOCATION location)
2396 FIXME("(%p)->(%d)\n", iface, location);
2397 return E_NOTIMPL;
2400 static void count_children(body_t *body, boolean recurse, ULONG *count)
2402 body_t *child;
2404 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2406 (*count)++;
2407 if(recurse) count_children(child, recurse, count);
2411 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2412 ULONG *pcBodies)
2414 HRESULT hr;
2415 MimeMessage *This = impl_from_IMimeMessage(iface);
2416 body_t *body;
2418 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2420 hr = find_body(&This->body_tree, hParent, &body);
2421 if(hr != S_OK) return hr;
2423 *pcBodies = 1;
2424 count_children(body, fRecurse, pcBodies);
2426 return S_OK;
2429 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2431 struct list *ptr;
2432 HBODY next;
2434 for (;;)
2436 if (!body) ptr = list_head( &This->body_tree );
2437 else
2439 ptr = list_head( &body->children );
2440 while (!ptr)
2442 if (!body->parent) return MIME_E_NOT_FOUND;
2443 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2447 body = LIST_ENTRY( ptr, body_t, entry );
2448 next = UlongToHandle( body->index );
2449 find->dwReserved = body->index;
2450 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2451 find->pszSubType) == S_OK)
2453 *out = next;
2454 return S_OK;
2457 return MIME_E_NOT_FOUND;
2460 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2462 MimeMessage *This = impl_from_IMimeMessage(iface);
2464 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2466 pFindBody->dwReserved = 0;
2467 return find_next(This, NULL, pFindBody, phBody);
2470 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2472 MimeMessage *This = impl_from_IMimeMessage(iface);
2473 body_t *body;
2474 HRESULT hr;
2476 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2478 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2479 if (hr != S_OK) return MIME_E_NOT_FOUND;
2480 return find_next(This, body, pFindBody, phBody);
2483 static HRESULT WINAPI MimeMessage_ResolveURL(
2484 IMimeMessage *iface,
2485 HBODY hRelated,
2486 LPCSTR pszBase,
2487 LPCSTR pszURL,
2488 DWORD dwFlags,
2489 LPHBODY phBody)
2491 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2492 return E_NOTIMPL;
2495 static HRESULT WINAPI MimeMessage_ToMultipart(
2496 IMimeMessage *iface,
2497 HBODY hBody,
2498 LPCSTR pszSubType,
2499 LPHBODY phMultipart)
2501 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2502 return E_NOTIMPL;
2505 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2506 IMimeMessage *iface,
2507 HBODY hBody,
2508 LPBODYOFFSETS pOffsets)
2510 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2511 return E_NOTIMPL;
2514 static HRESULT WINAPI MimeMessage_GetCharset(
2515 IMimeMessage *iface,
2516 LPHCHARSET phCharset)
2518 FIXME("(%p)->(%p)\n", iface, phCharset);
2519 *phCharset = NULL;
2520 return S_OK;
2523 static HRESULT WINAPI MimeMessage_SetCharset(
2524 IMimeMessage *iface,
2525 HCHARSET hCharset,
2526 CSETAPPLYTYPE applytype)
2528 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2529 return E_NOTIMPL;
2532 static HRESULT WINAPI MimeMessage_IsBodyType(
2533 IMimeMessage *iface,
2534 HBODY hBody,
2535 IMSGBODYTYPE bodytype)
2537 HRESULT hr;
2538 IMimeBody *mime_body;
2539 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2541 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2542 if(hr != S_OK) return hr;
2544 hr = IMimeBody_IsType(mime_body, bodytype);
2545 MimeBody_Release(mime_body);
2546 return hr;
2549 static HRESULT WINAPI MimeMessage_IsContentType(
2550 IMimeMessage *iface,
2551 HBODY hBody,
2552 LPCSTR pszPriType,
2553 LPCSTR pszSubType)
2555 HRESULT hr;
2556 IMimeBody *mime_body;
2557 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2558 debugstr_a(pszSubType));
2560 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2561 if(FAILED(hr)) return hr;
2563 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2564 IMimeBody_Release(mime_body);
2565 return hr;
2568 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2569 IMimeMessage *iface,
2570 HBODY hBody,
2571 LPCSTR pszName,
2572 LPCSTR pszCriteria,
2573 boolean fSubString,
2574 boolean fCaseSensitive)
2576 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2577 return E_NOTIMPL;
2580 static HRESULT WINAPI MimeMessage_GetBodyProp(
2581 IMimeMessage *iface,
2582 HBODY hBody,
2583 LPCSTR pszName,
2584 DWORD dwFlags,
2585 LPPROPVARIANT pValue)
2587 HRESULT hr;
2588 IMimeBody *mime_body;
2590 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2592 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2593 if(hr != S_OK) return hr;
2595 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2596 IMimeBody_Release(mime_body);
2598 return hr;
2601 static HRESULT WINAPI MimeMessage_SetBodyProp(
2602 IMimeMessage *iface,
2603 HBODY hBody,
2604 LPCSTR pszName,
2605 DWORD dwFlags,
2606 LPCPROPVARIANT pValue)
2608 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2609 return E_NOTIMPL;
2612 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2613 IMimeMessage *iface,
2614 HBODY hBody,
2615 LPCSTR pszName)
2617 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2618 return E_NOTIMPL;
2621 static HRESULT WINAPI MimeMessage_SetOption(
2622 IMimeMessage *iface,
2623 const TYPEDID oid,
2624 LPCPROPVARIANT pValue)
2626 HRESULT hr = S_OK;
2627 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2629 /* Message ID is checked before type.
2630 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2632 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2634 WARN("oid (%08x) out of range\n", oid);
2635 return MIME_E_INVALID_OPTION_ID;
2638 if(pValue->vt != TYPEDID_TYPE(oid))
2640 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2641 return S_OK;
2644 switch(oid)
2646 case OID_HIDE_TNEF_ATTACHMENTS:
2647 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2648 break;
2649 case OID_SHOW_MACBINARY:
2650 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2651 break;
2652 case OID_SAVEBODY_KEEPBOUNDARY:
2653 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal);
2654 break;
2655 case OID_CLEANUP_TREE_ON_SAVE:
2656 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal);
2657 break;
2658 default:
2659 FIXME("Unhandled oid %08x\n", oid);
2660 hr = MIME_E_INVALID_OPTION_ID;
2663 return hr;
2666 static HRESULT WINAPI MimeMessage_GetOption(
2667 IMimeMessage *iface,
2668 const TYPEDID oid,
2669 LPPROPVARIANT pValue)
2671 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2672 return E_NOTIMPL;
2675 /*** IMimeMessage methods ***/
2676 static HRESULT WINAPI MimeMessage_CreateWebPage(
2677 IMimeMessage *iface,
2678 IStream *pRootStm,
2679 LPWEBPAGEOPTIONS pOptions,
2680 IMimeMessageCallback *pCallback,
2681 IMoniker **ppMoniker)
2683 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2684 *ppMoniker = NULL;
2685 return E_NOTIMPL;
2688 static HRESULT WINAPI MimeMessage_GetProp(
2689 IMimeMessage *iface,
2690 LPCSTR pszName,
2691 DWORD dwFlags,
2692 LPPROPVARIANT pValue)
2694 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2695 return E_NOTIMPL;
2698 static HRESULT WINAPI MimeMessage_SetProp(
2699 IMimeMessage *iface,
2700 LPCSTR pszName,
2701 DWORD dwFlags,
2702 LPCPROPVARIANT pValue)
2704 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2705 return E_NOTIMPL;
2708 static HRESULT WINAPI MimeMessage_DeleteProp(
2709 IMimeMessage *iface,
2710 LPCSTR pszName)
2712 FIXME("(%p)->(%s)\n", iface, pszName);
2713 return E_NOTIMPL;
2716 static HRESULT WINAPI MimeMessage_QueryProp(
2717 IMimeMessage *iface,
2718 LPCSTR pszName,
2719 LPCSTR pszCriteria,
2720 boolean fSubString,
2721 boolean fCaseSensitive)
2723 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2724 return E_NOTIMPL;
2727 static HRESULT WINAPI MimeMessage_GetTextBody(
2728 IMimeMessage *iface,
2729 DWORD dwTxtType,
2730 ENCODINGTYPE ietEncoding,
2731 IStream **pStream,
2732 LPHBODY phBody)
2734 HRESULT hr;
2735 HBODY hbody;
2736 FINDBODY find_struct;
2737 IMimeBody *mime_body;
2738 static char text[] = "text";
2739 static char plain[] = "plain";
2740 static char html[] = "html";
2742 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2744 find_struct.pszPriType = text;
2746 switch(dwTxtType)
2748 case TXT_PLAIN:
2749 find_struct.pszSubType = plain;
2750 break;
2751 case TXT_HTML:
2752 find_struct.pszSubType = html;
2753 break;
2754 default:
2755 return MIME_E_INVALID_TEXT_TYPE;
2758 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2759 if(hr != S_OK)
2761 TRACE("not found hr %08x\n", hr);
2762 *phBody = NULL;
2763 return hr;
2766 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2768 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2769 *phBody = hbody;
2770 IMimeBody_Release(mime_body);
2771 return hr;
2774 static HRESULT WINAPI MimeMessage_SetTextBody(
2775 IMimeMessage *iface,
2776 DWORD dwTxtType,
2777 ENCODINGTYPE ietEncoding,
2778 HBODY hAlternative,
2779 IStream *pStream,
2780 LPHBODY phBody)
2782 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2783 return E_NOTIMPL;
2786 static HRESULT WINAPI MimeMessage_AttachObject(
2787 IMimeMessage *iface,
2788 REFIID riid,
2789 void *pvObject,
2790 LPHBODY phBody)
2792 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2793 return E_NOTIMPL;
2796 static HRESULT WINAPI MimeMessage_AttachFile(
2797 IMimeMessage *iface,
2798 LPCSTR pszFilePath,
2799 IStream *pstmFile,
2800 LPHBODY phBody)
2802 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2803 return E_NOTIMPL;
2806 static HRESULT WINAPI MimeMessage_AttachURL(
2807 IMimeMessage *iface,
2808 LPCSTR pszBase,
2809 LPCSTR pszURL,
2810 DWORD dwFlags,
2811 IStream *pstmURL,
2812 LPSTR *ppszCIDURL,
2813 LPHBODY phBody)
2815 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2816 return E_NOTIMPL;
2819 static HRESULT WINAPI MimeMessage_GetAttachments(
2820 IMimeMessage *iface,
2821 ULONG *pcAttach,
2822 LPHBODY *pprghAttach)
2824 HRESULT hr;
2825 FINDBODY find_struct;
2826 HBODY hbody;
2827 LPHBODY array;
2828 ULONG size = 10;
2830 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2832 *pcAttach = 0;
2833 array = CoTaskMemAlloc(size * sizeof(HBODY));
2835 find_struct.pszPriType = find_struct.pszSubType = NULL;
2836 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2837 while(hr == S_OK)
2839 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2840 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2841 if(hr != S_OK)
2843 if(*pcAttach + 1 > size)
2845 size *= 2;
2846 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2848 array[*pcAttach] = hbody;
2849 (*pcAttach)++;
2851 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2854 *pprghAttach = array;
2855 return S_OK;
2858 static HRESULT WINAPI MimeMessage_GetAddressTable(
2859 IMimeMessage *iface,
2860 IMimeAddressTable **ppTable)
2862 FIXME("(%p)->(%p)\n", iface, ppTable);
2863 return E_NOTIMPL;
2866 static HRESULT WINAPI MimeMessage_GetSender(
2867 IMimeMessage *iface,
2868 LPADDRESSPROPS pAddress)
2870 FIXME("(%p)->(%p)\n", iface, pAddress);
2871 return E_NOTIMPL;
2874 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2875 IMimeMessage *iface,
2876 DWORD dwAdrTypes,
2877 DWORD dwProps,
2878 LPADDRESSLIST pList)
2880 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2881 return E_NOTIMPL;
2884 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2885 IMimeMessage *iface,
2886 DWORD dwAdrTypes,
2887 ADDRESSFORMAT format,
2888 LPSTR *ppszFormat)
2890 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2891 return E_NOTIMPL;
2894 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2895 IMimeMessage *iface,
2896 DWORD dwAdrTypes,
2897 DWORD dwProps,
2898 IMimeEnumAddressTypes **ppEnum)
2900 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2901 return E_NOTIMPL;
2904 static HRESULT WINAPI MimeMessage_SplitMessage(
2905 IMimeMessage *iface,
2906 ULONG cbMaxPart,
2907 IMimeMessageParts **ppParts)
2909 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
2910 return E_NOTIMPL;
2913 static HRESULT WINAPI MimeMessage_GetRootMoniker(
2914 IMimeMessage *iface,
2915 IMoniker **ppMoniker)
2917 FIXME("(%p)->(%p)\n", iface, ppMoniker);
2918 return E_NOTIMPL;
2921 static const IMimeMessageVtbl MimeMessageVtbl =
2923 MimeMessage_QueryInterface,
2924 MimeMessage_AddRef,
2925 MimeMessage_Release,
2926 MimeMessage_GetClassID,
2927 MimeMessage_IsDirty,
2928 MimeMessage_Load,
2929 MimeMessage_Save,
2930 MimeMessage_GetSizeMax,
2931 MimeMessage_InitNew,
2932 MimeMessage_GetMessageSource,
2933 MimeMessage_GetMessageSize,
2934 MimeMessage_LoadOffsetTable,
2935 MimeMessage_SaveOffsetTable,
2936 MimeMessage_GetFlags,
2937 MimeMessage_Commit,
2938 MimeMessage_HandsOffStorage,
2939 MimeMessage_BindToObject,
2940 MimeMessage_SaveBody,
2941 MimeMessage_InsertBody,
2942 MimeMessage_GetBody,
2943 MimeMessage_DeleteBody,
2944 MimeMessage_MoveBody,
2945 MimeMessage_CountBodies,
2946 MimeMessage_FindFirst,
2947 MimeMessage_FindNext,
2948 MimeMessage_ResolveURL,
2949 MimeMessage_ToMultipart,
2950 MimeMessage_GetBodyOffsets,
2951 MimeMessage_GetCharset,
2952 MimeMessage_SetCharset,
2953 MimeMessage_IsBodyType,
2954 MimeMessage_IsContentType,
2955 MimeMessage_QueryBodyProp,
2956 MimeMessage_GetBodyProp,
2957 MimeMessage_SetBodyProp,
2958 MimeMessage_DeleteBodyProp,
2959 MimeMessage_SetOption,
2960 MimeMessage_GetOption,
2961 MimeMessage_CreateWebPage,
2962 MimeMessage_GetProp,
2963 MimeMessage_SetProp,
2964 MimeMessage_DeleteProp,
2965 MimeMessage_QueryProp,
2966 MimeMessage_GetTextBody,
2967 MimeMessage_SetTextBody,
2968 MimeMessage_AttachObject,
2969 MimeMessage_AttachFile,
2970 MimeMessage_AttachURL,
2971 MimeMessage_GetAttachments,
2972 MimeMessage_GetAddressTable,
2973 MimeMessage_GetSender,
2974 MimeMessage_GetAddressTypes,
2975 MimeMessage_GetAddressFormat,
2976 MimeMessage_EnumAddressTypes,
2977 MimeMessage_SplitMessage,
2978 MimeMessage_GetRootMoniker,
2981 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
2983 MimeMessage *This;
2984 MimeBody *mime_body;
2985 body_t *root_body;
2987 TRACE("(%p, %p)\n", outer, obj);
2989 if (outer)
2991 FIXME("outer unknown not supported yet\n");
2992 return E_NOTIMPL;
2995 *obj = NULL;
2997 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2998 if (!This) return E_OUTOFMEMORY;
3000 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
3001 This->ref = 1;
3002 This->stream = NULL;
3003 list_init(&This->body_tree);
3004 This->next_index = 1;
3006 mime_body = mimebody_create();
3007 root_body = new_body_entry(mime_body, This->next_index++, NULL);
3008 list_add_head(&This->body_tree, &root_body->entry);
3010 *obj = &This->IMimeMessage_iface;
3011 return S_OK;
3014 /***********************************************************************
3015 * MimeOleCreateMessage (INETCOMM.@)
3017 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
3019 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3020 return MimeMessage_create(NULL, (void **)ppMessage);
3023 /***********************************************************************
3024 * MimeOleSetCompatMode (INETCOMM.@)
3026 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3028 FIXME("(0x%x)\n", dwMode);
3029 return S_OK;
3032 /***********************************************************************
3033 * MimeOleCreateVirtualStream (INETCOMM.@)
3035 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3037 HRESULT hr;
3038 FIXME("(%p)\n", ppStream);
3040 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3041 return hr;
3044 typedef struct MimeSecurity
3046 IMimeSecurity IMimeSecurity_iface;
3047 LONG ref;
3048 } MimeSecurity;
3050 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3052 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3055 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3057 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3059 if (IsEqualIID(riid, &IID_IUnknown) ||
3060 IsEqualIID(riid, &IID_IMimeSecurity))
3062 *ppv = iface;
3063 IMimeSecurity_AddRef(iface);
3064 return S_OK;
3067 FIXME("no interface for %s\n", debugstr_guid(riid));
3068 *ppv = NULL;
3069 return E_NOINTERFACE;
3072 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3074 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3075 LONG ref = InterlockedIncrement(&This->ref);
3077 TRACE("(%p) ref=%d\n", This, ref);
3079 return ref;
3082 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3084 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3085 LONG ref = InterlockedDecrement(&This->ref);
3087 TRACE("(%p) ref=%d\n", This, ref);
3089 if (!ref)
3090 HeapFree(GetProcessHeap(), 0, This);
3092 return ref;
3095 static HRESULT WINAPI MimeSecurity_InitNew(
3096 IMimeSecurity* iface)
3098 FIXME("(%p)->(): stub\n", iface);
3099 return S_OK;
3102 static HRESULT WINAPI MimeSecurity_CheckInit(
3103 IMimeSecurity* iface)
3105 FIXME("(%p)->(): stub\n", iface);
3106 return E_NOTIMPL;
3109 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3110 IMimeSecurity* iface,
3111 IMimeMessageTree* pTree,
3112 DWORD dwFlags)
3114 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3115 return E_NOTIMPL;
3118 static HRESULT WINAPI MimeSecurity_EncodeBody(
3119 IMimeSecurity* iface,
3120 IMimeMessageTree* pTree,
3121 HBODY hEncodeRoot,
3122 DWORD dwFlags)
3124 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3125 return E_NOTIMPL;
3128 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3129 IMimeSecurity* iface,
3130 IMimeMessageTree* pTree,
3131 DWORD dwFlags)
3133 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3134 return E_NOTIMPL;
3137 static HRESULT WINAPI MimeSecurity_DecodeBody(
3138 IMimeSecurity* iface,
3139 IMimeMessageTree* pTree,
3140 HBODY hDecodeRoot,
3141 DWORD dwFlags)
3143 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3144 return E_NOTIMPL;
3147 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3148 IMimeSecurity* iface,
3149 HCAPICERTSTORE hc,
3150 DWORD dwUsage,
3151 PCX509CERT pPrev,
3152 PCX509CERT* ppCert)
3154 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3155 return E_NOTIMPL;
3158 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3159 IMimeSecurity* iface,
3160 const PCX509CERT pX509Cert,
3161 const CERTNAMETYPE cn,
3162 LPSTR* ppszName)
3164 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3165 return E_NOTIMPL;
3168 static HRESULT WINAPI MimeSecurity_GetMessageType(
3169 IMimeSecurity* iface,
3170 const HWND hwndParent,
3171 IMimeBody* pBody,
3172 DWORD* pdwSecType)
3174 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3175 return E_NOTIMPL;
3178 static HRESULT WINAPI MimeSecurity_GetCertData(
3179 IMimeSecurity* iface,
3180 const PCX509CERT pX509Cert,
3181 const CERTDATAID dataid,
3182 LPPROPVARIANT pValue)
3184 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3185 return E_NOTIMPL;
3189 static const IMimeSecurityVtbl MimeSecurityVtbl =
3191 MimeSecurity_QueryInterface,
3192 MimeSecurity_AddRef,
3193 MimeSecurity_Release,
3194 MimeSecurity_InitNew,
3195 MimeSecurity_CheckInit,
3196 MimeSecurity_EncodeMessage,
3197 MimeSecurity_EncodeBody,
3198 MimeSecurity_DecodeMessage,
3199 MimeSecurity_DecodeBody,
3200 MimeSecurity_EnumCertificates,
3201 MimeSecurity_GetCertificateName,
3202 MimeSecurity_GetMessageType,
3203 MimeSecurity_GetCertData
3206 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3208 MimeSecurity *This;
3210 *obj = NULL;
3212 if (outer) return CLASS_E_NOAGGREGATION;
3214 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3215 if (!This) return E_OUTOFMEMORY;
3217 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3218 This->ref = 1;
3220 *obj = &This->IMimeSecurity_iface;
3221 return S_OK;
3224 /***********************************************************************
3225 * MimeOleCreateSecurity (INETCOMM.@)
3227 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3229 return MimeSecurity_create(NULL, (void **)ppSecurity);
3232 static HRESULT WINAPI MimeAlloc_QueryInterface(
3233 IMimeAllocator* iface,
3234 REFIID riid,
3235 void **obj)
3237 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3239 if (IsEqualIID(riid, &IID_IUnknown) ||
3240 IsEqualIID(riid, &IID_IMalloc) ||
3241 IsEqualIID(riid, &IID_IMimeAllocator))
3243 *obj = iface;
3244 IMimeAllocator_AddRef(iface);
3245 return S_OK;
3248 FIXME("no interface for %s\n", debugstr_guid(riid));
3249 *obj = NULL;
3250 return E_NOINTERFACE;
3253 static ULONG WINAPI MimeAlloc_AddRef(
3254 IMimeAllocator* iface)
3256 return 2;
3259 static ULONG WINAPI MimeAlloc_Release(
3260 IMimeAllocator* iface)
3262 return 1;
3265 static LPVOID WINAPI MimeAlloc_Alloc(
3266 IMimeAllocator* iface,
3267 SIZE_T cb)
3269 return CoTaskMemAlloc(cb);
3272 static LPVOID WINAPI MimeAlloc_Realloc(
3273 IMimeAllocator* iface,
3274 LPVOID pv,
3275 SIZE_T cb)
3277 return CoTaskMemRealloc(pv, cb);
3280 static void WINAPI MimeAlloc_Free(
3281 IMimeAllocator* iface,
3282 LPVOID pv)
3284 CoTaskMemFree(pv);
3287 static SIZE_T WINAPI MimeAlloc_GetSize(
3288 IMimeAllocator* iface,
3289 LPVOID pv)
3291 FIXME("stub\n");
3292 return 0;
3295 static int WINAPI MimeAlloc_DidAlloc(
3296 IMimeAllocator* iface,
3297 LPVOID pv)
3299 FIXME("stub\n");
3300 return 0;
3303 static void WINAPI MimeAlloc_HeapMinimize(
3304 IMimeAllocator* iface)
3306 FIXME("stub\n");
3307 return;
3310 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3311 IMimeAllocator* iface,
3312 ULONG cParams,
3313 LPMIMEPARAMINFO prgParam,
3314 boolean fFreeArray)
3316 ULONG i;
3317 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3319 for(i = 0; i < cParams; i++)
3321 IMimeAllocator_Free(iface, prgParam[i].pszName);
3322 IMimeAllocator_Free(iface, prgParam[i].pszData);
3324 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3325 return S_OK;
3328 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3329 IMimeAllocator* iface,
3330 LPADDRESSLIST pList)
3332 FIXME("stub\n");
3333 return E_NOTIMPL;
3336 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3337 IMimeAllocator* iface,
3338 LPADDRESSPROPS pAddress)
3340 FIXME("stub\n");
3341 return E_NOTIMPL;
3344 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3345 IMimeAllocator* iface,
3346 ULONG cObjects,
3347 IUnknown **prgpUnknown,
3348 boolean fFreeArray)
3350 FIXME("stub\n");
3351 return E_NOTIMPL;
3355 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3356 IMimeAllocator* iface,
3357 ULONG cRows,
3358 LPENUMHEADERROW prgRow,
3359 boolean fFreeArray)
3361 FIXME("stub\n");
3362 return E_NOTIMPL;
3365 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3366 IMimeAllocator* iface,
3367 ULONG cProps,
3368 LPENUMPROPERTY prgProp,
3369 boolean fFreeArray)
3371 FIXME("stub\n");
3372 return E_NOTIMPL;
3375 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3376 IMimeAllocator* iface,
3377 THUMBBLOB *pthumbprint)
3379 FIXME("stub\n");
3380 return E_NOTIMPL;
3384 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3385 IMimeAllocator* iface,
3386 LPPROPVARIANT pProp)
3388 FIXME("stub\n");
3389 return E_NOTIMPL;
3392 static IMimeAllocatorVtbl mime_alloc_vtbl =
3394 MimeAlloc_QueryInterface,
3395 MimeAlloc_AddRef,
3396 MimeAlloc_Release,
3397 MimeAlloc_Alloc,
3398 MimeAlloc_Realloc,
3399 MimeAlloc_Free,
3400 MimeAlloc_GetSize,
3401 MimeAlloc_DidAlloc,
3402 MimeAlloc_HeapMinimize,
3403 MimeAlloc_FreeParamInfoArray,
3404 MimeAlloc_FreeAddressList,
3405 MimeAlloc_FreeAddressProps,
3406 MimeAlloc_ReleaseObjects,
3407 MimeAlloc_FreeEnumHeaderRowArray,
3408 MimeAlloc_FreeEnumPropertyArray,
3409 MimeAlloc_FreeThumbprint,
3410 MimeAlloc_PropVariantClear
3413 static IMimeAllocator mime_allocator =
3415 &mime_alloc_vtbl
3418 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3420 if(outer) return CLASS_E_NOAGGREGATION;
3422 *obj = &mime_allocator;
3423 return S_OK;
3426 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3428 return MimeAllocator_create(NULL, (void**)alloc);
3431 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3433 FIXME("(%p, %p)\n", outer, obj);
3435 *obj = NULL;
3436 if (outer) return CLASS_E_NOAGGREGATION;
3438 return MimeOleCreateVirtualStream((IStream **)obj);
3441 /* IMimePropertySchema Interface */
3442 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3444 propschema *This = impl_from_IMimePropertySchema(iface);
3445 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3447 *out = NULL;
3449 if (IsEqualIID(riid, &IID_IUnknown) ||
3450 IsEqualIID(riid, &IID_IMimePropertySchema))
3452 *out = iface;
3454 else
3456 FIXME("no interface for %s\n", debugstr_guid(riid));
3457 return E_NOINTERFACE;
3460 IMimePropertySchema_AddRef(iface);
3461 return S_OK;
3464 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3466 propschema *This = impl_from_IMimePropertySchema(iface);
3467 LONG ref = InterlockedIncrement(&This->ref);
3469 TRACE("(%p) ref=%d\n", This, ref);
3471 return ref;
3474 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3476 propschema *This = impl_from_IMimePropertySchema(iface);
3477 LONG ref = InterlockedDecrement(&This->ref);
3479 TRACE("(%p) ref=%d\n", This, ref);
3481 if (!ref)
3483 HeapFree(GetProcessHeap(), 0, This);
3486 return ref;
3489 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3490 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3492 propschema *This = impl_from_IMimePropertySchema(iface);
3493 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3494 return E_NOTIMPL;
3497 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3498 DWORD rownumber, VARTYPE vtdefault)
3500 propschema *This = impl_from_IMimePropertySchema(iface);
3501 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3502 return S_OK;
3505 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3507 propschema *This = impl_from_IMimePropertySchema(iface);
3508 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3509 return E_NOTIMPL;
3512 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3514 propschema *This = impl_from_IMimePropertySchema(iface);
3515 FIXME("(%p)->(%d, %p) stub\n", This, propid, name);
3516 return E_NOTIMPL;
3519 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3521 propschema *This = impl_from_IMimePropertySchema(iface);
3522 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3523 return E_NOTIMPL;
3526 static IMimePropertySchemaVtbl prop_schema_vtbl =
3528 propschema_QueryInterface,
3529 propschema_AddRef,
3530 propschema_Release,
3531 propschema_RegisterProperty,
3532 propschema_ModifyProperty,
3533 propschema_GetPropertyId,
3534 propschema_GetPropertyName,
3535 propschema_RegisterAddressType
3539 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3541 propschema *This;
3543 TRACE("(%p) stub\n", schema);
3545 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3546 if (!This)
3547 return E_OUTOFMEMORY;
3549 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3550 This->ref = 1;
3552 *schema = &This->IMimePropertySchema_iface;
3554 return S_OK;
3557 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3558 ADDRESSFORMAT addr_format, WCHAR **address)
3560 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3562 return E_NOTIMPL;
3565 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3566 REFIID riid, void **out, IMoniker **moniker_new)
3568 FIXME("(0x%08x, %p, %p, %s, %p, %p) stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3570 return E_NOTIMPL;