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