umon.c 41.9 KB
Newer Older
1 2 3
/*
 * UrlMon
 *
Jon Griffiths's avatar
Jon Griffiths committed
4
 * Copyright 1999 Ulrich Czekalla for Corel Corporation
5
 * Copyright 2002 Huw D M Davies for CodeWeavers
6
 * Copyright 2005 Jacek Caban for CodeWeavers
7
 *
8 9 10 11 12 13 14 15 16 17 18 19
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22
 */

23 24
#include <stdio.h>

Jacek Caban's avatar
Jacek Caban committed
25
#include "urlmon_main.h"
26

27
#include "winreg.h"
28
#include "winternl.h"
29
#include "wininet.h"
30
#include "shlwapi.h"
Jacek Caban's avatar
Jacek Caban committed
31 32

#include "wine/debug.h"
33

34
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
35 36

/* native urlmon.dll uses this key, too */
37
static WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
38

39 40
/*static BOOL registered_wndclass = FALSE;*/

41
typedef struct {
42
    const IBindingVtbl *lpVtbl;
43

44
    LONG ref;
45

46
    LPWSTR URLName;
47 48 49 50

    HWND hwndCallback;
    IBindCtx *pBC;
    HINTERNET hinternet, hconnect, hrequest;
51 52 53 54
    HANDLE hCacheFile;
    IUMCacheStream *pstrCache;
    IBindStatusCallback *pbscb;
    DWORD total_read, expected_size;
55
} Binding;
56

57
static HRESULT WINAPI Binding_QueryInterface(IBinding* iface, REFIID riid, void **ppvObject)
58
{
59
    Binding *This = (Binding*)iface;
60

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

63
    if((This == NULL) || (ppvObject == NULL))
64 65
	return E_INVALIDARG;

66
    if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IBinding, riid)) {
67
        *ppvObject = iface;
68 69 70
        IBinding_AddRef(iface);
        return S_OK;
    }
71

72 73 74
    *ppvObject = NULL;
    return E_NOINTERFACE;
}
75

76 77 78 79
static ULONG WINAPI Binding_AddRef(IBinding* iface)
{
    Binding *This = (Binding*)iface;
    ULONG ref = InterlockedIncrement(&This->ref);
80

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

    return ref;
84 85
}

86
static ULONG WINAPI Binding_Release(IBinding* iface)
87
{
88 89 90
    Binding *This = (Binding*)iface;
    ULONG ref = InterlockedDecrement(&This->ref);

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

    if(!ref) {
94
        heap_free(This->URLName);
95 96 97 98 99 100 101 102 103
        if (This->hCacheFile)
            CloseHandle(This->hCacheFile);
        if (This->pstrCache)
        {
            UMCloseCacheFileStream(This->pstrCache);
            IStream_Release((IStream *)This->pstrCache);
        }
        if (This->pbscb)
            IBindStatusCallback_Release(This->pbscb);
104

105
        heap_free(This);
106

107 108
        URLMON_UnlockModule();
    }
109

110
    return ref;
111 112
}

113
static HRESULT WINAPI Binding_Abort(IBinding* iface)
114
{
115
    Binding *This = (Binding*)iface;
116

117
    FIXME("(%p): stub\n", This);
118

119 120
    return E_NOTIMPL;
}
121

122 123 124
static HRESULT WINAPI Binding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved)
{
    Binding *This = (Binding*)iface;
125

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);

    return E_NOTIMPL;
}

static HRESULT WINAPI Binding_GetPriority(IBinding* iface, LONG* pnPriority)
{
    Binding *This = (Binding*)iface;

    FIXME("(%p)->(%p): stub\n", This, pnPriority);

    return E_NOTIMPL;
}

static HRESULT WINAPI Binding_Resume(IBinding* iface)
{
    Binding *This = (Binding*)iface;

    FIXME("(%p): stub\n", This);

    return E_NOTIMPL;
147 148
}

149 150 151 152
static HRESULT WINAPI Binding_SetPriority(IBinding* iface, LONG nPriority)
{
    Binding *This = (Binding*)iface;

153
    FIXME("(%p)->(%d): stub\n", This, nPriority);
154 155 156 157 158 159 160 161 162 163 164 165 166 167

    return E_NOTIMPL;
}

static HRESULT WINAPI Binding_Suspend(IBinding* iface)
{
    Binding *This = (Binding*)iface;

    FIXME("(%p): stub\n", This);

    return E_NOTIMPL;
}

static void Binding_CloseCacheDownload(Binding *This)
168 169 170 171 172 173 174 175
{
    CloseHandle(This->hCacheFile);
    This->hCacheFile = 0;
    UMCloseCacheFileStream(This->pstrCache);
    IStream_Release((IStream *)This->pstrCache);
    This->pstrCache = 0;
}

176
static HRESULT Binding_MoreCacheData(Binding *This, const char *buf, DWORD dwBytes)
177 178 179 180 181 182 183 184 185 186 187 188 189 190
{
    DWORD written;

    if (WriteFile(This->hCacheFile, buf, dwBytes, &written, NULL) && written == dwBytes)
    {
	HRESULT hr;

	This->total_read += written;
        hr = IBindStatusCallback_OnProgress(This->pbscb,
					    This->total_read + written,
					    This->expected_size,
					    (This->total_read == written) ?
					        BINDSTATUS_BEGINDOWNLOADDATA :
					        BINDSTATUS_DOWNLOADINGDATA,
191
					    This->URLName);
192
	if (hr == S_OK)
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
	{
	    STGMEDIUM stg;
	    FORMATETC fmt;

            fmt.cfFormat = 0;
            fmt.ptd = NULL;
            fmt.dwAspect = 0;
            fmt.lindex = -1;
            fmt.tymed = TYMED_ISTREAM;

	    stg.tymed = TYMED_ISTREAM;
	    stg.u.pstm = (IStream *)This->pstrCache;
	    stg.pUnkForRelease = NULL;

            hr = IBindStatusCallback_OnDataAvailable(This->pbscb,
			    			     (This->total_read == written) ?
							 BSCF_FIRSTDATANOTIFICATION :
						         BSCF_INTERMEDIATEDATANOTIFICATION,
						     This->total_read + written,
                                                     &fmt,
						     &stg);
	}
	if (written < dwBytes)
	    return STG_E_MEDIUMFULL;
	else
	    return hr;
    }
    return HRESULT_FROM_WIN32(GetLastError());
}

223
static void Binding_FinishedDownload(Binding *This, HRESULT hr)
224 225 226 227 228 229 230 231 232 233 234 235 236
{
    STGMEDIUM stg;
    FORMATETC fmt;

    fmt.ptd = NULL;
    fmt.dwAspect = 0;
    fmt.lindex = -1;
    fmt.tymed = TYMED_ISTREAM;

    stg.tymed = TYMED_ISTREAM;
    stg.u.pstm = (IStream *)This->pstrCache;
    stg.pUnkForRelease = NULL;

237 238
    IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size,
                                   BINDSTATUS_ENDDOWNLOADDATA, This->URLName);
239
    IBindStatusCallback_OnDataAvailable(This->pbscb, BSCF_LASTDATANOTIFICATION, This->total_read, &fmt, &stg);
240
    if (hr != S_OK)
241 242 243 244 245 246 247 248 249 250
    {
	WCHAR *pwchError = 0;

        FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
	                 FORMAT_MESSAGE_ALLOCATE_BUFFER,
                        NULL, (DWORD) hr,
		        0, (LPWSTR) &pwchError,
		        0, NULL);
	if (!pwchError)
	{
251
	    static const WCHAR achFormat[] = { '%', '0', '8', 'x', 0 };
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266

	    pwchError =(WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * 9);
	    wsprintfW(pwchError, achFormat, hr);
	}
        IBindStatusCallback_OnStopBinding(This->pbscb, hr, pwchError);
	LocalFree(pwchError);
    }
    else
    {
        IBindStatusCallback_OnStopBinding(This->pbscb, hr, NULL);
    }
    IBindStatusCallback_Release(This->pbscb);
    This->pbscb = 0;
}

267
static const IBindingVtbl BindingVtbl =
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
{
    Binding_QueryInterface,
    Binding_AddRef,
    Binding_Release,
    Binding_Abort,
    Binding_Suspend,
    Binding_Resume,
    Binding_SetPriority,
    Binding_GetPriority,
    Binding_GetBindResult
};

/* filemoniker data structure */
typedef struct {

283
    const IMonikerVtbl* lpvtbl;  /* VTable relative to the IMoniker interface.*/
284

285
    LONG ref; /* reference counter for this object */
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331

    LPOLESTR URLName; /* URL string identified by this URLmoniker */
} URLMonikerImpl;

/*******************************************************************************
 *        URLMoniker_QueryInterface
 *******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
{
    URLMonikerImpl *This = (URLMonikerImpl *)iface;

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

    /* Perform a sanity check on the parameters.*/
    if ( (This==0) || (ppvObject==0) )
	return E_INVALIDARG;

    /* Initialize the return parameter */
    *ppvObject = 0;

    /* Compare the riid with the interface IDs implemented by this object.*/
    if (IsEqualIID(&IID_IUnknown, riid)      ||
        IsEqualIID(&IID_IPersist, riid)      ||
        IsEqualIID(&IID_IPersistStream,riid) ||
        IsEqualIID(&IID_IMoniker, riid)
       )
        *ppvObject = iface;

    /* Check that we obtained an interface.*/
    if ((*ppvObject)==0)
        return E_NOINTERFACE;

    /* Query Interface always increases the reference count by one when it is successful */
    IMoniker_AddRef(iface);

    return S_OK;
}

/******************************************************************************
 *        URLMoniker_AddRef
 ******************************************************************************/
static ULONG WINAPI URLMonikerImpl_AddRef(IMoniker* iface)
{
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
    ULONG refCount = InterlockedIncrement(&This->ref);

Jacek Caban's avatar
Jacek Caban committed
332
    TRACE("(%p) ref=%u\n",This, refCount);
333 334 335 336 337 338 339 340 341 342 343 344

    return refCount;
}

/******************************************************************************
 *        URLMoniker_Release
 ******************************************************************************/
static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface)
{
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
    ULONG refCount = InterlockedDecrement(&This->ref);

Jacek Caban's avatar
Jacek Caban committed
345
    TRACE("(%p) ref=%u\n",This, refCount);
346 347 348

    /* destroy the object if there's no more reference on it */
    if (!refCount) {
349 350
        heap_free(This->URLName);
        heap_free(This);
351

Jacek Caban's avatar
Jacek Caban committed
352 353
        URLMON_UnlockModule();
    }
354 355 356 357 358

    return refCount;
}


359 360 361 362 363 364
/******************************************************************************
 *        URLMoniker_GetClassID
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_GetClassID(IMoniker* iface,
						CLSID *pClassID)/* Pointer to CLSID of object */
{
365
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
366

367
    TRACE("(%p,%p)\n",This,pClassID);
368 369 370

    if (pClassID==NULL)
        return E_POINTER;
371 372 373
    /* Windows always returns CLSID_StdURLMoniker */
    *pClassID = CLSID_StdURLMoniker;
    return S_OK;
374 375 376 377 378 379 380
}

/******************************************************************************
 *        URLMoniker_IsDirty
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_IsDirty(IMoniker* iface)
{
381
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
382 383 384 385 386 387 388 389 390 391 392
    /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
       method in the OLE-provided moniker interfaces always return S_FALSE because
       their internal state never changes. */

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

    return S_FALSE;
}

/******************************************************************************
 *        URLMoniker_Load
393 394 395 396
 *
 * NOTE
 *  Writes a ULONG containing length of unicode string, followed
 *  by that many unicode characters
397 398 399
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_Load(IMoniker* iface,IStream* pStm)
{
400
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
401 402
    
    HRESULT res;
403
    ULONG size;
404 405 406 407 408 409
    ULONG got;
    TRACE("(%p,%p)\n",This,pStm);

    if(!pStm)
        return E_INVALIDARG;

410
    res = IStream_Read(pStm, &size, sizeof(ULONG), &got);
411 412
    if(SUCCEEDED(res)) {
        if(got == sizeof(ULONG)) {
413 414
            heap_free(This->URLName);
            This->URLName = heap_alloc(size);
415 416 417
            if(!This->URLName)
                res = E_OUTOFMEMORY;
            else {
418 419
                res = IStream_Read(pStm, This->URLName, size, NULL);
                This->URLName[size/sizeof(WCHAR) - 1] = 0;
420 421 422 423 424 425
            }
        }
        else
            res = E_FAIL;
    }
    return res;
426 427 428 429 430 431 432 433 434
}

/******************************************************************************
 *        URLMoniker_Save
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_Save(IMoniker* iface,
					  IStream* pStm,/* pointer to the stream where the object is to be saved */
					  BOOL fClearDirty)/* Specifies whether to clear the dirty flag */
{
435
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
436

437
    HRESULT res;
438
    ULONG size;
439
    TRACE("(%p,%p,%d)\n",This,pStm,fClearDirty);
440

441 442 443
    if(!pStm)
        return E_INVALIDARG;

444 445
    size = (strlenW(This->URLName) + 1)*sizeof(WCHAR);
    res=IStream_Write(pStm,&size,sizeof(ULONG),NULL);
446
    if(SUCCEEDED(res))
447
        res=IStream_Write(pStm,This->URLName,size,NULL);
448
    return res;
449 450 451 452 453 454 455 456 457

}

/******************************************************************************
 *        URLMoniker_GetSizeMax
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_GetSizeMax(IMoniker* iface,
						ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */
{
458
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
459

460
    TRACE("(%p,%p)\n",This,pcbSize);
461

462 463 464
    if(!pcbSize)
        return E_INVALIDARG;

465
    pcbSize->QuadPart = sizeof(ULONG) + ((strlenW(This->URLName)+1) * sizeof(WCHAR));
466
    return S_OK;
467 468 469 470 471 472 473 474 475
}

/******************************************************************************
 *                  URLMoniker_BindToObject
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_BindToObject(IMoniker* iface,
						  IBindCtx* pbc,
						  IMoniker* pmkToLeft,
						  REFIID riid,
476
						  VOID** ppv)
477
{
478
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
479 480
    IRunningObjectTable *obj_tbl;
    HRESULT hres;
481

482
    TRACE("(%p)->(%p,%p,%s,%p): stub\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
483

484 485 486 487 488
    hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
    if(SUCCEEDED(hres)) {
        FIXME("use running object table\n");
        IRunningObjectTable_Release(obj_tbl);
    }
489

490
    return bind_to_object(iface, This->URLName, pbc, riid, ppv);
491 492 493 494 495
}

/******************************************************************************
 *        URLMoniker_BindToStorage
 ******************************************************************************/
496
static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, IBindCtx* pbc, VOID** ppvObject)
497 498 499 500
{
    HRESULT hres;
    BINDINFO bi;
    DWORD bindf;
501
    WCHAR szFileName[MAX_PATH + 1];
502 503
    Binding *bind;
    int len;
504

505
    WARN("(%s %p %p)\n", debugstr_w(URLName), pbc, ppvObject);
506

507
    bind = heap_alloc_zero(sizeof(Binding));
508 509 510 511
    bind->lpVtbl = &BindingVtbl;
    bind->ref = 1;
    URLMON_LockModule();

512
    len = lstrlenW(URLName)+1;
513
    bind->URLName = heap_alloc(len*sizeof(WCHAR));
514
    memcpy(bind->URLName, URLName, len*sizeof(WCHAR));
515 516

    hres = UMCreateStreamOnCacheFile(bind->URLName, 0, szFileName, &bind->hCacheFile, &bind->pstrCache);
517 518

    if(SUCCEEDED(hres)) {
519
        TRACE("Created stream...\n");
520

521 522
        *ppvObject = (void *) bind->pstrCache;
        IStream_AddRef((IStream *) bind->pstrCache);
523

524
        hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, (IUnknown**)&bind->pbscb);
525 526 527 528 529 530
        if(SUCCEEDED(hres)) {
            TRACE("Got IBindStatusCallback...\n");

            memset(&bi, 0, sizeof(bi));
            bi.cbSize = sizeof(bi);
            bindf = 0;
531
            hres = IBindStatusCallback_GetBindInfo(bind->pbscb, &bindf, &bi);
532 533
            if(SUCCEEDED(hres)) {
                URL_COMPONENTSW url;
534
                WCHAR *host, *path, *user, *pass;
535
                DWORD lensz = sizeof(bind->expected_size);
536 537
                DWORD dwService = 0;
                BOOL bSuccess;
538

539
                TRACE("got bindinfo. bindf = %08x extrainfo = %s bindinfof = %08x bindverb = %08x iid %s\n",
540
                      bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid));
541
                hres = IBindStatusCallback_OnStartBinding(bind->pbscb, 0, (IBinding*)bind);
542
                TRACE("OnStartBinding rets %08x\n", hres);
543

544 545
                bind->expected_size = 0;
                bind->total_read = 0;
546

547 548
                memset(&url, 0, sizeof(url));
                url.dwStructSize = sizeof(url);
549
                url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = url.dwPasswordLength = 1;
550
                InternetCrackUrlW(URLName, 0, ICU_ESCAPE, &url);
551
                host = heap_alloc((url.dwHostNameLength + 1) * sizeof(WCHAR));
552 553
                memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
                host[url.dwHostNameLength] = '\0';
554
                path = heap_alloc((url.dwUrlPathLength + 1) * sizeof(WCHAR));
555 556
                memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
                path[url.dwUrlPathLength] = '\0';
557 558
                if (url.dwUserNameLength)
                {
559
                    user = heap_alloc(((url.dwUserNameLength + 1) * sizeof(WCHAR)));
560 561 562 563 564 565 566 567 568
                    memcpy(user, url.lpszUserName, url.dwUserNameLength * sizeof(WCHAR));
                    user[url.dwUserNameLength] = 0;
                }
                else
                {
                    user = 0;
                }
                if (url.dwPasswordLength)
                {
569
                    pass = heap_alloc(((url.dwPasswordLength + 1) * sizeof(WCHAR)));
570 571 572 573 574 575 576
                    memcpy(pass, url.lpszPassword, url.dwPasswordLength * sizeof(WCHAR));
                    pass[url.dwPasswordLength] = 0;
                }
                else
                {
                    pass = 0;
                }
577

578

579 580
                do {
                    bind->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0);
581
                    if (!bind->hinternet)
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
                    {
                            hres = HRESULT_FROM_WIN32(GetLastError());
                            break;
                    }

                    switch ((DWORD) url.nScheme)
                    {
                    case INTERNET_SCHEME_FTP:
                        if (!url.nPort)
                            url.nPort = INTERNET_DEFAULT_FTP_PORT;
                        dwService = INTERNET_SERVICE_FTP;
                        break;
    
                    case INTERNET_SCHEME_GOPHER:
                        if (!url.nPort)
                            url.nPort = INTERNET_DEFAULT_GOPHER_PORT;
                        dwService = INTERNET_SERVICE_GOPHER;
                        break;

                    case INTERNET_SCHEME_HTTPS:
                        if (!url.nPort)
                            url.nPort = INTERNET_DEFAULT_HTTPS_PORT;
                        dwService = INTERNET_SERVICE_HTTP;
                        break;
                    }

608 609 610
                    bind->hconnect = InternetConnectW(bind->hinternet, host, url.nPort, user, pass,
                                                      dwService, 0, (DWORD)bind);
                    if (!bind->hconnect)
611 612
                    {
                            hres = HRESULT_FROM_WIN32(GetLastError());
613
                            CloseHandle(bind->hinternet);
614 615 616
                            break;
                    }

617 618 619 620
                    hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, 0x22, NULL);
                    hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL);
                    hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL);
                    hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);
621 622 623 624 625 626

                    bSuccess = FALSE;

                    switch (dwService)
                    {
                    case INTERNET_SERVICE_GOPHER:
627
                        bind->hrequest = GopherOpenFileW(bind->hconnect,
628 629 630 631
                                                         path,
                                                         0,
                                                         INTERNET_FLAG_RELOAD,
                                                         0);
632
                        if (bind->hrequest)
633 634 635 636 637 638
                                bSuccess = TRUE;
                        else
                                hres = HRESULT_FROM_WIN32(GetLastError());
                        break;

                    case INTERNET_SERVICE_FTP:
639
                        bind->hrequest = FtpOpenFileW(bind->hconnect,
640 641 642 643 644 645
                                                      path,
                                                      GENERIC_READ,
                                                      FTP_TRANSFER_TYPE_BINARY |
                                                       INTERNET_FLAG_TRANSFER_BINARY |
                                                       INTERNET_FLAG_RELOAD,
                                                      0);
646
                        if (bind->hrequest)
647 648 649 650 651 652
                                bSuccess = TRUE;
                        else
                                hres = HRESULT_FROM_WIN32(GetLastError());
                        break;

                    case INTERNET_SERVICE_HTTP:
653 654
                        bind->hrequest = HttpOpenRequestW(bind->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)bind);
                        if (!bind->hrequest)
655 656 657
                        {
                                hres = HRESULT_FROM_WIN32(GetLastError());
                        }
658
                        else if (!HttpSendRequestW(bind->hrequest, NULL, 0, NULL, 0))
659 660
                        {
                                hres = HRESULT_FROM_WIN32(GetLastError());
661
                                InternetCloseHandle(bind->hrequest);
662 663 664
                        }
                        else
                        {
665
                                HttpQueryInfoW(bind->hrequest,
666
                                               HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
667
                                               &bind->expected_size,
668 669 670 671 672 673 674 675
                                               &lensz,
                                               NULL);
                                bSuccess = TRUE;
                        }
                        break;
                    }
                    if(bSuccess)
                    {
676
                        TRACE("res = %d gle = %u url len = %d\n", hres, GetLastError(), bind->expected_size);
677

678
                        IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName);
679 680 681 682

                        while(1) {
                            char buf[4096];
                            DWORD bufread;
683
                            if(InternetReadFile(bind->hrequest, buf, sizeof(buf), &bufread)) {
684
                                TRACE("read %d bytes %s...\n", bufread, debugstr_an(buf, 10));
685
                                if(bufread == 0) break;
686
                                hres = Binding_MoreCacheData(bind, buf, bufread);
687 688 689
                            } else
                                break;
                        }
690
                        InternetCloseHandle(bind->hrequest);
691 692 693
                            hres = S_OK;
                    }
            
694 695
                    InternetCloseHandle(bind->hconnect);
                    InternetCloseHandle(bind->hinternet);
696
                } while(0);
697

698
                Binding_FinishedDownload(bind, hres);
699
                Binding_CloseCacheDownload(bind);
700

701 702 703 704
                heap_free(user);
                heap_free(pass);
                heap_free(path);
                heap_free(host);
705 706
            }
        }
707
    }
708 709 710

    IBinding_Release((IBinding*)bind);

711 712 713
    return hres;
}

714 715 716 717 718 719 720 721 722 723 724 725 726
static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface,
                                                   IBindCtx* pbc,
						   IMoniker* pmkToLeft,
						   REFIID riid,
						   VOID** ppvObject)
{
    URLMonikerImpl *This = (URLMonikerImpl*)iface;
    WCHAR schema[64];
    BOOL bret;

    URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW), schema,
        sizeof(schema)/sizeof(WCHAR), 0, NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0};

727
    if(pmkToLeft)
728
        FIXME("Unsupported pmkToLeft\n");
729

730 731
    bret = InternetCrackUrlW(This->URLName, 0, ICU_ESCAPE, &url);
    if(!bret) {
732
        ERR("InternetCrackUrl failed: %u\n", GetLastError());
733 734 735
        return E_FAIL;
    }

736 737 738 739 740
    if(IsEqualGUID(&IID_IStream, riid) &&
       (  url.nScheme == INTERNET_SCHEME_HTTPS
       || url.nScheme == INTERNET_SCHEME_FTP
       || url.nScheme == INTERNET_SCHEME_GOPHER))
        return URLMonikerImpl_BindToStorage_hack(This->URLName, pbc, ppvObject);
741

742
    TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
743

744
    return bind_to_storage(This->URLName, pbc, riid, ppvObject);
745 746
}

747 748 749 750 751 752 753 754 755
/******************************************************************************
 *        URLMoniker_Reduce
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_Reduce(IMoniker* iface,
					    IBindCtx* pbc,
					    DWORD dwReduceHowFar,
					    IMoniker** ppmkToLeft,
					    IMoniker** ppmkReduced)
{
756
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
757
    
758
    TRACE("(%p,%p,%d,%p,%p)\n",This,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
759

760 761 762 763 764 765
    if(!ppmkReduced)
        return E_INVALIDARG;

    URLMonikerImpl_AddRef(iface);
    *ppmkReduced = iface;
    return MK_S_REDUCED_TO_SELF;
766 767 768 769 770 771 772 773 774 775
}

/******************************************************************************
 *        URLMoniker_ComposeWith
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_ComposeWith(IMoniker* iface,
						 IMoniker* pmkRight,
						 BOOL fOnlyIfNotGeneric,
						 IMoniker** ppmkComposite)
{
776
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
777 778 779 780 781 782 783 784 785 786
    FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);

    return E_NOTIMPL;
}

/******************************************************************************
 *        URLMoniker_Enum
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
{
787
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
788
    TRACE("(%p,%d,%p)\n",This,fForward,ppenumMoniker);
789

790 791 792 793 794 795
    if(!ppenumMoniker)
        return E_INVALIDARG;

    /* Does not support sub-monikers */
    *ppenumMoniker = NULL;
    return S_OK;
796 797 798 799 800 801 802
}

/******************************************************************************
 *        URLMoniker_IsEqual
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
{
803
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
Kevin Koltzau's avatar
Kevin Koltzau committed
804 805 806 807
    CLSID clsid;
    LPOLESTR urlPath;
    IBindCtx* bind;
    HRESULT res;
808

Kevin Koltzau's avatar
Kevin Koltzau committed
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
    TRACE("(%p,%p)\n",This,pmkOtherMoniker);

    if(pmkOtherMoniker==NULL)
        return E_INVALIDARG;

    IMoniker_GetClassID(pmkOtherMoniker,&clsid);

    if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker))
        return S_FALSE;

    res = CreateBindCtx(0,&bind);
    if(FAILED(res))
        return res;

    res = S_FALSE;
    if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) {
        int result = lstrcmpiW(urlPath, This->URLName);
        CoTaskMemFree(urlPath);
        if(result == 0)
            res = S_OK;
    }
    IUnknown_Release(bind);
    return res;
832 833 834 835 836 837 838 839
}


/******************************************************************************
 *        URLMoniker_Hash
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
{
840
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
841 842 843 844
    
    int  h = 0,i,skip,len;
    int  off = 0;
    LPOLESTR val;
845

846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
    TRACE("(%p,%p)\n",This,pdwHash);

    if(!pdwHash)
        return E_INVALIDARG;

    val = This->URLName;
    len = lstrlenW(val);

    if(len < 16) {
        for(i = len ; i > 0; i--) {
            h = (h * 37) + val[off++];
        }
    }
    else {
        /* only sample some characters */
        skip = len / 8;
        for(i = len; i > 0; i -= skip, off += skip) {
            h = (h * 39) + val[off];
        }
    }
    *pdwHash = h;
    return S_OK;
868 869 870 871 872 873 874 875 876 877
}

/******************************************************************************
 *        URLMoniker_IsRunning
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_IsRunning(IMoniker* iface,
					       IBindCtx* pbc,
					       IMoniker* pmkToLeft,
					       IMoniker* pmkNewlyRunning)
{
878
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
879 880 881 882 883 884 885 886 887 888 889 890 891
    FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);

    return E_NOTIMPL;
}

/******************************************************************************
 *        URLMoniker_GetTimeOfLastChange
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
							 IBindCtx* pbc,
							 IMoniker* pmkToLeft,
							 FILETIME* pFileTime)
{
892
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
893 894 895 896 897 898 899 900 901 902
    FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pFileTime);

    return E_NOTIMPL;
}

/******************************************************************************
 *        URLMoniker_Inverse
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
{
903
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
904
    TRACE("(%p,%p)\n",This,ppmk);
905

906
    return MK_E_NOINVERSE;
907 908 909 910 911 912 913
}

/******************************************************************************
 *        URLMoniker_CommonPrefixWith
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
{
914
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
915 916 917 918 919 920 921 922 923 924
    FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);

    return E_NOTIMPL;
}

/******************************************************************************
 *        URLMoniker_RelativePathTo
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
{
925
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
926 927 928 929 930 931 932 933 934 935 936 937 938
    FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);

    return E_NOTIMPL;
}

/******************************************************************************
 *        URLMoniker_GetDisplayName
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_GetDisplayName(IMoniker* iface,
						    IBindCtx* pbc,
						    IMoniker* pmkToLeft,
						    LPOLESTR *ppszDisplayName)
{
939
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
    
    int len;
    
    TRACE("(%p,%p,%p,%p)\n",This,pbc,pmkToLeft,ppszDisplayName);
    
    if(!ppszDisplayName)
        return E_INVALIDARG;
    
    /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
        then look at pmkToLeft to try and complete the URL
    */
    len = lstrlenW(This->URLName)+1;
    *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
    if(!*ppszDisplayName)
        return E_OUTOFMEMORY;
    lstrcpyW(*ppszDisplayName, This->URLName);
    return S_OK;
957 958 959 960 961 962 963 964 965 966 967 968
}

/******************************************************************************
 *        URLMoniker_ParseDisplayName
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_ParseDisplayName(IMoniker* iface,
						      IBindCtx* pbc,
						      IMoniker* pmkToLeft,
						      LPOLESTR pszDisplayName,
						      ULONG* pchEaten,
						      IMoniker** ppmkOut)
{
969
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
970 971 972 973 974 975 976 977 978 979
    FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);

    return E_NOTIMPL;
}

/******************************************************************************
 *        URLMoniker_IsSystemMoniker
 ******************************************************************************/
static HRESULT WINAPI URLMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
{
980
    URLMonikerImpl *This = (URLMonikerImpl *)iface;
981
    TRACE("(%p,%p)\n",This,pwdMksys);
982

983 984 985 986 987
    if(!pwdMksys)
        return E_INVALIDARG;

    *pwdMksys = MKSYS_URLMONIKER;
    return S_OK;
988 989
}

990 991 992
/********************************************************************************/
/* Virtual function table for the URLMonikerImpl class which  include IPersist,*/
/* IPersistStream and IMoniker functions.                                       */
993
static const IMonikerVtbl VT_URLMonikerImpl =
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
{
    URLMonikerImpl_QueryInterface,
    URLMonikerImpl_AddRef,
    URLMonikerImpl_Release,
    URLMonikerImpl_GetClassID,
    URLMonikerImpl_IsDirty,
    URLMonikerImpl_Load,
    URLMonikerImpl_Save,
    URLMonikerImpl_GetSizeMax,
    URLMonikerImpl_BindToObject,
    URLMonikerImpl_BindToStorage,
    URLMonikerImpl_Reduce,
    URLMonikerImpl_ComposeWith,
    URLMonikerImpl_Enum,
    URLMonikerImpl_IsEqual,
    URLMonikerImpl_Hash,
    URLMonikerImpl_IsRunning,
    URLMonikerImpl_GetTimeOfLastChange,
    URLMonikerImpl_Inverse,
    URLMonikerImpl_CommonPrefixWith,
    URLMonikerImpl_RelativePathTo,
    URLMonikerImpl_GetDisplayName,
    URLMonikerImpl_ParseDisplayName,
    URLMonikerImpl_IsSystemMoniker
};

/******************************************************************************
 *         URLMoniker_Construct (local function)
 *******************************************************************************/
static HRESULT URLMonikerImpl_Construct(URLMonikerImpl* This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName)
{
    HRESULT hres;
1026
    DWORD sizeStr = 0;
1027 1028 1029

    TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName));

1030 1031
    This->lpvtbl = &VT_URLMonikerImpl;
    This->ref = 0;
1032

1033
    This->URLName = heap_alloc(INTERNET_MAX_URL_LENGTH*sizeof(WCHAR));
1034

1035
    if(lpszLeftURLName)
1036
        hres = CoInternetCombineUrl(lpszLeftURLName, lpszURLName, URL_FILE_USE_PATHURL,
1037 1038 1039 1040
                This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
    else
        hres = CoInternetParseUrl(lpszURLName, PARSE_CANONICALIZE, URL_FILE_USE_PATHURL,
                This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
1041

1042
    if(FAILED(hres)) {
1043
        heap_free(This->URLName);
1044
        return hres;
1045 1046
    }

Jacek Caban's avatar
Jacek Caban committed
1047 1048
    URLMON_LockModule();

1049
    if(sizeStr != INTERNET_MAX_URL_LENGTH)
1050
        This->URLName = heap_realloc(This->URLName, (sizeStr+1)*sizeof(WCHAR));
1051 1052 1053

    TRACE("URLName = %s\n", debugstr_w(This->URLName));

1054 1055 1056
    return S_OK;
}

1057
/***********************************************************************
1058
 *           CreateURLMonikerEx (URLMON.@)
1059
 *
Jon Griffiths's avatar
Jon Griffiths committed
1060
 * Create a url moniker.
1061
 *
Jon Griffiths's avatar
Jon Griffiths committed
1062 1063 1064 1065
 * PARAMS
 *    pmkContext [I] Context
 *    szURL      [I] Url to create the moniker for
 *    ppmk       [O] Destination for created moniker.
1066
 *    dwFlags    [I] Flags.
1067
 *
Jon Griffiths's avatar
Jon Griffiths committed
1068 1069 1070 1071
 * RETURNS
 *    Success: S_OK. ppmk contains the created IMoniker object.
 *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
 *             E_OUTOFMEMORY if memory allocation fails.
1072
 */
1073
HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
1074
{
1075 1076
    URLMonikerImpl *obj;
    HRESULT hres;
1077
    LPOLESTR lefturl = NULL;
1078

1079 1080 1081
    TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags);

    if (dwFlags & URL_MK_UNIFORM) FIXME("ignoring flag URL_MK_UNIFORM\n");
1082

1083
    if(!(obj = heap_alloc(sizeof(*obj))))
1084 1085
	return E_OUTOFMEMORY;

1086 1087
    if(pmkContext) {
        IBindCtx* bind;
1088 1089 1090 1091 1092
        DWORD dwMksys = 0;
        IMoniker_IsSystemMoniker(pmkContext, &dwMksys);
        if(dwMksys == MKSYS_URLMONIKER && SUCCEEDED(CreateBindCtx(0, &bind))) {
            IMoniker_GetDisplayName(pmkContext, bind, NULL, &lefturl);
            TRACE("lefturl = %s\n", debugstr_w(lefturl));
1093 1094 1095 1096 1097 1098
            IBindCtx_Release(bind);
        }
    }
        
    hres = URLMonikerImpl_Construct(obj, lefturl, szURL);
    CoTaskMemFree(lefturl);
1099
    if(SUCCEEDED(hres))
Jacek Caban's avatar
Jacek Caban committed
1100
	hres = URLMonikerImpl_QueryInterface((IMoniker*)obj, &IID_IMoniker, (void**)ppmk);
1101
    else
1102
	heap_free(obj);
1103
    return hres;
1104 1105
}

1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
/**********************************************************************
 *           CreateURLMoniker (URLMON.@)
 *
 * Create a url moniker.
 *
 * PARAMS
 *    pmkContext [I] Context
 *    szURL      [I] Url to create the moniker for
 *    ppmk       [O] Destination for created moniker.
 *
 * RETURNS
 *    Success: S_OK. ppmk contains the created IMoniker object.
 *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
 *             E_OUTOFMEMORY if memory allocation fails.
 */
HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk)
{
    return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY);
}

1126 1127 1128 1129 1130
/***********************************************************************
 *           IsAsyncMoniker (URLMON.@)
 */
HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
{
1131 1132 1133 1134 1135 1136 1137 1138 1139
    IUnknown *am;
    
    TRACE("(%p)\n", pmk);
    if(!pmk)
        return E_INVALIDARG;
    if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) {
        IUnknown_Release(am);
        return S_OK;
    }
1140 1141 1142
    return S_FALSE;
}

1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
/***********************************************************************
 *           BindAsyncMoniker (URLMON.@)
 *
 * Bind a bind status callback to an asynchronous URL Moniker.
 *
 * PARAMS
 *  pmk           [I] Moniker object to bind status callback to
 *  grfOpt        [I] Options, seems not used
 *  pbsc          [I] Status callback to bind
 *  iidResult     [I] Interface to return
 *  ppvResult     [O] Resulting asynchronous moniker object
 *
 * RETURNS
 *    Success: S_OK.
 *    Failure: E_INVALIDARG, if any argument is invalid, or
 *             E_OUTOFMEMORY if memory allocation fails.
 */
HRESULT WINAPI BindAsyncMoniker(IMoniker *pmk, DWORD grfOpt, IBindStatusCallback *pbsc, REFIID iidResult, LPVOID *ppvResult)
{
    LPBC pbc = NULL;
    HRESULT hr = E_INVALIDARG;

1165 1166
    TRACE("(%p %08x %p %s %p)\n", pmk, grfOpt, pbsc, debugstr_guid(iidResult), ppvResult);

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
    if (pmk && ppvResult)
    {
        *ppvResult = NULL;

        hr = CreateAsyncBindCtx(0, pbsc, NULL, &pbc);
        if (hr == NOERROR)
        {
            hr = IMoniker_BindToObject(pmk, pbc, NULL, iidResult, ppvResult);
            IBindCtx_Release(pbc);
        }
    }
    return hr;
}

1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
/***********************************************************************
 *           MkParseDisplayNameEx (URLMON.@)
 */
HRESULT WINAPI MkParseDisplayNameEx(IBindCtx *pbc, LPCWSTR szDisplayName, ULONG *pchEaten, LPMONIKER *ppmk)
{
    TRACE("(%p %s %p %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);

    if(is_registered_protocol(szDisplayName)) {
        HRESULT hres;

        hres = CreateURLMoniker(NULL, szDisplayName, ppmk);
        if(SUCCEEDED(hres)) {
            *pchEaten = strlenW(szDisplayName);
            return hres;
        }
    }

    return MkParseDisplayName(pbc, szDisplayName, pchEaten, ppmk);
}


1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
/***********************************************************************
 *           URLDownloadToCacheFileA (URLMON.@)
 */
HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName,
        DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
{
    LPWSTR url = NULL, file_name = NULL;
    int len;
    HRESULT hres;

1212
    TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName,
1213 1214 1215 1216
            dwBufLength, dwReserved, pBSC);

    if(szURL) {
        len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
1217
        url = heap_alloc(len*sizeof(WCHAR));
1218 1219 1220 1221
        MultiByteToWideChar(CP_ACP, 0, szURL, -1, url, -1);
    }

    if(szFileName)
1222
        file_name = heap_alloc(dwBufLength*sizeof(WCHAR));
1223 1224 1225 1226 1227 1228 1229

    hres = URLDownloadToCacheFileW(lpUnkCaller, url, file_name, dwBufLength*sizeof(WCHAR),
            dwReserved, pBSC);

    if(SUCCEEDED(hres) && file_name)
        WideCharToMultiByte(CP_ACP, 0, file_name, -1, szFileName, dwBufLength, NULL, NULL);

1230 1231
    heap_free(url);
    heap_free(file_name);
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241

    return hres;
}

/***********************************************************************
 *           URLDownloadToCacheFileW (URLMON.@)
 */
HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName,
                DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
{
1242 1243 1244 1245 1246
    WCHAR cache_path[MAX_PATH + 1];
    FILETIME expire, modified;
    HRESULT hr;
    LPWSTR ext;

1247
    static WCHAR header[] = {
1248 1249 1250 1251
        'H','T','T','P','/','1','.','0',' ','2','0','0',' ',
        'O','K','\\','r','\\','n','\\','r','\\','n',0
    };

1252
    TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL),
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
          szFileName, dwBufLength, dwReserved, pBSC);

    if (!szURL || !szFileName)
        return E_INVALIDARG;

    ext = PathFindExtensionW(szURL);

    if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0))
        return E_FAIL;

    hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC);
    if (FAILED(hr))
        return hr;

    expire.dwHighDateTime = 0;
    expire.dwLowDateTime = 0;
    modified.dwHighDateTime = 0;
    modified.dwLowDateTime = 0;

    if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY,
1273
                              header, sizeof(header), NULL, NULL))
1274 1275 1276 1277 1278 1279 1280 1281
        return E_FAIL;

    if (lstrlenW(cache_path) > dwBufLength)
        return E_OUTOFMEMORY;

    lstrcpyW(szFileName, cache_path);

    return S_OK;
1282 1283
}

1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
/***********************************************************************
 *           HlinkSimpleNavigateToString (URLMON.@)
 */
HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
    LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
    IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
{
    FIXME("%s\n", debugstr_w( szTarget ) );
    return E_NOTIMPL;
}

/***********************************************************************
 *           HlinkNavigateString (URLMON.@)
 */
HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget )
{
    TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) );
    return HlinkSimpleNavigateToString( 
               szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 );
}
1304 1305 1306 1307 1308 1309 1310 1311 1312

/***********************************************************************
 *           GetSoftwareUpdateInfo (URLMON.@)
 */
HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
{
    FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
    return E_FAIL;
}