[INETCOMM] Sync with Wine Staging 3.17. CORE-15127
[reactos.git] / dll / win32 / inetcomm / mimeole.c
1 /*
2 * MIME OLE Interfaces
3 *
4 * Copyright 2006 Robert Shearman for CodeWeavers
5 * Copyright 2007 Huw Davies for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "ole2.h"
33 #include "mimeole.h"
34 #ifdef __REACTOS__
35 #include <winreg.h>
36 #endif
37 #include "propvarutil.h"
38
39 #include "wine/heap.h"
40 #include "wine/list.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43
44 #include "inetcomm_private.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
47
48 typedef struct
49 {
50 LPCSTR name;
51 DWORD id;
52 DWORD flags; /* MIMEPROPFLAGS */
53 VARTYPE default_vt;
54 } property_t;
55
56 typedef struct
57 {
58 struct list entry;
59 property_t prop;
60 } property_list_entry_t;
61
62 static const property_t default_props[] =
63 {
64 {"X-Newsgroup", PID_HDR_NEWSGROUP, 0, VT_LPSTR},
65 {"Newsgroups", PID_HDR_NEWSGROUPS, 0, VT_LPSTR},
66 {"References", PID_HDR_REFS, 0, VT_LPSTR},
67 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
68 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
69 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
70 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
71 {"Rr", PID_HDR_RR, 0, VT_LPSTR},
72 {"Return-Receipt-To", PID_HDR_RETRCPTO, MPF_ADDRESS, VT_LPSTR},
73 {"Apparently-To", PID_HDR_APPARTO, MPF_ADDRESS, VT_LPSTR},
74 {"Date", PID_HDR_DATE, 0, VT_LPSTR},
75 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
76 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
77 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
78 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
79 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
80 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
81 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
82 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
83 {"Content-Description", PID_HDR_CNTDESC, MPF_MIME, VT_LPSTR},
84 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
85 {"Content-Base", PID_HDR_CNTBASE, MPF_MIME, VT_LPSTR},
86 {"Content-Location", PID_HDR_CNTLOC, MPF_MIME, VT_LPSTR},
87 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
88 {"Path", PID_HDR_PATH, 0, VT_LPSTR},
89 {"Followup-To", PID_HDR_FOLLOWUPTO, 0, VT_LPSTR},
90 {"Expires", PID_HDR_EXPIRES, 0, VT_LPSTR},
91 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
92 {"Control", PID_HDR_CONTROL, 0, VT_LPSTR},
93 {"Distribution", PID_HDR_DISTRIB, 0, VT_LPSTR},
94 {"Keywords", PID_HDR_KEYWORDS, 0, VT_LPSTR},
95 {"Summary", PID_HDR_SUMMARY, 0, VT_LPSTR},
96 {"Approved", PID_HDR_APPROVED, 0, VT_LPSTR},
97 {"Lines", PID_HDR_LINES, 0, VT_LPSTR},
98 {"Xref", PID_HDR_XREF, 0, VT_LPSTR},
99 {"Organization", PID_HDR_ORG, 0, VT_LPSTR},
100 {"X-Newsreader", PID_HDR_XNEWSRDR, 0, VT_LPSTR},
101 {"X-Priority", PID_HDR_XPRI, 0, VT_LPSTR},
102 {"X-MSMail-Priority", PID_HDR_XMSPRI, 0, VT_LPSTR},
103 {"par:content-disposition:filename", PID_PAR_FILENAME, 0, VT_LPSTR},
104 {"par:content-type:boundary", PID_PAR_BOUNDARY, 0, VT_LPSTR},
105 {"par:content-type:charset", PID_PAR_CHARSET, 0, VT_LPSTR},
106 {"par:content-type:name", PID_PAR_NAME, 0, VT_LPSTR},
107 {"att:filename", PID_ATT_FILENAME, 0, VT_LPSTR},
108 {"att:pri-content-type", PID_ATT_PRITYPE, 0, VT_LPSTR},
109 {"att:sub-content-type", PID_ATT_SUBTYPE, 0, VT_LPSTR},
110 {"att:illegal-lines", PID_ATT_ILLEGAL, 0, VT_LPSTR},
111 {"att:rendered", PID_ATT_RENDERED, 0, VT_LPSTR},
112 {"att:sent-time", PID_ATT_SENTTIME, 0, VT_LPSTR},
113 {"att:priority", PID_ATT_PRIORITY, 0, VT_LPSTR},
114 {"Comment", PID_HDR_COMMENT, 0, VT_LPSTR},
115 {"Encoding", PID_HDR_ENCODING, 0, VT_LPSTR},
116 {"Encrypted", PID_HDR_ENCRYPTED, 0, VT_LPSTR},
117 {"X-Offsets", PID_HDR_OFFSETS, 0, VT_LPSTR},
118 {"X-Unsent", PID_HDR_XUNSENT, 0, VT_LPSTR},
119 {"X-ArticleId", PID_HDR_ARTICLEID, 0, VT_LPSTR},
120 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
121 {"att:athena-server", PID_ATT_SERVER, 0, VT_LPSTR},
122 {"att:athena-account-id", PID_ATT_ACCOUNT, 0, VT_LPSTR},
123 {"att:athena-pop3-uidl", PID_ATT_UIDL, 0, VT_LPSTR},
124 {"att:athena-store-msgid", PID_ATT_STOREMSGID, 0, VT_LPSTR},
125 {"att:athena-user-name", PID_ATT_USERNAME, 0, VT_LPSTR},
126 {"att:athena-forward-to", PID_ATT_FORWARDTO, 0, VT_LPSTR},
127 {"att:athena-store-fdrid", PID_ATT_STOREFOLDERID,0, VT_LPSTR},
128 {"att:athena-ghosted", PID_ATT_GHOSTED, 0, VT_LPSTR},
129 {"att:athena-uncachedsize", PID_ATT_UNCACHEDSIZE, 0, VT_LPSTR},
130 {"att:athena-combined", PID_ATT_COMBINED, 0, VT_LPSTR},
131 {"att:auto-inlined", PID_ATT_AUTOINLINED, 0, VT_LPSTR},
132 {"Disposition-Notification-To", PID_HDR_DISP_NOTIFICATION_TO, 0, VT_LPSTR},
133 {"par:Content-Type:reply-type", PID_PAR_REPLYTYPE, 0, VT_LPSTR},
134 {"par:Content-Type:format", PID_PAR_FORMAT , 0, VT_LPSTR},
135 {"att:format", PID_ATT_FORMAT , 0, VT_LPSTR},
136 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
137 {"att:athena-account-name", PID_ATT_ACCOUNTNAME, 0, VT_LPSTR},
138 {NULL, 0, 0, 0}
139 };
140
141 typedef struct
142 {
143 struct list entry;
144 char *name;
145 char *value;
146 } param_t;
147
148 typedef struct
149 {
150 struct list entry;
151 const property_t *prop;
152 PROPVARIANT value;
153 struct list params;
154 } header_t;
155
156 typedef struct MimeBody
157 {
158 IMimeBody IMimeBody_iface;
159 LONG ref;
160
161 HBODY handle;
162
163 struct list headers;
164 struct list new_props; /* FIXME: This should be in a PropertySchema */
165 DWORD next_prop_id;
166 char *content_pri_type;
167 char *content_sub_type;
168 ENCODINGTYPE encoding;
169 void *data;
170 IID data_iid;
171 BODYOFFSETS body_offsets;
172 } MimeBody;
173
174 typedef struct
175 {
176 IStream IStream_iface;
177 LONG ref;
178 IStream *base;
179 ULARGE_INTEGER pos, start, length;
180 } sub_stream_t;
181
182 static inline sub_stream_t *impl_from_IStream(IStream *iface)
183 {
184 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
185 }
186
187 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
188 {
189 sub_stream_t *This = impl_from_IStream(iface);
190
191 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
192 *ppv = NULL;
193
194 if(IsEqualIID(riid, &IID_IUnknown) ||
195 IsEqualIID(riid, &IID_ISequentialStream) ||
196 IsEqualIID(riid, &IID_IStream))
197 {
198 IStream_AddRef(iface);
199 *ppv = iface;
200 return S_OK;
201 }
202 return E_NOINTERFACE;
203 }
204
205 static ULONG WINAPI sub_stream_AddRef(IStream *iface)
206 {
207 sub_stream_t *This = impl_from_IStream(iface);
208 LONG ref = InterlockedIncrement(&This->ref);
209
210 TRACE("(%p) ref=%d\n", This, ref);
211
212 return ref;
213 }
214
215 static ULONG WINAPI sub_stream_Release(IStream *iface)
216 {
217 sub_stream_t *This = impl_from_IStream(iface);
218 LONG ref = InterlockedDecrement(&This->ref);
219
220 TRACE("(%p) ref=%d\n", This, ref);
221
222 if(!ref)
223 {
224 IStream_Release(This->base);
225 HeapFree(GetProcessHeap(), 0, This);
226 }
227 return ref;
228 }
229
230 static HRESULT WINAPI sub_stream_Read(
231 IStream* iface,
232 void *pv,
233 ULONG cb,
234 ULONG *pcbRead)
235 {
236 sub_stream_t *This = impl_from_IStream(iface);
237 HRESULT hr;
238 LARGE_INTEGER tmp_pos;
239
240 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
241
242 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
243 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
244
245 if(This->pos.QuadPart + cb > This->length.QuadPart)
246 cb = This->length.QuadPart - This->pos.QuadPart;
247
248 hr = IStream_Read(This->base, pv, cb, pcbRead);
249
250 This->pos.QuadPart += *pcbRead;
251
252 return hr;
253 }
254
255 static HRESULT WINAPI sub_stream_Write(
256 IStream* iface,
257 const void *pv,
258 ULONG cb,
259 ULONG *pcbWritten)
260 {
261 FIXME("stub\n");
262 return E_NOTIMPL;
263 }
264
265 static HRESULT WINAPI sub_stream_Seek(
266 IStream* iface,
267 LARGE_INTEGER dlibMove,
268 DWORD dwOrigin,
269 ULARGE_INTEGER *plibNewPosition)
270 {
271 sub_stream_t *This = impl_from_IStream(iface);
272 LARGE_INTEGER new_pos;
273
274 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
275
276 switch(dwOrigin)
277 {
278 case STREAM_SEEK_SET:
279 new_pos = dlibMove;
280 break;
281 case STREAM_SEEK_CUR:
282 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
283 break;
284 case STREAM_SEEK_END:
285 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
286 break;
287 default:
288 return STG_E_INVALIDFUNCTION;
289 }
290
291 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
292 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
293
294 This->pos.QuadPart = new_pos.QuadPart;
295
296 if(plibNewPosition) *plibNewPosition = This->pos;
297 return S_OK;
298 }
299
300 static HRESULT WINAPI sub_stream_SetSize(
301 IStream* iface,
302 ULARGE_INTEGER libNewSize)
303 {
304 FIXME("stub\n");
305 return E_NOTIMPL;
306 }
307
308 static HRESULT WINAPI sub_stream_CopyTo(
309 IStream* iface,
310 IStream *pstm,
311 ULARGE_INTEGER cb,
312 ULARGE_INTEGER *pcbRead,
313 ULARGE_INTEGER *pcbWritten)
314 {
315 HRESULT hr = S_OK;
316 BYTE tmpBuffer[128];
317 ULONG bytesRead, bytesWritten, copySize;
318 ULARGE_INTEGER totalBytesRead;
319 ULARGE_INTEGER totalBytesWritten;
320
321 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
322
323 totalBytesRead.QuadPart = 0;
324 totalBytesWritten.QuadPart = 0;
325
326 while ( cb.QuadPart > 0 )
327 {
328 if ( cb.QuadPart >= sizeof(tmpBuffer) )
329 copySize = sizeof(tmpBuffer);
330 else
331 copySize = cb.u.LowPart;
332
333 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
334 if (FAILED(hr)) break;
335
336 totalBytesRead.QuadPart += bytesRead;
337
338 if (bytesRead)
339 {
340 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
341 if (FAILED(hr)) break;
342 totalBytesWritten.QuadPart += bytesWritten;
343 }
344
345 if (bytesRead != copySize)
346 cb.QuadPart = 0;
347 else
348 cb.QuadPart -= bytesRead;
349 }
350
351 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
352 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
353
354 return hr;
355 }
356
357 static HRESULT WINAPI sub_stream_Commit(
358 IStream* iface,
359 DWORD grfCommitFlags)
360 {
361 FIXME("stub\n");
362 return E_NOTIMPL;
363 }
364
365 static HRESULT WINAPI sub_stream_Revert(
366 IStream* iface)
367 {
368 FIXME("stub\n");
369 return E_NOTIMPL;
370 }
371
372 static HRESULT WINAPI sub_stream_LockRegion(
373 IStream* iface,
374 ULARGE_INTEGER libOffset,
375 ULARGE_INTEGER cb,
376 DWORD dwLockType)
377 {
378 FIXME("stub\n");
379 return E_NOTIMPL;
380 }
381
382 static HRESULT WINAPI sub_stream_UnlockRegion(
383 IStream* iface,
384 ULARGE_INTEGER libOffset,
385 ULARGE_INTEGER cb,
386 DWORD dwLockType)
387 {
388 FIXME("stub\n");
389 return E_NOTIMPL;
390 }
391
392 static HRESULT WINAPI sub_stream_Stat(
393 IStream* iface,
394 STATSTG *pstatstg,
395 DWORD grfStatFlag)
396 {
397 sub_stream_t *This = impl_from_IStream(iface);
398 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
399 memset(pstatstg, 0, sizeof(*pstatstg));
400 pstatstg->cbSize = This->length;
401 return S_OK;
402 }
403
404 static HRESULT WINAPI sub_stream_Clone(
405 IStream* iface,
406 IStream **ppstm)
407 {
408 FIXME("stub\n");
409 return E_NOTIMPL;
410 }
411
412 static struct IStreamVtbl sub_stream_vtbl =
413 {
414 sub_stream_QueryInterface,
415 sub_stream_AddRef,
416 sub_stream_Release,
417 sub_stream_Read,
418 sub_stream_Write,
419 sub_stream_Seek,
420 sub_stream_SetSize,
421 sub_stream_CopyTo,
422 sub_stream_Commit,
423 sub_stream_Revert,
424 sub_stream_LockRegion,
425 sub_stream_UnlockRegion,
426 sub_stream_Stat,
427 sub_stream_Clone
428 };
429
430 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
431 {
432 sub_stream_t *This;
433
434 *out = NULL;
435 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
436 if(!This) return E_OUTOFMEMORY;
437
438 This->IStream_iface.lpVtbl = &sub_stream_vtbl;
439 This->ref = 1;
440 This->start = start;
441 This->length = length;
442 This->pos.QuadPart = 0;
443 IStream_AddRef(stream);
444 This->base = stream;
445
446 *out = &This->IStream_iface;
447 return S_OK;
448 }
449
450 static HRESULT get_stream_size(IStream *stream, ULARGE_INTEGER *size)
451 {
452 STATSTG statstg = {NULL};
453 LARGE_INTEGER zero;
454 HRESULT hres;
455
456 hres = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
457 if(SUCCEEDED(hres)) {
458 *size = statstg.cbSize;
459 return S_OK;
460 }
461
462 zero.QuadPart = 0;
463 return IStream_Seek(stream, zero, STREAM_SEEK_END, size);
464 }
465
466 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
467 {
468 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
469 }
470
471 typedef struct propschema
472 {
473 IMimePropertySchema IMimePropertySchema_iface;
474 LONG ref;
475 } propschema;
476
477 static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
478 {
479 return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
480 }
481
482 static LPSTR strdupA(LPCSTR str)
483 {
484 char *ret;
485 int len = strlen(str);
486 ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
487 memcpy(ret, str, len + 1);
488 return ret;
489 }
490
491 #define PARSER_BUF_SIZE 1024
492
493 /*****************************************************
494 * copy_headers_to_buf [internal]
495 *
496 * Copies the headers into a '\0' terminated memory block and leave
497 * the stream's current position set to after the blank line.
498 */
499 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
500 {
501 char *buf = NULL;
502 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
503 HRESULT hr;
504 BOOL done = FALSE;
505
506 *ptr = NULL;
507
508 do
509 {
510 char *end;
511 DWORD read;
512
513 if(!buf)
514 buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
515 else
516 {
517 size *= 2;
518 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
519 }
520 if(!buf)
521 {
522 hr = E_OUTOFMEMORY;
523 goto fail;
524 }
525
526 hr = IStream_Read(stm, buf + offset, size - offset, &read);
527 if(FAILED(hr)) goto fail;
528
529 offset += read;
530 buf[offset] = '\0';
531
532 if(read == 0) done = TRUE;
533
534 while(!done && (end = strstr(buf + last_end, "\r\n")))
535 {
536 DWORD new_end = end - buf + 2;
537 if(new_end - last_end == 2)
538 {
539 LARGE_INTEGER off;
540 off.QuadPart = (LONGLONG)new_end - offset;
541 IStream_Seek(stm, off, STREAM_SEEK_CUR, NULL);
542 buf[new_end] = '\0';
543 done = TRUE;
544 }
545 else
546 last_end = new_end;
547 }
548 } while(!done);
549
550 *ptr = buf;
551 return S_OK;
552
553 fail:
554 HeapFree(GetProcessHeap(), 0, buf);
555 return hr;
556 }
557
558 static header_t *read_prop(MimeBody *body, char **ptr)
559 {
560 char *colon = strchr(*ptr, ':');
561 const property_t *prop;
562 header_t *ret;
563
564 if(!colon) return NULL;
565
566 *colon = '\0';
567
568 for(prop = default_props; prop->name; prop++)
569 {
570 if(!lstrcmpiA(*ptr, prop->name))
571 {
572 TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
573 break;
574 }
575 }
576
577 if(!prop->name)
578 {
579 property_list_entry_t *prop_entry;
580 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
581 {
582 if(!lstrcmpiA(*ptr, prop_entry->prop.name))
583 {
584 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
585 prop = &prop_entry->prop;
586 break;
587 }
588 }
589 if(!prop->name)
590 {
591 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
592 prop_entry->prop.name = strdupA(*ptr);
593 prop_entry->prop.id = body->next_prop_id++;
594 prop_entry->prop.flags = 0;
595 prop_entry->prop.default_vt = VT_LPSTR;
596 list_add_tail(&body->new_props, &prop_entry->entry);
597 prop = &prop_entry->prop;
598 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
599 }
600 }
601
602 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
603 ret->prop = prop;
604 PropVariantInit(&ret->value);
605 list_init(&ret->params);
606 *ptr = colon + 1;
607
608 return ret;
609 }
610
611 static void unfold_header(char *header, int len)
612 {
613 char *start = header, *cp = header;
614
615 do {
616 while(*cp == ' ' || *cp == '\t')
617 {
618 cp++;
619 len--;
620 }
621 if(cp != start)
622 memmove(start, cp, len + 1);
623
624 cp = strstr(start, "\r\n");
625 len -= (cp - start);
626 start = cp;
627 *start = ' ';
628 start++;
629 len--;
630 cp += 2;
631 } while(*cp == ' ' || *cp == '\t');
632
633 *(start - 1) = '\0';
634 }
635
636 static char *unquote_string(const char *str)
637 {
638 BOOL quoted = FALSE;
639 char *ret, *cp;
640
641 while(*str == ' ' || *str == '\t') str++;
642
643 if(*str == '"')
644 {
645 quoted = TRUE;
646 str++;
647 }
648 ret = strdupA(str);
649 for(cp = ret; *cp; cp++)
650 {
651 if(*cp == '\\')
652 memmove(cp, cp + 1, strlen(cp + 1) + 1);
653 else if(*cp == '"')
654 {
655 if(!quoted)
656 {
657 WARN("quote in unquoted string\n");
658 }
659 else
660 {
661 *cp = '\0';
662 break;
663 }
664 }
665 }
666 return ret;
667 }
668
669 static void add_param(header_t *header, const char *p)
670 {
671 const char *key = p, *value, *cp = p;
672 param_t *param;
673 char *name;
674
675 TRACE("got param %s\n", p);
676
677 while (*key == ' ' || *key == '\t' ) key++;
678
679 cp = strchr(key, '=');
680 if(!cp)
681 {
682 WARN("malformed parameter - skipping\n");
683 return;
684 }
685
686 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
687 memcpy(name, key, cp - key);
688 name[cp - key] = '\0';
689
690 value = cp + 1;
691
692 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
693 param->name = name;
694 param->value = unquote_string(value);
695 list_add_tail(&header->params, &param->entry);
696 }
697
698 static void split_params(header_t *header, char *value)
699 {
700 char *cp = value, *start = value;
701 BOOL in_quotes = FALSE, done_value = FALSE;
702
703 while(*cp)
704 {
705 if(!in_quotes && *cp == ';')
706 {
707 *cp = '\0';
708 if(done_value) add_param(header, start);
709 done_value = TRUE;
710 start = cp + 1;
711 }
712 else if(*cp == '"')
713 in_quotes = !in_quotes;
714 cp++;
715 }
716 if(done_value) add_param(header, start);
717 }
718
719 static void read_value(header_t *header, char **cur)
720 {
721 char *end = *cur, *value;
722 DWORD len;
723
724 do {
725 end = strstr(end, "\r\n");
726 end += 2;
727 } while(*end == ' ' || *end == '\t');
728
729 len = end - *cur;
730 value = HeapAlloc(GetProcessHeap(), 0, len + 1);
731 memcpy(value, *cur, len);
732 value[len] = '\0';
733
734 unfold_header(value, len);
735 TRACE("value %s\n", debugstr_a(value));
736
737 if(header->prop->flags & MPF_HASPARAMS)
738 {
739 split_params(header, value);
740 TRACE("value w/o params %s\n", debugstr_a(value));
741 }
742
743 header->value.vt = VT_LPSTR;
744 header->value.u.pszVal = value;
745
746 *cur = end;
747 }
748
749 static void init_content_type(MimeBody *body, header_t *header)
750 {
751 char *slash;
752 DWORD len;
753
754 slash = strchr(header->value.u.pszVal, '/');
755 if(!slash)
756 {
757 WARN("malformed context type value\n");
758 return;
759 }
760 len = slash - header->value.u.pszVal;
761 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
762 memcpy(body->content_pri_type, header->value.u.pszVal, len);
763 body->content_pri_type[len] = '\0';
764 body->content_sub_type = strdupA(slash + 1);
765 }
766
767 static void init_content_encoding(MimeBody *body, header_t *header)
768 {
769 const char *encoding = header->value.u.pszVal;
770
771 if(!strcasecmp(encoding, "base64"))
772 body->encoding = IET_BASE64;
773 else if(!strcasecmp(encoding, "quoted-printable"))
774 body->encoding = IET_QP;
775 else if(!strcasecmp(encoding, "7bit"))
776 body->encoding = IET_7BIT;
777 else if(!strcasecmp(encoding, "8bit"))
778 body->encoding = IET_8BIT;
779 else
780 FIXME("unknown encoding %s\n", debugstr_a(encoding));
781 }
782
783 static HRESULT parse_headers(MimeBody *body, IStream *stm)
784 {
785 char *header_buf, *cur_header_ptr;
786 HRESULT hr;
787 header_t *header;
788
789 hr = copy_headers_to_buf(stm, &header_buf);
790 if(FAILED(hr)) return hr;
791
792 cur_header_ptr = header_buf;
793 while((header = read_prop(body, &cur_header_ptr)))
794 {
795 read_value(header, &cur_header_ptr);
796 list_add_tail(&body->headers, &header->entry);
797
798 switch(header->prop->id) {
799 case PID_HDR_CNTTYPE:
800 init_content_type(body, header);
801 break;
802 case PID_HDR_CNTXFER:
803 init_content_encoding(body, header);
804 break;
805 }
806 }
807
808 HeapFree(GetProcessHeap(), 0, header_buf);
809 return hr;
810 }
811
812 static void empty_param_list(struct list *list)
813 {
814 param_t *param, *cursor2;
815
816 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
817 {
818 list_remove(&param->entry);
819 HeapFree(GetProcessHeap(), 0, param->name);
820 HeapFree(GetProcessHeap(), 0, param->value);
821 HeapFree(GetProcessHeap(), 0, param);
822 }
823 }
824
825 static void empty_header_list(struct list *list)
826 {
827 header_t *header, *cursor2;
828
829 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
830 {
831 list_remove(&header->entry);
832 PropVariantClear(&header->value);
833 empty_param_list(&header->params);
834 HeapFree(GetProcessHeap(), 0, header);
835 }
836 }
837
838 static void empty_new_prop_list(struct list *list)
839 {
840 property_list_entry_t *prop, *cursor2;
841
842 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
843 {
844 list_remove(&prop->entry);
845 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
846 HeapFree(GetProcessHeap(), 0, prop);
847 }
848 }
849
850 static void release_data(REFIID riid, void *data)
851 {
852 if(!data) return;
853
854 if(IsEqualIID(riid, &IID_IStream))
855 IStream_Release((IStream *)data);
856 else
857 FIXME("Unhandled data format %s\n", debugstr_guid(riid));
858 }
859
860 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
861 {
862 header_t *header;
863
864 *prop = NULL;
865
866 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
867 {
868 if(ISPIDSTR(name))
869 {
870 if(STRTOPID(name) == header->prop->id)
871 {
872 *prop = header;
873 return S_OK;
874 }
875 }
876 else if(!lstrcmpiA(name, header->prop->name))
877 {
878 *prop = header;
879 return S_OK;
880 }
881 }
882
883 return MIME_E_NOT_FOUND;
884 }
885
886 static const property_t *find_default_prop(const char *name)
887 {
888 const property_t *prop_def = NULL;
889
890 for(prop_def = default_props; prop_def->name; prop_def++)
891 {
892 if(ISPIDSTR(name))
893 {
894 if(STRTOPID(name) == prop_def->id)
895 {
896 break;
897 }
898 }
899 else if(!lstrcmpiA(name, prop_def->name))
900 {
901 break;
902 }
903 }
904
905 if(prop_def->id)
906 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
907 else
908 prop_def = NULL;
909
910 return prop_def;
911 }
912
913 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
914 REFIID riid,
915 void** ppvObject)
916 {
917 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
918
919 *ppvObject = NULL;
920
921 if (IsEqualIID(riid, &IID_IUnknown) ||
922 IsEqualIID(riid, &IID_IPersist) ||
923 IsEqualIID(riid, &IID_IPersistStreamInit) ||
924 IsEqualIID(riid, &IID_IMimePropertySet) ||
925 IsEqualIID(riid, &IID_IMimeBody))
926 {
927 *ppvObject = iface;
928 }
929
930 if(*ppvObject)
931 {
932 IUnknown_AddRef((IUnknown*)*ppvObject);
933 return S_OK;
934 }
935
936 FIXME("no interface for %s\n", debugstr_guid(riid));
937 return E_NOINTERFACE;
938 }
939
940 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
941 {
942 MimeBody *This = impl_from_IMimeBody(iface);
943 LONG ref = InterlockedIncrement(&This->ref);
944
945 TRACE("(%p) ref=%d\n", This, ref);
946
947 return ref;
948 }
949
950 static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
951 {
952 MimeBody *This = impl_from_IMimeBody(iface);
953 LONG ref = InterlockedDecrement(&This->ref);
954
955 TRACE("(%p) ref=%d\n", This, ref);
956
957 if (!ref)
958 {
959 empty_header_list(&This->headers);
960 empty_new_prop_list(&This->new_props);
961
962 HeapFree(GetProcessHeap(), 0, This->content_pri_type);
963 HeapFree(GetProcessHeap(), 0, This->content_sub_type);
964
965 release_data(&This->data_iid, This->data);
966
967 HeapFree(GetProcessHeap(), 0, This);
968 }
969
970 return ref;
971 }
972
973 static HRESULT WINAPI MimeBody_GetClassID(
974 IMimeBody* iface,
975 CLSID* pClassID)
976 {
977 MimeBody *This = impl_from_IMimeBody(iface);
978
979 TRACE("(%p)->(%p)\n", This, pClassID);
980
981 if(!pClassID)
982 return E_INVALIDARG;
983
984 *pClassID = IID_IMimeBody;
985 return S_OK;
986 }
987
988 static HRESULT WINAPI MimeBody_IsDirty(
989 IMimeBody* iface)
990 {
991 MimeBody *This = impl_from_IMimeBody(iface);
992 FIXME("(%p)->() stub\n", This);
993 return E_NOTIMPL;
994 }
995
996 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
997 {
998 MimeBody *This = impl_from_IMimeBody(iface);
999 TRACE("(%p)->(%p)\n", This, pStm);
1000 return parse_headers(This, pStm);
1001 }
1002
1003 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
1004 {
1005 MimeBody *This = impl_from_IMimeBody(iface);
1006 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
1007 return E_NOTIMPL;
1008 }
1009
1010 static HRESULT WINAPI MimeBody_GetSizeMax(
1011 IMimeBody* iface,
1012 ULARGE_INTEGER* pcbSize)
1013 {
1014 MimeBody *This = impl_from_IMimeBody(iface);
1015 FIXME("(%p)->(%p) stub\n", This, pcbSize);
1016 return E_NOTIMPL;
1017 }
1018
1019 static HRESULT WINAPI MimeBody_InitNew(
1020 IMimeBody* iface)
1021 {
1022 MimeBody *This = impl_from_IMimeBody(iface);
1023 TRACE("(%p)->()\n", This);
1024 return S_OK;
1025 }
1026
1027 static HRESULT WINAPI MimeBody_GetPropInfo(
1028 IMimeBody* iface,
1029 LPCSTR pszName,
1030 LPMIMEPROPINFO pInfo)
1031 {
1032 MimeBody *This = impl_from_IMimeBody(iface);
1033 header_t *header;
1034 HRESULT hr;
1035 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1036
1037 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1038
1039 if(!pszName || !pInfo)
1040 return E_INVALIDARG;
1041
1042 TRACE("mask 0x%04x\n", pInfo->dwMask);
1043
1044 if(pInfo->dwMask & ~supported)
1045 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
1046
1047 hr = find_prop(This, pszName, &header);
1048 if(hr == S_OK)
1049 {
1050 if(pInfo->dwMask & PIM_CHARSET)
1051 pInfo->hCharset = 0;
1052 if(pInfo->dwMask & PIM_FLAGS)
1053 pInfo->dwFlags = 0x00000000;
1054 if(pInfo->dwMask & PIM_ROWNUMBER)
1055 pInfo->dwRowNumber = 0;
1056 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1057 pInfo->ietEncoding = 0;
1058 if(pInfo->dwMask & PIM_VALUES)
1059 pInfo->cValues = 0;
1060 if(pInfo->dwMask & PIM_PROPID)
1061 pInfo->dwPropId = header->prop->id;
1062 if(pInfo->dwMask & PIM_VTDEFAULT)
1063 pInfo->vtDefault = header->prop->default_vt;
1064 if(pInfo->dwMask & PIM_VTCURRENT)
1065 pInfo->vtCurrent = 0;
1066 }
1067
1068 return hr;
1069 }
1070
1071 static HRESULT WINAPI MimeBody_SetPropInfo(
1072 IMimeBody* iface,
1073 LPCSTR pszName,
1074 LPCMIMEPROPINFO pInfo)
1075 {
1076 MimeBody *This = impl_from_IMimeBody(iface);
1077 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1078 return E_NOTIMPL;
1079 }
1080
1081 static HRESULT WINAPI MimeBody_GetProp(
1082 IMimeBody* iface,
1083 LPCSTR pszName,
1084 DWORD dwFlags,
1085 LPPROPVARIANT pValue)
1086 {
1087 MimeBody *This = impl_from_IMimeBody(iface);
1088 header_t *header;
1089 HRESULT hr;
1090
1091 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1092
1093 if(!pszName || !pValue)
1094 return E_INVALIDARG;
1095
1096 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1097 {
1098 PropVariantClear(pValue);
1099 pValue->vt = VT_LPSTR;
1100 pValue->u.pszVal = strdupA(This->content_pri_type);
1101 return S_OK;
1102 }
1103
1104 hr = find_prop(This, pszName, &header);
1105 if(hr == S_OK)
1106 {
1107 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1108
1109 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1110 if(FAILED(hr))
1111 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1112 }
1113
1114 return hr;
1115 }
1116
1117 static HRESULT WINAPI MimeBody_SetProp(
1118 IMimeBody* iface,
1119 LPCSTR pszName,
1120 DWORD dwFlags,
1121 LPCPROPVARIANT pValue)
1122 {
1123 MimeBody *This = impl_from_IMimeBody(iface);
1124 header_t *header;
1125 HRESULT hr;
1126
1127 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1128
1129 if(!pszName || !pValue)
1130 return E_INVALIDARG;
1131
1132 hr = find_prop(This, pszName, &header);
1133 if(hr != S_OK)
1134 {
1135 property_list_entry_t *prop_entry;
1136 const property_t *prop = NULL;
1137
1138 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1139 {
1140 if(ISPIDSTR(pszName))
1141 {
1142 if(STRTOPID(pszName) == prop_entry->prop.id)
1143 {
1144 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1145 prop = &prop_entry->prop;
1146 break;
1147 }
1148 }
1149 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1150 {
1151 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1152 prop = &prop_entry->prop;
1153 break;
1154 }
1155 }
1156
1157 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
1158 if(!header)
1159 return E_OUTOFMEMORY;
1160
1161 if(!prop)
1162 {
1163 const property_t *prop_def = NULL;
1164 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
1165 if(!prop_entry)
1166 {
1167 HeapFree(GetProcessHeap(), 0, header);
1168 return E_OUTOFMEMORY;
1169 }
1170
1171 prop_def = find_default_prop(pszName);
1172 if(prop_def)
1173 {
1174 prop_entry->prop.name = strdupA(prop_def->name);
1175 prop_entry->prop.id = prop_def->id;
1176 }
1177 else
1178 {
1179 if(ISPIDSTR(pszName))
1180 {
1181 HeapFree(GetProcessHeap(), 0, prop_entry);
1182 HeapFree(GetProcessHeap(), 0, header);
1183 return MIME_E_NOT_FOUND;
1184 }
1185
1186 prop_entry->prop.name = strdupA(pszName);
1187 prop_entry->prop.id = This->next_prop_id++;
1188 }
1189
1190 prop_entry->prop.flags = 0;
1191 prop_entry->prop.default_vt = pValue->vt;
1192 list_add_tail(&This->new_props, &prop_entry->entry);
1193 prop = &prop_entry->prop;
1194 TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
1195 }
1196
1197 header->prop = prop;
1198 PropVariantInit(&header->value);
1199 list_init(&header->params);
1200 list_add_tail(&This->headers, &header->entry);
1201 }
1202
1203 PropVariantCopy(&header->value, pValue);
1204
1205 return S_OK;
1206 }
1207
1208 static HRESULT WINAPI MimeBody_AppendProp(
1209 IMimeBody* iface,
1210 LPCSTR pszName,
1211 DWORD dwFlags,
1212 LPPROPVARIANT pValue)
1213 {
1214 MimeBody *This = impl_from_IMimeBody(iface);
1215 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1216 return E_NOTIMPL;
1217 }
1218
1219 static HRESULT WINAPI MimeBody_DeleteProp(
1220 IMimeBody* iface,
1221 LPCSTR pszName)
1222 {
1223 MimeBody *This = impl_from_IMimeBody(iface);
1224 header_t *cursor;
1225 BOOL found;
1226
1227 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1228
1229 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1230 {
1231 if(ISPIDSTR(pszName))
1232 found = STRTOPID(pszName) == cursor->prop->id;
1233 else
1234 found = !lstrcmpiA(pszName, cursor->prop->name);
1235
1236 if(found)
1237 {
1238 list_remove(&cursor->entry);
1239 HeapFree(GetProcessHeap(), 0, cursor);
1240 return S_OK;
1241 }
1242 }
1243
1244 return MIME_E_NOT_FOUND;
1245 }
1246
1247 static HRESULT WINAPI MimeBody_CopyProps(
1248 IMimeBody* iface,
1249 ULONG cNames,
1250 LPCSTR* prgszName,
1251 IMimePropertySet* pPropertySet)
1252 {
1253 MimeBody *This = impl_from_IMimeBody(iface);
1254 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1255 return E_NOTIMPL;
1256 }
1257
1258 static HRESULT WINAPI MimeBody_MoveProps(
1259 IMimeBody* iface,
1260 ULONG cNames,
1261 LPCSTR* prgszName,
1262 IMimePropertySet* pPropertySet)
1263 {
1264 MimeBody *This = impl_from_IMimeBody(iface);
1265 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1266 return E_NOTIMPL;
1267 }
1268
1269 static HRESULT WINAPI MimeBody_DeleteExcept(
1270 IMimeBody* iface,
1271 ULONG cNames,
1272 LPCSTR* prgszName)
1273 {
1274 MimeBody *This = impl_from_IMimeBody(iface);
1275 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
1276 return E_NOTIMPL;
1277 }
1278
1279 static HRESULT WINAPI MimeBody_QueryProp(
1280 IMimeBody* iface,
1281 LPCSTR pszName,
1282 LPCSTR pszCriteria,
1283 boolean fSubString,
1284 boolean fCaseSensitive)
1285 {
1286 MimeBody *This = impl_from_IMimeBody(iface);
1287 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1288 return E_NOTIMPL;
1289 }
1290
1291 static HRESULT WINAPI MimeBody_GetCharset(
1292 IMimeBody* iface,
1293 LPHCHARSET phCharset)
1294 {
1295 MimeBody *This = impl_from_IMimeBody(iface);
1296 FIXME("(%p)->(%p) stub\n", This, phCharset);
1297 *phCharset = NULL;
1298 return S_OK;
1299 }
1300
1301 static HRESULT WINAPI MimeBody_SetCharset(
1302 IMimeBody* iface,
1303 HCHARSET hCharset,
1304 CSETAPPLYTYPE applytype)
1305 {
1306 MimeBody *This = impl_from_IMimeBody(iface);
1307 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1308 return E_NOTIMPL;
1309 }
1310
1311 static HRESULT WINAPI MimeBody_GetParameters(
1312 IMimeBody* iface,
1313 LPCSTR pszName,
1314 ULONG* pcParams,
1315 LPMIMEPARAMINFO* pprgParam)
1316 {
1317 MimeBody *This = impl_from_IMimeBody(iface);
1318 HRESULT hr;
1319 header_t *header;
1320
1321 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1322
1323 *pprgParam = NULL;
1324 *pcParams = 0;
1325
1326 hr = find_prop(This, pszName, &header);
1327 if(hr != S_OK) return hr;
1328
1329 *pcParams = list_count(&header->params);
1330 if(*pcParams)
1331 {
1332 IMimeAllocator *alloc;
1333 param_t *param;
1334 MIMEPARAMINFO *info;
1335
1336 MimeOleGetAllocator(&alloc);
1337
1338 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1339 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1340 {
1341 int len;
1342
1343 len = strlen(param->name) + 1;
1344 info->pszName = IMimeAllocator_Alloc(alloc, len);
1345 memcpy(info->pszName, param->name, len);
1346 len = strlen(param->value) + 1;
1347 info->pszData = IMimeAllocator_Alloc(alloc, len);
1348 memcpy(info->pszData, param->value, len);
1349 info++;
1350 }
1351 IMimeAllocator_Release(alloc);
1352 }
1353 return S_OK;
1354 }
1355
1356 static HRESULT WINAPI MimeBody_IsContentType(
1357 IMimeBody* iface,
1358 LPCSTR pszPriType,
1359 LPCSTR pszSubType)
1360 {
1361 MimeBody *This = impl_from_IMimeBody(iface);
1362
1363 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1364 if(pszPriType)
1365 {
1366 const char *pri = This->content_pri_type;
1367 if(!pri) pri = "text";
1368 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1369 }
1370
1371 if(pszSubType)
1372 {
1373 const char *sub = This->content_sub_type;
1374 if(!sub) sub = "plain";
1375 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1376 }
1377
1378 return S_OK;
1379 }
1380
1381 static HRESULT WINAPI MimeBody_BindToObject(
1382 IMimeBody* iface,
1383 REFIID riid,
1384 void** ppvObject)
1385 {
1386 MimeBody *This = impl_from_IMimeBody(iface);
1387 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1388 return E_NOTIMPL;
1389 }
1390
1391 static HRESULT WINAPI MimeBody_Clone(
1392 IMimeBody* iface,
1393 IMimePropertySet** ppPropertySet)
1394 {
1395 MimeBody *This = impl_from_IMimeBody(iface);
1396 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1397 return E_NOTIMPL;
1398 }
1399
1400 static HRESULT WINAPI MimeBody_SetOption(
1401 IMimeBody* iface,
1402 const TYPEDID oid,
1403 LPCPROPVARIANT pValue)
1404 {
1405 MimeBody *This = impl_from_IMimeBody(iface);
1406 HRESULT hr = E_NOTIMPL;
1407 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
1408
1409 if(pValue->vt != TYPEDID_TYPE(oid))
1410 {
1411 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
1412 return E_INVALIDARG;
1413 }
1414
1415 switch(oid)
1416 {
1417 case OID_SECURITY_HWND_OWNER:
1418 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
1419 hr = S_OK;
1420 break;
1421 case OID_TRANSMIT_BODY_ENCODING:
1422 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
1423 hr = S_OK;
1424 break;
1425 default:
1426 FIXME("Unhandled oid %08x\n", oid);
1427 }
1428
1429 return hr;
1430 }
1431
1432 static HRESULT WINAPI MimeBody_GetOption(
1433 IMimeBody* iface,
1434 const TYPEDID oid,
1435 LPPROPVARIANT pValue)
1436 {
1437 MimeBody *This = impl_from_IMimeBody(iface);
1438 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
1439 return E_NOTIMPL;
1440 }
1441
1442 static HRESULT WINAPI MimeBody_EnumProps(
1443 IMimeBody* iface,
1444 DWORD dwFlags,
1445 IMimeEnumProperties** ppEnum)
1446 {
1447 MimeBody *This = impl_from_IMimeBody(iface);
1448 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
1449 return E_NOTIMPL;
1450 }
1451
1452 static HRESULT WINAPI MimeBody_IsType(
1453 IMimeBody* iface,
1454 IMSGBODYTYPE bodytype)
1455 {
1456 MimeBody *This = impl_from_IMimeBody(iface);
1457
1458 TRACE("(%p)->(%d)\n", This, bodytype);
1459 switch(bodytype)
1460 {
1461 case IBT_EMPTY:
1462 return This->data ? S_FALSE : S_OK;
1463 default:
1464 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1465 }
1466 return S_OK;
1467 }
1468
1469 static HRESULT WINAPI MimeBody_SetDisplayName(
1470 IMimeBody* iface,
1471 LPCSTR pszDisplay)
1472 {
1473 MimeBody *This = impl_from_IMimeBody(iface);
1474 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1475 return E_NOTIMPL;
1476 }
1477
1478 static HRESULT WINAPI MimeBody_GetDisplayName(
1479 IMimeBody* iface,
1480 LPSTR* ppszDisplay)
1481 {
1482 MimeBody *This = impl_from_IMimeBody(iface);
1483 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1484 return E_NOTIMPL;
1485 }
1486
1487 static HRESULT WINAPI MimeBody_GetOffsets(
1488 IMimeBody* iface,
1489 LPBODYOFFSETS pOffsets)
1490 {
1491 MimeBody *This = impl_from_IMimeBody(iface);
1492 TRACE("(%p)->(%p)\n", This, pOffsets);
1493
1494 *pOffsets = This->body_offsets;
1495
1496 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1497 return S_OK;
1498 }
1499
1500 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1501 IMimeBody* iface,
1502 ENCODINGTYPE* pietEncoding)
1503 {
1504 MimeBody *This = impl_from_IMimeBody(iface);
1505
1506 TRACE("(%p)->(%p)\n", This, pietEncoding);
1507
1508 *pietEncoding = This->encoding;
1509 return S_OK;
1510 }
1511
1512 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1513 IMimeBody* iface,
1514 ENCODINGTYPE ietEncoding)
1515 {
1516 MimeBody *This = impl_from_IMimeBody(iface);
1517
1518 TRACE("(%p)->(%d)\n", This, ietEncoding);
1519
1520 This->encoding = ietEncoding;
1521 return S_OK;
1522 }
1523
1524 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1525 IMimeBody* iface,
1526 ENCODINGTYPE ietEncoding,
1527 ULONG* pcbSize)
1528 {
1529 MimeBody *This = impl_from_IMimeBody(iface);
1530 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1531 return E_NOTIMPL;
1532 }
1533
1534 static HRESULT WINAPI MimeBody_GetDataHere(
1535 IMimeBody* iface,
1536 ENCODINGTYPE ietEncoding,
1537 IStream* pStream)
1538 {
1539 MimeBody *This = impl_from_IMimeBody(iface);
1540 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1541 return E_NOTIMPL;
1542 }
1543
1544 static const signed char base64_decode_table[] =
1545 {
1546 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1547 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1548 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1549 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1550 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1551 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1552 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1553 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1554 };
1555
1556 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1557 {
1558 const unsigned char *ptr, *end;
1559 unsigned char buf[1024];
1560 LARGE_INTEGER pos;
1561 unsigned char *ret;
1562 unsigned char in[4];
1563 IStream *output;
1564 DWORD size;
1565 int n = 0;
1566 HRESULT hres;
1567
1568 pos.QuadPart = 0;
1569 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1570 if(FAILED(hres))
1571 return hres;
1572
1573 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1574 if(FAILED(hres))
1575 return hres;
1576
1577 while(1) {
1578 hres = IStream_Read(input, buf, sizeof(buf), &size);
1579 if(FAILED(hres) || !size)
1580 break;
1581
1582 ptr = ret = buf;
1583 end = buf + size;
1584
1585 while(1) {
1586 /* skip invalid chars */
1587 while(ptr < end && (*ptr >= ARRAY_SIZE(base64_decode_table)
1588 || base64_decode_table[*ptr] == -1))
1589 ptr++;
1590 if(ptr == end)
1591 break;
1592
1593 in[n++] = base64_decode_table[*ptr++];
1594 switch(n) {
1595 case 2:
1596 *ret++ = in[0] << 2 | in[1] >> 4;
1597 continue;
1598 case 3:
1599 *ret++ = in[1] << 4 | in[2] >> 2;
1600 continue;
1601 case 4:
1602 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1603 n = 0;
1604 }
1605 }
1606
1607 if(ret > buf) {
1608 hres = IStream_Write(output, buf, ret - buf, NULL);
1609 if(FAILED(hres))
1610 break;
1611 }
1612 }
1613
1614 if(SUCCEEDED(hres))
1615 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1616 if(FAILED(hres)) {
1617 IStream_Release(output);
1618 return hres;
1619 }
1620
1621 *ret_stream = output;
1622 return S_OK;
1623 }
1624
1625 static int hex_digit(char c)
1626 {
1627 if('0' <= c && c <= '9')
1628 return c - '0';
1629 if('A' <= c && c <= 'F')
1630 return c - 'A' + 10;
1631 if('a' <= c && c <= 'f')
1632 return c - 'a' + 10;
1633 return -1;
1634 }
1635
1636 static HRESULT decode_qp(IStream *input, IStream **ret_stream)
1637 {
1638 const unsigned char *ptr, *end;
1639 unsigned char *ret, prev = 0;
1640 unsigned char buf[1024];
1641 LARGE_INTEGER pos;
1642 IStream *output;
1643 DWORD size;
1644 int n = -1;
1645 HRESULT hres;
1646
1647 pos.QuadPart = 0;
1648 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1649 if(FAILED(hres))
1650 return hres;
1651
1652 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1653 if(FAILED(hres))
1654 return hres;
1655
1656 while(1) {
1657 hres = IStream_Read(input, buf, sizeof(buf), &size);
1658 if(FAILED(hres) || !size)
1659 break;
1660
1661 ptr = ret = buf;
1662 end = buf + size;
1663
1664 while(ptr < end) {
1665 unsigned char byte = *ptr++;
1666
1667 switch(n) {
1668 case -1:
1669 if(byte == '=')
1670 n = 0;
1671 else
1672 *ret++ = byte;
1673 continue;
1674 case 0:
1675 prev = byte;
1676 n = 1;
1677 continue;
1678 case 1:
1679 if(prev != '\r' || byte != '\n') {
1680 int h1 = hex_digit(prev), h2 = hex_digit(byte);
1681 if(h1 != -1 && h2 != -1)
1682 *ret++ = (h1 << 4) | h2;
1683 else
1684 *ret++ = '=';
1685 }
1686 n = -1;
1687 continue;
1688 }
1689 }
1690
1691 if(ret > buf) {
1692 hres = IStream_Write(output, buf, ret - buf, NULL);
1693 if(FAILED(hres))
1694 break;
1695 }
1696 }
1697
1698 if(SUCCEEDED(hres))
1699 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1700 if(FAILED(hres)) {
1701 IStream_Release(output);
1702 return hres;
1703 }
1704
1705 *ret_stream = output;
1706 return S_OK;
1707 }
1708
1709 static HRESULT WINAPI MimeBody_GetData(
1710 IMimeBody* iface,
1711 ENCODINGTYPE ietEncoding,
1712 IStream** ppStream)
1713 {
1714 MimeBody *This = impl_from_IMimeBody(iface);
1715 ULARGE_INTEGER start, size;
1716 HRESULT hres;
1717
1718 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1719
1720 if(This->encoding != ietEncoding) {
1721 switch(This->encoding) {
1722 case IET_BASE64:
1723 hres = decode_base64(This->data, ppStream);
1724 break;
1725 case IET_QP:
1726 hres = decode_qp(This->data, ppStream);
1727 break;
1728 default:
1729 FIXME("Decoding %d is not supported.\n", This->encoding);
1730 hres = S_FALSE;
1731 }
1732 if(ietEncoding != IET_BINARY)
1733 FIXME("Encoding %d is not supported.\n", ietEncoding);
1734 if(hres != S_FALSE)
1735 return hres;
1736 }
1737
1738 start.QuadPart = 0;
1739 hres = get_stream_size(This->data, &size);
1740 if(SUCCEEDED(hres))
1741 hres = create_sub_stream(This->data, start, size, ppStream);
1742 return hres;
1743 }
1744
1745 static HRESULT WINAPI MimeBody_SetData(
1746 IMimeBody* iface,
1747 ENCODINGTYPE ietEncoding,
1748 LPCSTR pszPriType,
1749 LPCSTR pszSubType,
1750 REFIID riid,
1751 LPVOID pvObject)
1752 {
1753 MimeBody *This = impl_from_IMimeBody(iface);
1754 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1755 debugstr_guid(riid), pvObject);
1756
1757 if(IsEqualIID(riid, &IID_IStream))
1758 IStream_AddRef((IStream *)pvObject);
1759 else
1760 {
1761 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1762 return E_INVALIDARG;
1763 }
1764
1765 if(This->data)
1766 release_data(&This->data_iid, This->data);
1767
1768 This->data_iid = *riid;
1769 This->data = pvObject;
1770
1771 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1772
1773 /* FIXME: Update the content type.
1774 If pszPriType == NULL use 'application'
1775 If pszSubType == NULL use 'octet-stream' */
1776
1777 return S_OK;
1778 }
1779
1780 static HRESULT WINAPI MimeBody_EmptyData(
1781 IMimeBody* iface)
1782 {
1783 MimeBody *This = impl_from_IMimeBody(iface);
1784 FIXME("(%p)->() stub\n", This);
1785 return E_NOTIMPL;
1786 }
1787
1788 static HRESULT WINAPI MimeBody_CopyTo(
1789 IMimeBody* iface,
1790 IMimeBody* pBody)
1791 {
1792 MimeBody *This = impl_from_IMimeBody(iface);
1793 FIXME("(%p)->(%p) stub\n", This, pBody);
1794 return E_NOTIMPL;
1795 }
1796
1797 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1798 IMimeBody* iface,
1799 LPTRANSMITINFO pTransmitInfo)
1800 {
1801 MimeBody *This = impl_from_IMimeBody(iface);
1802 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1803 return E_NOTIMPL;
1804 }
1805
1806 static HRESULT WINAPI MimeBody_SaveToFile(
1807 IMimeBody* iface,
1808 ENCODINGTYPE ietEncoding,
1809 LPCSTR pszFilePath)
1810 {
1811 MimeBody *This = impl_from_IMimeBody(iface);
1812 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1813 return E_NOTIMPL;
1814 }
1815
1816 static HRESULT WINAPI MimeBody_GetHandle(
1817 IMimeBody* iface,
1818 LPHBODY phBody)
1819 {
1820 MimeBody *This = impl_from_IMimeBody(iface);
1821 TRACE("(%p)->(%p)\n", iface, phBody);
1822
1823 if(!phBody)
1824 return E_INVALIDARG;
1825
1826 *phBody = This->handle;
1827 return This->handle ? S_OK : MIME_E_NO_DATA;
1828 }
1829
1830 static IMimeBodyVtbl body_vtbl =
1831 {
1832 MimeBody_QueryInterface,
1833 MimeBody_AddRef,
1834 MimeBody_Release,
1835 MimeBody_GetClassID,
1836 MimeBody_IsDirty,
1837 MimeBody_Load,
1838 MimeBody_Save,
1839 MimeBody_GetSizeMax,
1840 MimeBody_InitNew,
1841 MimeBody_GetPropInfo,
1842 MimeBody_SetPropInfo,
1843 MimeBody_GetProp,
1844 MimeBody_SetProp,
1845 MimeBody_AppendProp,
1846 MimeBody_DeleteProp,
1847 MimeBody_CopyProps,
1848 MimeBody_MoveProps,
1849 MimeBody_DeleteExcept,
1850 MimeBody_QueryProp,
1851 MimeBody_GetCharset,
1852 MimeBody_SetCharset,
1853 MimeBody_GetParameters,
1854 MimeBody_IsContentType,
1855 MimeBody_BindToObject,
1856 MimeBody_Clone,
1857 MimeBody_SetOption,
1858 MimeBody_GetOption,
1859 MimeBody_EnumProps,
1860 MimeBody_IsType,
1861 MimeBody_SetDisplayName,
1862 MimeBody_GetDisplayName,
1863 MimeBody_GetOffsets,
1864 MimeBody_GetCurrentEncoding,
1865 MimeBody_SetCurrentEncoding,
1866 MimeBody_GetEstimatedSize,
1867 MimeBody_GetDataHere,
1868 MimeBody_GetData,
1869 MimeBody_SetData,
1870 MimeBody_EmptyData,
1871 MimeBody_CopyTo,
1872 MimeBody_GetTransmitInfo,
1873 MimeBody_SaveToFile,
1874 MimeBody_GetHandle
1875 };
1876
1877 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1878 {
1879 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1880 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1881
1882 body->body_offsets = *offsets;
1883 return S_OK;
1884 }
1885
1886 #define FIRST_CUSTOM_PROP_ID 0x100
1887
1888 static MimeBody *mimebody_create(void)
1889 {
1890 MimeBody *This;
1891 BODYOFFSETS body_offsets;
1892
1893 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1894 if (!This)
1895 return NULL;
1896
1897 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1898 This->ref = 1;
1899 This->handle = NULL;
1900 list_init(&This->headers);
1901 list_init(&This->new_props);
1902 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1903 This->content_pri_type = NULL;
1904 This->content_sub_type = NULL;
1905 This->encoding = IET_7BIT;
1906 This->data = NULL;
1907 This->data_iid = IID_NULL;
1908
1909 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1910 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1911 MimeBody_set_offsets(This, &body_offsets);
1912
1913 return This;
1914 }
1915
1916 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1917 {
1918 MimeBody *mb;
1919
1920 if(outer)
1921 return CLASS_E_NOAGGREGATION;
1922
1923 if ((mb = mimebody_create()))
1924 {
1925 *ppv = &mb->IMimeBody_iface;
1926 return S_OK;
1927 }
1928 else
1929 {
1930 *ppv = NULL;
1931 return E_OUTOFMEMORY;
1932 }
1933 }
1934
1935 typedef struct body_t
1936 {
1937 struct list entry;
1938 DWORD index;
1939 MimeBody *mime_body;
1940
1941 struct body_t *parent;
1942 struct list children;
1943 } body_t;
1944
1945 typedef struct MimeMessage
1946 {
1947 IMimeMessage IMimeMessage_iface;
1948 LONG ref;
1949 IStream *stream;
1950
1951 struct list body_tree;
1952 DWORD next_index;
1953 } MimeMessage;
1954
1955 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1956 {
1957 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1958 }
1959
1960 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1961 {
1962 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1963
1964 if (IsEqualIID(riid, &IID_IUnknown) ||
1965 IsEqualIID(riid, &IID_IPersist) ||
1966 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1967 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1968 IsEqualIID(riid, &IID_IMimeMessage))
1969 {
1970 *ppv = iface;
1971 IMimeMessage_AddRef(iface);
1972 return S_OK;
1973 }
1974
1975 FIXME("no interface for %s\n", debugstr_guid(riid));
1976 *ppv = NULL;
1977 return E_NOINTERFACE;
1978 }
1979
1980 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1981 {
1982 MimeMessage *This = impl_from_IMimeMessage(iface);
1983 ULONG ref = InterlockedIncrement(&This->ref);
1984
1985 TRACE("(%p) ref=%d\n", This, ref);
1986
1987 return ref;
1988 }
1989
1990 static void empty_body_list(struct list *list)
1991 {
1992 body_t *body, *cursor2;
1993 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1994 {
1995 empty_body_list(&body->children);
1996 list_remove(&body->entry);
1997 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1998 HeapFree(GetProcessHeap(), 0, body);
1999 }
2000 }
2001
2002 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
2003 {
2004 MimeMessage *This = impl_from_IMimeMessage(iface);
2005 ULONG ref = InterlockedDecrement(&This->ref);
2006
2007 TRACE("(%p) ref=%d\n", This, ref);
2008
2009 if (!ref)
2010 {
2011 empty_body_list(&This->body_tree);
2012
2013 if(This->stream) IStream_Release(This->stream);
2014 HeapFree(GetProcessHeap(), 0, This);
2015 }
2016
2017 return ref;
2018 }
2019
2020 /*** IPersist methods ***/
2021 static HRESULT WINAPI MimeMessage_GetClassID(
2022 IMimeMessage *iface,
2023 CLSID *pClassID)
2024 {
2025 FIXME("(%p)->(%p)\n", iface, pClassID);
2026 return E_NOTIMPL;
2027 }
2028
2029 /*** IPersistStreamInit methods ***/
2030 static HRESULT WINAPI MimeMessage_IsDirty(
2031 IMimeMessage *iface)
2032 {
2033 FIXME("(%p)->()\n", iface);
2034 return E_NOTIMPL;
2035 }
2036
2037 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
2038 {
2039 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
2040 if(body)
2041 {
2042 body->mime_body = mime_body;
2043 body->index = index;
2044 list_init(&body->children);
2045 body->parent = parent;
2046
2047 mime_body->handle = UlongToHandle(body->index);
2048 }
2049 return body;
2050 }
2051
2052 typedef struct
2053 {
2054 struct list entry;
2055 BODYOFFSETS offsets;
2056 } offset_entry_t;
2057
2058 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
2059 {
2060 HRESULT hr;
2061 DWORD read, boundary_start;
2062 int boundary_len = strlen(boundary);
2063 char *buf, *ptr, *overlap;
2064 DWORD start = 0, overlap_no;
2065 offset_entry_t *cur_body = NULL;
2066 BOOL is_first_line = TRUE;
2067 ULARGE_INTEGER cur;
2068 LARGE_INTEGER zero;
2069
2070 list_init(body_offsets);
2071
2072 overlap_no = boundary_len + 5;
2073
2074 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
2075
2076 zero.QuadPart = 0;
2077 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
2078 start = cur.u.LowPart;
2079
2080 do {
2081 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
2082 if(FAILED(hr)) goto end;
2083 if(read == 0) break;
2084 overlap[read] = '\0';
2085
2086 ptr = buf;
2087 while(1) {
2088 if(is_first_line) {
2089 is_first_line = FALSE;
2090 }else {
2091 ptr = strstr(ptr, "\r\n");
2092 if(!ptr)
2093 break;
2094 ptr += 2;
2095 }
2096
2097 boundary_start = start + ptr - buf;
2098
2099 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) {
2100 ptr += boundary_len + 2;
2101
2102 if(*ptr == '\r' && *(ptr + 1) == '\n')
2103 {
2104 ptr += 2;
2105 if(cur_body)
2106 {
2107 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2108 list_add_tail(body_offsets, &cur_body->entry);
2109 }
2110 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
2111 cur_body->offsets.cbBoundaryStart = boundary_start;
2112 cur_body->offsets.cbHeaderStart = start + ptr - buf;
2113 }
2114 else if(*ptr == '-' && *(ptr + 1) == '-')
2115 {
2116 if(cur_body)
2117 {
2118 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2119 list_add_tail(body_offsets, &cur_body->entry);
2120 goto end;
2121 }
2122 }
2123 }
2124 }
2125
2126 if(overlap == buf) /* 1st iteration */
2127 {
2128 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2129 overlap = buf + overlap_no;
2130 start += read - overlap_no;
2131 }
2132 else
2133 {
2134 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2135 start += read;
2136 }
2137 } while(1);
2138
2139 end:
2140 HeapFree(GetProcessHeap(), 0, buf);
2141 return hr;
2142 }
2143
2144 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2145 {
2146 ULARGE_INTEGER start, length;
2147 MimeBody *mime_body;
2148 HRESULT hr;
2149 body_t *body;
2150 LARGE_INTEGER pos;
2151
2152 pos.QuadPart = offset->cbHeaderStart;
2153 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL);
2154
2155 mime_body = mimebody_create();
2156 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2157
2158 pos.QuadPart = 0;
2159 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start);
2160 offset->cbBodyStart = start.QuadPart;
2161 if (parent) MimeBody_set_offsets(mime_body, offset);
2162
2163 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart;
2164 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data);
2165 mime_body->data_iid = IID_IStream;
2166
2167 body = new_body_entry(mime_body, msg->next_index++, parent);
2168
2169 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2170 {
2171 MIMEPARAMINFO *param_info;
2172 ULONG count, i;
2173 IMimeAllocator *alloc;
2174
2175 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2176 &param_info);
2177 if(hr != S_OK || count == 0) return body;
2178
2179 MimeOleGetAllocator(&alloc);
2180
2181 for(i = 0; i < count; i++)
2182 {
2183 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2184 {
2185 struct list offset_list;
2186 offset_entry_t *cur, *cursor2;
2187 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2188 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2189 {
2190 body_t *sub_body;
2191
2192 sub_body = create_sub_body(msg, pStm, &cur->offsets, body);
2193 list_add_tail(&body->children, &sub_body->entry);
2194 list_remove(&cur->entry);
2195 HeapFree(GetProcessHeap(), 0, cur);
2196 }
2197 break;
2198 }
2199 }
2200 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2201 IMimeAllocator_Release(alloc);
2202 }
2203 return body;
2204 }
2205
2206 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2207 {
2208 MimeMessage *This = impl_from_IMimeMessage(iface);
2209 body_t *root_body;
2210 BODYOFFSETS offsets;
2211 ULARGE_INTEGER cur;
2212 LARGE_INTEGER zero;
2213
2214 TRACE("(%p)->(%p)\n", iface, pStm);
2215
2216 if(This->stream)
2217 {
2218 FIXME("already loaded a message\n");
2219 return E_FAIL;
2220 }
2221
2222 empty_body_list(&This->body_tree);
2223
2224 IStream_AddRef(pStm);
2225 This->stream = pStm;
2226 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2227 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2228
2229 root_body = create_sub_body(This, pStm, &offsets, NULL);
2230
2231 zero.QuadPart = 0;
2232 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2233 offsets.cbBodyEnd = cur.u.LowPart;
2234 MimeBody_set_offsets(root_body->mime_body, &offsets);
2235
2236 list_add_head(&This->body_tree, &root_body->entry);
2237
2238 return S_OK;
2239 }
2240
2241 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2242 {
2243 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2244 return E_NOTIMPL;
2245 }
2246
2247 static HRESULT WINAPI MimeMessage_GetSizeMax(
2248 IMimeMessage *iface,
2249 ULARGE_INTEGER *pcbSize)
2250 {
2251 FIXME("(%p)->(%p)\n", iface, pcbSize);
2252 return E_NOTIMPL;
2253 }
2254
2255 static HRESULT WINAPI MimeMessage_InitNew(
2256 IMimeMessage *iface)
2257 {
2258 FIXME("(%p)->()\n", iface);
2259 return E_NOTIMPL;
2260 }
2261
2262 /*** IMimeMessageTree methods ***/
2263 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2264 DWORD dwFlags)
2265 {
2266 MimeMessage *This = impl_from_IMimeMessage(iface);
2267
2268 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
2269
2270 IStream_AddRef(This->stream);
2271 *ppStream = This->stream;
2272 return S_OK;
2273 }
2274
2275 static HRESULT WINAPI MimeMessage_GetMessageSize(
2276 IMimeMessage *iface,
2277 ULONG *pcbSize,
2278 DWORD dwFlags)
2279 {
2280 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
2281 return E_NOTIMPL;
2282 }
2283
2284 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2285 IMimeMessage *iface,
2286 IStream *pStream)
2287 {
2288 FIXME("(%p)->(%p)\n", iface, pStream);
2289 return E_NOTIMPL;
2290 }
2291
2292 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2293 IMimeMessage *iface,
2294 IStream *pStream,
2295 DWORD dwFlags)
2296 {
2297 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
2298 return E_NOTIMPL;
2299 }
2300
2301
2302 static HRESULT WINAPI MimeMessage_GetFlags(
2303 IMimeMessage *iface,
2304 DWORD *pdwFlags)
2305 {
2306 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2307 return E_NOTIMPL;
2308 }
2309
2310 static HRESULT WINAPI MimeMessage_Commit(
2311 IMimeMessage *iface,
2312 DWORD dwFlags)
2313 {
2314 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
2315 return S_OK;
2316 }
2317
2318
2319 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2320 IMimeMessage *iface)
2321 {
2322 FIXME("(%p)->()\n", iface);
2323 return E_NOTIMPL;
2324 }
2325
2326 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2327 {
2328 body_t *cur;
2329 HRESULT hr;
2330
2331 if(hbody == HBODY_ROOT)
2332 {
2333 *body = LIST_ENTRY(list_head(list), body_t, entry);
2334 return S_OK;
2335 }
2336
2337 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2338 {
2339 if(cur->index == HandleToUlong(hbody))
2340 {
2341 *body = cur;
2342 return S_OK;
2343 }
2344 hr = find_body(&cur->children, hbody, body);
2345 if(hr == S_OK) return S_OK;
2346 }
2347 return S_FALSE;
2348 }
2349
2350 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2351 void **ppvObject)
2352 {
2353 MimeMessage *This = impl_from_IMimeMessage(iface);
2354 HRESULT hr;
2355 body_t *body;
2356
2357 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2358
2359 hr = find_body(&This->body_tree, hBody, &body);
2360
2361 if(hr != S_OK) return hr;
2362
2363 if(IsEqualIID(riid, &IID_IMimeBody))
2364 {
2365 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2366 *ppvObject = &body->mime_body->IMimeBody_iface;
2367 return S_OK;
2368 }
2369
2370 return E_NOINTERFACE;
2371 }
2372
2373 static HRESULT WINAPI MimeMessage_SaveBody(
2374 IMimeMessage *iface,
2375 HBODY hBody,
2376 DWORD dwFlags,
2377 IStream *pStream)
2378 {
2379 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
2380 return E_NOTIMPL;
2381 }
2382
2383 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2384 {
2385 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2386 body_t *body;
2387 HRESULT hr;
2388 struct list *list;
2389
2390 if(location == IBL_ROOT)
2391 {
2392 *out = root;
2393 return S_OK;
2394 }
2395
2396 hr = find_body(&msg->body_tree, pivot, &body);
2397
2398 if(hr == S_OK)
2399 {
2400 switch(location)
2401 {
2402 case IBL_PARENT:
2403 if(body->parent)
2404 *out = body->parent;
2405 else
2406 hr = MIME_E_NOT_FOUND;
2407 break;
2408
2409 case IBL_FIRST:
2410 list = list_head(&body->children);
2411 if(list)
2412 *out = LIST_ENTRY(list, body_t, entry);
2413 else
2414 hr = MIME_E_NOT_FOUND;
2415 break;
2416
2417 case IBL_LAST:
2418 list = list_tail(&body->children);
2419 if(list)
2420 *out = LIST_ENTRY(list, body_t, entry);
2421 else
2422 hr = MIME_E_NOT_FOUND;
2423 break;
2424
2425 case IBL_NEXT:
2426 list = list_next(&body->parent->children, &body->entry);
2427 if(list)
2428 *out = LIST_ENTRY(list, body_t, entry);
2429 else
2430 hr = MIME_E_NOT_FOUND;
2431 break;
2432
2433 case IBL_PREVIOUS:
2434 list = list_prev(&body->parent->children, &body->entry);
2435 if(list)
2436 *out = LIST_ENTRY(list, body_t, entry);
2437 else
2438 hr = MIME_E_NOT_FOUND;
2439 break;
2440
2441 default:
2442 hr = E_FAIL;
2443 break;
2444 }
2445 }
2446
2447 return hr;
2448 }
2449
2450
2451 static HRESULT WINAPI MimeMessage_InsertBody(
2452 IMimeMessage *iface,
2453 BODYLOCATION location,
2454 HBODY hPivot,
2455 LPHBODY phBody)
2456 {
2457 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2458 return E_NOTIMPL;
2459 }
2460
2461 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2462 HBODY *phBody)
2463 {
2464 MimeMessage *This = impl_from_IMimeMessage(iface);
2465 body_t *body;
2466 HRESULT hr;
2467
2468 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2469
2470 if(!phBody)
2471 return E_INVALIDARG;
2472
2473 *phBody = NULL;
2474
2475 hr = get_body(This, location, hPivot, &body);
2476
2477 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2478
2479 return hr;
2480 }
2481
2482 static HRESULT WINAPI MimeMessage_DeleteBody(
2483 IMimeMessage *iface,
2484 HBODY hBody,
2485 DWORD dwFlags)
2486 {
2487 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
2488 return E_NOTIMPL;
2489 }
2490
2491 static HRESULT WINAPI MimeMessage_MoveBody(
2492 IMimeMessage *iface,
2493 HBODY hBody,
2494 BODYLOCATION location)
2495 {
2496 FIXME("(%p)->(%d)\n", iface, location);
2497 return E_NOTIMPL;
2498 }
2499
2500 static void count_children(body_t *body, boolean recurse, ULONG *count)
2501 {
2502 body_t *child;
2503
2504 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2505 {
2506 (*count)++;
2507 if(recurse) count_children(child, recurse, count);
2508 }
2509 }
2510
2511 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2512 ULONG *pcBodies)
2513 {
2514 HRESULT hr;
2515 MimeMessage *This = impl_from_IMimeMessage(iface);
2516 body_t *body;
2517
2518 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2519
2520 hr = find_body(&This->body_tree, hParent, &body);
2521 if(hr != S_OK) return hr;
2522
2523 *pcBodies = 1;
2524 count_children(body, fRecurse, pcBodies);
2525
2526 return S_OK;
2527 }
2528
2529 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2530 {
2531 struct list *ptr;
2532 HBODY next;
2533
2534 for (;;)
2535 {
2536 if (!body) ptr = list_head( &This->body_tree );
2537 else
2538 {
2539 ptr = list_head( &body->children );
2540 while (!ptr)
2541 {
2542 if (!body->parent) return MIME_E_NOT_FOUND;
2543 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2544 }
2545 }
2546
2547 body = LIST_ENTRY( ptr, body_t, entry );
2548 next = UlongToHandle( body->index );
2549 find->dwReserved = body->index;
2550 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2551 find->pszSubType) == S_OK)
2552 {
2553 *out = next;
2554 return S_OK;
2555 }
2556 }
2557 return MIME_E_NOT_FOUND;
2558 }
2559
2560 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2561 {
2562 MimeMessage *This = impl_from_IMimeMessage(iface);
2563
2564 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2565
2566 pFindBody->dwReserved = 0;
2567 return find_next(This, NULL, pFindBody, phBody);
2568 }
2569
2570 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2571 {
2572 MimeMessage *This = impl_from_IMimeMessage(iface);
2573 body_t *body;
2574 HRESULT hr;
2575
2576 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2577
2578 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2579 if (hr != S_OK) return MIME_E_NOT_FOUND;
2580 return find_next(This, body, pFindBody, phBody);
2581 }
2582
2583 static HRESULT WINAPI MimeMessage_ResolveURL(
2584 IMimeMessage *iface,
2585 HBODY hRelated,
2586 LPCSTR pszBase,
2587 LPCSTR pszURL,
2588 DWORD dwFlags,
2589 LPHBODY phBody)
2590 {
2591 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2592 return E_NOTIMPL;
2593 }
2594
2595 static HRESULT WINAPI MimeMessage_ToMultipart(
2596 IMimeMessage *iface,
2597 HBODY hBody,
2598 LPCSTR pszSubType,
2599 LPHBODY phMultipart)
2600 {
2601 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2602 return E_NOTIMPL;
2603 }
2604
2605 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2606 IMimeMessage *iface,
2607 HBODY hBody,
2608 LPBODYOFFSETS pOffsets)
2609 {
2610 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2611 return E_NOTIMPL;
2612 }
2613
2614 static HRESULT WINAPI MimeMessage_GetCharset(
2615 IMimeMessage *iface,
2616 LPHCHARSET phCharset)
2617 {
2618 FIXME("(%p)->(%p)\n", iface, phCharset);
2619 *phCharset = NULL;
2620 return S_OK;
2621 }
2622
2623 static HRESULT WINAPI MimeMessage_SetCharset(
2624 IMimeMessage *iface,
2625 HCHARSET hCharset,
2626 CSETAPPLYTYPE applytype)
2627 {
2628 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2629 return E_NOTIMPL;
2630 }
2631
2632 static HRESULT WINAPI MimeMessage_IsBodyType(
2633 IMimeMessage *iface,
2634 HBODY hBody,
2635 IMSGBODYTYPE bodytype)
2636 {
2637 HRESULT hr;
2638 IMimeBody *mime_body;
2639 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2640
2641 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2642 if(hr != S_OK) return hr;
2643
2644 hr = IMimeBody_IsType(mime_body, bodytype);
2645 MimeBody_Release(mime_body);
2646 return hr;
2647 }
2648
2649 static HRESULT WINAPI MimeMessage_IsContentType(
2650 IMimeMessage *iface,
2651 HBODY hBody,
2652 LPCSTR pszPriType,
2653 LPCSTR pszSubType)
2654 {
2655 HRESULT hr;
2656 IMimeBody *mime_body;
2657 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2658 debugstr_a(pszSubType));
2659
2660 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2661 if(FAILED(hr)) return hr;
2662
2663 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2664 IMimeBody_Release(mime_body);
2665 return hr;
2666 }
2667
2668 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2669 IMimeMessage *iface,
2670 HBODY hBody,
2671 LPCSTR pszName,
2672 LPCSTR pszCriteria,
2673 boolean fSubString,
2674 boolean fCaseSensitive)
2675 {
2676 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2677 return E_NOTIMPL;
2678 }
2679
2680 static HRESULT WINAPI MimeMessage_GetBodyProp(
2681 IMimeMessage *iface,
2682 HBODY hBody,
2683 LPCSTR pszName,
2684 DWORD dwFlags,
2685 LPPROPVARIANT pValue)
2686 {
2687 HRESULT hr;
2688 IMimeBody *mime_body;
2689
2690 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2691
2692 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2693 if(hr != S_OK) return hr;
2694
2695 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2696 IMimeBody_Release(mime_body);
2697
2698 return hr;
2699 }
2700
2701 static HRESULT WINAPI MimeMessage_SetBodyProp(
2702 IMimeMessage *iface,
2703 HBODY hBody,
2704 LPCSTR pszName,
2705 DWORD dwFlags,
2706 LPCPROPVARIANT pValue)
2707 {
2708 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2709 return E_NOTIMPL;
2710 }
2711
2712 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2713 IMimeMessage *iface,
2714 HBODY hBody,
2715 LPCSTR pszName)
2716 {
2717 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2718 return E_NOTIMPL;
2719 }
2720
2721 static HRESULT WINAPI MimeMessage_SetOption(
2722 IMimeMessage *iface,
2723 const TYPEDID oid,
2724 LPCPROPVARIANT pValue)
2725 {
2726 HRESULT hr = S_OK;
2727 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2728
2729 /* Message ID is checked before type.
2730 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2731 */
2732 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2733 {
2734 WARN("oid (%08x) out of range\n", oid);
2735 return MIME_E_INVALID_OPTION_ID;
2736 }
2737
2738 if(pValue->vt != TYPEDID_TYPE(oid))
2739 {
2740 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2741 return S_OK;
2742 }
2743
2744 switch(oid)
2745 {
2746 case OID_HIDE_TNEF_ATTACHMENTS:
2747 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2748 break;
2749 case OID_SHOW_MACBINARY:
2750 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2751 break;
2752 case OID_SAVEBODY_KEEPBOUNDARY:
2753 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal);
2754 break;
2755 case OID_CLEANUP_TREE_ON_SAVE:
2756 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal);
2757 break;
2758 default:
2759 FIXME("Unhandled oid %08x\n", oid);
2760 hr = MIME_E_INVALID_OPTION_ID;
2761 }
2762
2763 return hr;
2764 }
2765
2766 static HRESULT WINAPI MimeMessage_GetOption(
2767 IMimeMessage *iface,
2768 const TYPEDID oid,
2769 LPPROPVARIANT pValue)
2770 {
2771 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2772 return E_NOTIMPL;
2773 }
2774
2775 /*** IMimeMessage methods ***/
2776 static HRESULT WINAPI MimeMessage_CreateWebPage(
2777 IMimeMessage *iface,
2778 IStream *pRootStm,
2779 LPWEBPAGEOPTIONS pOptions,
2780 IMimeMessageCallback *pCallback,
2781 IMoniker **ppMoniker)
2782 {
2783 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2784 *ppMoniker = NULL;
2785 return E_NOTIMPL;
2786 }
2787
2788 static HRESULT WINAPI MimeMessage_GetProp(
2789 IMimeMessage *iface,
2790 LPCSTR pszName,
2791 DWORD dwFlags,
2792 LPPROPVARIANT pValue)
2793 {
2794 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2795 return E_NOTIMPL;
2796 }
2797
2798 static HRESULT WINAPI MimeMessage_SetProp(
2799 IMimeMessage *iface,
2800 LPCSTR pszName,
2801 DWORD dwFlags,
2802 LPCPROPVARIANT pValue)
2803 {
2804 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2805 return E_NOTIMPL;
2806 }
2807
2808 static HRESULT WINAPI MimeMessage_DeleteProp(
2809 IMimeMessage *iface,
2810 LPCSTR pszName)
2811 {
2812 FIXME("(%p)->(%s)\n", iface, pszName);
2813 return E_NOTIMPL;
2814 }
2815
2816 static HRESULT WINAPI MimeMessage_QueryProp(
2817 IMimeMessage *iface,
2818 LPCSTR pszName,
2819 LPCSTR pszCriteria,
2820 boolean fSubString,
2821 boolean fCaseSensitive)
2822 {
2823 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2824 return E_NOTIMPL;
2825 }
2826
2827 static HRESULT WINAPI MimeMessage_GetTextBody(
2828 IMimeMessage *iface,
2829 DWORD dwTxtType,
2830 ENCODINGTYPE ietEncoding,
2831 IStream **pStream,
2832 LPHBODY phBody)
2833 {
2834 HRESULT hr;
2835 HBODY hbody;
2836 FINDBODY find_struct;
2837 IMimeBody *mime_body;
2838 static char text[] = "text";
2839 static char plain[] = "plain";
2840 static char html[] = "html";
2841
2842 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2843
2844 find_struct.pszPriType = text;
2845
2846 switch(dwTxtType)
2847 {
2848 case TXT_PLAIN:
2849 find_struct.pszSubType = plain;
2850 break;
2851 case TXT_HTML:
2852 find_struct.pszSubType = html;
2853 break;
2854 default:
2855 return MIME_E_INVALID_TEXT_TYPE;
2856 }
2857
2858 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2859 if(hr != S_OK)
2860 {
2861 TRACE("not found hr %08x\n", hr);
2862 *phBody = NULL;
2863 return hr;
2864 }
2865
2866 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2867
2868 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2869 *phBody = hbody;
2870 IMimeBody_Release(mime_body);
2871 return hr;
2872 }
2873
2874 static HRESULT WINAPI MimeMessage_SetTextBody(
2875 IMimeMessage *iface,
2876 DWORD dwTxtType,
2877 ENCODINGTYPE ietEncoding,
2878 HBODY hAlternative,
2879 IStream *pStream,
2880 LPHBODY phBody)
2881 {
2882 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2883 return E_NOTIMPL;
2884 }
2885
2886 static HRESULT WINAPI MimeMessage_AttachObject(
2887 IMimeMessage *iface,
2888 REFIID riid,
2889 void *pvObject,
2890 LPHBODY phBody)
2891 {
2892 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2893 return E_NOTIMPL;
2894 }
2895
2896 static HRESULT WINAPI MimeMessage_AttachFile(
2897 IMimeMessage *iface,
2898 LPCSTR pszFilePath,
2899 IStream *pstmFile,
2900 LPHBODY phBody)
2901 {
2902 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2903 return E_NOTIMPL;
2904 }
2905
2906 static HRESULT WINAPI MimeMessage_AttachURL(
2907 IMimeMessage *iface,
2908 LPCSTR pszBase,
2909 LPCSTR pszURL,
2910 DWORD dwFlags,
2911 IStream *pstmURL,
2912 LPSTR *ppszCIDURL,
2913 LPHBODY phBody)
2914 {
2915 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2916 return E_NOTIMPL;
2917 }
2918
2919 static HRESULT WINAPI MimeMessage_GetAttachments(
2920 IMimeMessage *iface,
2921 ULONG *pcAttach,
2922 LPHBODY *pprghAttach)
2923 {
2924 HRESULT hr;
2925 FINDBODY find_struct;
2926 HBODY hbody;
2927 LPHBODY array;
2928 ULONG size = 10;
2929
2930 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2931
2932 *pcAttach = 0;
2933 array = CoTaskMemAlloc(size * sizeof(HBODY));
2934
2935 find_struct.pszPriType = find_struct.pszSubType = NULL;
2936 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2937 while(hr == S_OK)
2938 {
2939 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2940 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2941 if(hr != S_OK)
2942 {
2943 if(*pcAttach + 1 > size)
2944 {
2945 size *= 2;
2946 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2947 }
2948 array[*pcAttach] = hbody;
2949 (*pcAttach)++;
2950 }
2951 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2952 }
2953
2954 *pprghAttach = array;
2955 return S_OK;
2956 }
2957
2958 static HRESULT WINAPI MimeMessage_GetAddressTable(
2959 IMimeMessage *iface,
2960 IMimeAddressTable **ppTable)
2961 {
2962 FIXME("(%p)->(%p)\n", iface, ppTable);
2963 return E_NOTIMPL;
2964 }
2965
2966 static HRESULT WINAPI MimeMessage_GetSender(
2967 IMimeMessage *iface,
2968 LPADDRESSPROPS pAddress)
2969 {
2970 FIXME("(%p)->(%p)\n", iface, pAddress);
2971 return E_NOTIMPL;
2972 }
2973
2974 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2975 IMimeMessage *iface,
2976 DWORD dwAdrTypes,
2977 DWORD dwProps,
2978 LPADDRESSLIST pList)
2979 {
2980 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2981 return E_NOTIMPL;
2982 }
2983
2984 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2985 IMimeMessage *iface,
2986 DWORD dwAdrTypes,
2987 ADDRESSFORMAT format,
2988 LPSTR *ppszFormat)
2989 {
2990 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2991 return E_NOTIMPL;
2992 }
2993
2994 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2995 IMimeMessage *iface,
2996 DWORD dwAdrTypes,
2997 DWORD dwProps,
2998 IMimeEnumAddressTypes **ppEnum)
2999 {
3000 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
3001 return E_NOTIMPL;
3002 }
3003
3004 static HRESULT WINAPI MimeMessage_SplitMessage(
3005 IMimeMessage *iface,
3006 ULONG cbMaxPart,
3007 IMimeMessageParts **ppParts)
3008 {
3009 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
3010 return E_NOTIMPL;
3011 }
3012
3013 static HRESULT WINAPI MimeMessage_GetRootMoniker(
3014 IMimeMessage *iface,
3015 IMoniker **ppMoniker)
3016 {
3017 FIXME("(%p)->(%p)\n", iface, ppMoniker);
3018 return E_NOTIMPL;
3019 }
3020
3021 static const IMimeMessageVtbl MimeMessageVtbl =
3022 {
3023 MimeMessage_QueryInterface,
3024 MimeMessage_AddRef,
3025 MimeMessage_Release,
3026 MimeMessage_GetClassID,
3027 MimeMessage_IsDirty,
3028 MimeMessage_Load,
3029 MimeMessage_Save,
3030 MimeMessage_GetSizeMax,
3031 MimeMessage_InitNew,
3032 MimeMessage_GetMessageSource,
3033 MimeMessage_GetMessageSize,
3034 MimeMessage_LoadOffsetTable,
3035 MimeMessage_SaveOffsetTable,
3036 MimeMessage_GetFlags,
3037 MimeMessage_Commit,
3038 MimeMessage_HandsOffStorage,
3039 MimeMessage_BindToObject,
3040 MimeMessage_SaveBody,
3041 MimeMessage_InsertBody,
3042 MimeMessage_GetBody,
3043 MimeMessage_DeleteBody,
3044 MimeMessage_MoveBody,
3045 MimeMessage_CountBodies,
3046 MimeMessage_FindFirst,
3047 MimeMessage_FindNext,
3048 MimeMessage_ResolveURL,
3049 MimeMessage_ToMultipart,
3050 MimeMessage_GetBodyOffsets,
3051 MimeMessage_GetCharset,
3052 MimeMessage_SetCharset,
3053 MimeMessage_IsBodyType,
3054 MimeMessage_IsContentType,
3055 MimeMessage_QueryBodyProp,
3056 MimeMessage_GetBodyProp,
3057 MimeMessage_SetBodyProp,
3058 MimeMessage_DeleteBodyProp,
3059 MimeMessage_SetOption,
3060 MimeMessage_GetOption,
3061 MimeMessage_CreateWebPage,
3062 MimeMessage_GetProp,
3063 MimeMessage_SetProp,
3064 MimeMessage_DeleteProp,
3065 MimeMessage_QueryProp,
3066 MimeMessage_GetTextBody,
3067 MimeMessage_SetTextBody,
3068 MimeMessage_AttachObject,
3069 MimeMessage_AttachFile,
3070 MimeMessage_AttachURL,
3071 MimeMessage_GetAttachments,
3072 MimeMessage_GetAddressTable,
3073 MimeMessage_GetSender,
3074 MimeMessage_GetAddressTypes,
3075 MimeMessage_GetAddressFormat,
3076 MimeMessage_EnumAddressTypes,
3077 MimeMessage_SplitMessage,
3078 MimeMessage_GetRootMoniker,
3079 };
3080
3081 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
3082 {
3083 MimeMessage *This;
3084 MimeBody *mime_body;
3085 body_t *root_body;
3086
3087 TRACE("(%p, %p)\n", outer, obj);
3088
3089 if (outer)
3090 {
3091 FIXME("outer unknown not supported yet\n");
3092 return E_NOTIMPL;
3093 }
3094
3095 *obj = NULL;
3096
3097 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3098 if (!This) return E_OUTOFMEMORY;
3099
3100 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
3101 This->ref = 1;
3102 This->stream = NULL;
3103 list_init(&This->body_tree);
3104 This->next_index = 1;
3105
3106 mime_body = mimebody_create();
3107 root_body = new_body_entry(mime_body, This->next_index++, NULL);
3108 list_add_head(&This->body_tree, &root_body->entry);
3109
3110 *obj = &This->IMimeMessage_iface;
3111 return S_OK;
3112 }
3113
3114 /***********************************************************************
3115 * MimeOleCreateMessage (INETCOMM.@)
3116 */
3117 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
3118 {
3119 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3120 return MimeMessage_create(NULL, (void **)ppMessage);
3121 }
3122
3123 /***********************************************************************
3124 * MimeOleSetCompatMode (INETCOMM.@)
3125 */
3126 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3127 {
3128 FIXME("(0x%x)\n", dwMode);
3129 return S_OK;
3130 }
3131
3132 /***********************************************************************
3133 * MimeOleCreateVirtualStream (INETCOMM.@)
3134 */
3135 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3136 {
3137 HRESULT hr;
3138 FIXME("(%p)\n", ppStream);
3139
3140 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3141 return hr;
3142 }
3143
3144 typedef struct MimeSecurity
3145 {
3146 IMimeSecurity IMimeSecurity_iface;
3147 LONG ref;
3148 } MimeSecurity;
3149
3150 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3151 {
3152 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3153 }
3154
3155 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3156 {
3157 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3158
3159 if (IsEqualIID(riid, &IID_IUnknown) ||
3160 IsEqualIID(riid, &IID_IMimeSecurity))
3161 {
3162 *ppv = iface;
3163 IMimeSecurity_AddRef(iface);
3164 return S_OK;
3165 }
3166
3167 FIXME("no interface for %s\n", debugstr_guid(riid));
3168 *ppv = NULL;
3169 return E_NOINTERFACE;
3170 }
3171
3172 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3173 {
3174 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3175 LONG ref = InterlockedIncrement(&This->ref);
3176
3177 TRACE("(%p) ref=%d\n", This, ref);
3178
3179 return ref;
3180 }
3181
3182 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3183 {
3184 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3185 LONG ref = InterlockedDecrement(&This->ref);
3186
3187 TRACE("(%p) ref=%d\n", This, ref);
3188
3189 if (!ref)
3190 HeapFree(GetProcessHeap(), 0, This);
3191
3192 return ref;
3193 }
3194
3195 static HRESULT WINAPI MimeSecurity_InitNew(
3196 IMimeSecurity* iface)
3197 {
3198 FIXME("(%p)->(): stub\n", iface);
3199 return S_OK;
3200 }
3201
3202 static HRESULT WINAPI MimeSecurity_CheckInit(
3203 IMimeSecurity* iface)
3204 {
3205 FIXME("(%p)->(): stub\n", iface);
3206 return E_NOTIMPL;
3207 }
3208
3209 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3210 IMimeSecurity* iface,
3211 IMimeMessageTree* pTree,
3212 DWORD dwFlags)
3213 {
3214 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3215 return E_NOTIMPL;
3216 }
3217
3218 static HRESULT WINAPI MimeSecurity_EncodeBody(
3219 IMimeSecurity* iface,
3220 IMimeMessageTree* pTree,
3221 HBODY hEncodeRoot,
3222 DWORD dwFlags)
3223 {
3224 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3225 return E_NOTIMPL;
3226 }
3227
3228 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3229 IMimeSecurity* iface,
3230 IMimeMessageTree* pTree,
3231 DWORD dwFlags)
3232 {
3233 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3234 return E_NOTIMPL;
3235 }
3236
3237 static HRESULT WINAPI MimeSecurity_DecodeBody(
3238 IMimeSecurity* iface,
3239 IMimeMessageTree* pTree,
3240 HBODY hDecodeRoot,
3241 DWORD dwFlags)
3242 {
3243 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3244 return E_NOTIMPL;
3245 }
3246
3247 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3248 IMimeSecurity* iface,
3249 HCAPICERTSTORE hc,
3250 DWORD dwUsage,
3251 PCX509CERT pPrev,
3252 PCX509CERT* ppCert)
3253 {
3254 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3255 return E_NOTIMPL;
3256 }
3257
3258 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3259 IMimeSecurity* iface,
3260 const PCX509CERT pX509Cert,
3261 const CERTNAMETYPE cn,
3262 LPSTR* ppszName)
3263 {
3264 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3265 return E_NOTIMPL;
3266 }
3267
3268 static HRESULT WINAPI MimeSecurity_GetMessageType(
3269 IMimeSecurity* iface,
3270 const HWND hwndParent,
3271 IMimeBody* pBody,
3272 DWORD* pdwSecType)
3273 {
3274 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3275 return E_NOTIMPL;
3276 }
3277
3278 static HRESULT WINAPI MimeSecurity_GetCertData(
3279 IMimeSecurity* iface,
3280 const PCX509CERT pX509Cert,
3281 const CERTDATAID dataid,
3282 LPPROPVARIANT pValue)
3283 {
3284 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3285 return E_NOTIMPL;
3286 }
3287
3288
3289 static const IMimeSecurityVtbl MimeSecurityVtbl =
3290 {
3291 MimeSecurity_QueryInterface,
3292 MimeSecurity_AddRef,
3293 MimeSecurity_Release,
3294 MimeSecurity_InitNew,
3295 MimeSecurity_CheckInit,
3296 MimeSecurity_EncodeMessage,
3297 MimeSecurity_EncodeBody,
3298 MimeSecurity_DecodeMessage,
3299 MimeSecurity_DecodeBody,
3300 MimeSecurity_EnumCertificates,
3301 MimeSecurity_GetCertificateName,
3302 MimeSecurity_GetMessageType,
3303 MimeSecurity_GetCertData
3304 };
3305
3306 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3307 {
3308 MimeSecurity *This;
3309
3310 *obj = NULL;
3311
3312 if (outer) return CLASS_E_NOAGGREGATION;
3313
3314 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3315 if (!This) return E_OUTOFMEMORY;
3316
3317 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3318 This->ref = 1;
3319
3320 *obj = &This->IMimeSecurity_iface;
3321 return S_OK;
3322 }
3323
3324 /***********************************************************************
3325 * MimeOleCreateSecurity (INETCOMM.@)
3326 */
3327 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3328 {
3329 return MimeSecurity_create(NULL, (void **)ppSecurity);
3330 }
3331
3332 static HRESULT WINAPI MimeAlloc_QueryInterface(
3333 IMimeAllocator* iface,
3334 REFIID riid,
3335 void **obj)
3336 {
3337 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3338
3339 if (IsEqualIID(riid, &IID_IUnknown) ||
3340 IsEqualIID(riid, &IID_IMalloc) ||
3341 IsEqualIID(riid, &IID_IMimeAllocator))
3342 {
3343 *obj = iface;
3344 IMimeAllocator_AddRef(iface);
3345 return S_OK;
3346 }
3347
3348 FIXME("no interface for %s\n", debugstr_guid(riid));
3349 *obj = NULL;
3350 return E_NOINTERFACE;
3351 }
3352
3353 static ULONG WINAPI MimeAlloc_AddRef(
3354 IMimeAllocator* iface)
3355 {
3356 return 2;
3357 }
3358
3359 static ULONG WINAPI MimeAlloc_Release(
3360 IMimeAllocator* iface)
3361 {
3362 return 1;
3363 }
3364
3365 static LPVOID WINAPI MimeAlloc_Alloc(
3366 IMimeAllocator* iface,
3367 SIZE_T cb)
3368 {
3369 return CoTaskMemAlloc(cb);
3370 }
3371
3372 static LPVOID WINAPI MimeAlloc_Realloc(
3373 IMimeAllocator* iface,
3374 LPVOID pv,
3375 SIZE_T cb)
3376 {
3377 return CoTaskMemRealloc(pv, cb);
3378 }
3379
3380 static void WINAPI MimeAlloc_Free(
3381 IMimeAllocator* iface,
3382 LPVOID pv)
3383 {
3384 CoTaskMemFree(pv);
3385 }
3386
3387 static SIZE_T WINAPI MimeAlloc_GetSize(
3388 IMimeAllocator* iface,
3389 LPVOID pv)
3390 {
3391 FIXME("stub\n");
3392 return 0;
3393 }
3394
3395 static int WINAPI MimeAlloc_DidAlloc(
3396 IMimeAllocator* iface,
3397 LPVOID pv)
3398 {
3399 FIXME("stub\n");
3400 return 0;
3401 }
3402
3403 static void WINAPI MimeAlloc_HeapMinimize(
3404 IMimeAllocator* iface)
3405 {
3406 FIXME("stub\n");
3407 return;
3408 }
3409
3410 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3411 IMimeAllocator* iface,
3412 ULONG cParams,
3413 LPMIMEPARAMINFO prgParam,
3414 boolean fFreeArray)
3415 {
3416 ULONG i;
3417 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3418
3419 for(i = 0; i < cParams; i++)
3420 {
3421 IMimeAllocator_Free(iface, prgParam[i].pszName);
3422 IMimeAllocator_Free(iface, prgParam[i].pszData);
3423 }
3424 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3425 return S_OK;
3426 }
3427
3428 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3429 IMimeAllocator* iface,
3430 LPADDRESSLIST pList)
3431 {
3432 FIXME("stub\n");
3433 return E_NOTIMPL;
3434 }
3435
3436 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3437 IMimeAllocator* iface,
3438 LPADDRESSPROPS pAddress)
3439 {
3440 FIXME("stub\n");
3441 return E_NOTIMPL;
3442 }
3443
3444 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3445 IMimeAllocator* iface,
3446 ULONG cObjects,
3447 IUnknown **prgpUnknown,
3448 boolean fFreeArray)
3449 {
3450 FIXME("stub\n");
3451 return E_NOTIMPL;
3452 }
3453
3454
3455 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3456 IMimeAllocator* iface,
3457 ULONG cRows,
3458 LPENUMHEADERROW prgRow,
3459 boolean fFreeArray)
3460 {
3461 FIXME("stub\n");
3462 return E_NOTIMPL;
3463 }
3464
3465 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3466 IMimeAllocator* iface,
3467 ULONG cProps,
3468 LPENUMPROPERTY prgProp,
3469 boolean fFreeArray)
3470 {
3471 FIXME("stub\n");
3472 return E_NOTIMPL;
3473 }
3474
3475 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3476 IMimeAllocator* iface,
3477 THUMBBLOB *pthumbprint)
3478 {
3479 FIXME("stub\n");
3480 return E_NOTIMPL;
3481 }
3482
3483
3484 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3485 IMimeAllocator* iface,
3486 LPPROPVARIANT pProp)
3487 {
3488 FIXME("stub\n");
3489 return E_NOTIMPL;
3490 }
3491
3492 static IMimeAllocatorVtbl mime_alloc_vtbl =
3493 {
3494 MimeAlloc_QueryInterface,
3495 MimeAlloc_AddRef,
3496 MimeAlloc_Release,
3497 MimeAlloc_Alloc,
3498 MimeAlloc_Realloc,
3499 MimeAlloc_Free,
3500 MimeAlloc_GetSize,
3501 MimeAlloc_DidAlloc,
3502 MimeAlloc_HeapMinimize,
3503 MimeAlloc_FreeParamInfoArray,
3504 MimeAlloc_FreeAddressList,
3505 MimeAlloc_FreeAddressProps,
3506 MimeAlloc_ReleaseObjects,
3507 MimeAlloc_FreeEnumHeaderRowArray,
3508 MimeAlloc_FreeEnumPropertyArray,
3509 MimeAlloc_FreeThumbprint,
3510 MimeAlloc_PropVariantClear
3511 };
3512
3513 static IMimeAllocator mime_allocator =
3514 {
3515 &mime_alloc_vtbl
3516 };
3517
3518 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3519 {
3520 if(outer) return CLASS_E_NOAGGREGATION;
3521
3522 *obj = &mime_allocator;
3523 return S_OK;
3524 }
3525
3526 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3527 {
3528 return MimeAllocator_create(NULL, (void**)alloc);
3529 }
3530
3531 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3532 {
3533 FIXME("(%p, %p)\n", outer, obj);
3534
3535 *obj = NULL;
3536 if (outer) return CLASS_E_NOAGGREGATION;
3537
3538 return MimeOleCreateVirtualStream((IStream **)obj);
3539 }
3540
3541 /* IMimePropertySchema Interface */
3542 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3543 {
3544 propschema *This = impl_from_IMimePropertySchema(iface);
3545 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3546
3547 *out = NULL;
3548
3549 if (IsEqualIID(riid, &IID_IUnknown) ||
3550 IsEqualIID(riid, &IID_IMimePropertySchema))
3551 {
3552 *out = iface;
3553 }
3554 else
3555 {
3556 FIXME("no interface for %s\n", debugstr_guid(riid));
3557 return E_NOINTERFACE;
3558 }
3559
3560 IMimePropertySchema_AddRef(iface);
3561 return S_OK;
3562 }
3563
3564 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3565 {
3566 propschema *This = impl_from_IMimePropertySchema(iface);
3567 LONG ref = InterlockedIncrement(&This->ref);
3568
3569 TRACE("(%p) ref=%d\n", This, ref);
3570
3571 return ref;
3572 }
3573
3574 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3575 {
3576 propschema *This = impl_from_IMimePropertySchema(iface);
3577 LONG ref = InterlockedDecrement(&This->ref);
3578
3579 TRACE("(%p) ref=%d\n", This, ref);
3580
3581 if (!ref)
3582 {
3583 HeapFree(GetProcessHeap(), 0, This);
3584 }
3585
3586 return ref;
3587 }
3588
3589 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3590 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3591 {
3592 propschema *This = impl_from_IMimePropertySchema(iface);
3593 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3594 return E_NOTIMPL;
3595 }
3596
3597 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3598 DWORD rownumber, VARTYPE vtdefault)
3599 {
3600 propschema *This = impl_from_IMimePropertySchema(iface);
3601 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3602 return S_OK;
3603 }
3604
3605 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3606 {
3607 propschema *This = impl_from_IMimePropertySchema(iface);
3608 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3609 return E_NOTIMPL;
3610 }
3611
3612 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3613 {
3614 propschema *This = impl_from_IMimePropertySchema(iface);
3615 FIXME("(%p)->(%d, %p) stub\n", This, propid, name);
3616 return E_NOTIMPL;
3617 }
3618
3619 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3620 {
3621 propschema *This = impl_from_IMimePropertySchema(iface);
3622 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3623 return E_NOTIMPL;
3624 }
3625
3626 static IMimePropertySchemaVtbl prop_schema_vtbl =
3627 {
3628 propschema_QueryInterface,
3629 propschema_AddRef,
3630 propschema_Release,
3631 propschema_RegisterProperty,
3632 propschema_ModifyProperty,
3633 propschema_GetPropertyId,
3634 propschema_GetPropertyName,
3635 propschema_RegisterAddressType
3636 };
3637
3638
3639 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3640 {
3641 propschema *This;
3642
3643 TRACE("(%p) stub\n", schema);
3644
3645 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3646 if (!This)
3647 return E_OUTOFMEMORY;
3648
3649 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3650 This->ref = 1;
3651
3652 *schema = &This->IMimePropertySchema_iface;
3653
3654 return S_OK;
3655 }
3656
3657 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3658 ADDRESSFORMAT addr_format, WCHAR **address)
3659 {
3660 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3661
3662 return E_NOTIMPL;
3663 }
3664
3665 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
3666 {
3667 FIXME("(%s %p)\n", debugstr_guid(riid), ppv);
3668 *ppv = NULL;
3669 return E_NOINTERFACE;
3670 }
3671
3672 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface)
3673 {
3674 TRACE("\n");
3675 return 2;
3676 }
3677
3678 static ULONG WINAPI mime_obj_Release(IUnknown *iface)
3679 {
3680 TRACE("\n");
3681 return 1;
3682 }
3683
3684 static const IUnknownVtbl mime_obj_vtbl = {
3685 mime_obj_QueryInterface,
3686 mime_obj_AddRef,
3687 mime_obj_Release
3688 };
3689
3690 static IUnknown mime_obj = { &mime_obj_vtbl };
3691
3692 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3693 REFIID riid, void **out, IMoniker **moniker_new)
3694 {
3695 WCHAR *display_name, *mhtml_url;
3696 size_t len;
3697 HRESULT hres;
3698
3699 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'};
3700
3701 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3702
3703 if(!IsEqualGUID(&IID_IUnknown, riid)) {
3704 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
3705 return E_NOINTERFACE;
3706 }
3707
3708 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name);
3709 if(FAILED(hres))
3710 return hres;
3711
3712 TRACE("display name %s\n", debugstr_w(display_name));
3713
3714 len = strlenW(display_name);
3715 mhtml_url = heap_alloc((len+1)*sizeof(WCHAR) + sizeof(mhtml_prefixW));
3716 if(!mhtml_url)
3717 return E_OUTOFMEMORY;
3718
3719 memcpy(mhtml_url, mhtml_prefixW, sizeof(mhtml_prefixW));
3720 strcpyW(mhtml_url + ARRAY_SIZE(mhtml_prefixW), display_name);
3721 HeapFree(GetProcessHeap(), 0, display_name);
3722
3723 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new);
3724 heap_free(mhtml_url);
3725 if(FAILED(hres))
3726 return hres;
3727
3728 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */
3729 *out = &mime_obj;
3730 return S_OK;
3731 }