phoenix-firestorm/indra/newview/llfloaterscriptrecover.cpp

362 lines
12 KiB
C++

/**
*
* Copyright (c) 2011-2012, Kitty Barnett
*
* The source code in this file is provided to you under the terms of the
* GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
* in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
*
* By copying, modifying or distributing this software, you acknowledge that
* you have read and understood your obligations described above, and agree to
* abide by those obligations.
*
*/
#include "llviewerprecompiledheaders.h"
#include "llagent.h"
#include "llcheckboxctrl.h"
#include "lldiriterator.h"
#include "llfloaterreg.h"
#include "llfolderview.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llinventorypanel.h"
#include "llscrolllistctrl.h"
#include "lltrans.h"
#include "llviewerassettype.h"
#include "llviewerinventory.h"
#include "llviewerregion.h"
#include "llfloaterscriptrecover.h"
#include "llviewerassetupload.h"
const std::string NEW_LSL_NAME = "New Script";
std::string fixNewScriptDefaultName(const std::string& scriptName)
{
std::string fixedScriptName = scriptName;
if (scriptName == NEW_LSL_NAME)
{
LLStringUtil::replaceChar(fixedScriptName, ' ', '_');
}
return fixedScriptName;
}
// ============================================================================
// LLFloaterScriptRecover
//
LLFloaterScriptRecover::LLFloaterScriptRecover(const LLSD& sdKey)
: LLFloater(sdKey)
{
}
void LLFloaterScriptRecover::onOpen(const LLSD& sdKey)
{
LLScrollListCtrl* pListCtrl = findChild<LLScrollListCtrl>("script_list");
LLSD sdBhvrRow; LLSD& sdBhvrColumns = sdBhvrRow["columns"];
sdBhvrColumns[0] = LLSD().with("column", "script_check").with("type", "checkbox");
sdBhvrColumns[1] = LLSD().with("column", "script_name").with("type", "text");
pListCtrl->clearRows();
for (LLSD::array_const_iterator itFile = sdKey["files"].beginArray(), endFile = sdKey["files"].endArray();
itFile != endFile; ++itFile)
{
const LLSD& sdFile = *itFile;
sdBhvrRow["value"] = sdFile;
sdBhvrColumns[0]["value"] = true;
sdBhvrColumns[1]["value"] = sdFile["name"];
pListCtrl->addElement(sdBhvrRow, ADD_BOTTOM);
}
}
bool LLFloaterScriptRecover::postBuild()
{
findChild<LLUICtrl>("recover_btn")->setCommitCallback(boost::bind(&LLFloaterScriptRecover::onBtnRecover, this));
findChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterScriptRecover::onBtnCancel, this));
return true;
}
void LLFloaterScriptRecover::onBtnCancel()
{
LLScrollListCtrl* pListCtrl = findChild<LLScrollListCtrl>("script_list");
// Delete all listed files
std::vector<LLScrollListItem*> items = pListCtrl->getAllData();
for (std::vector<LLScrollListItem*>::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
{
LLFile::remove((*itItem)->getValue().asString());
}
closeFloater();
}
void LLFloaterScriptRecover::onBtnRecover()
{
LLScrollListCtrl* pListCtrl = findChild<LLScrollListCtrl>("script_list");
// Recover all selected, delete any unselected
std::vector<LLScrollListItem*> items = pListCtrl->getAllData(); LLSD sdFiles;
for (std::vector<LLScrollListItem*>::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
{
LLScrollListCheck* pCheckColumn = dynamic_cast<LLScrollListCheck*>((*itItem)->getColumn(0));
if (!pCheckColumn)
continue;
const LLSD sdFile = (*itItem)->getValue();
if (pCheckColumn->getCheckBox()->getValue().asBoolean())
sdFiles.append(sdFile);
else
LLFile::remove(sdFile["path"]);
}
if (!sdFiles.emptyArray())
new LLScriptRecoverQueue(sdFiles);
closeFloater();
}
// ============================================================================
// LLCreateRecoverScriptCallback
//
class LLCreateRecoverScriptCallback : public LLInventoryCallback
{
public:
LLCreateRecoverScriptCallback(LLScriptRecoverQueue* pRecoverQueue)
: LLInventoryCallback(), mRecoverQueue(pRecoverQueue)
{
}
void fire(const LLUUID& idItem)
{
mRecoverQueue->onCreateScript(idItem);
}
protected:
LLScriptRecoverQueue* mRecoverQueue;
};
// ============================================================================
// LLScriptRecoverQueue
//
// static
void LLScriptRecoverQueue::recoverIfNeeded()
{
const std::string strTempPath = LLFile::tmpdir();
LLSD sdData, &sdFiles = sdData["files"];
LLDirIterator itFiles(strTempPath, "*.lslbackup"); std::string strFilename;
while (itFiles.next(strFilename))
{
// Build a friendly name for the file
std::string strName = gDirUtilp->getBaseFileName(strFilename, true);
std::string agent_id_str = gAgentID.asString();
LLStringUtil::replaceString(agent_id_str, "-", "");
std::string::size_type agent_delim_offset = strName.find_first_of("_");
if (agent_delim_offset != std::string::npos && agent_delim_offset != 0)
{
std::string file_agent_id_str = strName.substr(0, agent_delim_offset);
if (file_agent_id_str != agent_id_str)
{
continue;
}
else
{
strName.erase(0, agent_delim_offset + 1);
}
}
std::string::size_type offset = strName.find_last_of("-");
if ( (std::string::npos != offset) && (offset != 0) && (offset == strName.length() - 9))
strName.erase(strName.length() - 9);
LLStringUtil::trim(strName);
if (0 == strName.length())
strName = LLTrans::getString("unknown_script");
sdFiles.append(LLSD().with("path", strTempPath + strFilename).with("name", strName));
}
LL_INFOS() << "Checking for recoverable scripts. Found: " << sdFiles.size() << LL_ENDL;
if (sdFiles.size())
LLFloaterReg::showInstance("script_recover", sdData);
}
LLScriptRecoverQueue::LLScriptRecoverQueue(const LLSD& sdFiles)
{
for (LLSD::array_const_iterator itFile = sdFiles.beginArray(), endFile = sdFiles.endArray(); itFile != endFile; ++itFile)
{
const LLSD& sdFile = *itFile;
if (LLFile::isfile(sdFile["path"]))
m_FileQueue.insert(std::pair<std::string, LLSD>(sdFile["path"], sdFile));
}
recoverNext();
}
bool LLScriptRecoverQueue::recoverNext()
{
/**
* Steps:
* (1) create a script inventory item under Lost and Found
* (2) once we have the item's UUID we can upload the script
* (3) once the script is uploaded we move on to the next item
*/
const LLUUID idFNF = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
// Sanity check - if the associated UUID is non-null then this file is already being processed
filename_queue_t::const_iterator itFile = m_FileQueue.begin();
while ( (itFile != m_FileQueue.end()) && (itFile->second.has("item")) && (itFile->second["item"].asUUID().notNull()) )
++itFile;
if (m_FileQueue.end() == itFile)
{
LLInventoryPanel* pInvPanel = LLInventoryPanel::getActiveInventoryPanel(true);
LLFolderViewFolder* pFVF = dynamic_cast<LLFolderViewFolder*>(pInvPanel ? pInvPanel->getItemByID(idFNF) : NULL);
if (pFVF)
{
pFVF->setOpenArrangeRecursively(true, LLFolderViewFolder::RECURSE_UP);
pInvPanel->setSelection(idFNF, true);
}
delete this;
return false;
}
std::string strItemDescr;
LLViewerAssetType::generateDescriptionFor(LLAssetType::AT_LSL_TEXT, strItemDescr);
// Ansariel: Need to work around a bug preventing us from creating a
// script with the default name for new scripts
std::string strScriptName = fixNewScriptDefaultName(itFile->second["name"].asString());
create_inventory_item(gAgent.getID(), gAgent.getSessionID(), idFNF, LLTransactionID::tnull,
strScriptName, strItemDescr, LLAssetType::AT_LSL_TEXT, LLInventoryType::IT_LSL,
NO_INV_SUBTYPE, PERM_MOVE | PERM_TRANSFER, new LLCreateRecoverScriptCallback(this));
return true;
}
void LLScriptRecoverQueue::onCreateScript(const LLUUID& idItem)
{
const LLViewerInventoryItem* pItem = gInventory.getItem(idItem);
if (!pItem)
{
// TODO: error handling
return;
}
std::string strFileName;
std::string strFilePath;
for (filename_queue_t::iterator itFile = m_FileQueue.begin(); itFile != m_FileQueue.end(); ++itFile)
{
if (fixNewScriptDefaultName(itFile->second["name"].asString()) != pItem->getName())
continue;
strFileName = itFile->second["path"].asString();
itFile->second["item"] = idItem;
strFilePath = itFile->first;
break;
}
std::string strCapsUrl = gAgent.getRegionCapability("UpdateScriptAgent");
if (!strCapsUrl.empty())
{
std::string buffer;
llstat stat;
if (0 == LLFile::stat(strFilePath, &stat) && stat.st_size > 0)
{
buffer.resize(stat.st_size);
LLFILE *pFile = LLFile::fopen(strFileName, "rb");
if (pFile)
{
size_t act_read = fread(&buffer[0], 1, stat.st_size, pFile);
if (act_read != stat.st_size)
{
LL_WARNS() << "Incomplete read of " << strFilePath << ": File size = " << stat.st_size << " - bytes read: " << act_read << LL_ENDL;
buffer = "";
}
LLFile::close(pFile);
}
else
{
buffer = "";
LL_WARNS() << "Cannot open " << strFilePath << LL_ENDL;
}
}
else
{
LL_WARNS() << "No access to " << strFilePath << LL_ENDL;
}
LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLScriptRecoverQueue::onSavedScript, this, _1, _2, _3, _4);
LLResourceUploadInfo::ptr_t uploadInfo(new LLScriptAssetUpload(idItem, buffer, proc, nullptr));
LLViewerAssetUpload::EnqueueInventoryUpload(strCapsUrl, uploadInfo);
}
else
{
LL_WARNS() << "Cannot recover script - no UpdateScriptAgent cap!" << LL_ENDL;
}
}
void LLScriptRecoverQueue::onSavedScript(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response)
{
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD( response[ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ] );
filename_queue_t::iterator itFile = m_FileQueue.begin();
while ( (itFile != m_FileQueue.end()) && ((!itFile->second.has("item")) || (itFile->second["item"].asUUID() != itemId)) )
++itFile;
if (itFile == m_FileQueue.end())
{
LL_WARNS() << "Unknown file" << LL_ENDL;
return;
}
if( HTTP_OK == status.getType() )
{
LL_INFOS() << "Recovered script uploaded successfully" << LL_ENDL;
LLPointer<LLViewerInventoryItem> pItem = gInventory.getItem(itemId);
if (pItem.notNull())
{
// Ansariel: Rename back scripts with default name
std::string strScriptName = itFile->second["name"].asString();
if (strScriptName == NEW_LSL_NAME)
{
LLPointer<LLViewerInventoryItem> pNewItem = new LLViewerInventoryItem(pItem);
pNewItem->rename(strScriptName);
pNewItem->updateServer(false);
gInventory.updateItem(pNewItem);
gInventory.notifyObservers();
}
LLFile::remove(itFile->first);
m_FileQueue.erase(itFile);
}
}
else
{
LL_WARNS() << "Recovered script upload FAILED" << LL_ENDL;
LLViewerInventoryItem* pItem = gInventory.getItem( itemId );
if (pItem)
gInventory.changeItemParent(pItem, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH), false);
m_FileQueue.erase(itFile);
}
recoverNext();
}
// ============================================================================