4 * Copyright 2007 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
34 #include "wine/test.h"
36 #define DEFINE_EXPECT(func) \
37 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
39 #define SET_EXPECT(func) \
40 expect_ ## func = TRUE
42 #define CHECK_EXPECT(func) \
44 ok(expect_ ##func, "unexpected call " #func "\n"); \
45 expect_ ## func = FALSE; \
46 called_ ## func = TRUE; \
49 #define CHECK_EXPECT2(func) \
51 ok(expect_ ##func, "unexpected call " #func "\n"); \
52 called_ ## func = TRUE; \
55 #define CHECK_CALLED(func) \
57 ok(called_ ## func, "expected " #func "\n"); \
58 expect_ ## func = called_ ## func = FALSE; \
61 DEFINE_EXPECT(Stream_Read
);
62 DEFINE_EXPECT(Stream_Stat
);
63 DEFINE_EXPECT(Stream_Seek
);
64 DEFINE_EXPECT(Stream_Seek_END
);
65 DEFINE_EXPECT(GetBindInfo
);
66 DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
67 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
68 DEFINE_EXPECT(ReportData
);
69 DEFINE_EXPECT(ReportResult
);
71 static const char msg1
[] =
72 "MIME-Version: 1.0\r\n"
73 "Content-Type: multipart/mixed;\r\n"
74 " boundary=\"------------1.5.0.6\";\r\n"
75 " stuff=\"du;nno\";\r\n"
76 " morestuff=\"so\\\\me\\\"thing\\\"\"\r\n"
78 "From: Huw Davies <huw@codeweavers.com>\r\n"
79 "From: Me <xxx@codeweavers.com>\r\n"
80 "To: wine-patches <wine-patches@winehq.org>\r\n"
81 "Cc: Huw Davies <huw@codeweavers.com>,\r\n"
82 " \"Fred Bloggs\" <fred@bloggs.com>\r\n"
86 "This is a multi-part message in MIME format.\r\n"
87 "--------------1.5.0.6\r\n"
88 "Content-Type: text/plain; format=fixed; charset=UTF-8\r\n"
89 "Content-Transfer-Encoding: 8bit\r\n"
92 "--------------1.5.0.6\r\n"
93 "Content-Type: text/plain; charset=\"us-ascii\"\r\n"
94 "Content-Transfer-Encoding: 7bit\r\n"
97 "--------------1.5.0.6--\r\n";
99 static const char mhtml_page1
[] =
100 "MIME-Version: 1.0\r\n"
101 "Content-Type: multipart/related; type:=\"text/html\"; boundary=\"----=_NextPart_000_00\"\r\n"
103 "------=_NextPart_000_00\r\n"
104 "Content-Type: text/html; charset=\"Windows-1252\"\r\n"
105 "Content-Transfer-Encoding: quoted-printable\r\n"
108 "------=_NextPart_000_00\r\n"
109 "Content-Type: Image/Jpeg\r\n"
110 "Content-Transfer-Encoding: base64\r\n"
111 "Content-Location: http://winehq.org/mhtmltest.html\r\n"
112 "\r\n\t\t\t\tVGVzdA==\r\n\r\n"
113 "------=_NextPart_000_00--";
115 static WCHAR
*a2w(const char *str
)
123 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
124 ret
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
125 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
129 static int strcmp_wa(const WCHAR
*strw
, const char *stra
)
132 MultiByteToWideChar(CP_ACP
, 0, stra
, -1, buf
, sizeof(buf
)/sizeof(WCHAR
));
133 return lstrcmpW(strw
, buf
);
136 static void test_CreateVirtualStream(void)
141 hr
= MimeOleCreateVirtualStream(&pstm
);
142 ok(hr
== S_OK
, "ret %08x\n", hr
);
144 IStream_Release(pstm
);
147 static void test_CreateSecurity(void)
152 hr
= MimeOleCreateSecurity(&sec
);
153 ok(hr
== S_OK
, "ret %08x\n", hr
);
155 IMimeSecurity_Release(sec
);
158 static IStream
*create_stream_from_string(const char *data
)
164 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
165 ok(hr
== S_OK
, "ret %08x\n", hr
);
167 hr
= IStream_Write(stream
, data
, strlen(data
), NULL
);
168 ok(hr
== S_OK
, "Write failed: %08x\n", hr
);
171 hr
= IStream_Seek(stream
, off
, STREAM_SEEK_SET
, NULL
);
172 ok(hr
== S_OK
, "Seek failed: %08x\n", hr
);
177 #define test_current_encoding(a,b) _test_current_encoding(__LINE__,a,b)
178 static void _test_current_encoding(unsigned line
, IMimeBody
*mime_body
, ENCODINGTYPE encoding
)
180 ENCODINGTYPE current_encoding
;
183 hres
= IMimeBody_GetCurrentEncoding(mime_body
, ¤t_encoding
);
184 ok_(__FILE__
,line
)(hres
== S_OK
, "GetCurrentEncoding failed: %08x\n", hres
);
185 ok_(__FILE__
,line
)(current_encoding
== encoding
, "encoding = %d, expected %d\n", current_encoding
, encoding
);
188 static void test_CreateBody(void)
192 HBODY handle
= (void *)0xdeadbeef;
196 ULONG count
, found_param
, i
;
197 MIMEPARAMINFO
*param_info
;
198 IMimeAllocator
*alloc
;
201 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
202 ok(hr
== S_OK
, "ret %08x\n", hr
);
204 hr
= IMimeBody_GetHandle(body
, &handle
);
205 ok(hr
== MIME_E_NO_DATA
, "ret %08x\n", hr
);
206 ok(handle
== NULL
, "handle %p\n", handle
);
208 in
= create_stream_from_string(msg1
);
210 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
211 hr
= IMimeBody_InitNew(body
);
212 ok(hr
== S_OK
, "ret %08x\n", hr
);
214 test_current_encoding(body
, IET_7BIT
);
216 hr
= IMimeBody_Load(body
, in
);
217 ok(hr
== S_OK
, "ret %08x\n", hr
);
219 IStream_Seek(in
, off
, STREAM_SEEK_CUR
, &pos
);
220 ok(pos
.u
.LowPart
== 359, "pos %u\n", pos
.u
.LowPart
);
222 hr
= IMimeBody_IsContentType(body
, "multipart", "mixed");
223 ok(hr
== S_OK
, "ret %08x\n", hr
);
224 hr
= IMimeBody_IsContentType(body
, "text", "plain");
225 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
226 hr
= IMimeBody_IsContentType(body
, NULL
, "mixed");
227 ok(hr
== S_OK
, "ret %08x\n", hr
);
228 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
229 ok(hr
== S_OK
, "got %08x\n", hr
);
231 hr
= IMimeBody_SetData(body
, IET_8BIT
, "text", "plain", &IID_IStream
, in
);
232 ok(hr
== S_OK
, "ret %08x\n", hr
);
233 hr
= IMimeBody_IsContentType(body
, "text", "plain");
235 ok(hr
== S_OK
, "ret %08x\n", hr
);
236 test_current_encoding(body
, IET_8BIT
);
238 memset(&offsets
, 0xcc, sizeof(offsets
));
239 hr
= IMimeBody_GetOffsets(body
, &offsets
);
240 ok(hr
== MIME_E_NO_DATA
, "ret %08x\n", hr
);
241 ok(offsets
.cbBoundaryStart
== 0, "got %d\n", offsets
.cbBoundaryStart
);
242 ok(offsets
.cbHeaderStart
== 0, "got %d\n", offsets
.cbHeaderStart
);
243 ok(offsets
.cbBodyStart
== 0, "got %d\n", offsets
.cbBodyStart
);
244 ok(offsets
.cbBodyEnd
== 0, "got %d\n", offsets
.cbBodyEnd
);
246 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
247 ok(hr
== S_FALSE
, "got %08x\n", hr
);
249 hr
= MimeOleGetAllocator(&alloc
);
250 ok(hr
== S_OK
, "ret %08x\n", hr
);
252 hr
= IMimeBody_GetParameters(body
, "nothere", &count
, ¶m_info
);
253 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
254 ok(count
== 0, "got %d\n", count
);
255 ok(!param_info
, "got %p\n", param_info
);
257 hr
= IMimeBody_GetParameters(body
, "bar", &count
, ¶m_info
);
258 ok(hr
== S_OK
, "ret %08x\n", hr
);
259 ok(count
== 0, "got %d\n", count
);
260 ok(!param_info
, "got %p\n", param_info
);
262 hr
= IMimeBody_GetParameters(body
, "Content-Type", &count
, ¶m_info
);
263 ok(hr
== S_OK
, "ret %08x\n", hr
);
264 todo_wine
/* native adds a charset parameter */
265 ok(count
== 4, "got %d\n", count
);
266 ok(param_info
!= NULL
, "got %p\n", param_info
);
269 for(i
= 0; i
< count
; i
++)
271 if(!strcmp(param_info
[i
].pszName
, "morestuff"))
274 ok(!strcmp(param_info
[i
].pszData
, "so\\me\"thing\""),
275 "got %s\n", param_info
[i
].pszData
);
277 else if(!strcmp(param_info
[i
].pszName
, "stuff"))
280 ok(!strcmp(param_info
[i
].pszData
, "du;nno"),
281 "got %s\n", param_info
[i
].pszData
);
284 ok(found_param
== 2, "matched %d params\n", found_param
);
286 hr
= IMimeAllocator_FreeParamInfoArray(alloc
, count
, param_info
, TRUE
);
287 ok(hr
== S_OK
, "ret %08x\n", hr
);
288 IMimeAllocator_Release(alloc
);
291 IMimeBody_Release(body
);
295 IStream IStream_iface
;
300 static inline TestStream
*impl_from_IStream(IStream
*iface
)
302 return CONTAINING_RECORD(iface
, TestStream
, IStream_iface
);
305 static HRESULT WINAPI
Stream_QueryInterface(IStream
*iface
, REFIID riid
, void **ppv
)
307 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ISequentialStream
, riid
) || IsEqualGUID(&IID_IStream
, riid
)) {
312 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
314 return E_NOINTERFACE
;
317 static ULONG WINAPI
Stream_AddRef(IStream
*iface
)
319 TestStream
*This
= impl_from_IStream(iface
);
320 return InterlockedIncrement(&This
->ref
);
323 static ULONG WINAPI
Stream_Release(IStream
*iface
)
325 TestStream
*This
= impl_from_IStream(iface
);
326 ULONG ref
= InterlockedDecrement(&This
->ref
);
329 HeapFree(GetProcessHeap(), 0, This
);
334 static HRESULT WINAPI
Stream_Read(IStream
*iface
, void *pv
, ULONG cb
, ULONG
*pcbRead
)
336 TestStream
*This
= impl_from_IStream(iface
);
340 CHECK_EXPECT(Stream_Read
);
342 for(i
= 0; i
< cb
; i
++)
343 output
[i
] = '0' + This
->pos
++;
348 static HRESULT WINAPI
Stream_Write(IStream
*iface
, const void *pv
, ULONG cb
, ULONG
*pcbWritten
)
350 ok(0, "unexpected call\n");
354 static DWORD expect_seek_pos
;
356 static HRESULT WINAPI
Stream_Seek(IStream
*iface
, LARGE_INTEGER dlibMove
, DWORD dwOrigin
,
357 ULARGE_INTEGER
*plibNewPosition
)
359 TestStream
*This
= impl_from_IStream(iface
);
361 if(dwOrigin
== STREAM_SEEK_END
) {
362 CHECK_EXPECT(Stream_Seek_END
);
363 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %u\n", dlibMove
.u
.LowPart
);
365 plibNewPosition
->QuadPart
= 10;
369 CHECK_EXPECT(Stream_Seek
);
371 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %u\n", dlibMove
.u
.LowPart
);
372 ok(dwOrigin
== STREAM_SEEK_SET
, "dwOrigin = %d\n", dwOrigin
);
373 This
->pos
= dlibMove
.QuadPart
;
375 plibNewPosition
->QuadPart
= This
->pos
;
379 static HRESULT WINAPI
Stream_SetSize(IStream
*iface
, ULARGE_INTEGER libNewSize
)
381 ok(0, "unexpected call\n");
385 static HRESULT WINAPI
Stream_CopyTo(IStream
*iface
, IStream
*pstm
, ULARGE_INTEGER cb
,
386 ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
388 ok(0, "unexpected call\n");
392 static HRESULT WINAPI
Stream_Commit(IStream
*iface
, DWORD grfCommitFlags
)
394 ok(0, "unexpected call\n");
398 static HRESULT WINAPI
Stream_Revert(IStream
*iface
)
400 ok(0, "unexpected call\n");
404 static HRESULT WINAPI
Stream_LockRegion(IStream
*iface
, ULARGE_INTEGER libOffset
,
405 ULARGE_INTEGER cb
, DWORD dwLockType
)
407 ok(0, "unexpected call\n");
411 static HRESULT WINAPI
Stream_UnlockRegion(IStream
*iface
,
412 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
414 ok(0, "unexpected call\n");
418 static HRESULT WINAPI
Stream_Stat(IStream
*iface
, STATSTG
*pstatstg
, DWORD dwStatFlag
)
420 CHECK_EXPECT(Stream_Stat
);
421 ok(dwStatFlag
== STATFLAG_NONAME
, "dwStatFlag = %x\n", dwStatFlag
);
425 static HRESULT WINAPI
Stream_Clone(IStream
*iface
, IStream
**ppstm
)
427 ok(0, "unexpected call\n");
431 static const IStreamVtbl StreamVtbl
= {
432 Stream_QueryInterface
,
448 static TestStream
*create_test_stream(void)
451 stream
= HeapAlloc(GetProcessHeap(), 0, sizeof(*stream
));
452 stream
->IStream_iface
.lpVtbl
= &StreamVtbl
;
458 #define test_stream_read(a,b,c,d) _test_stream_read(__LINE__,a,b,c,d)
459 static void _test_stream_read(unsigned line
, IStream
*stream
, HRESULT exhres
, const char *exdata
, unsigned read_size
)
461 ULONG read
= 0xdeadbeed, exread
= strlen(exdata
);
466 read_size
= sizeof(buf
)-1;
468 hres
= IStream_Read(stream
, buf
, read_size
, &read
);
469 ok_(__FILE__
,line
)(hres
== exhres
, "Read returned %08x, expected %08x\n", hres
, exhres
);
470 ok_(__FILE__
,line
)(read
== exread
, "unexpected read size %u, expected %u\n", read
, exread
);
472 ok_(__FILE__
,line
)(read
== exread
&& !memcmp(buf
, exdata
, read
), "unexpected data %s\n", buf
);
475 static void test_SetData(void)
477 IStream
*stream
, *stream2
;
478 TestStream
*test_stream
;
482 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
483 ok(hr
== S_OK
, "ret %08x\n", hr
);
485 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
486 hr
= IMimeBody_InitNew(body
);
487 ok(hr
== S_OK
, "ret %08x\n", hr
);
489 stream
= create_stream_from_string(msg1
);
490 hr
= IMimeBody_Load(body
, stream
);
491 ok(hr
== S_OK
, "ret %08x\n", hr
);
492 IStream_Release(stream
);
494 test_stream
= create_test_stream();
495 hr
= IMimeBody_SetData(body
, IET_BINARY
, "text", "plain", &IID_IStream
, &test_stream
->IStream_iface
);
497 ok(hr
== S_OK
, "ret %08x\n", hr
);
498 hr
= IMimeBody_IsContentType(body
, "text", "plain");
500 ok(hr
== S_OK
, "ret %08x\n", hr
);
502 test_current_encoding(body
, IET_BINARY
);
504 SET_EXPECT(Stream_Stat
);
505 SET_EXPECT(Stream_Seek_END
);
506 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
507 CHECK_CALLED(Stream_Stat
);
508 CHECK_CALLED(Stream_Seek_END
);
509 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
510 ok(stream
!= &test_stream
->IStream_iface
, "unexpected stream\n");
512 SET_EXPECT(Stream_Seek
);
513 SET_EXPECT(Stream_Read
);
514 test_stream_read(stream
, S_OK
, "012", 3);
515 CHECK_CALLED(Stream_Seek
);
516 CHECK_CALLED(Stream_Read
);
518 SET_EXPECT(Stream_Stat
);
519 SET_EXPECT(Stream_Seek_END
);
520 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream2
);
521 CHECK_CALLED(Stream_Stat
);
522 CHECK_CALLED(Stream_Seek_END
);
523 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
524 ok(stream2
!= stream
, "unexpected stream\n");
526 SET_EXPECT(Stream_Seek
);
527 SET_EXPECT(Stream_Read
);
528 test_stream_read(stream2
, S_OK
, "01", 2);
529 CHECK_CALLED(Stream_Seek
);
530 CHECK_CALLED(Stream_Read
);
533 SET_EXPECT(Stream_Seek
);
534 SET_EXPECT(Stream_Read
);
535 test_stream_read(stream
, S_OK
, "345", 3);
536 CHECK_CALLED(Stream_Seek
);
537 CHECK_CALLED(Stream_Read
);
539 IStream_Release(stream
);
540 IStream_Release(stream2
);
541 IStream_Release(&test_stream
->IStream_iface
);
543 stream
= create_stream_from_string(" \t\r\n|}~YWJj ZGV|}~mZw== \t"); /* "abcdefg" in base64 obscured by invalid chars */
544 hr
= IMimeBody_SetData(body
, IET_BASE64
, "text", "plain", &IID_IStream
, stream
);
545 IStream_Release(stream
);
546 ok(hr
== S_OK
, "SetData failed: %08x\n", hr
);
548 test_current_encoding(body
, IET_BASE64
);
550 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
551 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
553 test_stream_read(stream
, S_OK
, "abc", 3);
554 test_stream_read(stream
, S_OK
, "defg", -1);
556 IStream_Release(stream
);
558 hr
= IMimeBody_GetData(body
, IET_BASE64
, &stream
);
559 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
561 test_stream_read(stream
, S_OK
, " \t\r", 3);
562 IStream_Release(stream
);
564 stream
= create_stream_from_string(" =3d=3D\"one\" \t=\r\ntw= o=\nx3\n=34\r\n5");
565 hr
= IMimeBody_SetData(body
, IET_QP
, "text", "plain", &IID_IStream
, stream
);
566 IStream_Release(stream
);
567 ok(hr
== S_OK
, "SetData failed: %08x\n", hr
);
569 test_current_encoding(body
, IET_QP
);
571 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
572 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
574 test_stream_read(stream
, S_OK
, " ==\"one\" \ttw=o=3\n4\r\n5", -1);
576 IStream_Release(stream
);
578 IMimeBody_Release(body
);
581 static void test_Allocator(void)
584 IMimeAllocator
*alloc
;
586 hr
= MimeOleGetAllocator(&alloc
);
587 ok(hr
== S_OK
, "ret %08x\n", hr
);
588 IMimeAllocator_Release(alloc
);
591 static void test_CreateMessage(void)
601 FINDBODY find_struct
;
605 char text
[] = "text";
608 static const char att_pritype
[] = "att:pri-content-type";
610 hr
= MimeOleCreateMessage(NULL
, &msg
);
611 ok(hr
== S_OK
, "ret %08x\n", hr
);
613 stream
= create_stream_from_string(msg1
);
615 hr
= IMimeMessage_Load(msg
, stream
);
616 ok(hr
== S_OK
, "ret %08x\n", hr
);
618 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
619 ok(hr
== S_OK
, "ret %08x\n", hr
);
620 ok(count
== 3, "got %d\n", count
);
622 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, FALSE
, &count
);
623 ok(hr
== S_OK
, "ret %08x\n", hr
);
624 ok(count
== 3, "got %d\n", count
);
626 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
627 ok(hr
== S_OK
, "ret %08x\n", hr
);
628 hr
= IMimeBody_GetOffsets(body
, &offsets
);
629 ok(hr
== S_OK
, "ret %08x\n", hr
);
630 ok(offsets
.cbBoundaryStart
== 0, "got %d\n", offsets
.cbBoundaryStart
);
631 ok(offsets
.cbHeaderStart
== 0, "got %d\n", offsets
.cbHeaderStart
);
632 ok(offsets
.cbBodyStart
== 359, "got %d\n", offsets
.cbBodyStart
);
633 ok(offsets
.cbBodyEnd
== 666, "got %d\n", offsets
.cbBodyEnd
);
634 IMimeBody_Release(body
);
636 hr
= IMimeMessage_GetBody(msg
, IBL_ROOT
, NULL
, &hbody
);
637 ok(hr
== S_OK
, "ret %08x\n", hr
);
639 hr
= IMimeBody_GetHandle(body
, NULL
);
640 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
642 hr
= IMimeBody_GetHandle(body
, &handle
);
643 ok(hr
== S_OK
, "ret %08x\n", hr
);
644 ok(handle
!= NULL
, "handle %p\n", handle
);
646 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, NULL
);
647 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
649 hbody2
= (HBODY
)0xdeadbeef;
650 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, &hbody2
);
651 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
652 ok(hbody2
== NULL
, "hbody2 %p\n", hbody2
);
654 PropVariantInit(&prop
);
655 hr
= IMimeMessage_GetBodyProp(msg
, hbody
, att_pritype
, 0, &prop
);
656 ok(hr
== S_OK
, "ret %08x\n", hr
);
657 ok(prop
.vt
== VT_LPSTR
, "vt %08x\n", prop
.vt
);
658 ok(!strcasecmp(prop
.u
.pszVal
, "multipart"), "got %s\n", prop
.u
.pszVal
);
659 PropVariantClear(&prop
);
661 hr
= IMimeMessage_GetBody(msg
, IBL_FIRST
, hbody
, &hbody
);
662 ok(hr
== S_OK
, "ret %08x\n", hr
);
663 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
664 ok(hr
== S_OK
, "ret %08x\n", hr
);
666 hr
= IMimeBody_GetHandle(body
, &handle
);
667 ok(hr
== S_OK
, "ret %08x\n", hr
);
668 ok(handle
== hbody
, "handle %p\n", handle
);
670 hr
= IMimeBody_GetOffsets(body
, &offsets
);
671 ok(hr
== S_OK
, "ret %08x\n", hr
);
672 ok(offsets
.cbBoundaryStart
== 405, "got %d\n", offsets
.cbBoundaryStart
);
673 ok(offsets
.cbHeaderStart
== 428, "got %d\n", offsets
.cbHeaderStart
);
674 ok(offsets
.cbBodyStart
== 518, "got %d\n", offsets
.cbBodyStart
);
675 ok(offsets
.cbBodyEnd
== 523, "got %d\n", offsets
.cbBodyEnd
);
677 hr
= IMimeBody_GetCharset(body
, &hcs
);
678 ok(hr
== S_OK
, "ret %08x\n", hr
);
681 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
684 IMimeBody_Release(body
);
686 hr
= IMimeMessage_GetBody(msg
, IBL_NEXT
, hbody
, &hbody
);
687 ok(hr
== S_OK
, "ret %08x\n", hr
);
688 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
689 ok(hr
== S_OK
, "ret %08x\n", hr
);
691 hr
= IMimeBody_GetHandle(body
, &handle
);
692 ok(hr
== S_OK
, "ret %08x\n", hr
);
693 ok(handle
== hbody
, "handle %p\n", handle
);
695 hr
= IMimeBody_GetOffsets(body
, &offsets
);
696 ok(hr
== S_OK
, "ret %08x\n", hr
);
697 ok(offsets
.cbBoundaryStart
== 525, "got %d\n", offsets
.cbBoundaryStart
);
698 ok(offsets
.cbHeaderStart
== 548, "got %d\n", offsets
.cbHeaderStart
);
699 ok(offsets
.cbBodyStart
== 629, "got %d\n", offsets
.cbBodyStart
);
700 ok(offsets
.cbBodyEnd
== 639, "got %d\n", offsets
.cbBodyEnd
);
701 IMimeBody_Release(body
);
703 find_struct
.pszPriType
= text
;
704 find_struct
.pszSubType
= NULL
;
706 hr
= IMimeMessage_FindFirst(msg
, &find_struct
, &hbody
);
707 ok(hr
== S_OK
, "ret %08x\n", hr
);
709 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
710 ok(hr
== S_OK
, "ret %08x\n", hr
);
712 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
713 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
715 hr
= IMimeMessage_GetAttachments(msg
, &count
, &body_list
);
716 ok(hr
== S_OK
, "ret %08x\n", hr
);
717 ok(count
== 2, "got %d\n", count
);
720 IMimeBody
*attachment
;
723 PropVariantInit(&prop
);
725 hr
= IMimeMessage_BindToObject(msg
, body_list
[0], &IID_IMimeBody
, (void**)&attachment
);
726 ok(hr
== S_OK
, "ret %08x\n", hr
);
728 hr
= IMimeBody_IsContentType(attachment
, "multipart", NULL
);
729 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
731 test_current_encoding(attachment
, IET_8BIT
);
734 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
735 ok(hr
== S_OK
, "ret %08x\n", hr
);
737 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
738 ok(!strcmp(prop
.u
.pszVal
, "8bit"), "got %s\n", prop
.u
.pszVal
);
739 PropVariantClear(&prop
);
741 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
742 todo_wine
ok(hr
== S_FALSE
, "ret %08x\n", hr
);
744 IMimeBody_Release(attachment
);
746 hr
= IMimeMessage_BindToObject(msg
, body_list
[1], &IID_IMimeBody
, (void**)&attachment
);
747 ok(hr
== S_OK
, "ret %08x\n", hr
);
749 hr
= IMimeBody_IsContentType(attachment
, "multipart", NULL
);
750 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
752 test_current_encoding(attachment
, IET_7BIT
);
755 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
756 ok(hr
== S_OK
, "ret %08x\n", hr
);
757 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
758 ok(!strcmp(prop
.u
.pszVal
, "7bit"), "got %s\n", prop
.u
.pszVal
);
759 PropVariantClear(&prop
);
761 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
762 ok(hr
== S_OK
, "ret %08x\n", hr
);
764 IMimeBody_Release(attachment
);
766 CoTaskMemFree(body_list
);
768 hr
= IMimeBody_GetCharset(body
, &hcs
);
769 ok(hr
== S_OK
, "ret %08x\n", hr
);
772 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
775 IMimeMessage_Release(msg
);
777 ref
= IStream_AddRef(stream
);
779 broken(ref
== 1), /* win95 */
781 IStream_Release(stream
);
783 IStream_Release(stream
);
786 static void test_mhtml_message(void)
788 IMimeMessage
*mime_message
;
789 IMimeBody
*mime_body
;
795 hres
= MimeOleCreateMessage(NULL
, &mime_message
);
796 ok(hres
== S_OK
, "MimeOleCreateMessage failed: %08x\n", hres
);
798 stream
= create_stream_from_string(mhtml_page1
);
799 hres
= IMimeMessage_Load(mime_message
, stream
);
800 IStream_Release(stream
);
801 ok(hres
== S_OK
, "Load failed: %08x\n", hres
);
803 hres
= IMimeMessage_CountBodies(mime_message
, HBODY_ROOT
, TRUE
, &count
);
804 ok(hres
== S_OK
, "CountBodies failed: %08x\n", hres
);
805 ok(count
== 3, "got %d\n", count
);
807 hres
= IMimeMessage_GetAttachments(mime_message
, &count
, &body_list
);
808 ok(hres
== S_OK
, "GetAttachments failed: %08x\n", hres
);
809 ok(count
== 2, "count = %u\n", count
);
811 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[0], &IID_IMimeBody
, (void**)&mime_body
);
812 ok(hres
== S_OK
, "BindToObject failed: %08x\n", hres
);
814 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
815 ok(hres
== S_OK
, "GetData failed: %08x\n", hres
);
816 test_stream_read(stream
, S_OK
, "<HTML></HTML>", -1);
817 IStream_Release(stream
);
819 test_current_encoding(mime_body
, IET_QP
);
821 IMimeBody_Release(mime_body
);
823 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[1], &IID_IMimeBody
, (void**)&mime_body
);
824 ok(hres
== S_OK
, "BindToObject failed: %08x\n", hres
);
826 test_current_encoding(mime_body
, IET_BASE64
);
828 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
829 ok(hres
== S_OK
, "GetData failed: %08x\n", hres
);
830 test_stream_read(stream
, S_OK
, "Test", -1);
831 IStream_Release(stream
);
833 IMimeBody_Release(mime_body
);
835 CoTaskMemFree(body_list
);
837 IMimeMessage_Release(mime_message
);
840 static void test_MessageSetProp(void)
842 static const char topic
[] = "wine topic";
843 static const WCHAR topicW
[] = {'w','i','n','e',' ','t','o','p','i','c',0};
849 hr
= MimeOleCreateMessage(NULL
, &msg
);
850 ok(hr
== S_OK
, "ret %08x\n", hr
);
852 PropVariantInit(&prop
);
854 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
855 ok(hr
== S_OK
, "ret %08x\n", hr
);
857 hr
= IMimeBody_SetProp(body
, NULL
, 0, &prop
);
858 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
860 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, NULL
);
861 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
864 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
865 strcpy(prop
.u
.pszVal
, topic
);
866 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
867 ok(hr
== S_OK
, "ret %08x\n", hr
);
868 PropVariantClear(&prop
);
870 hr
= IMimeBody_GetProp(body
, NULL
, 0, &prop
);
871 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
873 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, NULL
);
874 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
876 hr
= IMimeBody_GetProp(body
, "Wine-Topic", 0, &prop
);
877 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
880 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, &prop
);
881 ok(hr
== S_OK
, "ret %08x\n", hr
);
884 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
885 ok(!strcmp(prop
.u
.pszVal
, topic
), "got %s\n", prop
.u
.pszVal
);
886 PropVariantClear(&prop
);
890 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
891 strcpy(prop
.u
.pszVal
, topic
);
892 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
893 ok(hr
== S_OK
, "ret %08x\n", hr
);
894 PropVariantClear(&prop
);
897 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
898 ok(hr
== S_OK
, "ret %08x\n", hr
);
901 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
902 ok(!strcmp(prop
.u
.pszVal
, topic
), "got %s\n", prop
.u
.pszVal
);
903 PropVariantClear(&prop
);
906 /* Using the name or PID returns the same result. */
908 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
909 ok(hr
== S_OK
, "ret %08x\n", hr
);
912 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
913 ok(!strcmp(prop
.u
.pszVal
, topic
), "got %s\n", prop
.u
.pszVal
);
914 PropVariantClear(&prop
);
918 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
919 ok(hr
== S_OK
, "ret %08x\n", hr
);
922 ok(prop
.vt
== VT_LPWSTR
, "type %d\n", prop
.vt
);
923 ok(!lstrcmpW(prop
.u
.pwszVal
, topicW
), "got %s\n", wine_dbgstr_w(prop
.u
.pwszVal
));
924 PropVariantClear(&prop
);
928 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
929 strcpy(prop
.u
.pszVal
, topic
);
930 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_TO
), 0, &prop
);
931 ok(hr
== S_OK
, "ret %08x\n", hr
);
932 PropVariantClear(&prop
);
934 /* Out of Range PID */
936 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
937 strcpy(prop
.u
.pszVal
, topic
);
938 hr
= IMimeBody_SetProp(body
, PIDTOSTR(124), 0, &prop
);
939 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
940 PropVariantClear(&prop
);
942 IMimeBody_Release(body
);
943 IMimeMessage_Release(msg
);
946 static void test_MessageGetPropInfo(void)
948 static const char topic
[] = "wine topic";
949 static const char subject
[] = "wine testing";
956 hr
= MimeOleCreateMessage(NULL
, &msg
);
957 ok(hr
== S_OK
, "ret %08x\n", hr
);
959 PropVariantInit(&prop
);
961 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
962 ok(hr
== S_OK
, "ret %08x\n", hr
);
965 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
966 strcpy(prop
.u
.pszVal
, topic
);
967 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
968 ok(hr
== S_OK
, "ret %08x\n", hr
);
969 PropVariantClear(&prop
);
972 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(subject
)+1);
973 strcpy(prop
.u
.pszVal
, subject
);
974 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
975 ok(hr
== S_OK
, "ret %08x\n", hr
);
976 PropVariantClear(&prop
);
978 memset(&info
, 0, sizeof(info
));
979 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
980 hr
= IMimeBody_GetPropInfo(body
, NULL
, &info
);
981 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
983 memset(&info
, 0, sizeof(info
));
984 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
985 hr
= IMimeBody_GetPropInfo(body
, "Subject", NULL
);
986 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
988 memset(&info
, 0xfe, sizeof(info
));
989 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
990 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
991 ok(hr
== S_OK
, "ret %08x\n", hr
);
994 ok(info
.dwMask
& (PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
), "Invalid mask 0x%08x\n", info
.dwFlags
);
995 todo_wine
ok(info
.dwFlags
& 0x10000000, "Invalid flags 0x%08x\n", info
.dwFlags
);
996 ok(info
.ietEncoding
== 0, "Invalid encoding %d\n", info
.ietEncoding
);
997 ok(info
.dwPropId
== PID_HDR_SUBJECT
, "Invalid propid %d\n", info
.dwPropId
);
998 ok(info
.cValues
== 0xfefefefe, "Invalid cValues %d\n", info
.cValues
);
1001 memset(&info
, 0xfe, sizeof(info
));
1003 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
1004 ok(hr
== S_OK
, "ret %08x\n", hr
);
1007 ok(info
.dwMask
== 0, "Invalid mask 0x%08x\n", info
.dwFlags
);
1008 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08x\n", info
.dwFlags
);
1009 ok(info
.ietEncoding
== -16843010, "Invalid encoding %d\n", info
.ietEncoding
);
1010 ok(info
.dwPropId
== -16843010, "Invalid propid %d\n", info
.dwPropId
);
1013 memset(&info
, 0xfe, sizeof(info
));
1015 info
.dwPropId
= 1024;
1016 info
.ietEncoding
= 99;
1017 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
1018 ok(hr
== S_OK
, "ret %08x\n", hr
);
1021 ok(info
.dwMask
== 0, "Invalid mask 0x%08x\n", info
.dwFlags
);
1022 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08x\n", info
.dwFlags
);
1023 ok(info
.ietEncoding
== 99, "Invalid encoding %d\n", info
.ietEncoding
);
1024 ok(info
.dwPropId
== 1024, "Invalid propid %d\n", info
.dwPropId
);
1027 memset(&info
, 0, sizeof(info
));
1028 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
1029 hr
= IMimeBody_GetPropInfo(body
, "Invalid Property", &info
);
1030 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1032 IMimeBody_Release(body
);
1033 IMimeMessage_Release(msg
);
1036 static void test_MessageOptions(void)
1038 static const char string
[] = "XXXXX";
1039 static const char zero
[] = "0";
1044 hr
= MimeOleCreateMessage(NULL
, &msg
);
1045 ok(hr
== S_OK
, "ret %08x\n", hr
);
1047 PropVariantInit(&prop
);
1050 prop
.u
.boolVal
= TRUE
;
1051 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1052 ok(hr
== S_OK
, "ret %08x\n", hr
);
1053 PropVariantClear(&prop
);
1055 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1056 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1057 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1058 todo_wine
ok(prop
.u
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.u
.boolVal
);
1059 PropVariantClear(&prop
);
1062 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(string
)+1);
1063 strcpy(prop
.u
.pszVal
, string
);
1064 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1065 ok(hr
== S_OK
, "ret %08x\n", hr
);
1066 PropVariantClear(&prop
);
1068 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1069 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1070 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1071 todo_wine
ok(prop
.u
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.u
.boolVal
);
1072 PropVariantClear(&prop
);
1074 /* Invalid property type doesn't change the value */
1076 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(zero
)+1);
1077 strcpy(prop
.u
.pszVal
, zero
);
1078 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1079 ok(hr
== S_OK
, "ret %08x\n", hr
);
1080 PropVariantClear(&prop
);
1082 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1083 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1084 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1085 todo_wine
ok(prop
.u
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.u
.boolVal
);
1086 PropVariantClear(&prop
);
1090 prop
.u
.boolVal
= TRUE
;
1091 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1092 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08x\n", hr
);
1093 PropVariantClear(&prop
);
1095 /* Out of range before type. */
1098 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1099 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08x\n", hr
);
1100 PropVariantClear(&prop
);
1102 IMimeMessage_Release(msg
);
1105 static void test_BindToObject(void)
1112 hr
= MimeOleCreateMessage(NULL
, &msg
);
1113 ok(hr
== S_OK
, "ret %08x\n", hr
);
1115 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
1116 ok(hr
== S_OK
, "ret %08x\n", hr
);
1117 ok(count
== 1, "got %d\n", count
);
1119 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1120 ok(hr
== S_OK
, "ret %08x\n", hr
);
1121 IMimeBody_Release(body
);
1123 IMimeMessage_Release(msg
);
1126 static void test_BodyDeleteProp(void)
1128 static const char topic
[] = "wine topic";
1134 hr
= MimeOleCreateMessage(NULL
, &msg
);
1135 ok(hr
== S_OK
, "ret %08x\n", hr
);
1137 PropVariantInit(&prop
);
1139 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1140 ok(hr
== S_OK
, "ret %08x\n", hr
);
1142 hr
= IMimeBody_DeleteProp(body
, "Subject");
1143 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1145 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1146 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1149 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1150 strcpy(prop
.u
.pszVal
, topic
);
1151 hr
= IMimeBody_SetProp(body
, "Subject", 0, &prop
);
1152 ok(hr
== S_OK
, "ret %08x\n", hr
);
1153 PropVariantClear(&prop
);
1155 hr
= IMimeBody_DeleteProp(body
, "Subject");
1156 ok(hr
== S_OK
, "ret %08x\n", hr
);
1158 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
1159 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1162 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1163 strcpy(prop
.u
.pszVal
, topic
);
1164 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1165 ok(hr
== S_OK
, "ret %08x\n", hr
);
1166 PropVariantClear(&prop
);
1168 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1169 ok(hr
== S_OK
, "ret %08x\n", hr
);
1171 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1172 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1174 IMimeBody_Release(body
);
1175 IMimeMessage_Release(msg
);
1178 static void test_MimeOleGetPropertySchema(void)
1181 IMimePropertySchema
*schema
= NULL
;
1183 hr
= MimeOleGetPropertySchema(&schema
);
1184 ok(hr
== S_OK
, "ret %08x\n", hr
);
1186 IMimePropertySchema_Release(schema
);
1191 const char *content
;
1194 } mhtml_binding_test_t
;
1196 static const mhtml_binding_test_t binding_tests
[] = {
1204 "mhtml:file://%s!http://winehq.org/mhtmltest.html",
1211 static const mhtml_binding_test_t
*current_binding_test
;
1212 static IInternetProtocol
*current_binding_protocol
;
1214 static HRESULT WINAPI
BindInfo_QueryInterface(IInternetBindInfo
*iface
, REFIID riid
, void **ppv
)
1216 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetBindInfo
, riid
)) {
1222 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1223 return E_NOINTERFACE
;
1226 static ULONG WINAPI
BindInfo_AddRef(IInternetBindInfo
*iface
)
1231 static ULONG WINAPI
BindInfo_Release(IInternetBindInfo
*iface
)
1236 static HRESULT WINAPI
BindInfo_GetBindInfo(IInternetBindInfo
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
1238 CHECK_EXPECT(GetBindInfo
);
1240 ok(grfBINDF
!= NULL
, "grfBINDF == NULL\n");
1241 ok(pbindinfo
!= NULL
, "pbindinfo == NULL\n");
1242 ok(pbindinfo
->cbSize
== sizeof(BINDINFO
), "wrong size of pbindinfo: %d\n", pbindinfo
->cbSize
);
1244 *grfBINDF
= BINDF_ASYNCHRONOUS
| BINDF_ASYNCSTORAGE
| BINDF_PULLDATA
| BINDF_FROMURLMON
| BINDF_NEEDFILE
;
1248 static HRESULT WINAPI
BindInfo_GetBindString(IInternetBindInfo
*iface
, ULONG ulStringType
, LPOLESTR
*ppwzStr
,
1249 ULONG cEl
, ULONG
*pcElFetched
)
1251 ok(0, "unexpected call\n");
1255 static IInternetBindInfoVtbl InternetBindInfoVtbl
= {
1256 BindInfo_QueryInterface
,
1259 BindInfo_GetBindInfo
,
1260 BindInfo_GetBindString
1263 static IInternetBindInfo bind_info
= {
1264 &InternetBindInfoVtbl
1267 static HRESULT WINAPI
ServiceProvider_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
1269 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
1271 return E_NOINTERFACE
;
1274 static ULONG WINAPI
ServiceProvider_AddRef(IServiceProvider
*iface
)
1279 static ULONG WINAPI
ServiceProvider_Release(IServiceProvider
*iface
)
1284 static HRESULT WINAPI
ServiceProvider_QueryService(IServiceProvider
*iface
, REFGUID guidService
,
1285 REFIID riid
, void **ppv
)
1287 if(IsEqualGUID(&CLSID_MimeEdit
, guidService
)) {
1289 return E_NOINTERFACE
;
1292 ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService
));
1296 static const IServiceProviderVtbl ServiceProviderVtbl
= {
1297 ServiceProvider_QueryInterface
,
1298 ServiceProvider_AddRef
,
1299 ServiceProvider_Release
,
1300 ServiceProvider_QueryService
1303 static IServiceProvider service_provider
= { &ServiceProviderVtbl
};
1305 static HRESULT WINAPI
ProtocolSink_QueryInterface(IInternetProtocolSink
*iface
, REFIID riid
, void **ppv
)
1307 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetProtocolSink
, riid
)) {
1312 if(IsEqualGUID(&IID_IServiceProvider
, riid
)) {
1313 *ppv
= &service_provider
;
1318 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1319 return E_NOINTERFACE
;
1322 static ULONG WINAPI
ProtocolSink_AddRef(IInternetProtocolSink
*iface
)
1327 static ULONG WINAPI
ProtocolSink_Release(IInternetProtocolSink
*iface
)
1332 static HRESULT WINAPI
ProtocolSink_Switch(IInternetProtocolSink
*iface
, PROTOCOLDATA
*pProtocolData
)
1334 ok(0, "unexpected call\n");
1338 static HRESULT WINAPI
ProtocolSink_ReportProgress(IInternetProtocolSink
*iface
, ULONG ulStatusCode
,
1339 const WCHAR
*szStatusText
)
1341 switch(ulStatusCode
) {
1342 case BINDSTATUS_MIMETYPEAVAILABLE
:
1343 CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1344 ok(!strcmp_wa(szStatusText
, current_binding_test
->mime
), "status text %s\n", wine_dbgstr_w(szStatusText
));
1346 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
1347 CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1350 ok(0, "unexpected call %u %s\n", ulStatusCode
, wine_dbgstr_w(szStatusText
));
1356 static HRESULT WINAPI
ProtocolSink_ReportData(IInternetProtocolSink
*iface
, DWORD grfBSCF
, ULONG ulProgress
,
1357 ULONG ulProgressMax
)
1363 CHECK_EXPECT(ReportData
);
1365 ok(!ulProgress
, "ulProgress = %u\n", ulProgress
);
1366 ok(ulProgress
== ulProgressMax
, "ulProgress != ulProgressMax\n");
1367 ok(grfBSCF
== (BSCF_FIRSTDATANOTIFICATION
| BSCF_INTERMEDIATEDATANOTIFICATION
1368 | BSCF_LASTDATANOTIFICATION
| BSCF_DATAFULLYAVAILABLE
| BSCF_AVAILABLEDATASIZEUNKNOWN
),
1369 "grcf = %08x\n", grfBSCF
);
1371 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1372 ok(hres
== S_OK
, "Read failed: %08x\n", hres
);
1374 ok(!strcmp(buf
, current_binding_test
->data
), "unexpected data: %s\n", buf
);
1376 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1377 ok(hres
== S_FALSE
, "Read failed: %08x\n", hres
);
1381 static HRESULT WINAPI
ProtocolSink_ReportResult(IInternetProtocolSink
*iface
, HRESULT hrResult
, DWORD dwError
,
1384 CHECK_EXPECT(ReportResult
);
1385 ok(hrResult
== S_OK
, "hrResult = %08x\n", hrResult
);
1386 ok(!dwError
, "dwError = %u\n", dwError
);
1387 ok(!szResult
, "szResult = %s\n", wine_dbgstr_w(szResult
));
1391 static IInternetProtocolSinkVtbl InternetProtocolSinkVtbl
= {
1392 ProtocolSink_QueryInterface
,
1393 ProtocolSink_AddRef
,
1394 ProtocolSink_Release
,
1395 ProtocolSink_Switch
,
1396 ProtocolSink_ReportProgress
,
1397 ProtocolSink_ReportData
,
1398 ProtocolSink_ReportResult
1401 static IInternetProtocolSink protocol_sink
= { &InternetProtocolSinkVtbl
};
1403 static void test_mhtml_protocol_binding(const mhtml_binding_test_t
*test
)
1405 char file_name
[MAX_PATH
+32], *p
, urla
[INTERNET_MAX_URL_LENGTH
];
1406 WCHAR test_url
[INTERNET_MAX_URL_LENGTH
];
1407 IInternetProtocol
*protocol
;
1413 p
= file_name
+ GetCurrentDirectoryA(sizeof(file_name
), file_name
);
1415 strcpy(p
, "winetest.mht");
1417 file
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
1418 FILE_ATTRIBUTE_NORMAL
, NULL
);
1419 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFile failed\n");
1421 WriteFile(file
, test
->content
, strlen(test
->content
), &size
, NULL
);
1424 sprintf(urla
, test
->url
, file_name
);
1425 MultiByteToWideChar(CP_ACP
, 0, urla
, -1, test_url
, sizeof(test_url
)/sizeof(WCHAR
));
1427 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IInternetProtocol
, (void**)&protocol
);
1428 ok(hres
== S_OK
, "Could not create protocol handler: %08x\n", hres
);
1430 hres
= IInternetProtocol_QueryInterface(protocol
, &IID_IInternetProtocolEx
, (void**)&unk
);
1431 ok(hres
== E_NOINTERFACE
, "Could get IInternetProtocolEx\n");
1433 current_binding_test
= test
;
1434 current_binding_protocol
= protocol
;
1436 SET_EXPECT(GetBindInfo
);
1437 SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1438 SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1439 SET_EXPECT(ReportData
);
1440 SET_EXPECT(ReportResult
);
1441 hres
= IInternetProtocol_Start(protocol
, test_url
, &protocol_sink
, &bind_info
, 0, 0);
1442 ok(hres
== S_OK
, "Start failed: %08x\n", hres
);
1443 CHECK_CALLED(GetBindInfo
);
1444 CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE
);
1445 todo_wine
CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE
);
1446 CHECK_CALLED(ReportData
);
1447 CHECK_CALLED(ReportResult
);
1449 IInternetProtocol_Release(protocol
);
1450 ok(DeleteFileA("winetest.mht"), "DeleteFile failed: %u\n", GetLastError());
1453 static const struct {
1454 const char *base_url
;
1455 const char *relative_url
;
1456 const char *expected_result
;
1458 } combine_tests
[] = {
1460 "mhtml:file:///c:/dir/test.mht", "http://test.org",
1461 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org"
1463 "mhtml:file:///c:/dir/test.mht", "3D\"http://test.org\"",
1464 "mhtml:file:///c:/dir/test.mht!x-usc:3D\"http://test.org\""
1466 "mhtml:file:///c:/dir/test.mht", "123abc",
1467 "mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1469 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "123abc",
1470 "mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1472 "MhtMl:file:///c:/dir/test.mht!x-usc:http://test.org/dir/dir2/file.html", "../..",
1473 "mhtml:file:///c:/dir/test.mht!x-usc:../.."
1474 }, {"mhtml:file:///c:/dir/test.mht!x-usc:file:///c:/dir/dir2/file.html", "../..",
1475 "mhtml:file:///c:/dir/test.mht!x-usc:../.."
1477 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "",
1478 "mhtml:file:///c:/dir/test.mht"
1480 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "mhtml:file:///d:/file.html",
1481 "file:///d:/file.html", TRUE
1483 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org",
1484 "mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org", TRUE
1486 "mhtml:file:///c:/dir/test.mht!http://test.org", "123abc",
1487 "mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1489 "mhtml:file:///c:/dir/test.mht!http://test.org", "",
1490 "mhtml:file:///c:/dir/test.mht"
1494 static void test_mhtml_protocol_info(void)
1496 WCHAR
*base_url
, *relative_url
, combined_url
[INTERNET_MAX_URL_LENGTH
];
1497 IInternetProtocolInfo
*protocol_info
;
1502 static const WCHAR http_url
[] = {'h','t','t','p',':','/','/','t','e','s','t','.','o','r','g',0};
1504 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
,
1505 &IID_IInternetProtocolInfo
, (void**)&protocol_info
);
1506 ok(hres
== S_OK
, "Could not create protocol info: %08x\n", hres
);
1508 for(i
= 0; i
< sizeof(combine_tests
)/sizeof(*combine_tests
); i
++) {
1509 base_url
= a2w(combine_tests
[i
].base_url
);
1510 relative_url
= a2w(combine_tests
[i
].relative_url
);
1512 combined_len
= 0xdeadbeef;
1513 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, base_url
, relative_url
, ICU_BROWSER_MODE
,
1514 combined_url
, sizeof(combined_url
)/sizeof(WCHAR
), &combined_len
, 0);
1515 todo_wine_if(combine_tests
[i
].todo
)
1516 ok(hres
== S_OK
, "[%u] CombineUrl failed: %08x\n", i
, hres
);
1517 if(SUCCEEDED(hres
)) {
1518 exlen
= strlen(combine_tests
[i
].expected_result
);
1519 ok(combined_len
== exlen
, "[%u] combined len is %u, expected %u\n", i
, combined_len
, exlen
);
1520 ok(!strcmp_wa(combined_url
, combine_tests
[i
].expected_result
), "[%u] combined URL is %s, expected %s\n",
1521 i
, wine_dbgstr_w(combined_url
), combine_tests
[i
].expected_result
);
1523 combined_len
= 0xdeadbeef;
1524 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, base_url
, relative_url
, ICU_BROWSER_MODE
,
1525 combined_url
, exlen
, &combined_len
, 0);
1526 ok(hres
== E_FAIL
, "[%u] CombineUrl returned: %08x\n", i
, hres
);
1527 ok(!combined_len
, "[%u] combined_len = %u\n", i
, combined_len
);
1530 HeapFree(GetProcessHeap(), 0, base_url
);
1531 HeapFree(GetProcessHeap(), 0, relative_url
);
1534 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, http_url
, http_url
, ICU_BROWSER_MODE
,
1535 combined_url
, sizeof(combined_url
)/sizeof(WCHAR
), &combined_len
, 0);
1536 ok(hres
== E_FAIL
, "CombineUrl failed: %08x\n", hres
);
1538 IInternetProtocolInfo_Release(protocol_info
);
1541 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
1543 ok(0, "unexpected call\n");
1544 return E_NOINTERFACE
;
1547 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
1552 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
1557 static const IUnknownVtbl outer_vtbl
= {
1558 outer_QueryInterface
,
1563 static BOOL broken_mhtml_resolver
;
1565 static void test_mhtml_protocol(void)
1567 IUnknown outer
= { &outer_vtbl
};
1568 IClassFactory
*class_factory
;
1569 IUnknown
*unk
, *unk2
;
1573 /* test class factory */
1574 hres
= CoGetClassObject(&CLSID_IMimeHtmlProtocol
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IUnknown
, (void**)&unk
);
1575 ok(hres
== S_OK
, "CoGetClassObject failed: %08x\n", hres
);
1577 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocolInfo
, (void**)&unk2
);
1578 ok(hres
== E_NOINTERFACE
, "IInternetProtocolInfo supported\n");
1580 hres
= IUnknown_QueryInterface(unk
, &IID_IClassFactory
, (void**)&class_factory
);
1581 ok(hres
== S_OK
, "Could not get IClassFactory iface: %08x\n", hres
);
1582 IUnknown_Release(unk
);
1584 hres
= IClassFactory_CreateInstance(class_factory
, &outer
, &IID_IUnknown
, (void**)&unk
);
1585 ok(hres
== S_OK
, "CreateInstance returned: %08x\n", hres
);
1586 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocol
, (void**)&unk2
);
1587 ok(hres
== S_OK
, "Could not get IInternetProtocol iface: %08x\n", hres
);
1588 IUnknown_Release(unk2
);
1589 IUnknown_Release(unk
);
1591 hres
= IClassFactory_CreateInstance(class_factory
, (IUnknown
*)0xdeadbeef, &IID_IInternetProtocol
, (void**)&unk2
);
1592 ok(hres
== CLASS_E_NOAGGREGATION
, "CreateInstance returned: %08x\n", hres
);
1594 IClassFactory_Release(class_factory
);
1596 if(!broken_mhtml_resolver
)
1597 test_mhtml_protocol_info();
1599 for(i
= 0; i
< sizeof(binding_tests
)/sizeof(*binding_tests
); i
++)
1600 test_mhtml_protocol_binding(binding_tests
+ i
);
1603 static void test_MimeOleObjectFromMoniker(void)
1605 IMoniker
*mon
, *new_mon
;
1606 WCHAR
*mhtml_url
, *url
;
1612 static const struct {
1614 const char *mhtml_url
;
1616 {"file:///x:\\dir\\file.mht", "mhtml:file://x:\\dir\\file.mht"},
1617 {"file:///x:/dir/file.mht", "mhtml:file://x:\\dir\\file.mht"},
1618 {"http://www.winehq.org/index.html?query#hash", "mhtml:http://www.winehq.org/index.html?query#hash"},
1619 {"../test.mht", "mhtml:../test.mht"}
1622 for(i
= 0; i
< sizeof(tests
)/sizeof(*tests
); i
++) {
1623 url
= a2w(tests
[i
].url
);
1624 hres
= CreateURLMoniker(NULL
, url
, &mon
);
1625 ok(hres
== S_OK
, "CreateURLMoniker failed: %08x\n", hres
);
1626 HeapFree(GetProcessHeap(), 0, url
);
1628 hres
= CreateBindCtx(0, &bind_ctx
);
1629 ok(hres
== S_OK
, "CreateBindCtx failed: %08x\n", hres
);
1631 hres
= MimeOleObjectFromMoniker(0, mon
, bind_ctx
, &IID_IUnknown
, (void**)&unk
, &new_mon
);
1632 ok(hres
== S_OK
|| broken(!i
&& hres
== INET_E_RESOURCE_NOT_FOUND
), "MimeOleObjectFromMoniker failed: %08x\n", hres
);
1633 IBindCtx_Release(bind_ctx
);
1634 if(hres
== INET_E_RESOURCE_NOT_FOUND
) { /* winxp */
1635 win_skip("Broken MHTML behaviour found. Skipping some tests.\n");
1636 broken_mhtml_resolver
= TRUE
;
1640 hres
= IMoniker_GetDisplayName(new_mon
, NULL
, NULL
, &mhtml_url
);
1641 ok(hres
== S_OK
, "GetDisplayName failed: %08x\n", hres
);
1642 ok(!strcmp_wa(mhtml_url
, tests
[i
].mhtml_url
), "[%d] unexpected mhtml URL: %s\n", i
, wine_dbgstr_w(mhtml_url
));
1643 CoTaskMemFree(mhtml_url
);
1645 IUnknown_Release(unk
);
1646 IMoniker_Release(new_mon
);
1647 IMoniker_Release(mon
);
1653 OleInitialize(NULL
);
1654 test_CreateVirtualStream();
1655 test_CreateSecurity();
1659 test_CreateMessage();
1660 test_MessageSetProp();
1661 test_MessageGetPropInfo();
1662 test_MessageOptions();
1663 test_BindToObject();
1664 test_BodyDeleteProp();
1665 test_MimeOleGetPropertySchema();
1666 test_mhtml_message();
1667 test_MimeOleObjectFromMoniker();
1668 test_mhtml_protocol();