bindctx.c 29.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Copyright 2007 Jacek Caban for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>

#include "urlmon_main.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(urlmon);

26
static WCHAR bscb_holderW[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
27 28 29 30

extern IID IID_IBindStatusCallbackHolder;

typedef struct {
31
    IBindStatusCallbackEx IBindStatusCallbackEx_iface;
32
    IInternetBindInfo     IInternetBindInfo_iface;
33 34 35
    IServiceProvider      IServiceProvider_iface;
    IHttpNegotiate2       IHttpNegotiate2_iface;
    IAuthenticate         IAuthenticate_iface;
36 37 38 39 40 41 42

    LONG ref;

    IBindStatusCallback *callback;
    IServiceProvider *serv_prov;
} BindStatusCallback;

43 44 45 46 47 48 49
static void *get_callback_iface(BindStatusCallback *This, REFIID riid)
{
    void *ret;
    HRESULT hres;

    hres = IBindStatusCallback_QueryInterface(This->callback, riid, (void**)&ret);
    if(FAILED(hres) && This->serv_prov)
50
        hres = IServiceProvider_QueryService(This->serv_prov, riid, riid, &ret);
51

52
    return SUCCEEDED(hres) ? ret : NULL;
53 54
}

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
static IBindStatusCallback *bsch_from_bctx(IBindCtx *bctx)
{
    IBindStatusCallback *bsc;
    IUnknown *unk;
    HRESULT hres;

    hres = IBindCtx_GetObjectParam(bctx, bscb_holderW, &unk);
    if(FAILED(hres))
        return NULL;

    hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)&bsc);
    IUnknown_Release(unk);
    return SUCCEEDED(hres) ? bsc : NULL;
}

70
IBindStatusCallback *bsc_from_bctx(IBindCtx *bctx)
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
{
    BindStatusCallback *holder;
    IBindStatusCallback *bsc;
    HRESULT hres;

    bsc = bsch_from_bctx(bctx);
    if(!bsc)
        return NULL;

    hres = IBindStatusCallback_QueryInterface(bsc, &IID_IBindStatusCallbackHolder, (void**)&holder);
    if(FAILED(hres))
        return bsc;

    if(holder->callback) {
        IBindStatusCallback_Release(bsc);
        bsc = holder->callback;
87
        IBindStatusCallback_AddRef(bsc);
88 89 90 91 92 93
    }

    IBindStatusCallbackEx_Release(&holder->IBindStatusCallbackEx_iface);
    return bsc;
}

94 95 96 97
static inline BindStatusCallback *impl_from_IBindStatusCallbackEx(IBindStatusCallbackEx *iface)
{
    return CONTAINING_RECORD(iface, BindStatusCallback, IBindStatusCallbackEx_iface);
}
98

99
static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallbackEx *iface,
100 101
        REFIID riid, void **ppv)
{
102
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
103 104 105 106 107

    *ppv = NULL;

    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
108
        *ppv = &This->IBindStatusCallbackEx_iface;
109 110
    }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
        TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
111
        *ppv = &This->IBindStatusCallbackEx_iface;
112 113
    }else if(IsEqualGUID(&IID_IBindStatusCallbackEx, riid)) {
        TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
114
        *ppv = &This->IBindStatusCallbackEx_iface;
115 116 117 118 119
    }else if(IsEqualGUID(&IID_IBindStatusCallbackHolder, riid)) {
        TRACE("(%p)->(IID_IBindStatusCallbackHolder, %p)\n", This, ppv);
        *ppv = This;
    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
        TRACE("(%p)->(IID_IServiceProvider, %p)\n", This, ppv);
120
        *ppv = &This->IServiceProvider_iface;
121 122
    }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
        TRACE("(%p)->(IID_IHttpNegotiate, %p)\n", This, ppv);
123
        *ppv = &This->IHttpNegotiate2_iface;
124 125
    }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
        TRACE("(%p)->(IID_IHttpNegotiate2, %p)\n", This, ppv);
126
        *ppv = &This->IHttpNegotiate2_iface;
127 128
    }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
        TRACE("(%p)->(IID_IAuthenticate, %p)\n", This, ppv);
129
        *ppv = &This->IAuthenticate_iface;
130 131 132
    }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
        TRACE("(%p)->(IID_IInternetBindInfo, %p)\n", This, ppv);
        *ppv = &This->IInternetBindInfo_iface;
133 134 135
    }

    if(*ppv) {
136
        IUnknown_AddRef((IUnknown*)*ppv);
137 138 139 140 141 142 143
        return S_OK;
    }

    TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
    return E_NOINTERFACE;
}

144
static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallbackEx *iface)
145
{
146
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
147 148 149 150 151 152 153
    LONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) ref = %d\n", This, ref);

    return ref;
}

154
static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallbackEx *iface)
155
{
156
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
157 158 159 160 161 162 163 164
    LONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) ref = %d\n", This, ref);

    if(!ref) {
        if(This->serv_prov)
            IServiceProvider_Release(This->serv_prov);
        IBindStatusCallback_Release(This->callback);
165
        heap_free(This);
166 167 168 169 170
    }

    return ref;
}

171
static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallbackEx *iface,
172 173
        DWORD dwReserved, IBinding *pbind)
{
174
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
175 176 177 178 179 180

    TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);

    return IBindStatusCallback_OnStartBinding(This->callback, 0xff, pbind);
}

181
static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallbackEx *iface, LONG *pnPriority)
182
{
183
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
184 185 186 187 188 189

    TRACE("(%p)->(%p)\n", This, pnPriority);

    return IBindStatusCallback_GetPriority(This->callback, pnPriority);
}

190
static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallbackEx *iface, DWORD reserved)
191
{
192
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
193 194 195 196 197 198

    TRACE("(%p)->(%d)\n", This, reserved);

    return IBindStatusCallback_OnLowResource(This->callback, reserved);
}

199
static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallbackEx *iface, ULONG ulProgress,
200 201
        ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
{
202
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
203

204
    TRACE("%p)->(%u %u %s %s)\n", This, ulProgress, ulProgressMax, debugstr_bindstatus(ulStatusCode),
205 206 207 208 209 210
            debugstr_w(szStatusText));

    return IBindStatusCallback_OnProgress(This->callback, ulProgress,
            ulProgressMax, ulStatusCode, szStatusText);
}

211
static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallbackEx *iface,
212 213
        HRESULT hresult, LPCWSTR szError)
{
214
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
215 216 217 218 219 220

    TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));

    return IBindStatusCallback_OnStopBinding(This->callback, hresult, szError);
}

221
static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallbackEx *iface,
222 223
        DWORD *grfBINDF, BINDINFO *pbindinfo)
{
224
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
225 226
    IBindStatusCallbackEx *bscex;
    HRESULT hres;
227 228 229

    TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);

230 231 232 233 234 235 236 237 238 239 240
    hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IBindStatusCallbackEx, (void**)&bscex);
    if(SUCCEEDED(hres)) {
        DWORD bindf2 = 0, reserv = 0;

        hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, grfBINDF, pbindinfo, &bindf2, &reserv);
        IBindStatusCallbackEx_Release(bscex);
    }else {
        hres = IBindStatusCallback_GetBindInfo(This->callback, grfBINDF, pbindinfo);
    }

    return hres;
241 242
}

243
static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallbackEx *iface,
244 245
        DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
{
246
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
247 248 249 250 251 252

    TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);

    return IBindStatusCallback_OnDataAvailable(This->callback, grfBSCF, dwSize, pformatetc, pstgmed);
}

253
static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallbackEx *iface,
254 255
        REFIID riid, IUnknown *punk)
{
256
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
257 258 259 260 261 262

    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);

    return IBindStatusCallback_OnObjectAvailable(This->callback, riid, punk);
}

263 264 265
static HRESULT WINAPI BindStatusCallback_GetBindInfoEx(IBindStatusCallbackEx *iface, DWORD *grfBINDF,
        BINDINFO *pbindinfo, DWORD *grfBINDF2, DWORD *pdwReserved)
{
266
    BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
    IBindStatusCallbackEx *bscex;
    HRESULT hres;

    TRACE("(%p)->(%p %p %p %p)\n", This, grfBINDF, pbindinfo, grfBINDF2, pdwReserved);

    hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IBindStatusCallbackEx, (void**)&bscex);
    if(SUCCEEDED(hres)) {
        hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, grfBINDF, pbindinfo, grfBINDF2, pdwReserved);
        IBindStatusCallbackEx_Release(bscex);
    }else {
        hres = IBindStatusCallback_GetBindInfo(This->callback, grfBINDF, pbindinfo);
    }

    return hres;
}

static const IBindStatusCallbackExVtbl BindStatusCallbackExVtbl = {
284 285 286 287 288 289 290 291 292 293
    BindStatusCallback_QueryInterface,
    BindStatusCallback_AddRef,
    BindStatusCallback_Release,
    BindStatusCallback_OnStartBinding,
    BindStatusCallback_GetPriority,
    BindStatusCallback_OnLowResource,
    BindStatusCallback_OnProgress,
    BindStatusCallback_OnStopBinding,
    BindStatusCallback_GetBindInfo,
    BindStatusCallback_OnDataAvailable,
294 295
    BindStatusCallback_OnObjectAvailable,
    BindStatusCallback_GetBindInfoEx
296 297
};

298 299 300 301
static inline BindStatusCallback *impl_from_IServiceProvider(IServiceProvider *iface)
{
    return CONTAINING_RECORD(iface, BindStatusCallback, IServiceProvider_iface);
}
302 303 304 305

static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
        REFIID riid, void **ppv)
{
306
    BindStatusCallback *This = impl_from_IServiceProvider(iface);
307
    return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
308 309 310 311
}

static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
{
312
    BindStatusCallback *This = impl_from_IServiceProvider(iface);
313
    return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
314 315 316 317
}

static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
{
318
    BindStatusCallback *This = impl_from_IServiceProvider(iface);
319
    return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
320 321 322 323 324
}

static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
        REFGUID guidService, REFIID riid, void **ppv)
{
325
    BindStatusCallback *This = impl_from_IServiceProvider(iface);
326 327 328 329
    HRESULT hres;

    if(IsEqualGUID(&IID_IHttpNegotiate, guidService)) {
        TRACE("(%p)->(IID_IHttpNegotiate %s %p)\n", This, debugstr_guid(riid), ppv);
330
        return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
331 332 333 334
    }

    if(IsEqualGUID(&IID_IHttpNegotiate2, guidService)) {
        TRACE("(%p)->(IID_IHttpNegotiate2 %s %p)\n", This, debugstr_guid(riid), ppv);
335
        return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
336 337 338 339
    }

    if(IsEqualGUID(&IID_IAuthenticate, guidService)) {
        TRACE("(%p)->(IID_IAuthenticate %s %p)\n", This, debugstr_guid(riid), ppv);
340
        return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
    }

    TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);

    hres = IBindStatusCallback_QueryInterface(This->callback, riid, ppv);
    if(SUCCEEDED(hres))
        return S_OK;

    if(This->serv_prov) {
        hres = IServiceProvider_QueryService(This->serv_prov, guidService, riid, ppv);
        if(SUCCEEDED(hres))
            return S_OK;
    }

    return E_NOINTERFACE;
}

static const IServiceProviderVtbl BSCServiceProviderVtbl = {
    BSCServiceProvider_QueryInterface,
    BSCServiceProvider_AddRef,
    BSCServiceProvider_Release,
    BSCServiceProvider_QueryService
};

365 366 367 368
static inline BindStatusCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface)
{
    return CONTAINING_RECORD(iface, BindStatusCallback, IHttpNegotiate2_iface);
}
369 370 371 372

static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
        REFIID riid, void **ppv)
{
373
    BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
374
    return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
375 376 377 378
}

static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate2 *iface)
{
379
    BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
380
    return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
381 382 383 384
}

static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate2 *iface)
{
385
    BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
386
    return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
387 388 389 390 391
}

static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
        LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
{
392
    BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
393 394
    IHttpNegotiate *http_negotiate;
    HRESULT hres = S_OK;
395 396 397 398 399 400

    TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
          pszAdditionalHeaders);

    *pszAdditionalHeaders = NULL;

401 402 403 404 405 406
    http_negotiate = get_callback_iface(This, &IID_IHttpNegotiate);
    if(http_negotiate) {
        hres = IHttpNegotiate_BeginningTransaction(http_negotiate, szURL, szHeaders,
                dwReserved, pszAdditionalHeaders);
        IHttpNegotiate_Release(http_negotiate);
    }
407

408
    return hres;
409 410 411 412 413 414
}

static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
        LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
        LPWSTR *pszAdditionalRequestHeaders)
{
415
    BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
416
    LPWSTR additional_headers = NULL;
417
    IHttpNegotiate *http_negotiate;
418 419 420 421 422
    HRESULT hres = S_OK;

    TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
          debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);

423 424 425 426 427 428
    http_negotiate = get_callback_iface(This, &IID_IHttpNegotiate);
    if(http_negotiate) {
        hres = IHttpNegotiate_OnResponse(http_negotiate, dwResponseCode, szResponseHeaders,
                szRequestHeaders, &additional_headers);
        IHttpNegotiate_Release(http_negotiate);
    }
429 430 431 432 433 434 435 436 437 438 439 440

    if(pszAdditionalRequestHeaders)
        *pszAdditionalRequestHeaders = additional_headers;
    else if(additional_headers)
        CoTaskMemFree(additional_headers);

    return hres;
}

static HRESULT WINAPI BSCHttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
        BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
{
441
    BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
442 443
    IHttpNegotiate2 *http_negotiate2;
    HRESULT hres = E_FAIL;
444 445 446

    TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);

447 448 449 450 451 452
    http_negotiate2 = get_callback_iface(This, &IID_IHttpNegotiate2);
    if(http_negotiate2) {
        hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, pbSecurityId,
                pcbSecurityId, dwReserved);
        IHttpNegotiate2_Release(http_negotiate2);
    }
453

454
    return hres;
455 456 457 458 459 460 461 462 463 464 465
}

static const IHttpNegotiate2Vtbl BSCHttpNegotiateVtbl = {
    BSCHttpNegotiate_QueryInterface,
    BSCHttpNegotiate_AddRef,
    BSCHttpNegotiate_Release,
    BSCHttpNegotiate_BeginningTransaction,
    BSCHttpNegotiate_OnResponse,
    BSCHttpNegotiate_GetRootSecurityId
};

466 467 468 469
static inline BindStatusCallback *impl_from_IAuthenticate(IAuthenticate *iface)
{
    return CONTAINING_RECORD(iface, BindStatusCallback, IAuthenticate_iface);
}
470 471 472

static HRESULT WINAPI BSCAuthenticate_QueryInterface(IAuthenticate *iface, REFIID riid, void **ppv)
{
473
    BindStatusCallback *This = impl_from_IAuthenticate(iface);
474
    return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
475 476 477 478
}

static ULONG WINAPI BSCAuthenticate_AddRef(IAuthenticate *iface)
{
479
    BindStatusCallback *This = impl_from_IAuthenticate(iface);
480
    return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
481 482 483 484
}

static ULONG WINAPI BSCAuthenticate_Release(IAuthenticate *iface)
{
485
    BindStatusCallback *This = impl_from_IAuthenticate(iface);
486
    return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
487 488 489 490 491
}

static HRESULT WINAPI BSCAuthenticate_Authenticate(IAuthenticate *iface,
        HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword)
{
492
    BindStatusCallback *This = impl_from_IAuthenticate(iface);
493 494 495 496 497 498 499 500 501 502 503
    FIXME("(%p)->(%p %p %p)\n", This, phwnd, pszUsername, pszPassword);
    return E_NOTIMPL;
}

static const IAuthenticateVtbl BSCAuthenticateVtbl = {
    BSCAuthenticate_QueryInterface,
    BSCAuthenticate_AddRef,
    BSCAuthenticate_Release,
    BSCAuthenticate_Authenticate
};

504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
static inline BindStatusCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
{
    return CONTAINING_RECORD(iface, BindStatusCallback, IInternetBindInfo_iface);
}

static HRESULT WINAPI BSCInternetBindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
{
    BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
    return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
}

static ULONG WINAPI BSCInternetBindInfo_AddRef(IInternetBindInfo *iface)
{
    BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
    return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
}

static ULONG WINAPI BSCInternetBindInfo_Release(IInternetBindInfo *iface)
{
    BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
    return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
}

static HRESULT WINAPI BSCInternetBindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *bindf, BINDINFO *bindinfo)
{
    BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
    FIXME("(%p)->(%p %p)\n", This, bindf, bindinfo);
    return E_NOTIMPL;
}

static HRESULT WINAPI BSCInternetBindInfo_GetBindString(IInternetBindInfo *iface, ULONG string_type,
        WCHAR **strs, ULONG cnt, ULONG *fetched)
{
    BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
    IInternetBindInfo *bind_info;
    HRESULT hres;

    TRACE("(%p)->(%d %p %d %p)\n", This, string_type, strs, cnt, fetched);

    hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo, (void**)&bind_info);
    if(FAILED(hres))
        return hres;

    hres = IInternetBindInfo_GetBindString(bind_info, string_type, strs, cnt, fetched);

    IInternetBindInfo_Release(bind_info);
    return hres;
}

static IInternetBindInfoVtbl BSCInternetBindInfoVtbl = {
    BSCInternetBindInfo_QueryInterface,
    BSCInternetBindInfo_AddRef,
    BSCInternetBindInfo_Release,
    BSCInternetBindInfo_GetBindInfo,
    BSCInternetBindInfo_GetBindString
};

561
static void set_callback(BindStatusCallback *This, IBindStatusCallback *bsc)
562
{
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
    IServiceProvider *serv_prov;
    HRESULT hres;

    if(This->callback)
        IBindStatusCallback_Release(This->callback);
    if(This->serv_prov)
        IServiceProvider_Release(This->serv_prov);

    IBindStatusCallback_AddRef(bsc);
    This->callback = bsc;

    hres = IBindStatusCallback_QueryInterface(bsc, &IID_IServiceProvider, (void**)&serv_prov);
    This->serv_prov = hres == S_OK ? serv_prov : NULL;
}

578
HRESULT wrap_callback(IBindStatusCallback *bsc, IBindStatusCallback **ret_iface)
579 580 581 582 583 584
{
    BindStatusCallback *ret;

    ret = heap_alloc_zero(sizeof(BindStatusCallback));
    if(!ret)
        return E_OUTOFMEMORY;
585

586
    ret->IBindStatusCallbackEx_iface.lpVtbl = &BindStatusCallbackExVtbl;
587
    ret->IInternetBindInfo_iface.lpVtbl = &BSCInternetBindInfoVtbl;
588 589 590
    ret->IServiceProvider_iface.lpVtbl = &BSCServiceProviderVtbl;
    ret->IHttpNegotiate2_iface.lpVtbl = &BSCHttpNegotiateVtbl;
    ret->IAuthenticate_iface.lpVtbl = &BSCAuthenticateVtbl;
591 592

    ret->ref = 1;
593
    set_callback(ret, bsc);
594

595
    *ret_iface = (IBindStatusCallback*)&ret->IBindStatusCallbackEx_iface;
596
    return S_OK;
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
}

/***********************************************************************
 *           RegisterBindStatusCallback (urlmon.@)
 *
 * Register a bind status callback.
 *
 * PARAMS
 *  pbc           [I] Binding context
 *  pbsc          [I] Callback to register
 *  ppbscPrevious [O] Destination for previous callback
 *  dwReserved    [I] Reserved, must be 0.
 *
 * RETURNS
 *    Success: S_OK.
 *    Failure: E_INVALIDARG, if any argument is invalid, or
 *             E_OUTOFMEMORY if memory allocation fails.
 */
HRESULT WINAPI RegisterBindStatusCallback(IBindCtx *pbc, IBindStatusCallback *pbsc,
        IBindStatusCallback **ppbscPrevious, DWORD dwReserved)
{
    BindStatusCallback *holder;
    IBindStatusCallback *bsc, *prev = NULL;
    HRESULT hres;

    TRACE("(%p %p %p %x)\n", pbc, pbsc, ppbscPrevious, dwReserved);

    if (!pbc || !pbsc)
        return E_INVALIDARG;

627 628 629
    bsc = bsch_from_bctx(pbc);
    if(bsc) {
        hres = IBindStatusCallback_QueryInterface(bsc, &IID_IBindStatusCallbackHolder, (void**)&holder);
630
        if(SUCCEEDED(hres)) {
631 632 633
            if(ppbscPrevious) {
                IBindStatusCallback_AddRef(holder->callback);
                *ppbscPrevious = holder->callback;
634
            }
635 636 637 638 639 640 641 642

            set_callback(holder, pbsc);

            IBindStatusCallback_Release(bsc);
            IBindStatusCallbackEx_Release(&holder->IBindStatusCallbackEx_iface);
            return S_OK;
        }else {
            prev = bsc;
643 644
        }

645
        IBindCtx_RevokeObjectParam(pbc, bscb_holderW);
646 647
    }

648 649
    hres = wrap_callback(pbsc, &bsc);
    if(SUCCEEDED(hres)) {
650
        hres = IBindCtx_RegisterObjectParam(pbc, bscb_holderW, (IUnknown*)bsc);
651 652
        IBindStatusCallback_Release(bsc);
    }
653
    if(FAILED(hres)) {
654 655
        if(prev)
            IBindStatusCallback_Release(prev);
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
        return hres;
    }

    if(ppbscPrevious)
        *ppbscPrevious = prev;
    return S_OK;
}

/***********************************************************************
 *           RevokeBindStatusCallback (URLMON.@)
 *
 * Unregister a bind status callback.
 *
 *  pbc           [I] Binding context
 *  pbsc          [I] Callback to unregister
 *
 * RETURNS
 *    Success: S_OK.
 *    Failure: E_INVALIDARG, if any argument is invalid
 */
HRESULT WINAPI RevokeBindStatusCallback(IBindCtx *pbc, IBindStatusCallback *pbsc)
{
    IBindStatusCallback *callback;

    TRACE("(%p %p)\n", pbc, pbsc);

    if (!pbc || !pbsc)
        return E_INVALIDARG;

685 686
    callback = bsc_from_bctx(pbc);
    if(!callback)
687 688
        return S_OK;

689 690
    if(callback == pbsc)
        IBindCtx_RevokeObjectParam(pbc, bscb_holderW);
691 692 693 694 695

    IBindStatusCallback_Release(callback);
    return S_OK;
}

696
typedef struct {
697
    IBindCtx IBindCtx_iface;
698 699 700 701 702 703

    LONG ref;

    IBindCtx *bindctx;
} AsyncBindCtx;

704 705 706 707
static inline AsyncBindCtx *impl_from_IBindCtx(IBindCtx *iface)
{
    return CONTAINING_RECORD(iface, AsyncBindCtx, IBindCtx_iface);
}
708 709 710

static HRESULT WINAPI AsyncBindCtx_QueryInterface(IBindCtx *iface, REFIID riid, void **ppv)
{
711
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
712 713 714 715 716

    *ppv = NULL;

    if(IsEqualGUID(riid, &IID_IUnknown)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
717
        *ppv = &This->IBindCtx_iface;
718 719
    }else if(IsEqualGUID(riid, &IID_IBindCtx)) {
        TRACE("(%p)->(IID_IBindCtx %p)\n", This, ppv);
720
        *ppv = &This->IBindCtx_iface;
721 722
    }else if(IsEqualGUID(riid, &IID_IAsyncBindCtx)) {
        TRACE("(%p)->(IID_IAsyncBindCtx %p)\n", This, ppv);
723
        *ppv = &This->IBindCtx_iface;
724 725 726 727 728 729 730 731 732 733 734 735 736
    }

    if(*ppv) {
        IUnknown_AddRef((IUnknown*)*ppv);
        return S_OK;
    }

    FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
    return E_NOINTERFACE;
}

static ULONG WINAPI AsyncBindCtx_AddRef(IBindCtx *iface)
{
737
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
738 739 740 741 742 743 744 745 746
    LONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    return ref;
}

static ULONG WINAPI AsyncBindCtx_Release(IBindCtx *iface)
{
747
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
748 749 750 751 752 753
    LONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    if(!ref) {
        IBindCtx_Release(This->bindctx);
754
        heap_free(This);
755 756 757 758 759 760 761
    }

    return ref;
}

static HRESULT WINAPI AsyncBindCtx_RegisterObjectBound(IBindCtx *iface, IUnknown *punk)
{
762
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
763 764 765 766 767 768 769 770

    TRACE("(%p)->(%p)\n", This, punk);

    return IBindCtx_RegisterObjectBound(This->bindctx, punk);
}

static HRESULT WINAPI AsyncBindCtx_RevokeObjectBound(IBindCtx *iface, IUnknown *punk)
{
771
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
772 773 774 775 776 777 778 779

    TRACE("(%p %p)\n", This, punk);

    return IBindCtx_RevokeObjectBound(This->bindctx, punk);
}

static HRESULT WINAPI AsyncBindCtx_ReleaseBoundObjects(IBindCtx *iface)
{
780
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
781 782 783 784 785 786 787 788

    TRACE("(%p)\n", This);

    return IBindCtx_ReleaseBoundObjects(This->bindctx);
}

static HRESULT WINAPI AsyncBindCtx_SetBindOptions(IBindCtx *iface, BIND_OPTS *pbindopts)
{
789
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
790 791 792 793 794 795 796 797

    TRACE("(%p)->(%p)\n", This, pbindopts);

    return IBindCtx_SetBindOptions(This->bindctx, pbindopts);
}

static HRESULT WINAPI AsyncBindCtx_GetBindOptions(IBindCtx *iface, BIND_OPTS *pbindopts)
{
798
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
799 800 801 802 803 804 805 806

    TRACE("(%p)->(%p)\n", This, pbindopts);

    return IBindCtx_GetBindOptions(This->bindctx, pbindopts);
}

static HRESULT WINAPI AsyncBindCtx_GetRunningObjectTable(IBindCtx *iface, IRunningObjectTable **pprot)
{
807
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
808 809 810 811 812 813 814 815

    TRACE("(%p)->(%p)\n", This, pprot);

    return IBindCtx_GetRunningObjectTable(This->bindctx, pprot);
}

static HRESULT WINAPI AsyncBindCtx_RegisterObjectParam(IBindCtx *iface, LPOLESTR pszkey, IUnknown *punk)
{
816
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
817 818 819 820 821 822 823 824

    TRACE("(%p)->(%s %p)\n", This, debugstr_w(pszkey), punk);

    return IBindCtx_RegisterObjectParam(This->bindctx, pszkey, punk);
}

static HRESULT WINAPI AsyncBindCtx_GetObjectParam(IBindCtx* iface, LPOLESTR pszkey, IUnknown **punk)
{
825
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
826 827 828 829 830 831

    TRACE("(%p)->(%s %p)\n", This, debugstr_w(pszkey), punk);

    return IBindCtx_GetObjectParam(This->bindctx, pszkey, punk);
}

832
static HRESULT WINAPI AsyncBindCtx_RevokeObjectParam(IBindCtx *iface, LPOLESTR pszkey)
833
{
834
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
835

836
    TRACE("(%p)->(%s)\n", This, debugstr_w(pszkey));
837

838
    return IBindCtx_RevokeObjectParam(This->bindctx, pszkey);
839 840 841 842
}

static HRESULT WINAPI AsyncBindCtx_EnumObjectParam(IBindCtx *iface, IEnumString **pszkey)
{
843
    AsyncBindCtx *This = impl_from_IBindCtx(iface);
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944

    TRACE("(%p)->(%p)\n", This, pszkey);

    return IBindCtx_EnumObjectParam(This->bindctx, pszkey);
}

static const IBindCtxVtbl AsyncBindCtxVtbl =
{
    AsyncBindCtx_QueryInterface,
    AsyncBindCtx_AddRef,
    AsyncBindCtx_Release,
    AsyncBindCtx_RegisterObjectBound,
    AsyncBindCtx_RevokeObjectBound,
    AsyncBindCtx_ReleaseBoundObjects,
    AsyncBindCtx_SetBindOptions,
    AsyncBindCtx_GetBindOptions,
    AsyncBindCtx_GetRunningObjectTable,
    AsyncBindCtx_RegisterObjectParam,
    AsyncBindCtx_GetObjectParam,
    AsyncBindCtx_EnumObjectParam,
    AsyncBindCtx_RevokeObjectParam
};

static HRESULT init_bindctx(IBindCtx *bindctx, DWORD options,
       IBindStatusCallback *callback, IEnumFORMATETC *format)
{
    BIND_OPTS bindopts;
    HRESULT hres;

    if(options)
        FIXME("not supported options %08x\n", options);
    if(format)
        FIXME("format is not supported\n");

    bindopts.cbStruct = sizeof(BIND_OPTS);
    bindopts.grfFlags = BIND_MAYBOTHERUSER;
    bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
    bindopts.dwTickCountDeadline = 0;

    hres = IBindCtx_SetBindOptions(bindctx, &bindopts);
    if(FAILED(hres))
       return hres;

    if(callback) {
        hres = RegisterBindStatusCallback(bindctx, callback, NULL, 0);
        if(FAILED(hres))
            return hres;
    }

    return S_OK;
}

/***********************************************************************
 *           CreateAsyncBindCtx (urlmon.@)
 */
HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback,
        IEnumFORMATETC *format, IBindCtx **pbind)
{
    IBindCtx *bindctx;
    HRESULT hres;

    TRACE("(%08x %p %p %p)\n", reserved, callback, format, pbind);

    if(!pbind || !callback)
        return E_INVALIDARG;

    hres = CreateBindCtx(0, &bindctx);
    if(FAILED(hres))
        return hres;

    hres = init_bindctx(bindctx, 0, callback, format);
    if(FAILED(hres)) {
        IBindCtx_Release(bindctx);
        return hres;
    }

    *pbind = bindctx;
    return S_OK;
}

/***********************************************************************
 *           CreateAsyncBindCtxEx (urlmon.@)
 *
 * Create an asynchronous bind context.
 */
HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options,
        IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx** pbind,
        DWORD reserved)
{
    AsyncBindCtx *ret;
    IBindCtx *bindctx;
    HRESULT hres;

    TRACE("(%p %08x %p %p %p %d)\n", ibind, options, callback, format, pbind, reserved);

    if(!pbind)
        return E_INVALIDARG;

    if(reserved)
        WARN("reserved=%d\n", reserved);

945 946 947 948 949 950 951 952
    if(ibind) {
        IBindCtx_AddRef(ibind);
        bindctx = ibind;
    }else {
        hres = CreateBindCtx(0, &bindctx);
        if(FAILED(hres))
            return hres;
    }
953

954
    ret = heap_alloc(sizeof(AsyncBindCtx));
955

956
    ret->IBindCtx_iface.lpVtbl = &AsyncBindCtxVtbl;
957 958 959
    ret->ref = 1;
    ret->bindctx = bindctx;

960
    hres = init_bindctx(&ret->IBindCtx_iface, options, callback, format);
961
    if(FAILED(hres)) {
962
        IBindCtx_Release(&ret->IBindCtx_iface);
963 964 965
        return hres;
    }

966
    *pbind = &ret->IBindCtx_iface;
967 968
    return S_OK;
}