//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1995.
//
//  File:       cnetstrm.cxx
//
//  Contents:   Implements the stream: protocol
//
//  Classes:    CINetStream
//
//  Functions:
//
//  History:    5/3/96 Created Craig Critchley [craigc]
//
//----------------------------------------------------------------------------
#include <trans.h>


//+---------------------------------------------------------------------------
//
//  Method:     CINetStream::CINetStream
//
//  Synopsis:   Constructs a stream protcol object
//
//  Arguments:  rclsid
//
//  Returns:
//
//  History:    5/3/96 Created Craig Critchley [craigc]
//
//  Notes:
//
//----------------------------------------------------------------------------
CINetStream::CINetStream(REFCLSID rclsid, IUnknown *pUnkOuter) : CINet(rclsid,pUnkOuter)
{
    DEBUG_ENTER((DBG_TRANS,
                None,
                "CINetStream::CINetStream",
                "this=%#x, %#x, %#x",
                this, &rclsid, pUnkOuter
                ));
                
   _dwIsA = DLD_PROTOCOL_STREAM;
   _pstm = NULL;

   DEBUG_LEAVE(0);
}

//+---------------------------------------------------------------------------
//
//  Method:     CINetStream::~CINetStream
//
//  Synopsis:   destroys a stream protocol object
//
//  Arguments:
//
//  Returns:
//
//  History:    5/3/96 Created Craig Critchley [craigc]
//
//  Notes:
//
//----------------------------------------------------------------------------
CINetStream::~CINetStream()
{
    DEBUG_ENTER((DBG_TRANS,
                None,
                "CINetStream::~CINetStream",
                "this=%#x",
                this
                ));
                
    if (_pstm)
    {
        _pstm->Release();
    }

    DEBUG_LEAVE(0);
}

//+---------------------------------------------------------------------------
//
//  Method:     CINetStream::INetAsyncOpen
//
//  Synopsis:   opens and synchronously downloads data from a stream
//
//  Arguments:  rclsid
//
//  Returns:
//
//  History:    5/3/96 Created Craig Critchley [craigc]
//
//  Notes:
//
//----------------------------------------------------------------------------
HRESULT CINetStream::INetAsyncOpen()
{
    DEBUG_ENTER((DBG_TRANS,
                Hresult,
                "CINetStream::INetAsyncOpen",
                "this=%#x",
                this
                ));
                
   IBindCtx * pbc = 0;
   IMoniker * pmk = 0;
   IStream * pstm = 0;
   IParseDisplayName * pParser = 0;
   STATSTG stat;
   CLSID clsid;
   CHAR szDisplayName[MAX_PATH];
   WCHAR wzDisplayName[MAX_PATH];
   WCHAR wzProgId[MAX_PATH];
   LPSTR pa, psz;
   LPWSTR pwz, pwzI;
   int cch;
   HRESULT hr = E_NOTIMPL;
   ULONG cchE;
   BOOL fGotMIMEType = FALSE;

   ReportNotification(BINDSTATUS_SENDINGREQUEST);

   // need one of these
   //
   if (FAILED(hr = CreateBindCtx(0,&pbc)))
      goto End;

   //   form is mk:@progid:moniker
   //
   strcpy(szDisplayName,GetServerName());
   strcat(szDisplayName,psz = GetObjectName());

   // if the moniker has a file extension, try to
   // determine the MIME type that way...
   //
   psz = FindFileExtension(psz);
   if (psz)
   {
       char szMime[MAX_PATH];
       DWORD cb = MAX_PATH;

       if (SUCCEEDED(GetMimeFromExt(psz,szMime,&cb)))
       {
           ReportNotification(BINDSTATUS_MIMETYPEAVAILABLE, szMime);
           fGotMIMEType = TRUE;
       }
   }

   A2W(szDisplayName,wzDisplayName,MAX_PATH);

   //   find progid
   //
   for (pwz = wzDisplayName, pwzI = wzProgId; *pwz; pwz++)
   {
       if (*pwz == '@')
       {
           pwzI = wzProgId;
       }
       else if (*pwz == ':')
       {
           *pwzI = 0;

           // the remainder may have a filename with a useful
           // extension... just in case, set the filename...
           //
           LPSTR pszStr = DupW2A(pwz+1);
           if (pszStr)
           {
               ReportNotification(BINDSTATUS_CACHEFILENAMEAVAILABLE, pszStr);
               delete pszStr;
           }

           break;
       }
       else
       {
           *pwzI++ = *pwz;
       }
   }

#if 0
   if (FAILED(hr = MkParseDisplayName(pbc,wzDisplayName,&cchE,&pmk)) && pmk)
       goto End;
#else
   // BUGBUG
   //
   //   MkParseDisplayName was opening another instance of app
   //   force inproc server.  ick.
   //

   if (FAILED(hr = CLSIDFromProgID(wzProgId,&clsid)))
   {
       goto End;
   }

   if (FAILED(hr = CoCreateInstance(clsid,0,CLSCTX_INPROC_SERVER,
                                    IID_IParseDisplayName,(void**)&pParser)))
   {
       goto End;
   }

   TransAssert((pParser));

   if (FAILED(hr = pParser->ParseDisplayName(pbc,wzDisplayName,&cchE,&pmk)))
   {
       goto End;
   }

   TransAssert((pmk));

#endif

   if (FAILED(hr = pmk->BindToStorage(pbc,0,IID_IStream,(void**)&pstm)))
   {
      hr = INET_E_RESOURCE_NOT_FOUND;
      goto End;
   }

   TransAssert((hr != MK_S_ASYNCHRONOUS));
   TransAssert((pstm));

   _pstm = pstm;
   _pstm->AddRef();

   // now we have a stream - stuff it into the trans data
   //
   if (FAILED(hr = pstm->Stat(&stat,STATFLAG_NONAME)))
   {
       goto End;
   }

   _cbTotalBytesRead = stat.cbSize.LowPart;
   _cbDataSize = stat.cbSize.LowPart;

   hr = _pCTrans->ReportData(BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION, stat.cbSize.LowPart,stat.cbSize.LowPart);

   _hrError = INET_E_DONE;

End:

   if (FAILED(hr))
   {
        SetCNetBindResult(GetLastError());
        _hrError = INET_E_RESOURCE_NOT_FOUND;
        ReportResultAndStop(_hrError);
   }

   // play nice, no leaks
   //
   if (pParser)
   {
      pParser->Release();
   }

   if (pmk)
   {
      pmk->Release();
   }
   if (pbc)
   {
      pbc->Release();
   }
   if (pstm)
   {
      pstm->Release();
   }

   // make sure I set this any way I get out
   //
   TransAssert((hr != E_NOTIMPL));

   DEBUG_LEAVE(hr);
   return hr;
}

//+---------------------------------------------------------------------------
//
//  Method:     CINetStream::ReadDataHere
//
//  Synopsis:
//
//  Arguments:  [pBuffer] --
//              [cbBytes] --
//              [pcbBytes] --
//
//  Returns:
//
//  History:    10-29-1996   JohannP (Johann Posch)   Created
//
//  Notes:
//
//----------------------------------------------------------------------------
HRESULT CINetStream::ReadDataHere(BYTE *pBuffer, DWORD cbBytes, DWORD *pcbBytes)
{
    DEBUG_ENTER((DBG_TRANS,
                Hresult,
                "CINetStream::ReadDataHere",
                "this=%#x, %#x, %#x, %#x",
                this, pBuffer, cbBytes, pcbBytes
                ));
            
    TransDebugOut((DEB_PROT, "%p _IN CINetStream::ReadDataHere\n", this));
    HRESULT hr = E_FAIL;

    TransAssert((cbBytes && pcbBytes));


    if (_pstm)
    {
        hr = _pstm->Read(pBuffer,cbBytes,pcbBytes);
    }

    TransDebugOut((DEB_PROT, "%p OUT CINetStream::ReadDataHere (_hrError:%lx, [hr:%lx,cbBytesAsked:%ld,cbBytesReturned:%ld]) \n",
                                this, _hrError, hr, cbBytes, *pcbBytes));

    DEBUG_LEAVE(hr);
    return hr;
}


//+---------------------------------------------------------------------------
//
//  Method:     CINetStream::INetSeek
//
//  Synopsis:
//
//  Arguments:  [DWORD] --
//              [ULARGE_INTEGER] --
//              [plibNewPosition] --
//
//  Returns:
//
//  History:    10-29-1996   JohannP (Johann Posch)   Created
//
//  Notes:
//
//----------------------------------------------------------------------------
HRESULT CINetStream::INetSeek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition)
{
    DEBUG_ENTER((DBG_TRANS,
                Hresult,
                "CINetStream::INetSeek",
                "this=%#x, %#x, %#x, %#x",
                this, dlibMove, dwOrigin, plibNewPosition
                ));
                
    TransDebugOut((DEB_PROT, "%p _IN CINetStream::INetSeek\n", this));
    HRESULT hr = E_FAIL;

    if (_pstm)
    {
        hr = _pstm->Seek(dlibMove, dwOrigin, plibNewPosition);
    }

    TransDebugOut((DEB_PROT, "%p OUT CINetStream::INetSeek (hr:%lx) \n",this, hr));

    DEBUG_LEAVE(hr);
    return hr;
}

//+---------------------------------------------------------------------------
//
//  Method:     CINetStream::LockFile
//
//  Synopsis:
//
//  Arguments:
//
//  Returns:
//
//  History:    8-13-96   JohannP (Johann Posch)   Created
//
//  Notes:
//
//----------------------------------------------------------------------------
HRESULT CINetStream::LockFile(BOOL fRetrieve)
{
    DEBUG_ENTER((DBG_TRANS,
                Hresult,
                "CINetStream::LockFile",
                "this=%#x, %B",
                this, fRetrieve
                ));
                
    TransDebugOut((DEB_PROT, "%p _IN CINetStream::LockFile\n", this));
    HRESULT hr = NOERROR;

    // nothing to do for now

    TransDebugOut((DEB_PROT,"%p OUT CINetStream::LockFile (hr:%lx)\n",this, hr));

    DEBUG_LEAVE(hr);
    return hr;
}

//+---------------------------------------------------------------------------
//
//  Method:     CINetStream::UnlockFile
//
//  Synopsis:   unlocks the file
//
//  Arguments:  (none)
//
//  Returns:
//
//  History:    8-13-96   JohannP (Johann Posch)   Created
//
//  Notes:
//
//----------------------------------------------------------------------------
HRESULT CINetStream::UnlockFile()
{
    DEBUG_ENTER((DBG_TRANS,
                Hresult,
                "CINetStream::UnlockFile",
                "this=%#x",
                this
                ));
                
    TransDebugOut((DEB_PROT, "%p IN CINetStream::UnlockFile\n", this));
    HRESULT hr = NOERROR;

    // nothing to do for now

    TransDebugOut((DEB_PROT,"%p OUT CINetStream::UnlockFile (hr:%lx)\n", this, hr));

    DEBUG_LEAVE(hr);
    return hr;
}