[INETCOMM] Sync with Wine Staging 2.16. CORE-13762
[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
958 TRACE("(%p)->(%p)\n", This, pClassID);
959
960 if(!pClassID)
961 return E_INVALIDARG;
962
963 *pClassID = IID_IMimeBody;
964 return S_OK;
965 }
966
967 static HRESULT WINAPI MimeBody_IsDirty(
968 IMimeBody* iface)
969 {
970 MimeBody *This = impl_from_IMimeBody(iface);
971 FIXME("(%p)->() stub\n", This);
972 return E_NOTIMPL;
973 }
974
975 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
976 {
977 MimeBody *This = impl_from_IMimeBody(iface);
978 TRACE("(%p)->(%p)\n", This, pStm);
979 return parse_headers(This, pStm);
980 }
981
982 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
983 {
984 MimeBody *This = impl_from_IMimeBody(iface);
985 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
986 return E_NOTIMPL;
987 }
988
989 static HRESULT WINAPI MimeBody_GetSizeMax(
990 IMimeBody* iface,
991 ULARGE_INTEGER* pcbSize)
992 {
993 MimeBody *This = impl_from_IMimeBody(iface);
994 FIXME("(%p)->(%p) stub\n", This, pcbSize);
995 return E_NOTIMPL;
996 }
997
998 static HRESULT WINAPI MimeBody_InitNew(
999 IMimeBody* iface)
1000 {
1001 MimeBody *This = impl_from_IMimeBody(iface);
1002 TRACE("(%p)->()\n", This);
1003 return S_OK;
1004 }
1005
1006 static HRESULT WINAPI MimeBody_GetPropInfo(
1007 IMimeBody* iface,
1008 LPCSTR pszName,
1009 LPMIMEPROPINFO pInfo)
1010 {
1011 MimeBody *This = impl_from_IMimeBody(iface);
1012 header_t *header;
1013 HRESULT hr;
1014 DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
1015
1016 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
1017
1018 if(!pszName || !pInfo)
1019 return E_INVALIDARG;
1020
1021 TRACE("mask 0x%04x\n", pInfo->dwMask);
1022
1023 if(pInfo->dwMask & ~supported)
1024 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
1025
1026 hr = find_prop(This, pszName, &header);
1027 if(hr == S_OK)
1028 {
1029 if(pInfo->dwMask & PIM_CHARSET)
1030 pInfo->hCharset = 0;
1031 if(pInfo->dwMask & PIM_FLAGS)
1032 pInfo->dwFlags = 0x00000000;
1033 if(pInfo->dwMask & PIM_ROWNUMBER)
1034 pInfo->dwRowNumber = 0;
1035 if(pInfo->dwMask & PIM_ENCODINGTYPE)
1036 pInfo->ietEncoding = 0;
1037 if(pInfo->dwMask & PIM_VALUES)
1038 pInfo->cValues = 0;
1039 if(pInfo->dwMask & PIM_PROPID)
1040 pInfo->dwPropId = header->prop->id;
1041 if(pInfo->dwMask & PIM_VTDEFAULT)
1042 pInfo->vtDefault = header->prop->default_vt;
1043 if(pInfo->dwMask & PIM_VTCURRENT)
1044 pInfo->vtCurrent = 0;
1045 }
1046
1047 return hr;
1048 }
1049
1050 static HRESULT WINAPI MimeBody_SetPropInfo(
1051 IMimeBody* iface,
1052 LPCSTR pszName,
1053 LPCMIMEPROPINFO pInfo)
1054 {
1055 MimeBody *This = impl_from_IMimeBody(iface);
1056 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
1057 return E_NOTIMPL;
1058 }
1059
1060 static HRESULT WINAPI MimeBody_GetProp(
1061 IMimeBody* iface,
1062 LPCSTR pszName,
1063 DWORD dwFlags,
1064 LPPROPVARIANT pValue)
1065 {
1066 MimeBody *This = impl_from_IMimeBody(iface);
1067 header_t *header;
1068 HRESULT hr;
1069
1070 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1071
1072 if(!pszName || !pValue)
1073 return E_INVALIDARG;
1074
1075 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
1076 {
1077 PropVariantClear(pValue);
1078 pValue->vt = VT_LPSTR;
1079 pValue->u.pszVal = strdupA(This->content_pri_type);
1080 return S_OK;
1081 }
1082
1083 hr = find_prop(This, pszName, &header);
1084 if(hr == S_OK)
1085 {
1086 TRACE("type %d->%d\n", header->value.vt, pValue->vt);
1087
1088 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
1089 if(FAILED(hr))
1090 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
1091 }
1092
1093 return hr;
1094 }
1095
1096 static HRESULT WINAPI MimeBody_SetProp(
1097 IMimeBody* iface,
1098 LPCSTR pszName,
1099 DWORD dwFlags,
1100 LPCPROPVARIANT pValue)
1101 {
1102 MimeBody *This = impl_from_IMimeBody(iface);
1103 header_t *header;
1104 HRESULT hr;
1105
1106 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
1107
1108 if(!pszName || !pValue)
1109 return E_INVALIDARG;
1110
1111 hr = find_prop(This, pszName, &header);
1112 if(hr != S_OK)
1113 {
1114 property_list_entry_t *prop_entry;
1115 const property_t *prop = NULL;
1116
1117 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
1118 {
1119 if(ISPIDSTR(pszName))
1120 {
1121 if(STRTOPID(pszName) == prop_entry->prop.id)
1122 {
1123 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1124 prop = &prop_entry->prop;
1125 break;
1126 }
1127 }
1128 else if(!lstrcmpiA(pszName, prop_entry->prop.name))
1129 {
1130 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
1131 prop = &prop_entry->prop;
1132 break;
1133 }
1134 }
1135
1136 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
1137 if(!header)
1138 return E_OUTOFMEMORY;
1139
1140 if(!prop)
1141 {
1142 const property_t *prop_def = NULL;
1143 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
1144 if(!prop_entry)
1145 {
1146 HeapFree(GetProcessHeap(), 0, header);
1147 return E_OUTOFMEMORY;
1148 }
1149
1150 prop_def = find_default_prop(pszName);
1151 if(prop_def)
1152 {
1153 prop_entry->prop.name = strdupA(prop_def->name);
1154 prop_entry->prop.id = prop_def->id;
1155 }
1156 else
1157 {
1158 if(ISPIDSTR(pszName))
1159 {
1160 HeapFree(GetProcessHeap(), 0, prop_entry);
1161 HeapFree(GetProcessHeap(), 0, header);
1162 return MIME_E_NOT_FOUND;
1163 }
1164
1165 prop_entry->prop.name = strdupA(pszName);
1166 prop_entry->prop.id = This->next_prop_id++;
1167 }
1168
1169 prop_entry->prop.flags = 0;
1170 prop_entry->prop.default_vt = pValue->vt;
1171 list_add_tail(&This->new_props, &prop_entry->entry);
1172 prop = &prop_entry->prop;
1173 TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
1174 }
1175
1176 header->prop = prop;
1177 PropVariantInit(&header->value);
1178 list_init(&header->params);
1179 list_add_tail(&This->headers, &header->entry);
1180 }
1181
1182 PropVariantCopy(&header->value, pValue);
1183
1184 return S_OK;
1185 }
1186
1187 static HRESULT WINAPI MimeBody_AppendProp(
1188 IMimeBody* iface,
1189 LPCSTR pszName,
1190 DWORD dwFlags,
1191 LPPROPVARIANT pValue)
1192 {
1193 MimeBody *This = impl_from_IMimeBody(iface);
1194 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
1195 return E_NOTIMPL;
1196 }
1197
1198 static HRESULT WINAPI MimeBody_DeleteProp(
1199 IMimeBody* iface,
1200 LPCSTR pszName)
1201 {
1202 MimeBody *This = impl_from_IMimeBody(iface);
1203 header_t *cursor;
1204 BOOL found;
1205
1206 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
1207
1208 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
1209 {
1210 if(ISPIDSTR(pszName))
1211 found = STRTOPID(pszName) == cursor->prop->id;
1212 else
1213 found = !lstrcmpiA(pszName, cursor->prop->name);
1214
1215 if(found)
1216 {
1217 list_remove(&cursor->entry);
1218 HeapFree(GetProcessHeap(), 0, cursor);
1219 return S_OK;
1220 }
1221 }
1222
1223 return MIME_E_NOT_FOUND;
1224 }
1225
1226 static HRESULT WINAPI MimeBody_CopyProps(
1227 IMimeBody* iface,
1228 ULONG cNames,
1229 LPCSTR* prgszName,
1230 IMimePropertySet* pPropertySet)
1231 {
1232 MimeBody *This = impl_from_IMimeBody(iface);
1233 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1234 return E_NOTIMPL;
1235 }
1236
1237 static HRESULT WINAPI MimeBody_MoveProps(
1238 IMimeBody* iface,
1239 ULONG cNames,
1240 LPCSTR* prgszName,
1241 IMimePropertySet* pPropertySet)
1242 {
1243 MimeBody *This = impl_from_IMimeBody(iface);
1244 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
1245 return E_NOTIMPL;
1246 }
1247
1248 static HRESULT WINAPI MimeBody_DeleteExcept(
1249 IMimeBody* iface,
1250 ULONG cNames,
1251 LPCSTR* prgszName)
1252 {
1253 MimeBody *This = impl_from_IMimeBody(iface);
1254 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
1255 return E_NOTIMPL;
1256 }
1257
1258 static HRESULT WINAPI MimeBody_QueryProp(
1259 IMimeBody* iface,
1260 LPCSTR pszName,
1261 LPCSTR pszCriteria,
1262 boolean fSubString,
1263 boolean fCaseSensitive)
1264 {
1265 MimeBody *This = impl_from_IMimeBody(iface);
1266 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
1267 return E_NOTIMPL;
1268 }
1269
1270 static HRESULT WINAPI MimeBody_GetCharset(
1271 IMimeBody* iface,
1272 LPHCHARSET phCharset)
1273 {
1274 MimeBody *This = impl_from_IMimeBody(iface);
1275 FIXME("(%p)->(%p) stub\n", This, phCharset);
1276 *phCharset = NULL;
1277 return S_OK;
1278 }
1279
1280 static HRESULT WINAPI MimeBody_SetCharset(
1281 IMimeBody* iface,
1282 HCHARSET hCharset,
1283 CSETAPPLYTYPE applytype)
1284 {
1285 MimeBody *This = impl_from_IMimeBody(iface);
1286 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
1287 return E_NOTIMPL;
1288 }
1289
1290 static HRESULT WINAPI MimeBody_GetParameters(
1291 IMimeBody* iface,
1292 LPCSTR pszName,
1293 ULONG* pcParams,
1294 LPMIMEPARAMINFO* pprgParam)
1295 {
1296 MimeBody *This = impl_from_IMimeBody(iface);
1297 HRESULT hr;
1298 header_t *header;
1299
1300 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
1301
1302 *pprgParam = NULL;
1303 *pcParams = 0;
1304
1305 hr = find_prop(This, pszName, &header);
1306 if(hr != S_OK) return hr;
1307
1308 *pcParams = list_count(&header->params);
1309 if(*pcParams)
1310 {
1311 IMimeAllocator *alloc;
1312 param_t *param;
1313 MIMEPARAMINFO *info;
1314
1315 MimeOleGetAllocator(&alloc);
1316
1317 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
1318 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
1319 {
1320 int len;
1321
1322 len = strlen(param->name) + 1;
1323 info->pszName = IMimeAllocator_Alloc(alloc, len);
1324 memcpy(info->pszName, param->name, len);
1325 len = strlen(param->value) + 1;
1326 info->pszData = IMimeAllocator_Alloc(alloc, len);
1327 memcpy(info->pszData, param->value, len);
1328 info++;
1329 }
1330 IMimeAllocator_Release(alloc);
1331 }
1332 return S_OK;
1333 }
1334
1335 static HRESULT WINAPI MimeBody_IsContentType(
1336 IMimeBody* iface,
1337 LPCSTR pszPriType,
1338 LPCSTR pszSubType)
1339 {
1340 MimeBody *This = impl_from_IMimeBody(iface);
1341
1342 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
1343 if(pszPriType)
1344 {
1345 const char *pri = This->content_pri_type;
1346 if(!pri) pri = "text";
1347 if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
1348 }
1349
1350 if(pszSubType)
1351 {
1352 const char *sub = This->content_sub_type;
1353 if(!sub) sub = "plain";
1354 if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
1355 }
1356
1357 return S_OK;
1358 }
1359
1360 static HRESULT WINAPI MimeBody_BindToObject(
1361 IMimeBody* iface,
1362 REFIID riid,
1363 void** ppvObject)
1364 {
1365 MimeBody *This = impl_from_IMimeBody(iface);
1366 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
1367 return E_NOTIMPL;
1368 }
1369
1370 static HRESULT WINAPI MimeBody_Clone(
1371 IMimeBody* iface,
1372 IMimePropertySet** ppPropertySet)
1373 {
1374 MimeBody *This = impl_from_IMimeBody(iface);
1375 FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
1376 return E_NOTIMPL;
1377 }
1378
1379 static HRESULT WINAPI MimeBody_SetOption(
1380 IMimeBody* iface,
1381 const TYPEDID oid,
1382 LPCPROPVARIANT pValue)
1383 {
1384 MimeBody *This = impl_from_IMimeBody(iface);
1385 HRESULT hr = E_NOTIMPL;
1386 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
1387
1388 if(pValue->vt != TYPEDID_TYPE(oid))
1389 {
1390 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
1391 return E_INVALIDARG;
1392 }
1393
1394 switch(oid)
1395 {
1396 case OID_SECURITY_HWND_OWNER:
1397 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
1398 hr = S_OK;
1399 break;
1400 case OID_TRANSMIT_BODY_ENCODING:
1401 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
1402 hr = S_OK;
1403 break;
1404 default:
1405 FIXME("Unhandled oid %08x\n", oid);
1406 }
1407
1408 return hr;
1409 }
1410
1411 static HRESULT WINAPI MimeBody_GetOption(
1412 IMimeBody* iface,
1413 const TYPEDID oid,
1414 LPPROPVARIANT pValue)
1415 {
1416 MimeBody *This = impl_from_IMimeBody(iface);
1417 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
1418 return E_NOTIMPL;
1419 }
1420
1421 static HRESULT WINAPI MimeBody_EnumProps(
1422 IMimeBody* iface,
1423 DWORD dwFlags,
1424 IMimeEnumProperties** ppEnum)
1425 {
1426 MimeBody *This = impl_from_IMimeBody(iface);
1427 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
1428 return E_NOTIMPL;
1429 }
1430
1431 static HRESULT WINAPI MimeBody_IsType(
1432 IMimeBody* iface,
1433 IMSGBODYTYPE bodytype)
1434 {
1435 MimeBody *This = impl_from_IMimeBody(iface);
1436
1437 TRACE("(%p)->(%d)\n", This, bodytype);
1438 switch(bodytype)
1439 {
1440 case IBT_EMPTY:
1441 return This->data ? S_FALSE : S_OK;
1442 default:
1443 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
1444 }
1445 return S_OK;
1446 }
1447
1448 static HRESULT WINAPI MimeBody_SetDisplayName(
1449 IMimeBody* iface,
1450 LPCSTR pszDisplay)
1451 {
1452 MimeBody *This = impl_from_IMimeBody(iface);
1453 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
1454 return E_NOTIMPL;
1455 }
1456
1457 static HRESULT WINAPI MimeBody_GetDisplayName(
1458 IMimeBody* iface,
1459 LPSTR* ppszDisplay)
1460 {
1461 MimeBody *This = impl_from_IMimeBody(iface);
1462 FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
1463 return E_NOTIMPL;
1464 }
1465
1466 static HRESULT WINAPI MimeBody_GetOffsets(
1467 IMimeBody* iface,
1468 LPBODYOFFSETS pOffsets)
1469 {
1470 MimeBody *This = impl_from_IMimeBody(iface);
1471 TRACE("(%p)->(%p)\n", This, pOffsets);
1472
1473 *pOffsets = This->body_offsets;
1474
1475 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
1476 return S_OK;
1477 }
1478
1479 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
1480 IMimeBody* iface,
1481 ENCODINGTYPE* pietEncoding)
1482 {
1483 MimeBody *This = impl_from_IMimeBody(iface);
1484
1485 TRACE("(%p)->(%p)\n", This, pietEncoding);
1486
1487 *pietEncoding = This->encoding;
1488 return S_OK;
1489 }
1490
1491 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
1492 IMimeBody* iface,
1493 ENCODINGTYPE ietEncoding)
1494 {
1495 MimeBody *This = impl_from_IMimeBody(iface);
1496
1497 TRACE("(%p)->(%d)\n", This, ietEncoding);
1498
1499 This->encoding = ietEncoding;
1500 return S_OK;
1501 }
1502
1503 static HRESULT WINAPI MimeBody_GetEstimatedSize(
1504 IMimeBody* iface,
1505 ENCODINGTYPE ietEncoding,
1506 ULONG* pcbSize)
1507 {
1508 MimeBody *This = impl_from_IMimeBody(iface);
1509 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
1510 return E_NOTIMPL;
1511 }
1512
1513 static HRESULT WINAPI MimeBody_GetDataHere(
1514 IMimeBody* iface,
1515 ENCODINGTYPE ietEncoding,
1516 IStream* pStream)
1517 {
1518 MimeBody *This = impl_from_IMimeBody(iface);
1519 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
1520 return E_NOTIMPL;
1521 }
1522
1523 static const signed char base64_decode_table[] =
1524 {
1525 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
1526 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
1527 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
1528 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
1529 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
1530 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
1531 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
1532 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */
1533 };
1534
1535 static HRESULT decode_base64(IStream *input, IStream **ret_stream)
1536 {
1537 const unsigned char *ptr, *end;
1538 unsigned char buf[1024];
1539 LARGE_INTEGER pos;
1540 unsigned char *ret;
1541 unsigned char in[4];
1542 IStream *output;
1543 DWORD size;
1544 int n = 0;
1545 HRESULT hres;
1546
1547 pos.QuadPart = 0;
1548 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1549 if(FAILED(hres))
1550 return hres;
1551
1552 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1553 if(FAILED(hres))
1554 return hres;
1555
1556 while(1) {
1557 hres = IStream_Read(input, buf, sizeof(buf), &size);
1558 if(FAILED(hres) || !size)
1559 break;
1560
1561 ptr = ret = buf;
1562 end = buf + size;
1563
1564 while(1) {
1565 /* skip invalid chars */
1566 while(ptr < end &&
1567 (*ptr >= sizeof(base64_decode_table)/sizeof(*base64_decode_table)
1568 || base64_decode_table[*ptr] == -1))
1569 ptr++;
1570 if(ptr == end)
1571 break;
1572
1573 in[n++] = base64_decode_table[*ptr++];
1574 switch(n) {
1575 case 2:
1576 *ret++ = in[0] << 2 | in[1] >> 4;
1577 continue;
1578 case 3:
1579 *ret++ = in[1] << 4 | in[2] >> 2;
1580 continue;
1581 case 4:
1582 *ret++ = ((in[2] << 6) & 0xc0) | in[3];
1583 n = 0;
1584 }
1585 }
1586
1587 if(ret > buf) {
1588 hres = IStream_Write(output, buf, ret - buf, NULL);
1589 if(FAILED(hres))
1590 break;
1591 }
1592 }
1593
1594 if(SUCCEEDED(hres))
1595 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1596 if(FAILED(hres)) {
1597 IStream_Release(output);
1598 return hres;
1599 }
1600
1601 *ret_stream = output;
1602 return S_OK;
1603 }
1604
1605 static int hex_digit(char c)
1606 {
1607 if('0' <= c && c <= '9')
1608 return c - '0';
1609 if('A' <= c && c <= 'F')
1610 return c - 'A' + 10;
1611 if('a' <= c && c <= 'f')
1612 return c - 'a' + 10;
1613 return -1;
1614 }
1615
1616 static HRESULT decode_qp(IStream *input, IStream **ret_stream)
1617 {
1618 const unsigned char *ptr, *end;
1619 unsigned char *ret, prev = 0;
1620 unsigned char buf[1024];
1621 LARGE_INTEGER pos;
1622 IStream *output;
1623 DWORD size;
1624 int n = -1;
1625 HRESULT hres;
1626
1627 pos.QuadPart = 0;
1628 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL);
1629 if(FAILED(hres))
1630 return hres;
1631
1632 hres = CreateStreamOnHGlobal(NULL, TRUE, &output);
1633 if(FAILED(hres))
1634 return hres;
1635
1636 while(1) {
1637 hres = IStream_Read(input, buf, sizeof(buf), &size);
1638 if(FAILED(hres) || !size)
1639 break;
1640
1641 ptr = ret = buf;
1642 end = buf + size;
1643
1644 while(ptr < end) {
1645 unsigned char byte = *ptr++;
1646
1647 switch(n) {
1648 case -1:
1649 if(byte == '=')
1650 n = 0;
1651 else
1652 *ret++ = byte;
1653 continue;
1654 case 0:
1655 prev = byte;
1656 n = 1;
1657 continue;
1658 case 1:
1659 if(prev != '\r' || byte != '\n') {
1660 int h1 = hex_digit(prev), h2 = hex_digit(byte);
1661 if(h1 != -1 && h2 != -1)
1662 *ret++ = (h1 << 4) | h2;
1663 else
1664 *ret++ = '=';
1665 }
1666 n = -1;
1667 continue;
1668 }
1669 }
1670
1671 if(ret > buf) {
1672 hres = IStream_Write(output, buf, ret - buf, NULL);
1673 if(FAILED(hres))
1674 break;
1675 }
1676 }
1677
1678 if(SUCCEEDED(hres))
1679 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL);
1680 if(FAILED(hres)) {
1681 IStream_Release(output);
1682 return hres;
1683 }
1684
1685 *ret_stream = output;
1686 return S_OK;
1687 }
1688
1689 static HRESULT WINAPI MimeBody_GetData(
1690 IMimeBody* iface,
1691 ENCODINGTYPE ietEncoding,
1692 IStream** ppStream)
1693 {
1694 MimeBody *This = impl_from_IMimeBody(iface);
1695 ULARGE_INTEGER start, size;
1696 HRESULT hres;
1697
1698 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream);
1699
1700 if(This->encoding != ietEncoding) {
1701 switch(This->encoding) {
1702 case IET_BASE64:
1703 hres = decode_base64(This->data, ppStream);
1704 break;
1705 case IET_QP:
1706 hres = decode_qp(This->data, ppStream);
1707 break;
1708 default:
1709 FIXME("Decoding %d is not supported.\n", This->encoding);
1710 hres = S_FALSE;
1711 }
1712 if(ietEncoding != IET_BINARY)
1713 FIXME("Encoding %d is not supported.\n", ietEncoding);
1714 if(hres != S_FALSE)
1715 return hres;
1716 }
1717
1718 start.QuadPart = 0;
1719 hres = get_stream_size(This->data, &size);
1720 if(SUCCEEDED(hres))
1721 hres = create_sub_stream(This->data, start, size, ppStream);
1722 return hres;
1723 }
1724
1725 static HRESULT WINAPI MimeBody_SetData(
1726 IMimeBody* iface,
1727 ENCODINGTYPE ietEncoding,
1728 LPCSTR pszPriType,
1729 LPCSTR pszSubType,
1730 REFIID riid,
1731 LPVOID pvObject)
1732 {
1733 MimeBody *This = impl_from_IMimeBody(iface);
1734 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
1735 debugstr_guid(riid), pvObject);
1736
1737 if(IsEqualIID(riid, &IID_IStream))
1738 IStream_AddRef((IStream *)pvObject);
1739 else
1740 {
1741 FIXME("Unhandled object type %s\n", debugstr_guid(riid));
1742 return E_INVALIDARG;
1743 }
1744
1745 if(This->data)
1746 release_data(&This->data_iid, This->data);
1747
1748 This->data_iid = *riid;
1749 This->data = pvObject;
1750
1751 IMimeBody_SetCurrentEncoding(iface, ietEncoding);
1752
1753 /* FIXME: Update the content type.
1754 If pszPriType == NULL use 'application'
1755 If pszSubType == NULL use 'octet-stream' */
1756
1757 return S_OK;
1758 }
1759
1760 static HRESULT WINAPI MimeBody_EmptyData(
1761 IMimeBody* iface)
1762 {
1763 MimeBody *This = impl_from_IMimeBody(iface);
1764 FIXME("(%p)->() stub\n", This);
1765 return E_NOTIMPL;
1766 }
1767
1768 static HRESULT WINAPI MimeBody_CopyTo(
1769 IMimeBody* iface,
1770 IMimeBody* pBody)
1771 {
1772 MimeBody *This = impl_from_IMimeBody(iface);
1773 FIXME("(%p)->(%p) stub\n", This, pBody);
1774 return E_NOTIMPL;
1775 }
1776
1777 static HRESULT WINAPI MimeBody_GetTransmitInfo(
1778 IMimeBody* iface,
1779 LPTRANSMITINFO pTransmitInfo)
1780 {
1781 MimeBody *This = impl_from_IMimeBody(iface);
1782 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
1783 return E_NOTIMPL;
1784 }
1785
1786 static HRESULT WINAPI MimeBody_SaveToFile(
1787 IMimeBody* iface,
1788 ENCODINGTYPE ietEncoding,
1789 LPCSTR pszFilePath)
1790 {
1791 MimeBody *This = impl_from_IMimeBody(iface);
1792 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
1793 return E_NOTIMPL;
1794 }
1795
1796 static HRESULT WINAPI MimeBody_GetHandle(
1797 IMimeBody* iface,
1798 LPHBODY phBody)
1799 {
1800 MimeBody *This = impl_from_IMimeBody(iface);
1801 TRACE("(%p)->(%p)\n", iface, phBody);
1802
1803 if(!phBody)
1804 return E_INVALIDARG;
1805
1806 *phBody = This->handle;
1807 return This->handle ? S_OK : MIME_E_NO_DATA;
1808 }
1809
1810 static IMimeBodyVtbl body_vtbl =
1811 {
1812 MimeBody_QueryInterface,
1813 MimeBody_AddRef,
1814 MimeBody_Release,
1815 MimeBody_GetClassID,
1816 MimeBody_IsDirty,
1817 MimeBody_Load,
1818 MimeBody_Save,
1819 MimeBody_GetSizeMax,
1820 MimeBody_InitNew,
1821 MimeBody_GetPropInfo,
1822 MimeBody_SetPropInfo,
1823 MimeBody_GetProp,
1824 MimeBody_SetProp,
1825 MimeBody_AppendProp,
1826 MimeBody_DeleteProp,
1827 MimeBody_CopyProps,
1828 MimeBody_MoveProps,
1829 MimeBody_DeleteExcept,
1830 MimeBody_QueryProp,
1831 MimeBody_GetCharset,
1832 MimeBody_SetCharset,
1833 MimeBody_GetParameters,
1834 MimeBody_IsContentType,
1835 MimeBody_BindToObject,
1836 MimeBody_Clone,
1837 MimeBody_SetOption,
1838 MimeBody_GetOption,
1839 MimeBody_EnumProps,
1840 MimeBody_IsType,
1841 MimeBody_SetDisplayName,
1842 MimeBody_GetDisplayName,
1843 MimeBody_GetOffsets,
1844 MimeBody_GetCurrentEncoding,
1845 MimeBody_SetCurrentEncoding,
1846 MimeBody_GetEstimatedSize,
1847 MimeBody_GetDataHere,
1848 MimeBody_GetData,
1849 MimeBody_SetData,
1850 MimeBody_EmptyData,
1851 MimeBody_CopyTo,
1852 MimeBody_GetTransmitInfo,
1853 MimeBody_SaveToFile,
1854 MimeBody_GetHandle
1855 };
1856
1857 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
1858 {
1859 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
1860 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
1861
1862 body->body_offsets = *offsets;
1863 return S_OK;
1864 }
1865
1866 #define FIRST_CUSTOM_PROP_ID 0x100
1867
1868 static MimeBody *mimebody_create(void)
1869 {
1870 MimeBody *This;
1871 BODYOFFSETS body_offsets;
1872
1873 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1874 if (!This)
1875 return NULL;
1876
1877 This->IMimeBody_iface.lpVtbl = &body_vtbl;
1878 This->ref = 1;
1879 This->handle = NULL;
1880 list_init(&This->headers);
1881 list_init(&This->new_props);
1882 This->next_prop_id = FIRST_CUSTOM_PROP_ID;
1883 This->content_pri_type = NULL;
1884 This->content_sub_type = NULL;
1885 This->encoding = IET_7BIT;
1886 This->data = NULL;
1887 This->data_iid = IID_NULL;
1888
1889 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
1890 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
1891 MimeBody_set_offsets(This, &body_offsets);
1892
1893 return This;
1894 }
1895
1896 HRESULT MimeBody_create(IUnknown *outer, void **ppv)
1897 {
1898 MimeBody *mb;
1899
1900 if(outer)
1901 return CLASS_E_NOAGGREGATION;
1902
1903 if ((mb = mimebody_create()))
1904 {
1905 *ppv = &mb->IMimeBody_iface;
1906 return S_OK;
1907 }
1908 else
1909 {
1910 *ppv = NULL;
1911 return E_OUTOFMEMORY;
1912 }
1913 }
1914
1915 typedef struct body_t
1916 {
1917 struct list entry;
1918 DWORD index;
1919 MimeBody *mime_body;
1920
1921 struct body_t *parent;
1922 struct list children;
1923 } body_t;
1924
1925 typedef struct MimeMessage
1926 {
1927 IMimeMessage IMimeMessage_iface;
1928 LONG ref;
1929 IStream *stream;
1930
1931 struct list body_tree;
1932 DWORD next_index;
1933 } MimeMessage;
1934
1935 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
1936 {
1937 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
1938 }
1939
1940 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
1941 {
1942 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1943
1944 if (IsEqualIID(riid, &IID_IUnknown) ||
1945 IsEqualIID(riid, &IID_IPersist) ||
1946 IsEqualIID(riid, &IID_IPersistStreamInit) ||
1947 IsEqualIID(riid, &IID_IMimeMessageTree) ||
1948 IsEqualIID(riid, &IID_IMimeMessage))
1949 {
1950 *ppv = iface;
1951 IMimeMessage_AddRef(iface);
1952 return S_OK;
1953 }
1954
1955 FIXME("no interface for %s\n", debugstr_guid(riid));
1956 *ppv = NULL;
1957 return E_NOINTERFACE;
1958 }
1959
1960 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
1961 {
1962 MimeMessage *This = impl_from_IMimeMessage(iface);
1963 ULONG ref = InterlockedIncrement(&This->ref);
1964
1965 TRACE("(%p) ref=%d\n", This, ref);
1966
1967 return ref;
1968 }
1969
1970 static void empty_body_list(struct list *list)
1971 {
1972 body_t *body, *cursor2;
1973 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
1974 {
1975 empty_body_list(&body->children);
1976 list_remove(&body->entry);
1977 IMimeBody_Release(&body->mime_body->IMimeBody_iface);
1978 HeapFree(GetProcessHeap(), 0, body);
1979 }
1980 }
1981
1982 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
1983 {
1984 MimeMessage *This = impl_from_IMimeMessage(iface);
1985 ULONG ref = InterlockedDecrement(&This->ref);
1986
1987 TRACE("(%p) ref=%d\n", This, ref);
1988
1989 if (!ref)
1990 {
1991 empty_body_list(&This->body_tree);
1992
1993 if(This->stream) IStream_Release(This->stream);
1994 HeapFree(GetProcessHeap(), 0, This);
1995 }
1996
1997 return ref;
1998 }
1999
2000 /*** IPersist methods ***/
2001 static HRESULT WINAPI MimeMessage_GetClassID(
2002 IMimeMessage *iface,
2003 CLSID *pClassID)
2004 {
2005 FIXME("(%p)->(%p)\n", iface, pClassID);
2006 return E_NOTIMPL;
2007 }
2008
2009 /*** IPersistStreamInit methods ***/
2010 static HRESULT WINAPI MimeMessage_IsDirty(
2011 IMimeMessage *iface)
2012 {
2013 FIXME("(%p)->()\n", iface);
2014 return E_NOTIMPL;
2015 }
2016
2017 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
2018 {
2019 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
2020 if(body)
2021 {
2022 body->mime_body = mime_body;
2023 body->index = index;
2024 list_init(&body->children);
2025 body->parent = parent;
2026
2027 mime_body->handle = UlongToHandle(body->index);
2028 }
2029 return body;
2030 }
2031
2032 typedef struct
2033 {
2034 struct list entry;
2035 BODYOFFSETS offsets;
2036 } offset_entry_t;
2037
2038 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
2039 {
2040 HRESULT hr;
2041 DWORD read, boundary_start;
2042 int boundary_len = strlen(boundary);
2043 char *buf, *ptr, *overlap;
2044 DWORD start = 0, overlap_no;
2045 offset_entry_t *cur_body = NULL;
2046 BOOL is_first_line = TRUE;
2047 ULARGE_INTEGER cur;
2048 LARGE_INTEGER zero;
2049
2050 list_init(body_offsets);
2051
2052 overlap_no = boundary_len + 5;
2053
2054 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
2055
2056 zero.QuadPart = 0;
2057 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
2058 start = cur.u.LowPart;
2059
2060 do {
2061 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
2062 if(FAILED(hr)) goto end;
2063 if(read == 0) break;
2064 overlap[read] = '\0';
2065
2066 ptr = buf;
2067 while(1) {
2068 if(is_first_line) {
2069 is_first_line = FALSE;
2070 }else {
2071 ptr = strstr(ptr, "\r\n");
2072 if(!ptr)
2073 break;
2074 ptr += 2;
2075 }
2076
2077 boundary_start = start + ptr - buf;
2078
2079 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) {
2080 ptr += boundary_len + 2;
2081
2082 if(*ptr == '\r' && *(ptr + 1) == '\n')
2083 {
2084 ptr += 2;
2085 if(cur_body)
2086 {
2087 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2088 list_add_tail(body_offsets, &cur_body->entry);
2089 }
2090 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
2091 cur_body->offsets.cbBoundaryStart = boundary_start;
2092 cur_body->offsets.cbHeaderStart = start + ptr - buf;
2093 }
2094 else if(*ptr == '-' && *(ptr + 1) == '-')
2095 {
2096 if(cur_body)
2097 {
2098 cur_body->offsets.cbBodyEnd = boundary_start - 2;
2099 list_add_tail(body_offsets, &cur_body->entry);
2100 goto end;
2101 }
2102 }
2103 }
2104 }
2105
2106 if(overlap == buf) /* 1st iteration */
2107 {
2108 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
2109 overlap = buf + overlap_no;
2110 start += read - overlap_no;
2111 }
2112 else
2113 {
2114 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
2115 start += read;
2116 }
2117 } while(1);
2118
2119 end:
2120 HeapFree(GetProcessHeap(), 0, buf);
2121 return hr;
2122 }
2123
2124 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
2125 {
2126 ULARGE_INTEGER start, length;
2127 MimeBody *mime_body;
2128 HRESULT hr;
2129 body_t *body;
2130 LARGE_INTEGER pos;
2131
2132 pos.QuadPart = offset->cbHeaderStart;
2133 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL);
2134
2135 mime_body = mimebody_create();
2136 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
2137
2138 pos.QuadPart = 0;
2139 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start);
2140 offset->cbBodyStart = start.QuadPart;
2141 if (parent) MimeBody_set_offsets(mime_body, offset);
2142
2143 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart;
2144 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data);
2145 mime_body->data_iid = IID_IStream;
2146
2147 body = new_body_entry(mime_body, msg->next_index++, parent);
2148
2149 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
2150 {
2151 MIMEPARAMINFO *param_info;
2152 ULONG count, i;
2153 IMimeAllocator *alloc;
2154
2155 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
2156 &param_info);
2157 if(hr != S_OK || count == 0) return body;
2158
2159 MimeOleGetAllocator(&alloc);
2160
2161 for(i = 0; i < count; i++)
2162 {
2163 if(!lstrcmpiA(param_info[i].pszName, "boundary"))
2164 {
2165 struct list offset_list;
2166 offset_entry_t *cur, *cursor2;
2167 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
2168 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
2169 {
2170 body_t *sub_body;
2171
2172 sub_body = create_sub_body(msg, pStm, &cur->offsets, body);
2173 list_add_tail(&body->children, &sub_body->entry);
2174 list_remove(&cur->entry);
2175 HeapFree(GetProcessHeap(), 0, cur);
2176 }
2177 break;
2178 }
2179 }
2180 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
2181 IMimeAllocator_Release(alloc);
2182 }
2183 return body;
2184 }
2185
2186 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
2187 {
2188 MimeMessage *This = impl_from_IMimeMessage(iface);
2189 body_t *root_body;
2190 BODYOFFSETS offsets;
2191 ULARGE_INTEGER cur;
2192 LARGE_INTEGER zero;
2193
2194 TRACE("(%p)->(%p)\n", iface, pStm);
2195
2196 if(This->stream)
2197 {
2198 FIXME("already loaded a message\n");
2199 return E_FAIL;
2200 }
2201
2202 empty_body_list(&This->body_tree);
2203
2204 IStream_AddRef(pStm);
2205 This->stream = pStm;
2206 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
2207 offsets.cbBodyStart = offsets.cbBodyEnd = 0;
2208
2209 root_body = create_sub_body(This, pStm, &offsets, NULL);
2210
2211 zero.QuadPart = 0;
2212 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
2213 offsets.cbBodyEnd = cur.u.LowPart;
2214 MimeBody_set_offsets(root_body->mime_body, &offsets);
2215
2216 list_add_head(&This->body_tree, &root_body->entry);
2217
2218 return S_OK;
2219 }
2220
2221 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
2222 {
2223 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
2224 return E_NOTIMPL;
2225 }
2226
2227 static HRESULT WINAPI MimeMessage_GetSizeMax(
2228 IMimeMessage *iface,
2229 ULARGE_INTEGER *pcbSize)
2230 {
2231 FIXME("(%p)->(%p)\n", iface, pcbSize);
2232 return E_NOTIMPL;
2233 }
2234
2235 static HRESULT WINAPI MimeMessage_InitNew(
2236 IMimeMessage *iface)
2237 {
2238 FIXME("(%p)->()\n", iface);
2239 return E_NOTIMPL;
2240 }
2241
2242 /*** IMimeMessageTree methods ***/
2243 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
2244 DWORD dwFlags)
2245 {
2246 MimeMessage *This = impl_from_IMimeMessage(iface);
2247
2248 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
2249
2250 IStream_AddRef(This->stream);
2251 *ppStream = This->stream;
2252 return S_OK;
2253 }
2254
2255 static HRESULT WINAPI MimeMessage_GetMessageSize(
2256 IMimeMessage *iface,
2257 ULONG *pcbSize,
2258 DWORD dwFlags)
2259 {
2260 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
2261 return E_NOTIMPL;
2262 }
2263
2264 static HRESULT WINAPI MimeMessage_LoadOffsetTable(
2265 IMimeMessage *iface,
2266 IStream *pStream)
2267 {
2268 FIXME("(%p)->(%p)\n", iface, pStream);
2269 return E_NOTIMPL;
2270 }
2271
2272 static HRESULT WINAPI MimeMessage_SaveOffsetTable(
2273 IMimeMessage *iface,
2274 IStream *pStream,
2275 DWORD dwFlags)
2276 {
2277 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
2278 return E_NOTIMPL;
2279 }
2280
2281
2282 static HRESULT WINAPI MimeMessage_GetFlags(
2283 IMimeMessage *iface,
2284 DWORD *pdwFlags)
2285 {
2286 FIXME("(%p)->(%p)\n", iface, pdwFlags);
2287 return E_NOTIMPL;
2288 }
2289
2290 static HRESULT WINAPI MimeMessage_Commit(
2291 IMimeMessage *iface,
2292 DWORD dwFlags)
2293 {
2294 FIXME("(%p)->(0x%x)\n", iface, dwFlags);
2295 return S_OK;
2296 }
2297
2298
2299 static HRESULT WINAPI MimeMessage_HandsOffStorage(
2300 IMimeMessage *iface)
2301 {
2302 FIXME("(%p)->()\n", iface);
2303 return E_NOTIMPL;
2304 }
2305
2306 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
2307 {
2308 body_t *cur;
2309 HRESULT hr;
2310
2311 if(hbody == HBODY_ROOT)
2312 {
2313 *body = LIST_ENTRY(list_head(list), body_t, entry);
2314 return S_OK;
2315 }
2316
2317 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
2318 {
2319 if(cur->index == HandleToUlong(hbody))
2320 {
2321 *body = cur;
2322 return S_OK;
2323 }
2324 hr = find_body(&cur->children, hbody, body);
2325 if(hr == S_OK) return S_OK;
2326 }
2327 return S_FALSE;
2328 }
2329
2330 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
2331 void **ppvObject)
2332 {
2333 MimeMessage *This = impl_from_IMimeMessage(iface);
2334 HRESULT hr;
2335 body_t *body;
2336
2337 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
2338
2339 hr = find_body(&This->body_tree, hBody, &body);
2340
2341 if(hr != S_OK) return hr;
2342
2343 if(IsEqualIID(riid, &IID_IMimeBody))
2344 {
2345 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
2346 *ppvObject = &body->mime_body->IMimeBody_iface;
2347 return S_OK;
2348 }
2349
2350 return E_NOINTERFACE;
2351 }
2352
2353 static HRESULT WINAPI MimeMessage_SaveBody(
2354 IMimeMessage *iface,
2355 HBODY hBody,
2356 DWORD dwFlags,
2357 IStream *pStream)
2358 {
2359 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
2360 return E_NOTIMPL;
2361 }
2362
2363 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
2364 {
2365 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
2366 body_t *body;
2367 HRESULT hr;
2368 struct list *list;
2369
2370 if(location == IBL_ROOT)
2371 {
2372 *out = root;
2373 return S_OK;
2374 }
2375
2376 hr = find_body(&msg->body_tree, pivot, &body);
2377
2378 if(hr == S_OK)
2379 {
2380 switch(location)
2381 {
2382 case IBL_PARENT:
2383 if(body->parent)
2384 *out = body->parent;
2385 else
2386 hr = MIME_E_NOT_FOUND;
2387 break;
2388
2389 case IBL_FIRST:
2390 list = list_head(&body->children);
2391 if(list)
2392 *out = LIST_ENTRY(list, body_t, entry);
2393 else
2394 hr = MIME_E_NOT_FOUND;
2395 break;
2396
2397 case IBL_LAST:
2398 list = list_tail(&body->children);
2399 if(list)
2400 *out = LIST_ENTRY(list, body_t, entry);
2401 else
2402 hr = MIME_E_NOT_FOUND;
2403 break;
2404
2405 case IBL_NEXT:
2406 list = list_next(&body->parent->children, &body->entry);
2407 if(list)
2408 *out = LIST_ENTRY(list, body_t, entry);
2409 else
2410 hr = MIME_E_NOT_FOUND;
2411 break;
2412
2413 case IBL_PREVIOUS:
2414 list = list_prev(&body->parent->children, &body->entry);
2415 if(list)
2416 *out = LIST_ENTRY(list, body_t, entry);
2417 else
2418 hr = MIME_E_NOT_FOUND;
2419 break;
2420
2421 default:
2422 hr = E_FAIL;
2423 break;
2424 }
2425 }
2426
2427 return hr;
2428 }
2429
2430
2431 static HRESULT WINAPI MimeMessage_InsertBody(
2432 IMimeMessage *iface,
2433 BODYLOCATION location,
2434 HBODY hPivot,
2435 LPHBODY phBody)
2436 {
2437 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2438 return E_NOTIMPL;
2439 }
2440
2441 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
2442 HBODY *phBody)
2443 {
2444 MimeMessage *This = impl_from_IMimeMessage(iface);
2445 body_t *body;
2446 HRESULT hr;
2447
2448 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
2449
2450 if(!phBody)
2451 return E_INVALIDARG;
2452
2453 *phBody = NULL;
2454
2455 hr = get_body(This, location, hPivot, &body);
2456
2457 if(hr == S_OK) *phBody = UlongToHandle(body->index);
2458
2459 return hr;
2460 }
2461
2462 static HRESULT WINAPI MimeMessage_DeleteBody(
2463 IMimeMessage *iface,
2464 HBODY hBody,
2465 DWORD dwFlags)
2466 {
2467 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
2468 return E_NOTIMPL;
2469 }
2470
2471 static HRESULT WINAPI MimeMessage_MoveBody(
2472 IMimeMessage *iface,
2473 HBODY hBody,
2474 BODYLOCATION location)
2475 {
2476 FIXME("(%p)->(%d)\n", iface, location);
2477 return E_NOTIMPL;
2478 }
2479
2480 static void count_children(body_t *body, boolean recurse, ULONG *count)
2481 {
2482 body_t *child;
2483
2484 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
2485 {
2486 (*count)++;
2487 if(recurse) count_children(child, recurse, count);
2488 }
2489 }
2490
2491 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
2492 ULONG *pcBodies)
2493 {
2494 HRESULT hr;
2495 MimeMessage *This = impl_from_IMimeMessage(iface);
2496 body_t *body;
2497
2498 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
2499
2500 hr = find_body(&This->body_tree, hParent, &body);
2501 if(hr != S_OK) return hr;
2502
2503 *pcBodies = 1;
2504 count_children(body, fRecurse, pcBodies);
2505
2506 return S_OK;
2507 }
2508
2509 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
2510 {
2511 struct list *ptr;
2512 HBODY next;
2513
2514 for (;;)
2515 {
2516 if (!body) ptr = list_head( &This->body_tree );
2517 else
2518 {
2519 ptr = list_head( &body->children );
2520 while (!ptr)
2521 {
2522 if (!body->parent) return MIME_E_NOT_FOUND;
2523 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
2524 }
2525 }
2526
2527 body = LIST_ENTRY( ptr, body_t, entry );
2528 next = UlongToHandle( body->index );
2529 find->dwReserved = body->index;
2530 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
2531 find->pszSubType) == S_OK)
2532 {
2533 *out = next;
2534 return S_OK;
2535 }
2536 }
2537 return MIME_E_NOT_FOUND;
2538 }
2539
2540 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2541 {
2542 MimeMessage *This = impl_from_IMimeMessage(iface);
2543
2544 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2545
2546 pFindBody->dwReserved = 0;
2547 return find_next(This, NULL, pFindBody, phBody);
2548 }
2549
2550 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
2551 {
2552 MimeMessage *This = impl_from_IMimeMessage(iface);
2553 body_t *body;
2554 HRESULT hr;
2555
2556 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
2557
2558 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
2559 if (hr != S_OK) return MIME_E_NOT_FOUND;
2560 return find_next(This, body, pFindBody, phBody);
2561 }
2562
2563 static HRESULT WINAPI MimeMessage_ResolveURL(
2564 IMimeMessage *iface,
2565 HBODY hRelated,
2566 LPCSTR pszBase,
2567 LPCSTR pszURL,
2568 DWORD dwFlags,
2569 LPHBODY phBody)
2570 {
2571 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
2572 return E_NOTIMPL;
2573 }
2574
2575 static HRESULT WINAPI MimeMessage_ToMultipart(
2576 IMimeMessage *iface,
2577 HBODY hBody,
2578 LPCSTR pszSubType,
2579 LPHBODY phMultipart)
2580 {
2581 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
2582 return E_NOTIMPL;
2583 }
2584
2585 static HRESULT WINAPI MimeMessage_GetBodyOffsets(
2586 IMimeMessage *iface,
2587 HBODY hBody,
2588 LPBODYOFFSETS pOffsets)
2589 {
2590 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
2591 return E_NOTIMPL;
2592 }
2593
2594 static HRESULT WINAPI MimeMessage_GetCharset(
2595 IMimeMessage *iface,
2596 LPHCHARSET phCharset)
2597 {
2598 FIXME("(%p)->(%p)\n", iface, phCharset);
2599 *phCharset = NULL;
2600 return S_OK;
2601 }
2602
2603 static HRESULT WINAPI MimeMessage_SetCharset(
2604 IMimeMessage *iface,
2605 HCHARSET hCharset,
2606 CSETAPPLYTYPE applytype)
2607 {
2608 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
2609 return E_NOTIMPL;
2610 }
2611
2612 static HRESULT WINAPI MimeMessage_IsBodyType(
2613 IMimeMessage *iface,
2614 HBODY hBody,
2615 IMSGBODYTYPE bodytype)
2616 {
2617 HRESULT hr;
2618 IMimeBody *mime_body;
2619 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
2620
2621 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2622 if(hr != S_OK) return hr;
2623
2624 hr = IMimeBody_IsType(mime_body, bodytype);
2625 MimeBody_Release(mime_body);
2626 return hr;
2627 }
2628
2629 static HRESULT WINAPI MimeMessage_IsContentType(
2630 IMimeMessage *iface,
2631 HBODY hBody,
2632 LPCSTR pszPriType,
2633 LPCSTR pszSubType)
2634 {
2635 HRESULT hr;
2636 IMimeBody *mime_body;
2637 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
2638 debugstr_a(pszSubType));
2639
2640 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2641 if(FAILED(hr)) return hr;
2642
2643 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
2644 IMimeBody_Release(mime_body);
2645 return hr;
2646 }
2647
2648 static HRESULT WINAPI MimeMessage_QueryBodyProp(
2649 IMimeMessage *iface,
2650 HBODY hBody,
2651 LPCSTR pszName,
2652 LPCSTR pszCriteria,
2653 boolean fSubString,
2654 boolean fCaseSensitive)
2655 {
2656 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2657 return E_NOTIMPL;
2658 }
2659
2660 static HRESULT WINAPI MimeMessage_GetBodyProp(
2661 IMimeMessage *iface,
2662 HBODY hBody,
2663 LPCSTR pszName,
2664 DWORD dwFlags,
2665 LPPROPVARIANT pValue)
2666 {
2667 HRESULT hr;
2668 IMimeBody *mime_body;
2669
2670 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2671
2672 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
2673 if(hr != S_OK) return hr;
2674
2675 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
2676 IMimeBody_Release(mime_body);
2677
2678 return hr;
2679 }
2680
2681 static HRESULT WINAPI MimeMessage_SetBodyProp(
2682 IMimeMessage *iface,
2683 HBODY hBody,
2684 LPCSTR pszName,
2685 DWORD dwFlags,
2686 LPCPROPVARIANT pValue)
2687 {
2688 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
2689 return E_NOTIMPL;
2690 }
2691
2692 static HRESULT WINAPI MimeMessage_DeleteBodyProp(
2693 IMimeMessage *iface,
2694 HBODY hBody,
2695 LPCSTR pszName)
2696 {
2697 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
2698 return E_NOTIMPL;
2699 }
2700
2701 static HRESULT WINAPI MimeMessage_SetOption(
2702 IMimeMessage *iface,
2703 const TYPEDID oid,
2704 LPCPROPVARIANT pValue)
2705 {
2706 HRESULT hr = S_OK;
2707 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
2708
2709 /* Message ID is checked before type.
2710 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later.
2711 */
2712 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64))
2713 {
2714 WARN("oid (%08x) out of range\n", oid);
2715 return MIME_E_INVALID_OPTION_ID;
2716 }
2717
2718 if(pValue->vt != TYPEDID_TYPE(oid))
2719 {
2720 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
2721 return S_OK;
2722 }
2723
2724 switch(oid)
2725 {
2726 case OID_HIDE_TNEF_ATTACHMENTS:
2727 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
2728 break;
2729 case OID_SHOW_MACBINARY:
2730 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
2731 break;
2732 case OID_SAVEBODY_KEEPBOUNDARY:
2733 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal);
2734 break;
2735 case OID_CLEANUP_TREE_ON_SAVE:
2736 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal);
2737 break;
2738 default:
2739 FIXME("Unhandled oid %08x\n", oid);
2740 hr = MIME_E_INVALID_OPTION_ID;
2741 }
2742
2743 return hr;
2744 }
2745
2746 static HRESULT WINAPI MimeMessage_GetOption(
2747 IMimeMessage *iface,
2748 const TYPEDID oid,
2749 LPPROPVARIANT pValue)
2750 {
2751 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
2752 return E_NOTIMPL;
2753 }
2754
2755 /*** IMimeMessage methods ***/
2756 static HRESULT WINAPI MimeMessage_CreateWebPage(
2757 IMimeMessage *iface,
2758 IStream *pRootStm,
2759 LPWEBPAGEOPTIONS pOptions,
2760 IMimeMessageCallback *pCallback,
2761 IMoniker **ppMoniker)
2762 {
2763 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
2764 *ppMoniker = NULL;
2765 return E_NOTIMPL;
2766 }
2767
2768 static HRESULT WINAPI MimeMessage_GetProp(
2769 IMimeMessage *iface,
2770 LPCSTR pszName,
2771 DWORD dwFlags,
2772 LPPROPVARIANT pValue)
2773 {
2774 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2775 return E_NOTIMPL;
2776 }
2777
2778 static HRESULT WINAPI MimeMessage_SetProp(
2779 IMimeMessage *iface,
2780 LPCSTR pszName,
2781 DWORD dwFlags,
2782 LPCPROPVARIANT pValue)
2783 {
2784 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
2785 return E_NOTIMPL;
2786 }
2787
2788 static HRESULT WINAPI MimeMessage_DeleteProp(
2789 IMimeMessage *iface,
2790 LPCSTR pszName)
2791 {
2792 FIXME("(%p)->(%s)\n", iface, pszName);
2793 return E_NOTIMPL;
2794 }
2795
2796 static HRESULT WINAPI MimeMessage_QueryProp(
2797 IMimeMessage *iface,
2798 LPCSTR pszName,
2799 LPCSTR pszCriteria,
2800 boolean fSubString,
2801 boolean fCaseSensitive)
2802 {
2803 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
2804 return E_NOTIMPL;
2805 }
2806
2807 static HRESULT WINAPI MimeMessage_GetTextBody(
2808 IMimeMessage *iface,
2809 DWORD dwTxtType,
2810 ENCODINGTYPE ietEncoding,
2811 IStream **pStream,
2812 LPHBODY phBody)
2813 {
2814 HRESULT hr;
2815 HBODY hbody;
2816 FINDBODY find_struct;
2817 IMimeBody *mime_body;
2818 static char text[] = "text";
2819 static char plain[] = "plain";
2820 static char html[] = "html";
2821
2822 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
2823
2824 find_struct.pszPriType = text;
2825
2826 switch(dwTxtType)
2827 {
2828 case TXT_PLAIN:
2829 find_struct.pszSubType = plain;
2830 break;
2831 case TXT_HTML:
2832 find_struct.pszSubType = html;
2833 break;
2834 default:
2835 return MIME_E_INVALID_TEXT_TYPE;
2836 }
2837
2838 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2839 if(hr != S_OK)
2840 {
2841 TRACE("not found hr %08x\n", hr);
2842 *phBody = NULL;
2843 return hr;
2844 }
2845
2846 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
2847
2848 IMimeBody_GetData(mime_body, ietEncoding, pStream);
2849 *phBody = hbody;
2850 IMimeBody_Release(mime_body);
2851 return hr;
2852 }
2853
2854 static HRESULT WINAPI MimeMessage_SetTextBody(
2855 IMimeMessage *iface,
2856 DWORD dwTxtType,
2857 ENCODINGTYPE ietEncoding,
2858 HBODY hAlternative,
2859 IStream *pStream,
2860 LPHBODY phBody)
2861 {
2862 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
2863 return E_NOTIMPL;
2864 }
2865
2866 static HRESULT WINAPI MimeMessage_AttachObject(
2867 IMimeMessage *iface,
2868 REFIID riid,
2869 void *pvObject,
2870 LPHBODY phBody)
2871 {
2872 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
2873 return E_NOTIMPL;
2874 }
2875
2876 static HRESULT WINAPI MimeMessage_AttachFile(
2877 IMimeMessage *iface,
2878 LPCSTR pszFilePath,
2879 IStream *pstmFile,
2880 LPHBODY phBody)
2881 {
2882 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
2883 return E_NOTIMPL;
2884 }
2885
2886 static HRESULT WINAPI MimeMessage_AttachURL(
2887 IMimeMessage *iface,
2888 LPCSTR pszBase,
2889 LPCSTR pszURL,
2890 DWORD dwFlags,
2891 IStream *pstmURL,
2892 LPSTR *ppszCIDURL,
2893 LPHBODY phBody)
2894 {
2895 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
2896 return E_NOTIMPL;
2897 }
2898
2899 static HRESULT WINAPI MimeMessage_GetAttachments(
2900 IMimeMessage *iface,
2901 ULONG *pcAttach,
2902 LPHBODY *pprghAttach)
2903 {
2904 HRESULT hr;
2905 FINDBODY find_struct;
2906 HBODY hbody;
2907 LPHBODY array;
2908 ULONG size = 10;
2909
2910 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
2911
2912 *pcAttach = 0;
2913 array = CoTaskMemAlloc(size * sizeof(HBODY));
2914
2915 find_struct.pszPriType = find_struct.pszSubType = NULL;
2916 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
2917 while(hr == S_OK)
2918 {
2919 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
2920 TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
2921 if(hr != S_OK)
2922 {
2923 if(*pcAttach + 1 > size)
2924 {
2925 size *= 2;
2926 array = CoTaskMemRealloc(array, size * sizeof(HBODY));
2927 }
2928 array[*pcAttach] = hbody;
2929 (*pcAttach)++;
2930 }
2931 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
2932 }
2933
2934 *pprghAttach = array;
2935 return S_OK;
2936 }
2937
2938 static HRESULT WINAPI MimeMessage_GetAddressTable(
2939 IMimeMessage *iface,
2940 IMimeAddressTable **ppTable)
2941 {
2942 FIXME("(%p)->(%p)\n", iface, ppTable);
2943 return E_NOTIMPL;
2944 }
2945
2946 static HRESULT WINAPI MimeMessage_GetSender(
2947 IMimeMessage *iface,
2948 LPADDRESSPROPS pAddress)
2949 {
2950 FIXME("(%p)->(%p)\n", iface, pAddress);
2951 return E_NOTIMPL;
2952 }
2953
2954 static HRESULT WINAPI MimeMessage_GetAddressTypes(
2955 IMimeMessage *iface,
2956 DWORD dwAdrTypes,
2957 DWORD dwProps,
2958 LPADDRESSLIST pList)
2959 {
2960 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
2961 return E_NOTIMPL;
2962 }
2963
2964 static HRESULT WINAPI MimeMessage_GetAddressFormat(
2965 IMimeMessage *iface,
2966 DWORD dwAdrTypes,
2967 ADDRESSFORMAT format,
2968 LPSTR *ppszFormat)
2969 {
2970 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
2971 return E_NOTIMPL;
2972 }
2973
2974 static HRESULT WINAPI MimeMessage_EnumAddressTypes(
2975 IMimeMessage *iface,
2976 DWORD dwAdrTypes,
2977 DWORD dwProps,
2978 IMimeEnumAddressTypes **ppEnum)
2979 {
2980 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
2981 return E_NOTIMPL;
2982 }
2983
2984 static HRESULT WINAPI MimeMessage_SplitMessage(
2985 IMimeMessage *iface,
2986 ULONG cbMaxPart,
2987 IMimeMessageParts **ppParts)
2988 {
2989 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
2990 return E_NOTIMPL;
2991 }
2992
2993 static HRESULT WINAPI MimeMessage_GetRootMoniker(
2994 IMimeMessage *iface,
2995 IMoniker **ppMoniker)
2996 {
2997 FIXME("(%p)->(%p)\n", iface, ppMoniker);
2998 return E_NOTIMPL;
2999 }
3000
3001 static const IMimeMessageVtbl MimeMessageVtbl =
3002 {
3003 MimeMessage_QueryInterface,
3004 MimeMessage_AddRef,
3005 MimeMessage_Release,
3006 MimeMessage_GetClassID,
3007 MimeMessage_IsDirty,
3008 MimeMessage_Load,
3009 MimeMessage_Save,
3010 MimeMessage_GetSizeMax,
3011 MimeMessage_InitNew,
3012 MimeMessage_GetMessageSource,
3013 MimeMessage_GetMessageSize,
3014 MimeMessage_LoadOffsetTable,
3015 MimeMessage_SaveOffsetTable,
3016 MimeMessage_GetFlags,
3017 MimeMessage_Commit,
3018 MimeMessage_HandsOffStorage,
3019 MimeMessage_BindToObject,
3020 MimeMessage_SaveBody,
3021 MimeMessage_InsertBody,
3022 MimeMessage_GetBody,
3023 MimeMessage_DeleteBody,
3024 MimeMessage_MoveBody,
3025 MimeMessage_CountBodies,
3026 MimeMessage_FindFirst,
3027 MimeMessage_FindNext,
3028 MimeMessage_ResolveURL,
3029 MimeMessage_ToMultipart,
3030 MimeMessage_GetBodyOffsets,
3031 MimeMessage_GetCharset,
3032 MimeMessage_SetCharset,
3033 MimeMessage_IsBodyType,
3034 MimeMessage_IsContentType,
3035 MimeMessage_QueryBodyProp,
3036 MimeMessage_GetBodyProp,
3037 MimeMessage_SetBodyProp,
3038 MimeMessage_DeleteBodyProp,
3039 MimeMessage_SetOption,
3040 MimeMessage_GetOption,
3041 MimeMessage_CreateWebPage,
3042 MimeMessage_GetProp,
3043 MimeMessage_SetProp,
3044 MimeMessage_DeleteProp,
3045 MimeMessage_QueryProp,
3046 MimeMessage_GetTextBody,
3047 MimeMessage_SetTextBody,
3048 MimeMessage_AttachObject,
3049 MimeMessage_AttachFile,
3050 MimeMessage_AttachURL,
3051 MimeMessage_GetAttachments,
3052 MimeMessage_GetAddressTable,
3053 MimeMessage_GetSender,
3054 MimeMessage_GetAddressTypes,
3055 MimeMessage_GetAddressFormat,
3056 MimeMessage_EnumAddressTypes,
3057 MimeMessage_SplitMessage,
3058 MimeMessage_GetRootMoniker,
3059 };
3060
3061 HRESULT MimeMessage_create(IUnknown *outer, void **obj)
3062 {
3063 MimeMessage *This;
3064 MimeBody *mime_body;
3065 body_t *root_body;
3066
3067 TRACE("(%p, %p)\n", outer, obj);
3068
3069 if (outer)
3070 {
3071 FIXME("outer unknown not supported yet\n");
3072 return E_NOTIMPL;
3073 }
3074
3075 *obj = NULL;
3076
3077 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3078 if (!This) return E_OUTOFMEMORY;
3079
3080 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
3081 This->ref = 1;
3082 This->stream = NULL;
3083 list_init(&This->body_tree);
3084 This->next_index = 1;
3085
3086 mime_body = mimebody_create();
3087 root_body = new_body_entry(mime_body, This->next_index++, NULL);
3088 list_add_head(&This->body_tree, &root_body->entry);
3089
3090 *obj = &This->IMimeMessage_iface;
3091 return S_OK;
3092 }
3093
3094 /***********************************************************************
3095 * MimeOleCreateMessage (INETCOMM.@)
3096 */
3097 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
3098 {
3099 TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
3100 return MimeMessage_create(NULL, (void **)ppMessage);
3101 }
3102
3103 /***********************************************************************
3104 * MimeOleSetCompatMode (INETCOMM.@)
3105 */
3106 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
3107 {
3108 FIXME("(0x%x)\n", dwMode);
3109 return S_OK;
3110 }
3111
3112 /***********************************************************************
3113 * MimeOleCreateVirtualStream (INETCOMM.@)
3114 */
3115 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
3116 {
3117 HRESULT hr;
3118 FIXME("(%p)\n", ppStream);
3119
3120 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
3121 return hr;
3122 }
3123
3124 typedef struct MimeSecurity
3125 {
3126 IMimeSecurity IMimeSecurity_iface;
3127 LONG ref;
3128 } MimeSecurity;
3129
3130 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
3131 {
3132 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
3133 }
3134
3135 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
3136 {
3137 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3138
3139 if (IsEqualIID(riid, &IID_IUnknown) ||
3140 IsEqualIID(riid, &IID_IMimeSecurity))
3141 {
3142 *ppv = iface;
3143 IMimeSecurity_AddRef(iface);
3144 return S_OK;
3145 }
3146
3147 FIXME("no interface for %s\n", debugstr_guid(riid));
3148 *ppv = NULL;
3149 return E_NOINTERFACE;
3150 }
3151
3152 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
3153 {
3154 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3155 LONG ref = InterlockedIncrement(&This->ref);
3156
3157 TRACE("(%p) ref=%d\n", This, ref);
3158
3159 return ref;
3160 }
3161
3162 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
3163 {
3164 MimeSecurity *This = impl_from_IMimeSecurity(iface);
3165 LONG ref = InterlockedDecrement(&This->ref);
3166
3167 TRACE("(%p) ref=%d\n", This, ref);
3168
3169 if (!ref)
3170 HeapFree(GetProcessHeap(), 0, This);
3171
3172 return ref;
3173 }
3174
3175 static HRESULT WINAPI MimeSecurity_InitNew(
3176 IMimeSecurity* iface)
3177 {
3178 FIXME("(%p)->(): stub\n", iface);
3179 return S_OK;
3180 }
3181
3182 static HRESULT WINAPI MimeSecurity_CheckInit(
3183 IMimeSecurity* iface)
3184 {
3185 FIXME("(%p)->(): stub\n", iface);
3186 return E_NOTIMPL;
3187 }
3188
3189 static HRESULT WINAPI MimeSecurity_EncodeMessage(
3190 IMimeSecurity* iface,
3191 IMimeMessageTree* pTree,
3192 DWORD dwFlags)
3193 {
3194 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3195 return E_NOTIMPL;
3196 }
3197
3198 static HRESULT WINAPI MimeSecurity_EncodeBody(
3199 IMimeSecurity* iface,
3200 IMimeMessageTree* pTree,
3201 HBODY hEncodeRoot,
3202 DWORD dwFlags)
3203 {
3204 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
3205 return E_NOTIMPL;
3206 }
3207
3208 static HRESULT WINAPI MimeSecurity_DecodeMessage(
3209 IMimeSecurity* iface,
3210 IMimeMessageTree* pTree,
3211 DWORD dwFlags)
3212 {
3213 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
3214 return E_NOTIMPL;
3215 }
3216
3217 static HRESULT WINAPI MimeSecurity_DecodeBody(
3218 IMimeSecurity* iface,
3219 IMimeMessageTree* pTree,
3220 HBODY hDecodeRoot,
3221 DWORD dwFlags)
3222 {
3223 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
3224 return E_NOTIMPL;
3225 }
3226
3227 static HRESULT WINAPI MimeSecurity_EnumCertificates(
3228 IMimeSecurity* iface,
3229 HCAPICERTSTORE hc,
3230 DWORD dwUsage,
3231 PCX509CERT pPrev,
3232 PCX509CERT* ppCert)
3233 {
3234 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
3235 return E_NOTIMPL;
3236 }
3237
3238 static HRESULT WINAPI MimeSecurity_GetCertificateName(
3239 IMimeSecurity* iface,
3240 const PCX509CERT pX509Cert,
3241 const CERTNAMETYPE cn,
3242 LPSTR* ppszName)
3243 {
3244 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
3245 return E_NOTIMPL;
3246 }
3247
3248 static HRESULT WINAPI MimeSecurity_GetMessageType(
3249 IMimeSecurity* iface,
3250 const HWND hwndParent,
3251 IMimeBody* pBody,
3252 DWORD* pdwSecType)
3253 {
3254 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
3255 return E_NOTIMPL;
3256 }
3257
3258 static HRESULT WINAPI MimeSecurity_GetCertData(
3259 IMimeSecurity* iface,
3260 const PCX509CERT pX509Cert,
3261 const CERTDATAID dataid,
3262 LPPROPVARIANT pValue)
3263 {
3264 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
3265 return E_NOTIMPL;
3266 }
3267
3268
3269 static const IMimeSecurityVtbl MimeSecurityVtbl =
3270 {
3271 MimeSecurity_QueryInterface,
3272 MimeSecurity_AddRef,
3273 MimeSecurity_Release,
3274 MimeSecurity_InitNew,
3275 MimeSecurity_CheckInit,
3276 MimeSecurity_EncodeMessage,
3277 MimeSecurity_EncodeBody,
3278 MimeSecurity_DecodeMessage,
3279 MimeSecurity_DecodeBody,
3280 MimeSecurity_EnumCertificates,
3281 MimeSecurity_GetCertificateName,
3282 MimeSecurity_GetMessageType,
3283 MimeSecurity_GetCertData
3284 };
3285
3286 HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
3287 {
3288 MimeSecurity *This;
3289
3290 *obj = NULL;
3291
3292 if (outer) return CLASS_E_NOAGGREGATION;
3293
3294 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3295 if (!This) return E_OUTOFMEMORY;
3296
3297 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
3298 This->ref = 1;
3299
3300 *obj = &This->IMimeSecurity_iface;
3301 return S_OK;
3302 }
3303
3304 /***********************************************************************
3305 * MimeOleCreateSecurity (INETCOMM.@)
3306 */
3307 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
3308 {
3309 return MimeSecurity_create(NULL, (void **)ppSecurity);
3310 }
3311
3312 static HRESULT WINAPI MimeAlloc_QueryInterface(
3313 IMimeAllocator* iface,
3314 REFIID riid,
3315 void **obj)
3316 {
3317 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
3318
3319 if (IsEqualIID(riid, &IID_IUnknown) ||
3320 IsEqualIID(riid, &IID_IMalloc) ||
3321 IsEqualIID(riid, &IID_IMimeAllocator))
3322 {
3323 *obj = iface;
3324 IMimeAllocator_AddRef(iface);
3325 return S_OK;
3326 }
3327
3328 FIXME("no interface for %s\n", debugstr_guid(riid));
3329 *obj = NULL;
3330 return E_NOINTERFACE;
3331 }
3332
3333 static ULONG WINAPI MimeAlloc_AddRef(
3334 IMimeAllocator* iface)
3335 {
3336 return 2;
3337 }
3338
3339 static ULONG WINAPI MimeAlloc_Release(
3340 IMimeAllocator* iface)
3341 {
3342 return 1;
3343 }
3344
3345 static LPVOID WINAPI MimeAlloc_Alloc(
3346 IMimeAllocator* iface,
3347 SIZE_T cb)
3348 {
3349 return CoTaskMemAlloc(cb);
3350 }
3351
3352 static LPVOID WINAPI MimeAlloc_Realloc(
3353 IMimeAllocator* iface,
3354 LPVOID pv,
3355 SIZE_T cb)
3356 {
3357 return CoTaskMemRealloc(pv, cb);
3358 }
3359
3360 static void WINAPI MimeAlloc_Free(
3361 IMimeAllocator* iface,
3362 LPVOID pv)
3363 {
3364 CoTaskMemFree(pv);
3365 }
3366
3367 static SIZE_T WINAPI MimeAlloc_GetSize(
3368 IMimeAllocator* iface,
3369 LPVOID pv)
3370 {
3371 FIXME("stub\n");
3372 return 0;
3373 }
3374
3375 static int WINAPI MimeAlloc_DidAlloc(
3376 IMimeAllocator* iface,
3377 LPVOID pv)
3378 {
3379 FIXME("stub\n");
3380 return 0;
3381 }
3382
3383 static void WINAPI MimeAlloc_HeapMinimize(
3384 IMimeAllocator* iface)
3385 {
3386 FIXME("stub\n");
3387 return;
3388 }
3389
3390 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
3391 IMimeAllocator* iface,
3392 ULONG cParams,
3393 LPMIMEPARAMINFO prgParam,
3394 boolean fFreeArray)
3395 {
3396 ULONG i;
3397 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
3398
3399 for(i = 0; i < cParams; i++)
3400 {
3401 IMimeAllocator_Free(iface, prgParam[i].pszName);
3402 IMimeAllocator_Free(iface, prgParam[i].pszData);
3403 }
3404 if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
3405 return S_OK;
3406 }
3407
3408 static HRESULT WINAPI MimeAlloc_FreeAddressList(
3409 IMimeAllocator* iface,
3410 LPADDRESSLIST pList)
3411 {
3412 FIXME("stub\n");
3413 return E_NOTIMPL;
3414 }
3415
3416 static HRESULT WINAPI MimeAlloc_FreeAddressProps(
3417 IMimeAllocator* iface,
3418 LPADDRESSPROPS pAddress)
3419 {
3420 FIXME("stub\n");
3421 return E_NOTIMPL;
3422 }
3423
3424 static HRESULT WINAPI MimeAlloc_ReleaseObjects(
3425 IMimeAllocator* iface,
3426 ULONG cObjects,
3427 IUnknown **prgpUnknown,
3428 boolean fFreeArray)
3429 {
3430 FIXME("stub\n");
3431 return E_NOTIMPL;
3432 }
3433
3434
3435 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
3436 IMimeAllocator* iface,
3437 ULONG cRows,
3438 LPENUMHEADERROW prgRow,
3439 boolean fFreeArray)
3440 {
3441 FIXME("stub\n");
3442 return E_NOTIMPL;
3443 }
3444
3445 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
3446 IMimeAllocator* iface,
3447 ULONG cProps,
3448 LPENUMPROPERTY prgProp,
3449 boolean fFreeArray)
3450 {
3451 FIXME("stub\n");
3452 return E_NOTIMPL;
3453 }
3454
3455 static HRESULT WINAPI MimeAlloc_FreeThumbprint(
3456 IMimeAllocator* iface,
3457 THUMBBLOB *pthumbprint)
3458 {
3459 FIXME("stub\n");
3460 return E_NOTIMPL;
3461 }
3462
3463
3464 static HRESULT WINAPI MimeAlloc_PropVariantClear(
3465 IMimeAllocator* iface,
3466 LPPROPVARIANT pProp)
3467 {
3468 FIXME("stub\n");
3469 return E_NOTIMPL;
3470 }
3471
3472 static IMimeAllocatorVtbl mime_alloc_vtbl =
3473 {
3474 MimeAlloc_QueryInterface,
3475 MimeAlloc_AddRef,
3476 MimeAlloc_Release,
3477 MimeAlloc_Alloc,
3478 MimeAlloc_Realloc,
3479 MimeAlloc_Free,
3480 MimeAlloc_GetSize,
3481 MimeAlloc_DidAlloc,
3482 MimeAlloc_HeapMinimize,
3483 MimeAlloc_FreeParamInfoArray,
3484 MimeAlloc_FreeAddressList,
3485 MimeAlloc_FreeAddressProps,
3486 MimeAlloc_ReleaseObjects,
3487 MimeAlloc_FreeEnumHeaderRowArray,
3488 MimeAlloc_FreeEnumPropertyArray,
3489 MimeAlloc_FreeThumbprint,
3490 MimeAlloc_PropVariantClear
3491 };
3492
3493 static IMimeAllocator mime_allocator =
3494 {
3495 &mime_alloc_vtbl
3496 };
3497
3498 HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
3499 {
3500 if(outer) return CLASS_E_NOAGGREGATION;
3501
3502 *obj = &mime_allocator;
3503 return S_OK;
3504 }
3505
3506 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
3507 {
3508 return MimeAllocator_create(NULL, (void**)alloc);
3509 }
3510
3511 HRESULT VirtualStream_create(IUnknown *outer, void **obj)
3512 {
3513 FIXME("(%p, %p)\n", outer, obj);
3514
3515 *obj = NULL;
3516 if (outer) return CLASS_E_NOAGGREGATION;
3517
3518 return MimeOleCreateVirtualStream((IStream **)obj);
3519 }
3520
3521 /* IMimePropertySchema Interface */
3522 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out)
3523 {
3524 propschema *This = impl_from_IMimePropertySchema(iface);
3525 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out);
3526
3527 *out = NULL;
3528
3529 if (IsEqualIID(riid, &IID_IUnknown) ||
3530 IsEqualIID(riid, &IID_IMimePropertySchema))
3531 {
3532 *out = iface;
3533 }
3534 else
3535 {
3536 FIXME("no interface for %s\n", debugstr_guid(riid));
3537 return E_NOINTERFACE;
3538 }
3539
3540 IMimePropertySchema_AddRef(iface);
3541 return S_OK;
3542 }
3543
3544 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface)
3545 {
3546 propschema *This = impl_from_IMimePropertySchema(iface);
3547 LONG ref = InterlockedIncrement(&This->ref);
3548
3549 TRACE("(%p) ref=%d\n", This, ref);
3550
3551 return ref;
3552 }
3553
3554 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface)
3555 {
3556 propschema *This = impl_from_IMimePropertySchema(iface);
3557 LONG ref = InterlockedDecrement(&This->ref);
3558
3559 TRACE("(%p) ref=%d\n", This, ref);
3560
3561 if (!ref)
3562 {
3563 HeapFree(GetProcessHeap(), 0, This);
3564 }
3565
3566 return ref;
3567 }
3568
3569 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3570 DWORD rownumber, VARTYPE vtdefault, DWORD *propid)
3571 {
3572 propschema *This = impl_from_IMimePropertySchema(iface);
3573 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid);
3574 return E_NOTIMPL;
3575 }
3576
3577 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags,
3578 DWORD rownumber, VARTYPE vtdefault)
3579 {
3580 propschema *This = impl_from_IMimePropertySchema(iface);
3581 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault);
3582 return S_OK;
3583 }
3584
3585 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid)
3586 {
3587 propschema *This = impl_from_IMimePropertySchema(iface);
3588 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid);
3589 return E_NOTIMPL;
3590 }
3591
3592 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name)
3593 {
3594 propschema *This = impl_from_IMimePropertySchema(iface);
3595 FIXME("(%p)->(%d, %p) stub\n", This, propid, name);
3596 return E_NOTIMPL;
3597 }
3598
3599 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype)
3600 {
3601 propschema *This = impl_from_IMimePropertySchema(iface);
3602 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype);
3603 return E_NOTIMPL;
3604 }
3605
3606 static IMimePropertySchemaVtbl prop_schema_vtbl =
3607 {
3608 propschema_QueryInterface,
3609 propschema_AddRef,
3610 propschema_Release,
3611 propschema_RegisterProperty,
3612 propschema_ModifyProperty,
3613 propschema_GetPropertyId,
3614 propschema_GetPropertyName,
3615 propschema_RegisterAddressType
3616 };
3617
3618
3619 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
3620 {
3621 propschema *This;
3622
3623 TRACE("(%p) stub\n", schema);
3624
3625 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
3626 if (!This)
3627 return E_OUTOFMEMORY;
3628
3629 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl;
3630 This->ref = 1;
3631
3632 *schema = &This->IMimePropertySchema_iface;
3633
3634 return S_OK;
3635 }
3636
3637 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type,
3638 ADDRESSFORMAT addr_format, WCHAR **address)
3639 {
3640 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address);
3641
3642 return E_NOTIMPL;
3643 }
3644
3645 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
3646 {
3647 FIXME("(%s %p)\n", debugstr_guid(riid), ppv);
3648 *ppv = NULL;
3649 return E_NOINTERFACE;
3650 }
3651
3652 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface)
3653 {
3654 TRACE("\n");
3655 return 2;
3656 }
3657
3658 static ULONG WINAPI mime_obj_Release(IUnknown *iface)
3659 {
3660 TRACE("\n");
3661 return 1;
3662 }
3663
3664 static const IUnknownVtbl mime_obj_vtbl = {
3665 mime_obj_QueryInterface,
3666 mime_obj_AddRef,
3667 mime_obj_Release
3668 };
3669
3670 static IUnknown mime_obj = { &mime_obj_vtbl };
3671
3672 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding,
3673 REFIID riid, void **out, IMoniker **moniker_new)
3674 {
3675 WCHAR *display_name, *mhtml_url;
3676 size_t len;
3677 HRESULT hres;
3678
3679 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'};
3680
3681 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new);
3682
3683 if(!IsEqualGUID(&IID_IUnknown, riid)) {
3684 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
3685 return E_NOINTERFACE;
3686 }
3687
3688 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name);
3689 if(FAILED(hres))
3690 return hres;
3691
3692 TRACE("display name %s\n", debugstr_w(display_name));
3693
3694 len = strlenW(display_name);
3695 mhtml_url = heap_alloc((len+1)*sizeof(WCHAR) + sizeof(mhtml_prefixW));
3696 if(!mhtml_url)
3697 return E_OUTOFMEMORY;
3698
3699 memcpy(mhtml_url, mhtml_prefixW, sizeof(mhtml_prefixW));
3700 strcpyW(mhtml_url + sizeof(mhtml_prefixW)/sizeof(WCHAR), display_name);
3701 HeapFree(GetProcessHeap(), 0, display_name);
3702
3703 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new);
3704 heap_free(mhtml_url);
3705 if(FAILED(hres))
3706 return hres;
3707
3708 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */
3709 *out = &mime_obj;
3710 return S_OK;
3711 }