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