home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / cxnet1.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  20.5 KB  |  734 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. // network.cpp : implementation file
  19. //
  20.  
  21. #include "stdafx.h"
  22.  
  23. #include "cxnet1.h"
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // Context functions
  27.  
  28. XP_Bool CNetworkCX::Confirm(MWContext *pContext, const char *pConfirmMessage)    {
  29.     //    Always return true, we don't want any dialogs coming up.
  30.     //    Don't call the base.
  31.     //    This will cause the prompt functions to be called multiple times as
  32.     //        needed since both the netlib and this object cache different
  33.     //        passwords.
  34.     return(TRUE);
  35. }
  36.  
  37. void CNetworkCX::Alert(MWContext *pContext, const char *pMessage)    {
  38.     //    Hand over this in the error string, even if it's not an error.
  39.     //    Can't have dialogs popping up everywhere.
  40.     m_lFlags |= m_ERRS;
  41.     m_csErrorMessage = pMessage;
  42.  
  43.     //    Do not call the base or a dialog comes up.
  44. }
  45.  
  46. char *CNetworkCX::Prompt(MWContext *pContext, const char *pPrompt, const char *pDefault)    {
  47.     //    So, LJM tells me that this function is used to query for a username.
  48.     //    Do that here.
  49.     //    Only if not already asked for during this load.
  50.     if((m_lFlags & m_USER) == 0)    {
  51.         SetUsernameRequested();
  52.         return(AllocUsername());
  53.     }
  54.     return(NULL);
  55. }
  56.  
  57. char *CNetworkCX::PromptPassword(MWContext *pContext, const char *pMessage)    {
  58.     //    The caller should have proactively set the password before an Open().
  59.     //    If not, then they will have to figure it out.
  60.     //    Mark that a password was required for the transfer.
  61.     //    Only if not already asked for during this load.
  62.     if((m_lFlags & m_PASS) == 0)    {
  63.         SetPasswordRequested();
  64.         return(AllocPassword());
  65.     }
  66.     return(NULL);
  67. }
  68.  
  69. XP_Bool CNetworkCX::PromptUsernameAndPassword(MWContext *pContext, const char *pMessage, char **ppUsername, char **ppPassword)    {
  70.     //    Initialize.
  71.     *ppPassword = NULL;
  72.     *ppUsername = NULL;
  73.  
  74.     //    If both have already been asked for, don't continue.
  75.     if((m_lFlags & m_USER) != 0 && (m_lFlags & m_PASS) != 0)    {
  76.         return(FALSE);
  77.     }
  78.  
  79.     //    Prompt for both username and password.
  80.     //    Default values are given, and if not already specified by the caller, then we can just use them.
  81.     //    Set that both a username and a password were required for the transfer.
  82.     SetPasswordRequested();
  83.     SetUsernameRequested();
  84.  
  85.     //    Copy and set any user/password values that the controller has preemptively set.
  86.     char *pPass = AllocPassword();
  87.     if(pPass != NULL)    {
  88.         *ppPassword = pPass;
  89.     }
  90.     char *pUser = AllocUsername();
  91.     if(pUser != NULL)    {
  92.         *ppUsername = pUser;
  93.     }
  94.     return(TRUE);
  95. }
  96.  
  97. XP_Bool CNetworkCX::ShowAllNewsArticles(MWContext *pContext)    {
  98.     //    Set to show all the news articles.
  99.     return(GetFlagShowAllNews());
  100. }
  101.  
  102. XP_Bool CNetworkCX::UseFancyFTP(MWContext *pContext)    {
  103.     //    Check to see if we are to use Fancy FTP.
  104.     return(GetFlagFancyFTP());
  105. }
  106.  
  107. XP_Bool CNetworkCX::UseFancyNewsgroupListing(MWContext *pContext)    {
  108.     //    See if we should use full newsgroup listings with descriptions.
  109.     return(GetFlagFancyNews());
  110. }
  111.  
  112. #ifdef _DEBUG
  113. #undef THIS_FILE
  114. static char BASED_CODE THIS_FILE[] = __FILE__;
  115. #endif
  116.  
  117. /////////////////////////////////////////////////////////////////////////////
  118. // CNetworkCX
  119. #ifndef _AFXDLL
  120. #undef new
  121. #endif
  122. IMPLEMENT_DYNCREATE(CNetworkCX, CCmdTarget)
  123. #ifndef _AFXDLL
  124. #define new DEBUG_NEW
  125. #endif
  126.  
  127. CNetworkCX::CNetworkCX()
  128. {
  129.     EnableAutomation();
  130.     
  131.     // To keep the application running as long as an OLE automation 
  132.     //    object is active, the constructor calls AfxOleLockApp.
  133.     
  134.     AfxOleLockApp();
  135.  
  136.     //    Set the type of context that we are.
  137.     m_cxType = Network;
  138.     GetContext()->type = MWContextOleNetwork;
  139.  
  140.     //    Initialize our URL property, other members won't work unless this is defined.
  141.     m_pUrlData = NULL;
  142.  
  143.     //    Our buffer is initially empty.
  144.     ASSERT(m_cplBuffers.IsEmpty());
  145.  
  146.     //    We're done loading any stream, as none have started.
  147.     m_bStreamComplete = TRUE;
  148.  
  149.     //    We don't want to initially show all news articles.
  150.     m_bShowAllNews = FALSE;
  151.  
  152.     //    We do want to use Fancy News and Fancy FTP by default.
  153.     m_bFancyNews = TRUE;
  154.     m_bFancyFTP = TRUE;
  155.  
  156.     //    We've no current status flags.
  157.     m_lFlags = m_OK;
  158.  
  159.     //    Username and password should be empty initially anyhow.
  160.  
  161.     TRACE("Netscape.Network.1 started\n");
  162. }
  163.  
  164. CNetworkCX::~CNetworkCX()
  165. {
  166.     // To terminate the application when all objects created with
  167.     //     with OLE automation, the destructor calls AfxOleUnlockApp.
  168.     
  169.     AfxOleUnlockApp();
  170.  
  171.     TRACE("Netscape.Network.1 ended\n");
  172. }
  173.  
  174. void CNetworkCX::OnFinalRelease()
  175. {
  176.     // When the last reference for an automation object is released
  177.     //    OnFinalRelease is called.  This implementation deletes the 
  178.     //    object.  Add additional cleanup required for your object before
  179.     //    deleting it from memory.
  180.  
  181.     //    If we have a currently loading stream, we need to do cleanup there.
  182.     if(m_pUrlData != NULL)    {
  183.         Close();
  184.     }
  185.  
  186.     DestroyContext();
  187. }
  188.  
  189. char *CNetworkCX::AllocUsername()    {
  190.     //    See if we even have a username to allocate.
  191.     if(m_csUsername.IsEmpty() == TRUE)    {
  192.         return(NULL);
  193.     }
  194.     return(XP_STRDUP(m_csUsername));
  195. }
  196.  
  197. char *CNetworkCX::AllocPassword()    {
  198.     //    See if we even have a password to allocate.
  199.     if(m_csPassword.IsEmpty() == TRUE)    {
  200.         return(NULL);
  201.     }
  202.     return(XP_STRDUP(m_csPassword));
  203. }
  204.  
  205. BEGIN_MESSAGE_MAP(CNetworkCX, CCmdTarget)
  206.     //{{AFX_MSG_MAP(CNetworkCX)
  207.         // NOTE - the ClassWizard will add and remove mapping macros here.
  208.     //}}AFX_MSG_MAP
  209. END_MESSAGE_MAP()
  210.  
  211. BEGIN_DISPATCH_MAP(CNetworkCX, CCmdTarget)
  212.     //{{AFX_DISPATCH_MAP(CNetworkCX)
  213.     DISP_PROPERTY_EX(CNetworkCX, "Username", GetUsername, SetUsername, VT_BSTR)
  214.     DISP_PROPERTY_EX(CNetworkCX, "Password", GetPassword, SetPassword, VT_BSTR)
  215.     DISP_PROPERTY_EX(CNetworkCX, "FlagShowAllNews", GetFlagShowAllNews, SetFlagShowAllNews, VT_BOOL)
  216.     DISP_PROPERTY_EX(CNetworkCX, "FlagFancyFTP", GetFlagFancyFTP, SetFlagFancyFTP, VT_BOOL)
  217.     DISP_PROPERTY_EX(CNetworkCX, "FlagFancyNews", GetFlagFancyNews, SetFlagFancyNews, VT_BOOL)
  218.     DISP_FUNCTION(CNetworkCX, "Close", Close, VT_EMPTY, VTS_NONE)
  219.     DISP_FUNCTION(CNetworkCX, "Read", Read, VT_I2, VTS_PBSTR VTS_I2)
  220.     DISP_FUNCTION(CNetworkCX, "GetStatus", GetStatus, VT_I4, VTS_NONE)
  221.     DISP_FUNCTION(CNetworkCX, "Open", Open, VT_BOOL, VTS_BSTR VTS_I2 VTS_BSTR VTS_I4 VTS_BSTR)
  222.     DISP_FUNCTION(CNetworkCX, "GetErrorMessage", GetErrorMessage, VT_BSTR, VTS_NONE)
  223.     DISP_FUNCTION(CNetworkCX, "GetServerStatus", GetServerStatus, VT_I2, VTS_NONE)
  224.     DISP_FUNCTION(CNetworkCX, "GetContentLength", GetContentLength, VT_I4, VTS_NONE)
  225.     DISP_FUNCTION(CNetworkCX, "GetContentType", GetContentType, VT_BSTR, VTS_NONE)
  226.     DISP_FUNCTION(CNetworkCX, "GetContentEncoding", GetContentEncoding, VT_BSTR, VTS_NONE)
  227.     DISP_FUNCTION(CNetworkCX, "GetExpires", GetExpires, VT_BSTR, VTS_NONE)
  228.     DISP_FUNCTION(CNetworkCX, "GetLastModified", GetLastModified, VT_BSTR, VTS_NONE)
  229.     DISP_FUNCTION(CNetworkCX, "Resolve", Resolve, VT_BSTR, VTS_BSTR VTS_BSTR)
  230.     DISP_FUNCTION(CNetworkCX, "IsFinished", IsFinished, VT_BOOL, VTS_NONE)
  231.     DISP_FUNCTION(CNetworkCX, "BytesReady", BytesReady, VT_I2, VTS_NONE)
  232.     //}}AFX_DISPATCH_MAP
  233. END_DISPATCH_MAP()
  234.  
  235. IMPLEMENT_OLECREATE(CNetworkCX, "Netscape.Network.1", 0xef5f7050, 0x385a, 0x11ce, 0x81, 0x93, 0x0, 0x20, 0xaf, 0x18, 0xf9, 0x5)
  236.  
  237. /////////////////////////////////////////////////////////////////////////////
  238. // CNetworkCX message handlers
  239.  
  240. BOOL CNetworkCX::Open(LPCTSTR pURL, short iMethod, LPCTSTR pPostData, long lPostDataSize, LPCTSTR pPostHeaders) 
  241. {
  242.     //    Reset our status flags.
  243.     m_lFlags = m_OK;
  244.     m_csErrorMessage.Empty();
  245.  
  246.     //    See if we're busy.
  247.     if(winfeInProcessNet == TRUE)    {
  248.         m_lFlags |= m_BUSY;
  249.         return(FALSE);
  250.     }
  251.  
  252.     //    If we're handling a request already, shut it down.
  253.     if(m_pUrlData != NULL)    {
  254.         Close();
  255.     }
  256.  
  257.     //    Create the URL we want to load.
  258.     m_pUrlData = NET_CreateURLStruct(pURL, NET_DONT_RELOAD);
  259.  
  260.     //    Create the ncapi data for the URL.
  261.     //    Don't let it free off the URL in the exit routine.
  262.     //    This is done in close.
  263.     //    A pointer to the class is saved in the URL struct, and will
  264.     //        be freed off in FE_DeleteUrlData.
  265.     CNcapiUrlData *pDontCare = new CNcapiUrlData(this, m_pUrlData);
  266.     pDontCare->DontFreeUrl();
  267.  
  268.     //    Set the method for the load.
  269.     //    GET 0
  270.     //    POST 1
  271.     //    HEAD 3
  272.     m_pUrlData->method = iMethod;
  273.  
  274.     //    Contruct the post stuff.
  275.     if(pPostData != NULL && strlen(pPostData) != 0 && m_pUrlData->method == 1)    {
  276.         m_pUrlData->post_data = (char *)XP_ALLOC(lPostDataSize);
  277.         memcpy(m_pUrlData->post_data, pPostData, CASTSIZE_T(lPostDataSize));
  278.  
  279.         m_pUrlData->post_data_size = lPostDataSize;
  280.  
  281.         if(pPostHeaders != NULL && strlen(pPostHeaders) != 0)    {
  282.             m_pUrlData->post_headers = (char *)XP_ALLOC(strlen(pPostHeaders) + 1);
  283.             memcpy(m_pUrlData->post_headers, pPostHeaders, strlen(pPostHeaders) + 1);
  284.         }
  285.         else    {
  286.             m_pUrlData->post_headers = strdup("Content-type: application/x-www-form-urlencoded");
  287.  
  288.         }
  289.         StrAllocCat(m_pUrlData->post_headers, CRLF);
  290.  
  291.         //    Manually add the content-length.
  292.         //    This was done automatically in versions of Netscape prior to 2.0.
  293.         char aBuffer[1024];
  294.         sprintf(aBuffer, "Content-length: %ld", lPostDataSize);
  295.         StrAllocCat(m_pUrlData->post_headers, aBuffer);
  296.         StrAllocCat(m_pUrlData->post_headers, CRLF);
  297.     }
  298.  
  299.     //    Finally, set that the stream is not yet completed.
  300.     m_bStreamComplete = FALSE;
  301.  
  302.     //    Need to request a URL for a particular format out, in our special context.
  303.     //    Any errors should be caught in the exit routine.
  304.     GetUrl(m_pUrlData, FO_CACHE_AND_OLE_NETWORK);
  305.  
  306.     return TRUE;
  307. }
  308.  
  309. short CNetworkCX::Read(BSTR FAR* pBuffer, short iAmount) 
  310. {
  311.     //    First, check for end of file condition.
  312.     if(m_cplBuffers.IsEmpty() && m_bStreamComplete == TRUE)    {
  313.         return(-1);
  314.     }
  315.  
  316.     //    If the buffer's empty, we should just return right now.
  317.     if(m_cplBuffers.IsEmpty())    {
  318.         return(0);
  319.     }
  320.  
  321.     //    We'll want to either copy over the amount of data they are asking for,
  322.     //        or copy over how much data we have in the buffer,
  323.     //        whichever is less.
  324.     //    To do this, we need to figure out the amount of data in the buffers first
  325.     //        entry only.
  326.  
  327.     //    Get the first entry out.
  328.     CNetBuffer *pNetBuffer = (CNetBuffer *)m_cplBuffers.GetHead();
  329.  
  330.     //    See how much data we should be handling here.
  331.     int iBuffer = pNetBuffer->m_iSize - pNetBuffer->m_iHead;
  332.     ASSERT(iBuffer);
  333.  
  334.     iAmount = min(iBuffer, iAmount);
  335.     if(iAmount <= 0)    {
  336.         return(0);
  337.     }
  338.  
  339.     //    Copy over that amount from our buffer.
  340. #if !defined(_UNICODE) && !defined(OLE2ANSI) && defined(MSVC4)
  341.     //  Need to encode unicode ourselves.
  342.     MultiByteToWideChar(CP_ACP, 0, (pNetBuffer->m_pData + pNetBuffer->m_iHead), iAmount, *pBuffer, sizeof(OLECHAR) * iAmount);
  343.  
  344. #ifdef DEBUG
  345.     //  Here's some extra goodies to make sure the conversion isn't lossy, as we can also transfer binary data.
  346.  
  347.     //  Can we reverse it correctly?
  348.     char *pCompare = new char[iAmount];
  349.     int iConvert = WideCharToMultiByte(CP_ACP, 0, *pBuffer, iAmount, pCompare, iAmount, NULL, NULL);
  350.     ASSERT(iConvert);
  351.  
  352.     //  Was the conversion correct?
  353.     int iCompare = memcmp(pCompare, (pNetBuffer->m_pData + pNetBuffer->m_iHead), iAmount);
  354.     ASSERT(!iCompare);
  355.  
  356.     delete [] pCompare;
  357. #endif
  358.  
  359. #else
  360.     memcpy(*pBuffer, (pNetBuffer->m_pData + pNetBuffer->m_iHead), iAmount);
  361. #endif
  362.     pNetBuffer->m_iHead += iAmount;
  363.     ASSERT(pNetBuffer->m_iHead <= pNetBuffer->m_iSize);
  364.  
  365.     //    See if we should get rid of the buffer entry if completely read now.
  366.     if(pNetBuffer->m_iHead == pNetBuffer->m_iSize)    {
  367.         //    Get rid of it.
  368.         m_cplBuffers.RemoveHead();
  369.         delete pNetBuffer;
  370.     }
  371.  
  372.     //    Return the amount read.
  373.     return(iAmount);
  374. }
  375.  
  376. void CNetworkCX::Close() 
  377. {
  378.     //    Destroy the URL, if we have one.
  379.     if(m_pUrlData != NULL)    {
  380.         //    We really should check for reentrancy, but can't, as this event could happen beyond our control, such
  381.         //        as the controlling application deleting their automation object.
  382.         //    Only do this if we are actually loading, as netlib has probably unregistered this otherwise...
  383.         if(m_bStreamComplete == FALSE)    {
  384.             BOOL bOld = winfeInProcessNet;
  385.             winfeInProcessNet = TRUE;
  386.             NET_InterruptStream(m_pUrlData);
  387.             winfeInProcessNet = bOld;
  388.         }
  389.  
  390.         NET_FreeURLStruct(m_pUrlData);
  391.         m_pUrlData = NULL;
  392.     }
  393.  
  394.     //    Reset the end of the buffer, our stutus, et al.
  395.     CNetBuffer *pDelMe;
  396.     while(m_cplBuffers.IsEmpty() == FALSE)    {
  397.         pDelMe = (CNetBuffer *)m_cplBuffers.RemoveHead();
  398.         delete pDelMe;
  399.     }
  400.  
  401.     m_lFlags = m_OK;
  402.     m_csErrorMessage.Empty();
  403.     m_bStreamComplete = TRUE;
  404. }
  405.  
  406. BSTR CNetworkCX::GetUsername() 
  407. {
  408.     //    Return what the current username is.
  409.     //    Up to caller to free the information.
  410.     return m_csUsername.AllocSysString();
  411. }
  412.  
  413. void CNetworkCX::SetUsername(LPCTSTR lpszNewValue) 
  414. {
  415.     //    Modify the current username to be something new.
  416.     if(lpszNewValue == NULL)    {
  417.         m_csUsername.Empty();
  418.         return;
  419.     }
  420.     m_csUsername = lpszNewValue;
  421. }
  422.  
  423. BSTR CNetworkCX::GetPassword() 
  424. {
  425.     //    Return the current password setting.
  426.     //    Up to caller to free the information.
  427.     return m_csPassword.AllocSysString();
  428. }
  429.  
  430. void CNetworkCX::SetPassword(LPCTSTR lpszNewValue) 
  431. {
  432.     //    Set the password to something new.
  433.     if(lpszNewValue == NULL)    {
  434.         m_csPassword.Empty();
  435.         return;
  436.     }
  437.     m_csPassword = lpszNewValue;
  438. }
  439.  
  440. long CNetworkCX::GetStatus() 
  441. {
  442.     //    Give them the current status flags since the last open occurred.
  443.     return(m_lFlags);
  444. }
  445.  
  446. BOOL CNetworkCX::GetFlagShowAllNews() 
  447. {
  448.     return m_bShowAllNews;
  449. }
  450.  
  451. void CNetworkCX::SetFlagShowAllNews(BOOL bNewValue) 
  452. {
  453.     m_bShowAllNews = bNewValue;
  454. }
  455.  
  456. BOOL CNetworkCX::GetFlagFancyFTP() 
  457. {
  458.     return m_bFancyFTP;
  459. }
  460.  
  461. void CNetworkCX::SetFlagFancyFTP(BOOL bNewValue) 
  462. {
  463.     m_bFancyFTP = bNewValue;
  464. }
  465.  
  466. BOOL CNetworkCX::GetFlagFancyNews() 
  467. {
  468.     return m_bFancyNews;
  469. }
  470.  
  471. void CNetworkCX::SetFlagFancyNews(BOOL bNewValue) 
  472. {
  473.     m_bFancyNews = bNewValue;
  474. }
  475.  
  476. int CNetworkCX::StreamWrite(const char *pWriteData, int32 lLength)    {
  477.     //    if we don't have a url, then don't do this.
  478.     if(m_pUrlData == NULL)    {
  479.         return(-1);
  480.     }
  481.  
  482.     //    We should never get called to copy over more data than is reported by StreamReady.
  483.     //    However, we don't care anymore.
  484.     //    Allocate a new buffer in which to store the data.
  485.     ASSERT(lLength <= NETBUFSIZE);
  486.     CNetBuffer *pNewBuf = new CNetBuffer(CASTINT(lLength));
  487.     memcpy(pNewBuf->m_pData, pWriteData, pNewBuf->m_iSize);
  488.  
  489.     //    Add it to the tail of our buffer list.
  490.     m_cplBuffers.AddTail((void *)pNewBuf);
  491.  
  492.     return(MK_DATA_LOADED);
  493. }
  494.  
  495. unsigned int CNetworkCX::StreamReady()    {
  496.     //    If we don't have a URL, we won't take data.
  497.     if(m_pUrlData == NULL)    {
  498.         return(0);
  499.     }
  500.  
  501.     //    If we already have n entries in our buffered data, don't do this.
  502.     //    We can however take more if the netlib screws up due to this new
  503.     //        buffer system.
  504.     if(m_cplBuffers.IsEmpty() == FALSE && m_cplBuffers.GetCount() >= 10)    {
  505.         return(0);
  506.     }
  507.  
  508.     //    Return our max allowed size, don't really care if they fulfill this
  509.     //        completely.
  510.     return(NETBUFSIZE);
  511. }
  512.  
  513. void CNetworkCX::StreamComplete()    {
  514.     //    Function not utilized.
  515.     //    Stream complete considered to be the URL exit routine.
  516. }
  517.  
  518. void CNetworkCX::StreamAbort(int iStatus)    {
  519.     //    Function not utilized.
  520.     //    Stream complete considered to be the URL exit routine.
  521. }
  522.  
  523. void CNetworkCX::GetUrlExitRoutine(URL_Struct *pUrl, int iStatus, MWContext *pContext)    {
  524.     //    URL is done loading.
  525.     m_bStreamComplete = TRUE;
  526.  
  527.     //    Check for internal loading errors.
  528.     if(iStatus != MK_DATA_LOADED)    {
  529.         m_lFlags |= m_INTL;
  530.     }
  531.     else if(pUrl->server_status / 100 != 2 && pUrl->server_status / 100 != 3 && iStatus == MK_DATA_LOADED && pUrl->server_status != 0)    {
  532.         m_lFlags |= m_SRVR;
  533.     }
  534.  
  535.     //    If we have any error message what so ever, then we will save it here and set that an error occurred.
  536.     if(m_lFlags & (m_SRVR | m_INTL))    {
  537.         if(pUrl->error_msg != NULL)    {
  538.             if(strlen(pUrl->error_msg) != 0)    {
  539.                 m_lFlags |= m_ERRS;
  540.                 m_csErrorMessage = pUrl->error_msg;
  541.             }
  542.         }
  543.     }
  544.  
  545.     //    Call the base.
  546.     CStubsCX::GetUrlExitRoutine(pUrl, iStatus, pContext);
  547. }
  548.  
  549. BSTR CNetworkCX::GetErrorMessage() 
  550. {
  551.     //    Simply return any error message that we currently have.
  552.     return m_csErrorMessage.AllocSysString();
  553. }
  554.  
  555. extern "C"    {
  556.  
  557. NET_StreamClass *nfe_OleStream(int iFormatOut, void *pDataObj, URL_Struct *pUrlData, MWContext *pContext)    {
  558.     //    Return a new stream class, pass the object along for the ride.
  559.     return(NET_NewStream("Netscape_Network_1",
  560.         nfe_StreamWrite,
  561.         nfe_StreamComplete,
  562.         nfe_StreamAbort,
  563.         nfe_StreamReady,
  564.         CX2VOID(pContext->fe.cx, CNetworkCX),
  565.         pContext));
  566. }
  567.  
  568. int nfe_StreamWrite(NET_StreamClass *stream, const char *pWriteData, int32 lLength)    {
  569.     void *pDataObj=stream->data_object;
  570.     CNetworkCX *pOle = VOID2CX(pDataObj, CNetworkCX);    
  571.  
  572.     //    Have our object handle it.
  573.     return(pOle->StreamWrite(pWriteData, lLength));
  574. }
  575.  
  576. void nfe_StreamComplete(NET_StreamClass *stream)    {
  577.     void *pDataObj=stream->data_object;
  578.     CNetworkCX *pOle = VOID2CX(pDataObj, CNetworkCX);    
  579.  
  580.     //    Have our object handle it.
  581.     pOle->StreamComplete();
  582. }
  583.  
  584. void nfe_StreamAbort(NET_StreamClass *stream, int iStatus)    {
  585.     void *pDataObj=stream->data_object;
  586.     CNetworkCX *pOle = VOID2CX(pDataObj, CNetworkCX);
  587.  
  588.     //    Have our object handle it.
  589.     pOle->StreamAbort(iStatus);
  590. }
  591.  
  592. unsigned int nfe_StreamReady(NET_StreamClass *stream)    {
  593.     void *pDataObj=stream->data_object;
  594.     CNetworkCX *pOle = VOID2CX(pDataObj, CNetworkCX);
  595.     
  596.     //    Have our object handle it.
  597.     return(pOle->StreamReady());
  598. }
  599.  
  600. };
  601.  
  602. short CNetworkCX::GetServerStatus() 
  603. {
  604.     //    Don't do this if we don't have a URL.
  605.     if(m_pUrlData == NULL)    {
  606.         return(-1);
  607.     }
  608.     else if(m_bStreamComplete != TRUE)    {
  609.         //    Also can't do this unless the load is done.
  610.         return(-1);
  611.     }
  612.  
  613.     return(m_pUrlData->server_status);
  614. }
  615.  
  616. long CNetworkCX::GetContentLength() 
  617. {
  618.     //    Don't do this if we don't have a URL.
  619.     if(m_pUrlData == NULL)    {
  620.         return(-1);
  621.     }
  622.  
  623.     return(m_pUrlData->content_length);
  624. }
  625.  
  626. BSTR CNetworkCX::GetContentType() 
  627. {
  628.     //    Don't do this if we don't have a URL.
  629.     if(m_pUrlData == NULL)    {
  630.         return(NULL);
  631.     }
  632.     else if(m_pUrlData->content_type == NULL)    {
  633.         return(NULL);
  634.     }
  635.     else if(strlen(m_pUrlData->content_type) == 0)    {
  636.         return(NULL);
  637.     }
  638.  
  639.     CString s = m_pUrlData->content_type;
  640.     return s.AllocSysString();
  641. }
  642.  
  643. BSTR CNetworkCX::GetContentEncoding() 
  644. {
  645.     //    Don't do this if we don't have a URL.
  646.     if(m_pUrlData == NULL)    {
  647.         return(NULL);
  648.     }
  649.     else if(m_pUrlData->content_encoding == NULL)    {
  650.         return(NULL);
  651.     }
  652.     else if(strlen(m_pUrlData->content_encoding) == 0)    {
  653.         return(NULL);
  654.     }
  655.  
  656.     CString s = m_pUrlData->content_encoding;
  657.     return s.AllocSysString();
  658. }
  659.  
  660. BSTR CNetworkCX::GetExpires() 
  661. {
  662.     //    Don't do this if we don't have a URL.
  663.     if(m_pUrlData == NULL)    {
  664.         return(NULL);
  665.     }
  666.     else if(m_pUrlData->expires == (time_t)0)    {
  667.         return(NULL);
  668.     }
  669.  
  670.     char *pTime = ctime(&(m_pUrlData->expires));
  671.     if(pTime == NULL)    {
  672.         return(NULL);
  673.     }
  674.  
  675.     CString s = pTime;
  676.     return s.AllocSysString();
  677. }
  678.  
  679. BSTR CNetworkCX::GetLastModified() 
  680. {
  681.     //    Don't do this if we don't have a URL.
  682.     if(m_pUrlData == NULL)    {
  683.         return(NULL);
  684.     }
  685.     else if(m_pUrlData->last_modified == (time_t)0)    {
  686.         return(NULL);
  687.     }
  688.  
  689.     char *pTime = ctime(&(m_pUrlData->last_modified));
  690.     if(pTime == NULL)    {
  691.         return(NULL);
  692.     }
  693.  
  694.     CString s = pTime;
  695.     return s.AllocSysString();
  696. }
  697.  
  698. BSTR CNetworkCX::Resolve(LPCTSTR pBase, LPCTSTR pRelative) 
  699. {
  700.     //    Have the netlib resolve the url stuff for us.
  701.     char *cpURL = NET_MakeAbsoluteURL((char *)pBase, (char *)pRelative);
  702.     if(cpURL == NULL)    {
  703.         return(NULL);
  704.     }
  705.  
  706.     CString s = cpURL;
  707.     XP_FREE(cpURL);
  708.     return s.AllocSysString();
  709. }
  710.  
  711. BOOL CNetworkCX::IsFinished() 
  712. {
  713.     //    Check for end of file condition.
  714.     if(m_cplBuffers.IsEmpty() && m_bStreamComplete == TRUE)    {
  715.         return(TRUE);
  716.     }
  717.  
  718.     return(FALSE);
  719. }
  720.  
  721. short CNetworkCX::BytesReady() 
  722. {
  723.     //    Check to see if there's any load ready.
  724.     if(m_cplBuffers.IsEmpty() && m_bStreamComplete == TRUE)    {
  725.         return(0);
  726.     }
  727.  
  728.     //    Return the number of bytes we are currently ready to dish out.
  729.     CNetBuffer *pReady = (CNetBuffer *)m_cplBuffers.GetHead();
  730.     int iBuffer = pReady->m_iSize - pReady->m_iHead;
  731.     ASSERT(iBuffer);
  732.     return(iBuffer);
  733. }
  734.