// $Id: inetop.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ #include "camtypes.h" #include "sgliboil.h" //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "galstr.h" #include "sglcart.h" #include "sgfonts.h" #include "sglib.h" //#include "sgscan.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "sgscanf.h" //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "selop.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "filedlgs.h" //#include "resource.h" // _R(IDS_CANCEL) #include "camdoc.h" //#include "webster.h" //#include "richard.h" #include "pathnmex.h" #include "inetop.h" #include "sglbase.h" #include "progress.h" #include "sglfills.h" #include "backgrnd.h" #include // for FileExists #include #include using namespace InetUtils; CC_IMPLEMENT_DYNCREATE(DownloadOp, Operation) CC_IMPLEMENT_DYNCREATE(OpAsynchClipartImport, OpClipartImport) CC_IMPLEMENT_DYNCREATE(OpAddWebFolders, Operation) CC_IMPLEMENT_DYNCREATE(OpAddWebLibrary, Operation) CC_IMPLEMENT_DYNCREATE(OpThumbDownload, Operation) CC_IMPLEMENT_DYNCREATE(OpAsynchFontInstall, DownloadOp) CC_IMPLEMENT_DYNCREATE(OpAsynchBitmapImport, DownloadOp) #define new CAM_DEBUG_NEW void* DownloadOpParam::pAllocatedMemory; DownloadOpParam::DownloadOpParam() { #ifdef _DEBUG if ((void*) this != pAllocatedMemory) ERROR3("DownloadOpParam-derived objects should be allocated using the new operator"); pAllocatedMemory = NULL; #endif // default to clipart download parameters type = TYPE_CLIPART; priority = AsynchDownload::PRIORITY_HIGH; bHasProgressDlg = TRUE; strDescription = _T(""); } /******************************************************************************************** > DownloadOp::~DownloadOp() Author: Adrian_Stoicar (Xara Group Ltd) Created: 3/04/97 Inputs: - Outputs: - Returns: - Purpose: DownloadOp constructor Errors: - SeeAlso: - ********************************************************************************************/ DownloadOp::DownloadOp() { pParam = NULL; m_hDownload = 0; m_nPercentageCompleted = 0; OpFlags.HasOwnTimeIndicator = TRUE; // GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_LOW, this); // start the polling loop } /******************************************************************************************** > DownloadOp::~DownloadOp() Author: Adrian_Stoicar (Xara Group Ltd) Created: 4/04/97 Inputs: - Outputs: - Returns: - Purpose: DownloadOp destructor Errors: - SeeAlso: - ********************************************************************************************/ DownloadOp::~DownloadOp() { GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_LOW, this); // end polling loop if (pParam) delete pParam; } /****************************************************************************************** > BOOL DownloadOp::Init() Author: Adrian_Stoicar (Xara Group Ltd) Created: 4/04/97 Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for a DownloadOp SeeAlso: ******************************************************************************************/ BOOL DownloadOp::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_OPDOWNLOAD), // String resource ID CC_RUNTIME_CLASS(DownloadOp), // Runtime class OPTOKEN_OPDOWNLOAD, // Token string DownloadOp::GetState, // GetState function 0, // Help ID 0, // Bubble ID 0, // Resource ID 0 // Control ID ); } /****************************************************************************************** > OpState DownloadOp::GetState(String_256* pString, OpDescriptor* pOpDesc) Author: Adrian_Stoicar (Xara Group Ltd) Created: 4/04/97 Purpose: Returns the OpState of the DownloadOp operation. SeeAlso: ******************************************************************************************/ OpState DownloadOp::GetState(String_256* pString, OpDescriptor* pOpDesc) { OpState OpSt; return(OpSt); } /******************************************************************************************** > void DownloadOp::Do(OpDescriptor*) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/1/97 Inputs: OpDescriptor* (unused) Outputs: - Returns: - Purpose: Errors: Always fails - should not be called SeeAlso: - ******************************************************************************************/ void DownloadOp::Do(OpDescriptor *NotUsed) { ERROR3("This operation does not provide a Do() function - Use DoWithParam"); End(); } /****************************************************************************************** > void DownloadOp::DoWithParam(OpDescriptor* pOp, OpParam* pDownloadOpParam) Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: pOp - OpDescriptor as for all Do() functions pDownloadOpParam - pointer to DownloadOpParam structure . This structure must be created on the heap as it should not be destroyed when it goes out of scope. Outputs: - none Note that this function returns immediately after starting the download. Returns: - Purpose: Request a download with the parameters passed in pDownloadOpParam ******************************************************************************************/ void DownloadOp::DoWithParam(OpDescriptor* pOp, OpParam* pDownloadOpParam) { DownloadOpParam *pInfo = (DownloadOpParam*) pDownloadOpParam; if (pInfo == NULL) { ERROR3("DoWithParam called with invalid pointer"); goto FAIL; } else { if (!pInfo->file.IsValid() || pInfo->strURL.IsEmpty()) { ERROR3("Invalid file path or URL"); goto FAIL; } // Register the file for download DOWNLOADINFO downloadInfo; downloadInfo.strURL = pInfo->strURL; downloadInfo.strLocalFile = (String_256) pInfo->file.GetPath(); downloadInfo.nFileType = pInfo->type; downloadInfo.nPriority = pInfo->priority; downloadInfo.strDescription = pInfo->strDescription; downloadInfo.bHasProgressDlg = TRUE; // NEW! Tell this downloader that we can handle status messages // (We don't use Idle event polling) downloadInfo.hwndNotifyWindow = GetMainFrame()->GetSafeHwnd(); downloadInfo.lNotifyToken = (INT32)this; m_hDownload = InternetManager::RegisterDownload(&downloadInfo); if (!m_hDownload || m_hDownload == (DOWNLOAD_HANDLE) INVALID_HANDLE_VALUE) { ERROR3("Failed to register download"); goto FAIL; } pParam = pInfo; if (pInfo->Output) *(pInfo->Output) = TRUE; } return; FAIL: if (pInfo->Output) *(pInfo->Output) = FALSE; FailAndDiscard(); End(); } /******************************************************************************************** > void DownloadOp::End() Author: Adrian_Stoicar (Xara Group Ltd) Created: 21/01/97 Inputs: - Outputs: - Returns: - Purpose: overrides Operation::End() to avoid having an ERROR2 (caused by Document::GetSelectedSpread() returning NULL) go off when Camelot exits while a download is still in progress Errors: - SeeAlso: Operation::End() ********************************************************************************************/ void DownloadOp::End() { if (m_hDownload) InternetManager::UnregisterDownload(m_hDownload); if (Document::GetSelectedSpread()) Operation::End(); else EndOp(); } /****************************************************************************************** > virtual BOOL DownloadOp::OnIdleEvent() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - TRUE if we want to continue polling, FALSE otherwise Purpose: - idle time polling loop; continues until either the download completes or the operation is terminated on receiving a death message. The appropriate functions are called according to the state of the download on completion (succeeded/aborted/failed) ******************************************************************************************/ BOOL DownloadOp::OnIdleEvent() { //ERROR2(FALSE, "DownloadOp::OnIdleEvent should no longer be called!!!"); INT32 nPercentageCompleted = 0; ERROR2IF(!pParam, FALSE, "Unexpected NULL pointer"); switch (InternetManager::GetDownloadState(m_hDownload)) { case AsynchDownload::STATE_PENDING: // check the percentage downloaded so far nPercentageCompleted = InternetManager::GetPercentageDownloaded(m_hDownload); ERROR3IF(nPercentageCompleted == -1, "Invalid download handle"); if (nPercentageCompleted != m_nPercentageCompleted) // we made some progress { m_nPercentageCompleted = nPercentageCompleted; OnDownloadProgress(nPercentageCompleted); } // download pending, so we continue polling return TRUE; case AsynchDownload::STATE_SUCCEEDED: // file has transferred successfully, we call OnDownloadSuccess() to process it OnDownloadSuccess(); SucceedAndDiscard(); End(); return FALSE; case AsynchDownload::STATE_FAILED: OnDownloadFail(); break; case AsynchDownload::STATE_ABORTED: OnDownloadAbort(); break; default: ERROR3("Error or unrecognized state"); } FailAndDiscard(); End(); return FALSE; } /****************************************************************************************** > virtual void DownloadOp::OnDownloadSuccess() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - Purpose: - This function is called if the file download completes successfully so that we can process it or take some other action. Derived classes should override this function - the current implementation does nothing. ******************************************************************************************/ void DownloadOp::OnDownloadSuccess() { } /****************************************************************************************** > virtual void DownloadOp::OnDownloadFail() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - Purpose: - This function is called if the file download fails. The current implemention simply outputs an error message based on the file type declared in DownloadOpParam. If you want something more sophisticated override this function in your class. ******************************************************************************************/ void DownloadOp::OnDownloadFail() { String_256 strTemp; strTemp.MakeMsg(_R(IDS_DOWNLOADFAILED), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) pParam->strDescription); Error::SetError(0, strTemp, 0); InformError(); } /****************************************************************************************** > virtual void DownloadOp::OnDownloadAbort() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - Purpose: - This function is called if the file download is cancelled by the user. Derived classes should override this function if some specific action is required in this case. ******************************************************************************************/ void DownloadOp::OnDownloadAbort() { } /****************************************************************************************** > virtual void DownloadOp::OnDownloadPending() Author: Phil_Martin (Xara Group Ltd) Created: 04/05/2004 Inputs: - Outputs: - Returns: - Purpose: - This function is called if the file download is just in the process of working. Derived classes should override this function if some specific action is required in this case. ******************************************************************************************/ void DownloadOp::OnDownloadPending() { // check the percentage downloaded so far INT32 nPercentageCompleted = 0; nPercentageCompleted = InternetManager::GetPercentageDownloaded(m_hDownload); // ERROR3IF(nPercentageCompleted == -1, "Invalid download handle"); if (nPercentageCompleted != -1) { if (nPercentageCompleted != m_nPercentageCompleted) // we made some progress { m_nPercentageCompleted = nPercentageCompleted; OnDownloadProgress(nPercentageCompleted); } } } // Asynchonous clipart import /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AsynchClipartImportParam::AsynchClipartImportParam() { Import = FALSE; bDropped = FALSE; } AsynchClipartImportParam::~AsynchClipartImportParam() { } OpAsynchClipartImport::OpAsynchClipartImport() { pParam = NULL; m_hDownload = 0; m_pTargetDoc = NULL; m_pCurrentSelDoc = NULL; GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_LOW, this); } /******************************************************************************************** > OpAsynchClipartImport::~OpAsynchClipartImport() Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Inputs: - Outputs: - Returns: - Purpose: OpAsynchClipartImport destructor Errors: - SeeAlso: - ********************************************************************************************/ OpAsynchClipartImport::~OpAsynchClipartImport() { GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_LOW, this); if (pParam) delete pParam; } /****************************************************************************************** > BOOL OpAsynchClipartImport::Init() Author: Adrian_Stoicar (Xara Group Ltd) Created: 4/01/97 Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for an AsynchClipartImport operation SeeAlso: ******************************************************************************************/ BOOL OpAsynchClipartImport::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_OPASYNCHCLIPARTIMPORT), // String resource ID CC_RUNTIME_CLASS(OpAsynchClipartImport), // Runtime class OPTOKEN_OPASYNCHCLIPARTIMPORT, // Token string OpAsynchClipartImport::GetState, // GetState function 0, // Help ID 0, // Bubble ID 0, // Resource ID 0 // Control ID ); } /****************************************************************************************** > OpState OpAsynchClipartImport::GetState(String_256* pString, OpDescriptor* pOpDesc) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/3/95 Purpose: Returns the OpState of the OpAsynchClipartImport operation. SeeAlso: ******************************************************************************************/ OpState OpAsynchClipartImport::GetState(String_256* pString, OpDescriptor* pOpDesc) { OpState OpSt; return(OpSt); } /****************************************************************************************** > BOOL OpAsynchClipartImport::OnDocChangingMsg(Document* pChangingDoc, DocChangingMsg::DocState State) Author: Adrian_Stoicar (Xara Group Ltd) Created: 12/01/97 Returns: - Purpose: Notifies us if the document we intend to import into is about to be destroyed, in which case we should abort the operation SeeAlso: MessageHandler::OnDocChangingMsg() ******************************************************************************************/ BOOL OpAsynchClipartImport::OnDocChangingMsg(Document* pChangingDoc, DocChangingMsg::DocState State) { if (pChangingDoc == m_pTargetDoc && State == DocChangingMsg::ABOUTTODIE) { // We end the operation, but don't abort the clipart download - it's up to the user to do that FailAndExecute(); End(); } return TRUE; } /******************************************************************************************** > void OpAsynchClipartImport::Do(OpDescriptor*) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/1/97 Inputs: OpClipartImport (unused) Outputs: - Returns: - Purpose: Errors: Always fails - should not be called SeeAlso: - ******************************************************************************************/ void OpAsynchClipartImport::Do(OpDescriptor *NotUsed) { ERROR3("OpAsynchClipartImport does not provide a Do() function - Use DoWithParam"); End(); } /****************************************************************************************** > void OpAsynchClipartImport::DoWithParam(OpDescriptor* pOp, OpParam* pClipartImportParam) Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: pOp - OpDescriptor as for all Do() functions pClipartImportParam - pointer to AsynchClipartImport structure . This structure must be created on the heap as it should not be destroyed when it goes out of scope. Outputs: - none Note that this function returns immediately after starting the download, so its success is not relevant to the outcome of the actual clipart import operation, which will be done on the idle loop if the download eventually succeeds. In case of failure, however, the user will be informed that the download - and clipart import - cannot be started. Returns: - Purpose: Performs an asynch clipart import / open depending on the parameters Notes: In case the downloads succeeds, the actual clipart import will be done on the idle loop in order to avoid reentering the import code (potentially messy) in case of multiple symultaneous downloads SeeAlso: OpClipartImport, OpAsynchClipartImport::OnIdleEvent() ******************************************************************************************/ void OpAsynchClipartImport::DoWithParam(OpDescriptor* pOp, OpParam* pClipartImportParam) { AsynchClipartImportParam *pInfo = (AsynchClipartImportParam*) pClipartImportParam; if(pInfo == NULL) { ERROR3("OpAsynchClipartImport called with NULL info pointer"); goto FAIL; } else { if (!pInfo->File.IsValid() || pInfo->strURL.IsEmpty()) { ERROR3("Invalid file path or URL"); goto FAIL; } // Remember the document pointer m_pTargetDoc = Document::GetSelected(); m_pCurrentSelDoc = Document::GetSelected(); // target and selected are the same at this stage // Register the file for download DOWNLOADINFO downloadInfo; downloadInfo.strURL = pInfo->strURL; downloadInfo.strLocalFile = (String_256) pInfo->File.GetPath(); downloadInfo.nFileType = TYPE_CLIPART; downloadInfo.nPriority = AsynchDownload::PRIORITY_HIGH; downloadInfo.strDescription = pInfo->strDescription; downloadInfo.bHasProgressDlg = TRUE; downloadInfo.hwndNotifyWindow = 0; downloadInfo.lNotifyToken = 0; m_hDownload = InternetManager::RegisterDownload(&downloadInfo); if (!m_hDownload || m_hDownload == (DOWNLOAD_HANDLE) INVALID_HANDLE_VALUE) { ERROR3("Failed to register download"); goto FAIL; } pParam = pInfo; } return; FAIL: FailAndExecute(); End(); } /******************************************************************************************** > void OpAsynchClipartImport::End() Author: Adrian_Stoicar (Xara Group Ltd) Created: 21/01/97 Inputs: - Outputs: - Returns: - Purpose: overwrites Operation::End() to avoid having an ERROR2 (caused by Document::GetSelectedSpread() returning NULL) go off when Webster exits while an asynch clipart import is still in progress Errors: - SeeAlso: Operation::End() ********************************************************************************************/ void OpAsynchClipartImport::End() { if (Document::GetSelectedSpread()) Operation::End(); else EndOp(); } /****************************************************************************************** > virtual BOOL OpAsynchClipartImport::OnIdleEvent() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - TRUE if we want to continue polling, FALSE otherwise Purpose: - idle time polling loop; continues until either the download completes or the operation is terminated on receiving a death message. Different actions are taken according to the state of the download on completion (succeeded/aborted/failed) ******************************************************************************************/ BOOL OpAsynchClipartImport::OnIdleEvent() { ERROR2IF(!pParam, FALSE, "Unexpected NULL pointer"); switch (InternetManager::GetDownloadState(m_hDownload)) { case AsynchDownload::STATE_PENDING: // download pending, so we continue polling return TRUE; case AsynchDownload::STATE_SUCCEEDED: { // file has transferred successfully, so we can proceed with a synchronous import/open operation if (pParam->Import) { if (m_pTargetDoc != Document::GetSelected()) { m_pCurrentSelDoc = Document::GetSelected(); Document::SetSelectedViewAndSpread(m_pTargetDoc); // If the target document is not selected yet we keep on polling until it is if (m_pTargetDoc != Document::GetSelected()) return TRUE; } OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpClipartImport)); if (pOpDesc != NULL) { ClipartImportParam Param; // Set up the parameters which we require to import the clipart Param.File = &(pParam->File); Param.Import = pParam->Import; Param.Result = TRUE; if (pParam->bDropped) // if the file has been dropped on the page, get positioning informatiom Param.DropInfo = &(pParam->DropInfo); pOpDesc->Invoke((OpParam*) &Param); BOOL ok = Param.Result; if (!ok) { ERROR3("LibClipartSGallery::ImportClipart - Problem importing file"); } } if (m_pCurrentSelDoc != m_pTargetDoc) Document::SetSelectedViewAndSpread(m_pCurrentSelDoc); } else // open the file as new document { CWinApp* pApp = AfxGetApp(); BaseFileDialog::SelectedFilter = 0; // Open a document CCamDoc* pDoc = (CCamDoc*) pApp->OpenDocumentFile((TCHAR*) String_256(pParam->File.GetPath())); // And redraw the imported document if(pDoc) pDoc->GetKernelDoc()->ForceRedraw(); } if (LibFillsSGallery::ThisGallery) LibFillsSGallery::ThisGallery->SelectionHasChanged(); SucceedAndDiscard(); End(); return FALSE; } case AsynchDownload::STATE_FAILED: { String_256 strTemp; strTemp.MakeMsg(_R(IDS_DOWNLOADFAILED), (TCHAR*) (String_256) GetStringField((UINT32) SGLib_ClipArt, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) pParam->strDescription); Error::SetError(0, strTemp, 0); InformError(); goto FAIL; } case AsynchDownload::STATE_ABORTED: { // no errror message as this state is the result of a user cancel goto FAIL; } default: ERROR3("Error or unrecognized state"); goto FAIL; } FAIL: FailAndDiscard(); End(); return FALSE; } // OpAddWebFolders /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL OpAddWebFolders::Success[8]; OpAddWebFolders::OpAddWebFolders() { pParam = NULL; GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_LOW, this); OpFlags.HasOwnTimeIndicator = TRUE; m_hDownload = 0; } /******************************************************************************************** > OpAddWebFolders::~OpAddWebFolders() Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Inputs: - Outputs: - Returns: - Purpose: OpAddWebFolders destructor Errors: - SeeAlso: - ********************************************************************************************/ OpAddWebFolders::~OpAddWebFolders() { GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_LOW, this); if (pParam) delete pParam; } /****************************************************************************************** > BOOL OpAddWebFolders::Init() Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for an OpAddWebFolders operation SeeAlso: ******************************************************************************************/ BOOL OpAddWebFolders::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_OPADDWEBFOLDERS), // String resource ID CC_RUNTIME_CLASS(OpAddWebFolders), // Runtime class OPTOKEN_OPADDWEBFOLDERS, // Token string OpAddWebFolders::GetState, // GetState function 0, // Help ID 0, // Bubble ID 0, // Resource ID 0 // Control ID ); } /****************************************************************************************** > OpState OpAddWebFolders::GetState(String_256* pString, OpDescriptor* pOpDesc) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Purpose: Returns the OpState of the OpAddWebFolders operation. SeeAlso: ******************************************************************************************/ OpState OpAddWebFolders::GetState(String_256* pString, OpDescriptor* pOpDesc) { OpState OpSt; return(OpSt); } /******************************************************************************************** > void OpAddWebFolders::Do(OpDescriptor*) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/3/95 Inputs: OpAddWebFolders (unused) Outputs: - Returns: - Purpose: Errors: Always fails - should not be called SeeAlso: - ********************************************************************************************/ void OpAddWebFolders::Do(OpDescriptor *NotUsed) { ERROR3("OpAddWebFolders does not provide a Do() function - Use DoWithParam"); End(); } /****************************************************************************************** > void OpAddWebFolders::DoWithParam(OpDescriptor* pOp, OpParam* pAddWebFoldersParam) Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: pOp - OpDescriptor as for all Do() functions pAddWebFoldersParam - pointer to AddWebFoldersParam structure Outputs: - none Returns: - Purpose: attempts to download asynchronously the main web clipart index file, and if this succeeds it goes on to parse it and launch separate downloads for each of the catalog files referenced by the index ******************************************************************************************/ void OpAddWebFolders::DoWithParam(OpDescriptor* pOp, OpParam* pAddWebFoldersParam) { AddWebFoldersParam *pInfo = (AddWebFoldersParam*) pAddWebFoldersParam; if (pInfo == NULL) { ERROR3("OpAddWebFolders called with NULL info pointer"); goto FAIL; } else { if (!pInfo->localFile.IsValid() || pInfo->strURL.IsEmpty() || !pInfo->pLibGal) { ERROR3("OpAddWebFolders: invalid parameters"); goto FAIL; } // Register the file for download DOWNLOADINFO downloadInfo; downloadInfo.strURL = pInfo->strURL; downloadInfo.strLocalFile = (String_256) pInfo->localFile.GetPath(); downloadInfo.nFileType = TYPE_CATALOG; downloadInfo.nPriority = AsynchDownload::PRIORITY_NORMAL; downloadInfo.bHasProgressDlg = TRUE; downloadInfo.hwndNotifyWindow = 0; downloadInfo.lNotifyToken = 0; m_hDownload = InternetManager::RegisterDownload(&downloadInfo); if (!m_hDownload || m_hDownload == (DOWNLOAD_HANDLE) INVALID_HANDLE_VALUE) { InformError(_R(IDS_CATALOGDOWNLOADFAILED), _R(IDS_OK)); goto FAIL; } pParam = pInfo; } // Make some optimistic assumptions... Success[pParam->type] = TRUE; return; FAIL: Success[pParam->type] = FALSE; FailAndExecute(); End(); } /****************************************************************************************** > virtual BOOL OpAddWebFolders::OnDeathMsg() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - always TRUE Purpose: - aborts the download (so that we won't leak resources) and ends the op on Webster exit ******************************************************************************************/ BOOL OpAddWebFolders::OnDeathMsg() { InternetManager::UnregisterDownload(m_hDownload); End(); return TRUE; } /****************************************************************************************** > virtual BOOL OpAddWebFolders::OnIdleEvent() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - TRUE if we want to continue polling, FALSE otherwise Purpose: - idle time polling loop; continues until either the download completes or the operation is terminated on receiving a death message. Different actions are taken according to the state of the download on completion (succeeded/aborted/failed) ******************************************************************************************/ BOOL OpAddWebFolders::OnIdleEvent() { ERROR2IF(!pParam, FALSE, "Unexpected NULL pointer"); CCDiskFile mainIndex; switch (InternetManager::GetDownloadState(m_hDownload)) { case AsynchDownload::STATE_PENDING: // download pending, so we continue polling return TRUE; case AsynchDownload::STATE_SUCCEEDED: { // file has transferred successfully, so we can go on and parse it if (!mainIndex.open(pParam->localFile,ios::in)) { // I/O error - no need to inform the user as CCDiskFile is error reporting by default goto FAIL; } if (!mainIndex.InitLexer()) { String_256 strErrorMsg; if (pParam->type == SGLib_ClipArt || pParam->type == SGLib_ClipArt_WebThemes) strErrorMsg = _T("Failed to parse web clipart index file - web folders cannot be updated"); else if (pParam->type == SGLib_Font) strErrorMsg = _T("Failed to parse web fonts index file - web folders cannot be updated"); ERROR2(FALSE,strErrorMsg); goto FAIL; } LexTokenType tokType = TOKEN_EOL; // Initialise lexing routines, and aspects of the lexer mainIndex.SetDelimiters("\r\n"); // Set token delimiting characters mainIndex.SetCommentMarker('#'); // Set comment marker char mainIndex.SetWhitespace("\t"); // Set whitespace chars const TCHAR* TokenBuf = mainIndex.GetTokenBuf(); // Token buffer remains constant until lexer deinitialisation String_256 strFolderName(""); String_256 strRelativePath(""); String_256 strRootURL(""); INT32 nFieldOffset = 0; INT32 nRecords = 0; while (tokType != TOKEN_EOF) { mainIndex.GetToken(); tokType = mainIndex.GetTokenType(); if (tokType == TOKEN_NORMAL) { switch (nFieldOffset) { case 0: // first field strFolderName = TokenBuf; break; case 1: // second field strRelativePath = TokenBuf; break; case 2: // third field strRootURL = TokenBuf; break; default: InformError(_R(IDS_CORRUPTEDINDEXFILE), _R(IDS_OK)); mainIndex.DeinitLexer(); goto FAIL; } if (nFieldOffset == 2) // finished reading a line, so try adding the corresponding library { // append a slash to the root URL if necessary if (camStrstr((TCHAR*) strRootURL, _T("file://"))) { if (strRootURL[strRootURL.Length() - 1] != _T('\\')) strRootURL += _T('\\'); } else if (strRootURL[strRootURL.Length() - 1] != _T('/')) strRootURL += _T('/'); Library::URLBase = strRootURL; // set the base URL (this is a static variable at present) OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpAddWebLibrary)); if (pOpDesc != NULL) { AddWebFoldersParam* Param = NULL; try { Param = new AddWebFoldersParam; } catch (CMemoryException* pExc) { pExc->Delete(); Error::SetError(_R(IDS_OUT_OF_MEMORY)); InformError(); mainIndex.DeinitLexer(); goto FAIL; } // Set up the web library's param Param->localFile.SetPathName((TCHAR *) MakeLocalPath(strRelativePath)); // local path of catalog file // We change the file extention from .txt to .tmp to avoid overwriting the old one - if any - so that we can compare // their sizes and figure out if the web catalog has been modified since the last download ERROR3IF(Param->localFile.GetType() != _T("txt") && Param->localFile.GetType() != _T("TXT"), "Catalog files are expected to have the .txt extention"); Param->localFile.SetType(String_32(_T("tmp"))); Param->strURL = MakeURL(strRelativePath, strRootURL); // URL of catalog file on our web server Param->pLibGal = pParam->pLibGal; // pass on the pointer to the gallery Param->strFolderName = strFolderName; Param->type = pParam->type; // pass on the gallery type // Invoke the operation // This will initiate a download of the catalog file - if it succeeds, the folder will be added to the gallery pOpDesc->Invoke((OpParam*) Param); } nRecords++; // we've gone through another record nFieldOffset = 0; // reset field pointer } else { nFieldOffset++; } } else if (tokType == TOKEN_EOL) { // if the field pointer is not 0, the previous line must have had either less or more than 3 fields - the // file might have been corrupted or contains an error, so we skip the rest if (nFieldOffset) { InformError(_R(IDS_CORRUPTEDINDEXFILE), _R(IDS_OK)); mainIndex.DeinitLexer(); goto FAIL; } } } // We are now finished with the lexer mainIndex.DeinitLexer(); mainIndex.close(); // remove the file as we don't need it anymore. Using remove() is OK in this case as the file is not in the cache _tremove((TCHAR*) String_256(pParam->localFile.GetPath())); if (!nRecords) // eof reached without coming across any records - a bit fishy { InformError(_R(IDS_CORRUPTEDINDEXFILE), _R(IDS_OK)); goto FAIL; } // if we got this far we can assume we succeeded SucceedAndDiscard(); End(); return FALSE; } case AsynchDownload::STATE_FAILED: { String_256 strErrorMsg; strErrorMsg.MakeMsg(_R(IDS_CATALOGDOWNLOADFAILED), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GETX_CAPTIONS))); Error::SetError(0, strErrorMsg, 0); InformError(); goto FAIL; } case AsynchDownload::STATE_ABORTED: { // no errror message as this state is the result of a user cancel goto FAIL; } default: ERROR3("Error or unrecognized state"); goto FAIL; } FAIL: // Make sure the file is closed so we can delete it if (mainIndex.isOpen()) mainIndex.close(); _tremove((TCHAR*) String_256(pParam->localFile.GetPath())); Success[pParam->type] = FALSE; FailAndDiscard(); End(); return FALSE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // OpAddWebLibrary /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// INT32 OpAddWebLibrary::InstanceCount[8]; INT32 OpAddWebLibrary::FoldersAdded[8]; INT32 OpAddWebLibrary::ErrorCount[8]; INT32 OpAddWebLibrary::CachedFilesUsed[8]; BOOL OpAddWebLibrary::m_bIsSuspended = FALSE; std::list OpAddWebLibrary::m_lstPendingDownloads; OpAddWebLibrary::OpAddWebLibrary() { // The instance count is incremented in DoWithParam and not here, as at this point the type of the op is not known pParam = NULL; GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_LOW, this); m_hDownload = 0; OpFlags.HasOwnTimeIndicator = TRUE; } /******************************************************************************************** > OpAddWebLibrary::~OpAddWebLibrary() Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Inputs: - Outputs: - Returns: - Purpose: OpAddWebLibrary destructor Errors: - SeeAlso: - ********************************************************************************************/ OpAddWebLibrary::~OpAddWebLibrary() { GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_LOW, this); if (pParam) { InstanceCount[pParam->type]--; delete pParam; } } /****************************************************************************************** > BOOL OpAddWebLibrary::Init() Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for an OpAddWebLibrary operation SeeAlso: ******************************************************************************************/ BOOL OpAddWebLibrary::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_OPADDWEBLIBRARY), // String resource ID CC_RUNTIME_CLASS(OpAddWebLibrary), // Runtime class OPTOKEN_OPADDWEBLIBRARY, // Token string OpAddWebLibrary::GetState, // GetState function 0, // Help ID 0, // Bubble ID 0, // Resource ID 0 // Control ID ); } /****************************************************************************************** > OpState OpAddWebLibrary::GetState(String_256* pString, OpDescriptor* pOpDesc) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Purpose: Returns the OpState of the OpAddWebLibrary operation. SeeAlso: ******************************************************************************************/ OpState OpAddWebLibrary::GetState(String_256* pString, OpDescriptor* pOpDesc) { OpState OpSt; return(OpSt); } /******************************************************************************************** > void OpAddWebLibrary::Do(OpDescriptor*) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/3/95 Inputs: OpAddWebLibrary (unused) Outputs: - Returns: - Purpose: Errors: Always fails - should not be called SeeAlso: - ********************************************************************************************/ void OpAddWebLibrary::Do(OpDescriptor *NotUsed) { ERROR3("OpAddWebLibrary does not provide a Do() function - Use DoWithParam"); End(); } /****************************************************************************************** > void OpAddWebLibrary::DoWithParam(OpDescriptor* pOp, OpParam* pAddWebFoldersParam) Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: pOp - OpDescriptor as for all Do() functions pAddWebFoldersParam - pointer to AddWebFoldersParam structure Outputs: - none Returns: - Purpose: attempts to download asynchronously the library's catalog (xaraclip.txt) file - in case of success a corresponding folder will be added to the clipart gallery ******************************************************************************************/ void OpAddWebLibrary::DoWithParam(OpDescriptor* pOp, OpParam* pAddWebFoldersParam) { AddWebFoldersParam* pInfo = (AddWebFoldersParam*) pAddWebFoldersParam; if (pInfo == NULL || m_bIsSuspended) { ERROR3IF(!pInfo, "OpAddWebLibrary called with NULL info pointer"); goto FAIL; } else { if (!pInfo->localFile.IsValid() || pInfo->strURL.IsEmpty() || pInfo->strFolderName.IsEmpty() || !pInfo->pLibGal) { ERROR3("OpAddWebLibrary: invalid parameters"); goto FAIL; } // Register the file for download String_256 strDescription(GetStringField((UINT32) pInfo->type, _R(IDS_GALLERY_DESCRIPTIONS))); strDescription += String_32(_R(IDS_CATALOGFILE)); DOWNLOADINFO downloadInfo; downloadInfo.strURL = pInfo->strURL; downloadInfo.strLocalFile = (String_256) pInfo->localFile.GetPath(); downloadInfo.nFileType = TYPE_CATALOG; downloadInfo.nPriority = AsynchDownload::PRIORITY_NORMAL; downloadInfo.strDescription = strDescription; downloadInfo.bHasProgressDlg = TRUE; downloadInfo.hwndNotifyWindow = 0; downloadInfo.lNotifyToken = 0; m_hDownload = InternetManager::RegisterDownload(&downloadInfo); if (!m_hDownload || m_hDownload == (DOWNLOAD_HANDLE) INVALID_HANDLE_VALUE) { String_256 strErrorMsg; strErrorMsg.MakeMsg(_R(IDS_CATALOGDOWNLOADFAILED), (TCHAR*) (String_256) GetStringField((UINT32) pInfo->type, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) (String_256) GetStringField((UINT32) pInfo->type, _R(IDS_GETX_CAPTIONS))); Error::SetError(0, strErrorMsg, 0); InformError(); } else m_lstPendingDownloads.push_back(m_hDownload); pParam = pInfo; InstanceCount[pParam->type]++; // update instance count if (InstanceCount[pParam->type] == 1) // first instance, reset counters { ErrorCount[pParam->type] = 0; FoldersAdded[pParam->type] = 0; CachedFilesUsed[pParam->type] = 0; } } return; FAIL: OpAddWebFolders::Success[pParam->type] = FALSE; FailAndExecute(); End(); } /****************************************************************************************** > virtual BOOL OpAddWebLibrary::OnDeathMsg() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - always TRUE Purpose: - aborts the download (so that we won't leak resources) and ends the op on Webster exit ******************************************************************************************/ BOOL OpAddWebLibrary::OnDeathMsg() { InternetManager::UnregisterDownload(m_hDownload); End(); return TRUE; } /****************************************************************************************** > virtual BOOL OpAddWebLibrary::OnIdleEvent() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - TRUE if we want to continue polling, FALSE otherwise Purpose: - idle time polling loop; continues until either the download completes or the operation is terminated on receiving a death message. Different actions are taken according to the state of the download on completion (succeeded/aborted/failed) ******************************************************************************************/ BOOL OpAddWebLibrary::OnIdleEvent() { ERROR2IF(!pParam, FALSE, "Unexpected NULL pointer"); if (m_bIsSuspended) return FALSE; UINT32 nModifiedFlag = FOLDER_UNMODIFIED; // flag indicating folder's status (FOLDER_UNMODIFIED/FOLDER_UPDATED/FOLDER_NEW) BOOL bHaveCatalogFile = FALSE; // flag indicating if we should add this folder to the gallery PathName localFile(pParam->localFile); // path to local (current) catalog file (may not exist if this is a new folder) localFile.SetType(String_32(_T("txt"))); // should be a .txt file PathName oldFile(pParam->localFile); // path to old catalog file (may not exist if this is a new folder) oldFile.SetType(String_32(_T("old"))); LibraryGallery* pGallery = pParam->pLibGal; switch (InternetManager::GetDownloadState(m_hDownload)) { case AsynchDownload::STATE_PENDING: // download pending, so we continue polling return TRUE; case AsynchDownload::STATE_SUCCEEDED: { // Check if the folder exists BOOL bFolderExists = (pGallery->FindLibrary((String_256) localFile.GetPath())) ? TRUE : FALSE; // File has transferred successfully, check if we have an older copy if (_taccess((String_256) localFile.GetPath(), 0) == -1) // not found { if (DownloadCache::RenameFile((String_256) pParam->localFile.GetPath(), (String_256) localFile.GetPath())) { InformError(_R(IDS_LOCALFILEERROR), _R(IDS_OK)); goto FAIL; // couldn't rename it for some reason } else { bHaveCatalogFile = TRUE; nModifiedFlag = FOLDER_NEW; } } else // we already have an older version of this file, so we compare the sizes to see if the web version is different { CCDiskFile currentVersion, newVersion; if (!currentVersion.open(localFile, ios::in) || !newVersion.open(pParam->localFile, ios::in)) { // Cannot compare sizes due to some I/O error, so in case one of the files is good we'll just use that BOOL bCurrentVersionBad = currentVersion.bad(); BOOL bNewVersionBad = newVersion.bad(); currentVersion.close(); newVersion.close(); if (!bNewVersionBad) { // move the new version over the old one if (DownloadCache::RemoveFile((String_256) localFile.GetPath())) // failed - can't move { InformError(_R(IDS_LOCALFILEERROR), _R(IDS_OK)); DownloadCache::RemoveFile((String_256) pParam->localFile.GetPath()); goto FAIL; } else // rename the new version { if (DownloadCache::RenameFile((String_256) pParam->localFile.GetPath(), (String_256) localFile.GetPath())) { InformError(_R(IDS_LOCALFILEERROR), _R(IDS_OK)); goto FAIL; // couldn't rename it for some reason } else { bHaveCatalogFile = TRUE; if (!bFolderExists) nModifiedFlag = FOLDER_NEW; } } } else if (!bCurrentVersionBad) { // the downloaded catalog file may be corrupted, so delete it and use the current one DownloadCache::RemoveFile((String_256) pParam->localFile.GetPath()); bHaveCatalogFile = TRUE; if (!bFolderExists) nModifiedFlag = FOLDER_NEW; } else // none of the files can be opened - just clean up and inform the error { DownloadCache::RemoveFile((String_256) pParam->localFile.GetPath()); InformError(_R(IDS_LOCALFILEERROR), _R(IDS_OK)); goto FAIL; } } else { if (!bFolderExists) nModifiedFlag = FOLDER_NEW; else if (newVersion.Size() != currentVersion.Size()) nModifiedFlag = FOLDER_UPDATED; currentVersion.close(); newVersion.close(); DownloadCache::RemoveFile((String_256) oldFile.GetPath()); if (DownloadCache::RenameFile((String_256) localFile.GetPath(), (String_256) oldFile.GetPath())) // failed - can't move { InformError(_R(IDS_LOCALFILEERROR), _R(IDS_OK)); DownloadCache::RemoveFile((String_256) pParam->localFile.GetPath()); goto FAIL; } else // rename the new version { if (DownloadCache::RenameFile((String_256) pParam->localFile.GetPath(), (String_256) localFile.GetPath())) { InformError(_R(IDS_LOCALFILEERROR), _R(IDS_OK)); goto FAIL; // couldn't rename it for some reason } else { bHaveCatalogFile = TRUE; } } } } } break; case AsynchDownload::STATE_FAILED: { ErrorCount[pParam->type]++; OpAddWebFolders::Success[pParam->type] = FALSE; // If we have on older catalog file we'll use that, otherwise we'll FAIL if (_taccess((String_256) localFile.GetPath(), 0) == -1) // not found { goto FAIL; } else { CachedFilesUsed[pParam->type]++; bHaveCatalogFile = TRUE; } } break; case AsynchDownload::STATE_ABORTED: { // no errror message as this state is the result of a user cancel Suspend(); // ensure we are not reentered while we remove pending downloads std::list::iterator listIterator = m_lstPendingDownloads.begin(); INT32 nListSize = m_lstPendingDownloads.size(); for (INT32 i = 0; i < nListSize; i++) InternetManager::UnregisterDownload(*listIterator++); Resume(); goto FAIL; } default: ERROR3("Error or unrecognized state"); goto FAIL; } // Add/update the folder if everything's fine if (bHaveCatalogFile && (nModifiedFlag == FOLDER_UPDATED || nModifiedFlag == FOLDER_NEW)) { LibraryFile* LibFile = NULL; try { LibFile = new LibraryFile; } catch (CMemoryException* pExc) { pExc->Delete(); Error::SetError(_R(IDS_OUT_OF_MEMORY)); InformError(); goto FAIL; } String_256 strFileName(localFile.GetFileName()); PathName FilesPath(localFile.GetLocation()); pGallery->RemoveSimilarLibraryGroups(&FilesPath, &strFileName, TRUE, FALSE, NULL); if (!LibFile->AddSpecificIndex(pGallery, &localFile, pParam->type, &pParam->strFolderName, nModifiedFlag, TRUE)) { delete LibFile; goto FAIL; } else { pGallery->OpenLibFiles.AddTail(LibFile); LibFile->DoScrollRedraw(); FoldersAdded[pParam->type]++; } // If we got this far we can assume we succeeded SucceedAndDiscard(); goto END; } else { goto END; } FAIL: OpAddWebFolders::Success[pParam->type] = FALSE; FailAndDiscard(); END: // inform errors, if any if (InstanceCount[pParam->type] == 1 && ErrorCount[pParam->type]) { String_256 strErrorMsg; if (FoldersAdded[pParam->type]) // partial failure (we have added some of the folders) { if (CachedFilesUsed[pParam->type]) strErrorMsg.MakeMsg(_R(IDS_CATALOGPARTIALUSECACHE), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GETX_CAPTIONS))); else strErrorMsg.MakeMsg(_R(IDS_CATALOGDOWNLOADPARTIALFAIL), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GETX_CAPTIONS))); } else { if (CachedFilesUsed[pParam->type]) strErrorMsg.MakeMsg(_R(IDS_CATALOGUSECACHE), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GETX_CAPTIONS))); else // failed completely... strErrorMsg.MakeMsg(_R(IDS_CATALOGDOWNLOADFAILED), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GALLERY_DESCRIPTIONS)), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GETX_CAPTIONS))); } Error::SetError(0, strErrorMsg, 0); InformError(); } m_lstPendingDownloads.remove(m_hDownload); End(); return FALSE; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Thumbnail downloading ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// INT32 OpThumbDownload::ErrorCount[8]; INT32 OpThumbDownload::ThumbsDownloaded[8]; INT32 OpThumbDownload::InstanceCount[8]; BOOL OpThumbDownload::m_bIsSuspended = FALSE; std::list OpThumbDownload::m_lstFailedItems; ThumbDownloadParam::ThumbDownloadParam() { pItem = NULL; pOp = NULL; bSuccess = FALSE; type = SGLib_Blank; } ThumbDownloadParam::~ThumbDownloadParam() { } OpThumbDownload::OpThumbDownload() { pParam = NULL; m_nPercentageCompleted = 0; m_hDownload = 0; pGallery = NULL; GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_LOW, this); OpFlags.HasOwnTimeIndicator = TRUE; } /******************************************************************************************** > OpThumbDownload::~OpThumbDownload() Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/12/96 Inputs: - Outputs: - Returns: - Purpose: OpThumbDownload destructor Errors: - SeeAlso: - ********************************************************************************************/ OpThumbDownload::~OpThumbDownload() { GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_LOW, this); if (pParam) { InstanceCount[pParam->type]--; delete pParam; } } /****************************************************************************************** > BOOL OpThumbDownload::Init() Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/3/95 Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for an OpThumbDownload operation SeeAlso: ******************************************************************************************/ BOOL OpThumbDownload::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_OPTHUMBDOWNLOAD), // String resource ID CC_RUNTIME_CLASS(OpThumbDownload), // Runtime class OPTOKEN_OPTHUMBDOWNLOAD, // Token string OpThumbDownload::GetState, // GetState function 0, // Help ID 0, // Bubble ID 0, // Resource ID 0 // Control ID ); } /****************************************************************************************** > OpState OpThumbDownload::GetState(String_256* pString, OpDescriptor* pOpDesc) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/3/95 Purpose: Returns the OpState of the OpThumbDownload operation. SeeAlso: ******************************************************************************************/ OpState OpThumbDownload::GetState(String_256* pString, OpDescriptor* pOpDesc) { OpState OpSt; return(OpSt); } /******************************************************************************************** > void OpThumbDownload::Do(OpDescriptor*) Author: Adrian_Stoicar (Xara Group Ltd) Created: 20/01/97 Inputs: (unused) Outputs: - Returns: - Purpose: Errors: Always fails - should not be called SeeAlso: - ******************************************************************************************/ void OpThumbDownload::Do(OpDescriptor *NotUsed) { ERROR3("OpThumbDownload does not provide a Do() function - Use DoWithParam"); End(); } /****************************************************************************************** > void OpThumbDownload::DoWithParam(OpDescriptor* pOp, OpParam* pThumbDownloadParam) Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: pOp - OpDescriptor as for all Do() functions pThumbDownloadParam - pointer to ThumbDownloadParam structure . This structure must be created on the heap as it should not be destroyed when it goes out of scope. Outputs: - none Note that this function returns immediately after starting the download, so its success is not relevant to the outcome of the download operation. Returns: - Purpose: - starts a thumbnail download ******************************************************************************************/ void OpThumbDownload::DoWithParam(OpDescriptor* pOp, OpParam* pThumbDownloadParam) { ThumbDownloadParam* pInfo = (ThumbDownloadParam*) pThumbDownloadParam; if (pInfo == NULL || pInfo->pItem == NULL) { ERROR3("OpThumbDownload called with NULL info pointer"); End(); } else { String_256 thumbPath; if (!pInfo->pItem->GetThumbFileName(&thumbPath)) { ERROR3("Can't get thumbnail file name"); goto FAIL; } String_256 thumbNetPath = thumbPath; Library* pLibrary = pInfo->pItem->GetParentLibrary(); if (!pLibrary) { ERROR3("Illegal NULL pointer"); goto FAIL; } if (!pLibrary->IsWebLibrary()) goto FAIL; pLibrary->LocalPath2URL(&thumbNetPath); // Register the file for download DOWNLOADINFO downloadInfo; downloadInfo.strURL = thumbNetPath; downloadInfo.strLocalFile = thumbPath; downloadInfo.nFileType = TYPE_THUMBNAIL; downloadInfo.nPriority = AsynchDownload::PRIORITY_HIGH; downloadInfo.bHasProgressDlg = FALSE; downloadInfo.hwndNotifyWindow = 0; downloadInfo.lNotifyToken = 0; m_hDownload = InternetManager::RegisterDownload(&downloadInfo); if (!m_hDownload || m_hDownload == (DOWNLOAD_HANDLE) INVALID_HANDLE_VALUE) { InformWarning(_R(IDS_THUMBDOWNLOADFAILED), _R(IDS_OK)); if (pGallery = (LibraryGallery*) pInfo->pItem->GetParentGallery()) pGallery->bThumbDownloading = FALSE; // turn off thumb downloading so we don't flood the user with error messages goto FAIL; } pParam = pInfo; if (pGallery = (LibraryGallery*) pInfo->pItem->GetParentGallery()) pGallery->m_lstPendingThumbs.push_back(this); pInfo->pOp = this; pInfo->bSuccess = TRUE; InstanceCount[pParam->type]++; // thumb downloads occur in "bursts", so when a new burst begins we must reset the error and download counters // so that we don't get confused by previous errors if (InstanceCount[pParam->type] == 1) { ErrorCount[pParam->type] = 0; ThumbsDownloaded[pParam->type] = 0; pGallery->SelectionHasChanged(); } return; } FAIL: FailAndExecute(); End(); } /******************************************************************************************** > void OpThumbDownload::End() Author: Adrian_Stoicar (Xara Group Ltd) Created: 21/01/97 Inputs: - Outputs: - Returns: - Purpose: Ends the download operation, displaying the thumbnail if successful Errors: - SeeAlso: Operation::End() ********************************************************************************************/ void OpThumbDownload::End() { // Abort the download if still pending - this can only happen if the item is being destroyed if (m_hDownload && InternetManager::GetDownloadState(m_hDownload) == AsynchDownload::STATE_PENDING) InternetManager::UnregisterDownload(m_hDownload); LibraryGallery* pGallery = (LibraryGallery*) pParam->pItem->GetParentGallery(); if (pGallery) { pGallery->m_lstPendingThumbs.remove(this); if (InstanceCount[pParam->type] == 1) pGallery->SelectionHasChanged(); } if (pParam && pParam->pItem) // tell the item that the thumb download is finished pParam->pItem->OnThumbDownloadComplete(); Operation::End(); } /******************************************************************************************** > void OpThumbDownload::Abort() Author: Adrian_Stoicar (Xara Group Ltd) Created: 21/01/97 Inputs: - Outputs: - Returns: - Purpose: Aborts the download operation Errors: - SeeAlso: Operation::End() ********************************************************************************************/ void OpThumbDownload::Abort() { if (m_hDownload && InternetManager::GetDownloadState(m_hDownload) == AsynchDownload::STATE_PENDING) InternetManager::UnregisterDownload(m_hDownload); LibraryGallery* pGallery = (LibraryGallery*) pParam->pItem->GetParentGallery(); if (pGallery) { pGallery->m_lstPendingThumbs.remove(this); if (InstanceCount[pParam->type] == 1) pGallery->SelectionHasChanged(); } Operation::End(); } /****************************************************************************************** > virtual BOOL OpThumbDownload::OnIdleEvent() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - TRUE if we want to continue polling, FALSE otherwise Purpose: - idle time polling loop; continues until either the download completes or the operation is terminated by a call to End(). Different actions are taken according to the state of the download on completion (succeeded/aborted/failed) ******************************************************************************************/ BOOL OpThumbDownload::OnIdleEvent() { ERROR2IF(!pParam, FALSE, "Unexpected NULL pointer"); if (m_bIsSuspended) // if the Op is suspended we don't do anything return FALSE; switch (InternetManager::GetDownloadState(m_hDownload)) { case AsynchDownload::STATE_PENDING: { // check the percentage downloaded so far INT32 nPercentageCompleted = InternetManager::GetPercentageDownloaded(m_hDownload); ERROR3IF(nPercentageCompleted == -1, "Invalid download handle"); if (nPercentageCompleted != m_nPercentageCompleted) // we made some progress { m_nPercentageCompleted = nPercentageCompleted; if (pParam && pParam->pItem) // tell the item to update itself pParam->pItem->OnThumbDownloadProgress(nPercentageCompleted); } // the download is still pending, so we continue polling return TRUE; } case AsynchDownload::STATE_SUCCEEDED: { // We got lucky ThumbsDownloaded[pParam->type]++; SucceedAndDiscard(); goto END; } case AsynchDownload::STATE_FAILED: { ErrorCount[pParam->type]++; m_lstFailedItems.push_back(pParam->pItem); goto FAIL; } case AsynchDownload::STATE_ABORTED: { // user cancel goto FAIL; } default: ERROR3("Error or unrecognized state"); goto FAIL; } FAIL: FailAndDiscard(); END: // Thumb downloads occur in "bursts", so we report errors only once per burst if (InstanceCount[pParam->type] == 1 && ErrorCount[pParam->type]) { String_256 strErrorMsg; if (ThumbsDownloaded[pParam->type]) // partial failure strErrorMsg.MakeMsg(_R(IDS_THUMBDOWNLOADPARTIALFAIL), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GETX_CAPTIONS))); else // complete failure... strErrorMsg.MakeMsg(_R(IDS_THUMBDOWNLOADFAILED), (TCHAR*) (String_256) GetStringField((UINT32) pParam->type, _R(IDS_GETX_CAPTIONS))); // As something went wrong (most likely a connection problem) suspend thumb downloading. This means the // user can scroll this gallery without more such error popups. Fixes,with LibraryGallery change, #10471 pGallery->bThumbDownloading = FALSE; Error::SetError(0, strErrorMsg, 0); InformError(); } End(); return FALSE; } /****************************************************************************************** > static INT32 OpThumbDownload::GetLastError(SGLibDisplayItem* pItem) Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - pointer to a SGLibDisplayItem Outputs: - Returns: - an error code (DOWNLOAD_ERROR) if the item got an error while downloading its thumb, 0 otherwise Purpose: - used to decide whether or not we should reattempt a download - if the item got an error no further attempts are made before the error is cleared by the user ******************************************************************************************/ INT32 OpThumbDownload::GetLastError(SGLibDisplayItem* pItem) { if (m_lstFailedItems.empty()) return 0; std::list::iterator listIterator = m_lstFailedItems.begin(); INT32 nListSize = m_lstFailedItems.size(); for (INT32 i = 0; i < nListSize; i++) if (pItem == *listIterator++) return DOWNLOAD_ERROR; return 0; } /****************************************************************************************** > static void OpThumbDownload::ClearErrors() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - Purpose: - resets the error counter and flushes the list of items with download problems, which will allow us to reattempt downloads for these items ******************************************************************************************/ void OpThumbDownload::ClearErrors() { memset(&ErrorCount, 0x00, sizeof(ErrorCount)); if (!m_lstFailedItems.empty()) { std::list::iterator itrBegin = m_lstFailedItems.begin(); std::list::iterator itrEnd = m_lstFailedItems.end(); m_lstFailedItems.erase(itrBegin, itrEnd); // zapp the entire list ERROR3IF(!m_lstFailedItems.empty(), "Warning: failed to empty error list"); } } // OpAsynchFontInstall ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// WebFontInstallParam::WebFontInstallParam() { bIsTemp = FALSE; pGallery = NULL; } WebFontInstallParam::~WebFontInstallParam() { } /******************************************************************************************** > BOOL OpAsynchFontInstall::Init() Author: Adrian_Stoicar (Xara Group Ltd) Created: 4/04/97 Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for an WebFontInstall operation SeeAlso: ******************************************************************************************/ BOOL OpAsynchFontInstall::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_OPASYNCHFONTINSTALL), // String resource ID CC_RUNTIME_CLASS(OpAsynchFontInstall), // Runtime class OPTOKEN_OPASYNCHFONTINSTALL, // Token string DownloadOp::GetState, // GetState function 0, // Help ID 0, // Bubble ID 0, // Resource ID 0 // Control ID ); } /****************************************************************************************** > virtual void OpAsynchFontInstall::OnDownloadSuccess() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - Purpose: - Performs the actual install using the font file just downloaded. ******************************************************************************************/ void OpAsynchFontInstall::OnDownloadSuccess() { // Verify that the pointer is valid & the right type WebFontInstallParam* pInstallParam = (WebFontInstallParam*) pParam; if (!pInstallParam->pGallery || !pInstallParam->pGallery->IsKindOf(CC_RUNTIME_CLASS(FontsSGallery))) { ERROR3("Invalid gallery pointer"); return; } // if we have just downloaded a "pfb" file we need to download the // corresponding .pfm file String_256 FileExt((String_256)pInstallParam->file.GetType()); FileExt.toLower(); if (FileExt == String_256("pfb")) { OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpAsynchFontInstall)); if (pOpDesc != NULL) { BOOL ok = TRUE; WebFontInstallParam* Param = new WebFontInstallParam; ERROR3IF(!Param, "Memory allocation error"); if (!Param) return; // Set up the parameters which we need to download and install the font Param->type = TYPE_FONT; Param->priority = AsynchDownload::PRIORITY_HIGH; Param->pGallery = pInstallParam->pGallery; PathName FileName(pInstallParam->file); FileName.SetType("pfm"); Param->file = FileName; Param->strDescription = pInstallParam->strDescription; Param->strAltDescription = pInstallParam->strAltDescription; // get the url address of the font String_256 URL; UINT32 Count = pInstallParam->strURL.Length() - FileName.GetFileName().Length(); pInstallParam->strURL.Left(&Param->strURL, Count); // add the file name String_256 FName = FileName.GetFileName(); FName.toLower(); Param->strURL += FName; Param->bIsTemp = FALSE; Param->Output = &ok; // Invoke the operation pOpDesc->Invoke((OpParam*) Param); return; } else { ERROR3("Can't find Op descriptor"); } return; } else if (FileExt == String_256("pfm")) pInstallParam->file.SetType(String_256("pfb")); FontsSGallery* pFontsGallery = (FontsSGallery*) pInstallParam->pGallery; // the cast should be safe at this point String_64 SlowJob; SlowJob.MakeMsg(_R(IDS_FONTS_INSTALLING), (TCHAR*) pInstallParam->strAltDescription); BeginSlowJob(-1, FALSE, &SlowJob); FontsSGallery::DontUpdate = TRUE; BOOL ok = pFontsGallery->InstallFont(&pInstallParam->file, &pInstallParam->strDescription, pInstallParam->bIsTemp); FontsSGallery::DontUpdate = FALSE; EndSlowJob(); if (!ok) { // Problems installing a specified font String_256 ErrMsg; ErrMsg.MakeMsg(_R(IDS_PROBLEMS_INSTALLING), (TCHAR *) pInstallParam->strAltDescription); Error::SetError(0, ErrMsg, 0); InformError(); Error::ClearError(); } else { // Warn everyone that the fonts have changed - and update our gallery SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); } // remove the temporary font file DownloadCache::RemoveFile((String_256) pInstallParam->file.GetPath()); pFontsGallery->SelectionHasChanged(); } // OpAsynchBitmapImport ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AsynchBitmapImportParam::AsynchBitmapImportParam() { pTargetDoc = 0; TagObjectToFill = 0; TagObjectValid = false; pObject = 0; pObjectValid = false; } /******************************************************************************************** > BOOL OpAsynchBitmapImport::Init() Author: Adrian_Stoicar (Xara Group Ltd) Created: 4/04/97 Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for an AsynchBitmapImport operation SeeAlso: ******************************************************************************************/ BOOL OpAsynchBitmapImport::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_OPASYNCHBITMAPIMPORT), // String resource ID CC_RUNTIME_CLASS(OpAsynchBitmapImport), // Runtime class OPTOKEN_ASYNCHBITMAPIMPORT, // Token string DownloadOp::GetState, // GetState function 0, // Help ID 0, // Bubble ID 0, // Resource ID 0 // Control ID ); } /****************************************************************************************** > virtual void OpAsynchBitmapImport::OnDownloadSuccess() Author: Adrian_Stoicar (Xara Group Ltd) Created: 7/01/97 Inputs: - Outputs: - Returns: - Purpose: - Performs - if required - the actual import using the bitmap file just downloaded. ******************************************************************************************/ void OpAsynchBitmapImport::OnDownloadSuccess() { AsynchBitmapImportParam* pImportParam = (AsynchBitmapImportParam*) pParam; OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpBitmapImport)); if (pOpDesc != 0) { BitmapImportParam Param; Param.File = &pImportParam->file; Param.Result = TRUE; Param.FillType = pImportParam->FillType; Param.pTargetDoc = pImportParam->pTargetDoc; Param.TagObjectToFill = pImportParam->TagObjectToFill; Param.TagObjectValid = pImportParam->TagObjectValid; Param.pObject = pImportParam->pObject; Param.pObjectValid = pImportParam->pObjectValid; Param.pSpread = pImportParam->pSpread; Param.DropPos = pImportParam->DropPos; // Do it... pOpDesc->Invoke((OpParam *) &Param); if (!Param.Result) ERROR3("Problem importing file from internet"); } } /****************************************************************************************** > BOOL OpAsynchBitmapImport::OnDocChangingMsg(Document* pChangingDoc, DocChangingMsg::DocState State) Author: Adrian_Stoicar (Xara Group Ltd) Created: 12/01/97 Returns: - Purpose: Notifies us if the document we intend to import into is about to be destroyed, in which case we should abort the operation SeeAlso: MessageHandler::OnDocChangingMsg() ******************************************************************************************/ BOOL OpAsynchBitmapImport::OnDocChangingMsg(Document* pChangingDoc, DocChangingMsg::DocState State) { AsynchBitmapImportParam* pImportParam = (AsynchBitmapImportParam*) pParam; if (pChangingDoc == pImportParam->pTargetDoc && State == DocChangingMsg::ABOUTTODIE) { // We end the operation, but don't abort the clipart download - it's up to the user to do that FailAndExecute(); End(); } return TRUE; }