344 lines
10 KiB
C++
344 lines
10 KiB
C++
/**
|
|
* @file lldonotdisturbnotificationstorage.cpp
|
|
* @brief Implementation of lldonotdisturbnotificationstorage
|
|
* @author Stinson@lindenlab.com
|
|
*
|
|
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2012, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "lldonotdisturbnotificationstorage.h"
|
|
|
|
#include "llcommunicationchannel.h"
|
|
#include "lldir.h"
|
|
#include "llerror.h"
|
|
#include "llfloaterreg.h"
|
|
#include "llimview.h"
|
|
#include "llnotifications.h"
|
|
#include "llnotificationhandler.h"
|
|
#include "llnotificationstorage.h"
|
|
#include "llscriptfloater.h"
|
|
#include "llsd.h"
|
|
#include "llsingleton.h"
|
|
#include "lluuid.h"
|
|
|
|
static const F32 DND_TIMER = 3.0;
|
|
const char * LLDoNotDisturbNotificationStorage::toastName = "IMToast";
|
|
const char * LLDoNotDisturbNotificationStorage::offerName = "UserGiveItem";
|
|
|
|
LLDoNotDisturbNotificationStorageTimer::LLDoNotDisturbNotificationStorageTimer() : LLEventTimer(DND_TIMER)
|
|
{
|
|
|
|
}
|
|
|
|
LLDoNotDisturbNotificationStorageTimer::~LLDoNotDisturbNotificationStorageTimer()
|
|
{
|
|
|
|
}
|
|
|
|
BOOL LLDoNotDisturbNotificationStorageTimer::tick()
|
|
{
|
|
LLDoNotDisturbNotificationStorage * doNotDisturbNotificationStorage = LLDoNotDisturbNotificationStorage::getInstance();
|
|
|
|
if(doNotDisturbNotificationStorage
|
|
&& doNotDisturbNotificationStorage->getDirty())
|
|
{
|
|
doNotDisturbNotificationStorage->saveNotifications();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage()
|
|
: LLSingleton<LLDoNotDisturbNotificationStorage>()
|
|
, LLNotificationStorage("")
|
|
, mDirty(false)
|
|
{
|
|
nameToPayloadParameterMap[toastName] = "SESSION_ID";
|
|
nameToPayloadParameterMap[offerName] = "object_id";
|
|
}
|
|
|
|
LLDoNotDisturbNotificationStorage::~LLDoNotDisturbNotificationStorage()
|
|
{
|
|
}
|
|
|
|
void LLDoNotDisturbNotificationStorage::initialize()
|
|
{
|
|
setFileName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml"));
|
|
getCommunicationChannel()->connectFailedFilter(boost::bind(&LLDoNotDisturbNotificationStorage::onChannelChanged, this, _1));
|
|
}
|
|
|
|
bool LLDoNotDisturbNotificationStorage::getDirty()
|
|
{
|
|
return mDirty;
|
|
}
|
|
|
|
void LLDoNotDisturbNotificationStorage::resetDirty()
|
|
{
|
|
mDirty = false;
|
|
}
|
|
|
|
static LLTrace::BlockTimerStatHandle FTM_SAVE_DND_NOTIFICATIONS("Save DND Notifications");
|
|
|
|
void LLDoNotDisturbNotificationStorage::saveNotifications()
|
|
{
|
|
LL_RECORD_BLOCK_TIME(FTM_SAVE_DND_NOTIFICATIONS);
|
|
|
|
LLNotificationChannelPtr channelPtr = getCommunicationChannel();
|
|
const LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
|
|
llassert(commChannel != NULL);
|
|
|
|
LLSD output = LLSD::emptyMap();
|
|
LLSD& data = output["data"];
|
|
data = LLSD::emptyArray();
|
|
|
|
for (LLCommunicationChannel::history_list_t::const_iterator historyIter = commChannel->beginHistory();
|
|
historyIter != commChannel->endHistory(); ++historyIter)
|
|
{
|
|
LLNotificationPtr notificationPtr = historyIter->second;
|
|
|
|
if (!notificationPtr->isRespondedTo() && !notificationPtr->isCancelled() &&
|
|
!notificationPtr->isExpired() && !notificationPtr->isPersistent())
|
|
{
|
|
data.append(notificationPtr->asLLSD(true));
|
|
}
|
|
}
|
|
|
|
writeNotifications(output);
|
|
|
|
resetDirty();
|
|
}
|
|
|
|
static LLTrace::BlockTimerStatHandle FTM_LOAD_DND_NOTIFICATIONS("Load DND Notifications");
|
|
|
|
void LLDoNotDisturbNotificationStorage::loadNotifications()
|
|
{
|
|
LL_RECORD_BLOCK_TIME(FTM_LOAD_DND_NOTIFICATIONS);
|
|
|
|
LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL;
|
|
|
|
LLSD input;
|
|
if (!readNotifications(input) ||input.isUndefined())
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLSD& data = input["data"];
|
|
if (data.isUndefined())
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLNotifications& instance = LLNotifications::instance();
|
|
bool imToastExists = false;
|
|
bool group_ad_hoc_toast_exists = false;
|
|
S32 toastSessionType;
|
|
bool offerExists = false;
|
|
|
|
for (LLSD::array_const_iterator notification_it = data.beginArray();
|
|
notification_it != data.endArray();
|
|
++notification_it)
|
|
{
|
|
LLSD notification_params = *notification_it;
|
|
const LLUUID& notificationID = notification_params["id"];
|
|
std::string notificationName = notification_params["name"];
|
|
LLNotificationPtr notification = instance.find(notificationID);
|
|
|
|
if(notificationName == toastName)
|
|
{
|
|
toastSessionType = notification_params["payload"]["SESSION_TYPE"];
|
|
if(toastSessionType == LLIMModel::LLIMSession::P2P_SESSION)
|
|
{
|
|
imToastExists = true;
|
|
}
|
|
//Don't add group/ad-hoc messages to the notification system because
|
|
//this means the group/ad-hoc session has to be re-created
|
|
else if(toastSessionType == LLIMModel::LLIMSession::GROUP_SESSION
|
|
|| toastSessionType == LLIMModel::LLIMSession::ADHOC_SESSION)
|
|
{
|
|
//Just allows opening the conversation log for group/ad-hoc messages upon startup
|
|
group_ad_hoc_toast_exists = true;
|
|
continue;
|
|
}
|
|
}
|
|
else if(notificationName == offerName)
|
|
{
|
|
offerExists = true;
|
|
}
|
|
|
|
//Notification already exists due to persistent storage adding it first into the notification system
|
|
if(notification)
|
|
{
|
|
notification->setDND(true);
|
|
instance.update(instance.find(notificationID));
|
|
}
|
|
//New notification needs to be added
|
|
else
|
|
{
|
|
notification = (LLNotificationPtr) new LLNotification(notification_params.with("is_dnd", true));
|
|
LLNotificationResponderInterface* responder = createResponder(notification_params["responder_sd"]["responder_type"], notification_params["responder_sd"]);
|
|
if (responder == NULL)
|
|
{
|
|
LL_WARNS("LLDoNotDisturbNotificationStorage") << "cannot create responder for notification of type '"
|
|
<< notification->getType() << "'" << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
LLNotificationResponderPtr responderPtr(responder);
|
|
notification->setResponseFunctor(responderPtr);
|
|
}
|
|
|
|
instance.add(notification);
|
|
}
|
|
|
|
}
|
|
|
|
bool isConversationLoggingAllowed = gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0;
|
|
if(group_ad_hoc_toast_exists && isConversationLoggingAllowed)
|
|
{
|
|
LLFloaterReg::showInstance("conversation");
|
|
}
|
|
|
|
if(imToastExists || group_ad_hoc_toast_exists || offerExists)
|
|
{
|
|
make_ui_sound_deferred("UISndNewIncomingIMSession");
|
|
}
|
|
|
|
//writes out empty .xml file (since LLCommunicationChannel::mHistory is empty)
|
|
saveNotifications();
|
|
|
|
LL_INFOS("LLDoNotDisturbNotificationStorage") << "finished loading notifications" << LL_ENDL;
|
|
}
|
|
|
|
void LLDoNotDisturbNotificationStorage::updateNotifications()
|
|
{
|
|
|
|
LLNotificationChannelPtr channelPtr = getCommunicationChannel();
|
|
LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
|
|
llassert(commChannel != NULL);
|
|
|
|
LLNotifications& instance = LLNotifications::instance();
|
|
bool imToastExists = false;
|
|
bool offerExists = false;
|
|
|
|
for (LLCommunicationChannel::history_list_t::const_iterator it = commChannel->beginHistory();
|
|
it != commChannel->endHistory();
|
|
++it)
|
|
{
|
|
LLNotificationPtr notification = it->second;
|
|
std::string notificationName = notification->getName();
|
|
|
|
if(notificationName == toastName)
|
|
{
|
|
imToastExists = true;
|
|
}
|
|
else if(notificationName == offerName)
|
|
{
|
|
offerExists = true;
|
|
}
|
|
|
|
//Notification already exists in notification pipeline (same instance of app running)
|
|
if (notification)
|
|
{
|
|
notification->setDND(true);
|
|
instance.update(notification);
|
|
}
|
|
}
|
|
|
|
if(imToastExists || offerExists)
|
|
{
|
|
make_ui_sound("UISndNewIncomingIMSession");
|
|
}
|
|
|
|
//When exit DND mode, write empty notifications file
|
|
if(commChannel->getHistorySize())
|
|
{
|
|
commChannel->clearHistory();
|
|
saveNotifications();
|
|
}
|
|
}
|
|
|
|
LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChannel() const
|
|
{
|
|
LLNotificationChannelPtr channelPtr = LLNotifications::getInstance()->getChannel("Communication");
|
|
llassert(channelPtr);
|
|
return channelPtr;
|
|
}
|
|
|
|
void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, const LLUUID& id)
|
|
{
|
|
LLNotifications& instance = LLNotifications::instance();
|
|
LLNotificationChannelPtr channelPtr = getCommunicationChannel();
|
|
LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get());
|
|
LLNotificationPtr notification;
|
|
LLSD payload;
|
|
LLUUID notificationObjectID;
|
|
std::string notificationName;
|
|
std::string payloadVariable = nameToPayloadParameterMap[name];
|
|
LLCommunicationChannel::history_list_t::iterator it;
|
|
std::vector<LLCommunicationChannel::history_list_t::iterator> itemsToRemove;
|
|
|
|
//Find notification with the matching session id
|
|
for (it = commChannel->beginHistory();
|
|
it != commChannel->endHistory();
|
|
++it)
|
|
{
|
|
notification = it->second;
|
|
payload = notification->getPayload();
|
|
notificationObjectID = payload[payloadVariable].asUUID();
|
|
notificationName = notification->getName();
|
|
|
|
if((notificationName == name)
|
|
&& id == notificationObjectID)
|
|
{
|
|
itemsToRemove.push_back(it);
|
|
}
|
|
}
|
|
|
|
|
|
//Remove the notifications
|
|
if(itemsToRemove.size())
|
|
{
|
|
while(itemsToRemove.size())
|
|
{
|
|
it = itemsToRemove.back();
|
|
notification = it->second;
|
|
commChannel->removeItemFromHistory(notification);
|
|
instance.cancel(notification);
|
|
itemsToRemove.pop_back();
|
|
}
|
|
//Trigger saving of notifications to xml once all have been removed
|
|
saveNotifications();
|
|
}
|
|
}
|
|
|
|
|
|
bool LLDoNotDisturbNotificationStorage::onChannelChanged(const LLSD& pPayload)
|
|
{
|
|
if (pPayload["sigtype"].asString() != "load")
|
|
{
|
|
mDirty = true;
|
|
}
|
|
|
|
return false;
|
|
}
|