682 lines
22 KiB
C++
682 lines
22 KiB
C++
/**
|
|
* @file llconversationlog.h
|
|
*
|
|
* $LicenseInfo:firstyear=2002&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 "llagent.h"
|
|
#include "llavatarnamecache.h"
|
|
#include "llconversationlog.h"
|
|
#include "lldiriterator.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "lltrans.h"
|
|
// <FS:CR>
|
|
#include "llviewercontrol.h"
|
|
#include "fsfloaterim.h"
|
|
// </FS:CR>
|
|
|
|
#include "boost/lexical_cast.hpp"
|
|
|
|
// <FS:CR> Commenting out, let the user decide
|
|
//const S32Days CONVERSATION_LIFETIME = (S32Days)30; // lifetime of LLConversation is 30 days by spec
|
|
|
|
struct ConversationParams : public LLInitParam::Block<ConversationParams>
|
|
{
|
|
Mandatory<U64Seconds > time;
|
|
Mandatory<std::string> timestamp;
|
|
Mandatory<SessionType> conversation_type;
|
|
Mandatory<std::string> conversation_name,
|
|
history_filename;
|
|
Mandatory<LLUUID> session_id,
|
|
participant_id;
|
|
Mandatory<bool> has_offline_ims;
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* LLConversation implementation */
|
|
/************************************************************************/
|
|
|
|
LLConversation::LLConversation(const ConversationParams& params)
|
|
: mTime(params.time),
|
|
mTimestamp(params.timestamp.isProvided() ? params.timestamp : createTimestamp(params.time)),
|
|
mConversationType(params.conversation_type),
|
|
mConversationName(params.conversation_name),
|
|
mHistoryFileName(params.history_filename),
|
|
mSessionID(params.session_id),
|
|
mParticipantID(params.participant_id),
|
|
mHasOfflineIMs(params.has_offline_ims)
|
|
{
|
|
setListenIMFloaterOpened();
|
|
}
|
|
|
|
LLConversation::LLConversation(const LLIMModel::LLIMSession& session)
|
|
: mTime(time_corrected()),
|
|
mTimestamp(createTimestamp(mTime)),
|
|
mConversationType(session.mSessionType),
|
|
mConversationName(session.mName),
|
|
mHistoryFileName(session.mHistoryFileName),
|
|
mSessionID(session.isOutgoingAdHoc() ? session.generateOutgoingAdHocHash() : session.mSessionID),
|
|
mParticipantID(session.mOtherParticipantID),
|
|
mHasOfflineIMs(session.mHasOfflineMessage)
|
|
{
|
|
setListenIMFloaterOpened();
|
|
}
|
|
|
|
LLConversation::LLConversation(const LLConversation& conversation)
|
|
{
|
|
mTime = conversation.getTime();
|
|
mTimestamp = conversation.getTimestamp();
|
|
mConversationType = conversation.getConversationType();
|
|
mConversationName = conversation.getConversationName();
|
|
mHistoryFileName = conversation.getHistoryFileName();
|
|
mSessionID = conversation.getSessionID();
|
|
mParticipantID = conversation.getParticipantID();
|
|
mHasOfflineIMs = conversation.hasOfflineMessages();
|
|
|
|
setListenIMFloaterOpened();
|
|
}
|
|
|
|
LLConversation::~LLConversation()
|
|
{
|
|
mIMFloaterShowedConnection.disconnect();
|
|
}
|
|
|
|
void LLConversation::updateTimestamp()
|
|
{
|
|
mTime = (U64Seconds)time_corrected();
|
|
mTimestamp = createTimestamp(mTime);
|
|
}
|
|
|
|
void LLConversation::onIMFloaterShown(const LLUUID& session_id)
|
|
{
|
|
if (mSessionID == session_id)
|
|
{
|
|
mHasOfflineIMs = false;
|
|
}
|
|
}
|
|
|
|
// static
|
|
const std::string LLConversation::createTimestamp(const U64Seconds& utc_time)
|
|
{
|
|
std::string timeStr;
|
|
LLSD substitution;
|
|
substitution["datetime"] = (S32)utc_time.value();
|
|
|
|
timeStr = "["+LLTrans::getString ("TimeMonth")+"]/["
|
|
+LLTrans::getString ("TimeDay")+"]/["
|
|
+LLTrans::getString ("TimeYear")+"] ["
|
|
+LLTrans::getString ("TimeHour")+"]:["
|
|
+LLTrans::getString ("TimeMin")+"]";
|
|
|
|
|
|
LLStringUtil::format (timeStr, substitution);
|
|
return timeStr;
|
|
}
|
|
|
|
bool LLConversation::isOlderThan(U32Days days) const
|
|
{
|
|
U64Seconds now(time_corrected());
|
|
U32Days age = now - mTime;
|
|
|
|
return age > days;
|
|
}
|
|
|
|
void LLConversation::setListenIMFloaterOpened()
|
|
{
|
|
// <FS:CR> [Firestorm Communications UI]
|
|
//LLFloaterIMSession* floater = LLFloaterIMSession::findInstance(mSessionID);
|
|
FSFloaterIM* floater = FSFloaterIM::findInstance(mSessionID);
|
|
|
|
//bool offline_ims_visible = LLFloaterIMSession::isVisible(floater) && floater->hasFocus();
|
|
bool offline_ims_visible = FSFloaterIM::isVisible(floater) && floater->hasFocus();
|
|
|
|
// we don't need to listen for im floater with this conversation is opened
|
|
// if floater is already opened or this conversation doesn't have unread offline messages
|
|
if (mHasOfflineIMs && !offline_ims_visible)
|
|
{
|
|
//mIMFloaterShowedConnection = LLFloaterIMSession::setIMFloaterShowedCallback(boost::bind(&LLConversation::onIMFloaterShown, this, _1));
|
|
mIMFloaterShowedConnection = FSFloaterIM::setIMFloaterShowedCallback(boost::bind(&LLConversation::onIMFloaterShown, this, _1));
|
|
// </FS:CR>
|
|
}
|
|
else
|
|
{
|
|
mHasOfflineIMs = false;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* LLConversationLogFriendObserver implementation */
|
|
/************************************************************************/
|
|
|
|
// Note : An LLSingleton like LLConversationLog cannot be an LLFriendObserver
|
|
// at the same time.
|
|
// This is because avatar observers are deleted by the observed object which
|
|
// conflicts with the way LLSingleton are deleted.
|
|
|
|
class LLConversationLogFriendObserver : public LLFriendObserver
|
|
{
|
|
public:
|
|
LLConversationLogFriendObserver() {}
|
|
virtual ~LLConversationLogFriendObserver() {}
|
|
virtual void changed(U32 mask);
|
|
};
|
|
|
|
void LLConversationLogFriendObserver::changed(U32 mask)
|
|
{
|
|
if (mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE))
|
|
{
|
|
LLConversationLog::instance().notifyObservers();
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* LLConversationLog implementation */
|
|
/************************************************************************/
|
|
|
|
LLConversationLog::LLConversationLog() :
|
|
mAvatarNameCacheConnection(),
|
|
mLoggingEnabled(false)
|
|
{
|
|
}
|
|
|
|
void LLConversationLog::enableLogging(S32 log_mode)
|
|
{
|
|
mLoggingEnabled = log_mode > 0;
|
|
if (log_mode > 0)
|
|
{
|
|
mConversations.clear();
|
|
loadFromFile(getFileName());
|
|
LLIMMgr::instance().addSessionObserver(this);
|
|
mNewMessageSignalConnection = LLIMModel::instance().addNewMsgCallback(boost::bind(&LLConversationLog::onNewMessageReceived, this, _1));
|
|
|
|
mFriendObserver = new LLConversationLogFriendObserver;
|
|
LLAvatarTracker::instance().addObserver(mFriendObserver);
|
|
}
|
|
else
|
|
{
|
|
saveToFile(getFileName());
|
|
|
|
LLIMMgr::instance().removeSessionObserver(this);
|
|
mNewMessageSignalConnection.disconnect();
|
|
LLAvatarTracker::instance().removeObserver(mFriendObserver);
|
|
}
|
|
|
|
notifyObservers();
|
|
}
|
|
|
|
void LLConversationLog::logConversation(const LLUUID& session_id, bool has_offline_msg)
|
|
{
|
|
const LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
|
|
LLConversation* conversation = findConversation(session);
|
|
|
|
if (session && session->mOtherParticipantID != gAgentID)
|
|
{
|
|
if (conversation)
|
|
{
|
|
if(has_offline_msg)
|
|
{
|
|
updateOfflineIMs(session, has_offline_msg);
|
|
}
|
|
updateConversationTimestamp(conversation);
|
|
}
|
|
else
|
|
{
|
|
createConversation(session);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::createConversation(const LLIMModel::LLIMSession* session)
|
|
{
|
|
if (session)
|
|
{
|
|
LLConversation conversation(*session);
|
|
mConversations.push_back(conversation);
|
|
|
|
if (LLIMModel::LLIMSession::P2P_SESSION == session->mSessionType)
|
|
{
|
|
if (mAvatarNameCacheConnection.connected())
|
|
{
|
|
mAvatarNameCacheConnection.disconnect();
|
|
}
|
|
mAvatarNameCacheConnection = LLAvatarNameCache::get(session->mOtherParticipantID, boost::bind(&LLConversationLog::onAvatarNameCache, this, _1, _2, session));
|
|
}
|
|
|
|
notifyObservers();
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::updateConversationName(const LLIMModel::LLIMSession* session, const std::string& name)
|
|
{
|
|
if (!session)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLConversation* conversation = findConversation(session);
|
|
if (conversation)
|
|
{
|
|
conversation->setConversationName(name);
|
|
notifyParticularConversationObservers(conversation->getSessionID(), LLConversationLogObserver::CHANGED_NAME);
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::updateOfflineIMs(const LLIMModel::LLIMSession* session, bool new_messages)
|
|
{
|
|
if (!session)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLConversation* conversation = findConversation(session);
|
|
if (conversation)
|
|
{
|
|
conversation->setOfflineMessages(new_messages);
|
|
notifyParticularConversationObservers(conversation->getSessionID(), LLConversationLogObserver::CHANGED_OfflineIMs);
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::updateConversationTimestamp(LLConversation* conversation)
|
|
{
|
|
if (conversation)
|
|
{
|
|
conversation->updateTimestamp();
|
|
notifyParticularConversationObservers(conversation->getSessionID(), LLConversationLogObserver::CHANGED_TIME);
|
|
}
|
|
}
|
|
|
|
LLConversation* LLConversationLog::findConversation(const LLIMModel::LLIMSession* session)
|
|
{
|
|
if (session)
|
|
{
|
|
const LLUUID session_id = session->isOutgoingAdHoc() ? session->generateOutgoingAdHocHash() : session->mSessionID;
|
|
|
|
conversations_vec_t::iterator conv_it = mConversations.begin();
|
|
for(; conv_it != mConversations.end(); ++conv_it)
|
|
{
|
|
if (conv_it->getSessionID() == session_id)
|
|
{
|
|
return &*conv_it;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void LLConversationLog::removeConversation(const LLConversation& conversation)
|
|
{
|
|
conversations_vec_t::iterator conv_it = mConversations.begin();
|
|
for(; conv_it != mConversations.end(); ++conv_it)
|
|
{
|
|
if (conv_it->getSessionID() == conversation.getSessionID() && conv_it->getTime() == conversation.getTime())
|
|
{
|
|
mConversations.erase(conv_it);
|
|
notifyObservers();
|
|
cache();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
const LLConversation* LLConversationLog::getConversation(const LLUUID& session_id)
|
|
{
|
|
conversations_vec_t::const_iterator conv_it = mConversations.begin();
|
|
for(; conv_it != mConversations.end(); ++conv_it)
|
|
{
|
|
if (conv_it->getSessionID() == session_id)
|
|
{
|
|
return &*conv_it;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void LLConversationLog::addObserver(LLConversationLogObserver* observer)
|
|
{
|
|
mObservers.insert(observer);
|
|
}
|
|
|
|
void LLConversationLog::removeObserver(LLConversationLogObserver* observer)
|
|
{
|
|
mObservers.erase(observer);
|
|
}
|
|
|
|
void LLConversationLog::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg)
|
|
{
|
|
logConversation(session_id, has_offline_msg);
|
|
}
|
|
|
|
void LLConversationLog::cache()
|
|
{
|
|
if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0)
|
|
{
|
|
saveToFile(getFileName());
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::getListOfBackupLogs(std::vector<std::string>& list_of_backup_logs)
|
|
{
|
|
// get Users log directory
|
|
std::string dirname = gDirUtilp->getPerAccountChatLogsDir();
|
|
|
|
// add final OS dependent delimiter
|
|
dirname += gDirUtilp->getDirDelimiter();
|
|
|
|
// create search pattern
|
|
std::string pattern = "conversation.log.backup*";
|
|
|
|
LLDirIterator iter(dirname, pattern);
|
|
std::string filename;
|
|
while (iter.next(filename))
|
|
{
|
|
list_of_backup_logs.push_back(gDirUtilp->add(dirname, filename));
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::deleteBackupLogs()
|
|
{
|
|
std::vector<std::string> backup_logs;
|
|
getListOfBackupLogs(backup_logs);
|
|
|
|
for (const std::string& fullpath : backup_logs)
|
|
{
|
|
LLFile::remove(fullpath);
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::verifyFilename(const LLUUID& session_id, const std::string &expected_filename, const std::string &new_session_name)
|
|
{
|
|
conversations_vec_t::iterator conv_it = mConversations.begin();
|
|
for (; conv_it != mConversations.end(); ++conv_it)
|
|
{
|
|
if (conv_it->getSessionID() == session_id)
|
|
{
|
|
if (conv_it->getHistoryFileName() != expected_filename)
|
|
{
|
|
LLLogChat::renameLogFile(conv_it->getHistoryFileName(), expected_filename);
|
|
conv_it->updateHistoryFileName(expected_filename);
|
|
conv_it->setConversationName(new_session_name);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LLConversationLog::moveLog(const std::string &originDirectory, const std::string &targetDirectory)
|
|
{
|
|
|
|
std::string backupFileName;
|
|
unsigned backupFileCount = 0;
|
|
|
|
//Does the file exist in the current path, if it does lets move it
|
|
if(LLFile::isfile(originDirectory))
|
|
{
|
|
//The target directory contains that file already, so lets store it
|
|
if(LLFile::isfile(targetDirectory))
|
|
{
|
|
backupFileName = targetDirectory + ".backup";
|
|
|
|
//If needed store backup file as .backup1 etc.
|
|
while(LLFile::isfile(backupFileName))
|
|
{
|
|
++backupFileCount;
|
|
backupFileName = targetDirectory + ".backup" + std::to_string(backupFileCount);
|
|
}
|
|
|
|
//Rename the file to its backup name so it is not overwritten
|
|
LLFile::rename(targetDirectory, backupFileName);
|
|
}
|
|
|
|
//Move the file from the current path to target path
|
|
if(LLFile::rename(originDirectory, targetDirectory) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void LLConversationLog::initLoggingState()
|
|
{
|
|
if (gSavedPerAccountSettings.controlExists("KeepConversationLogTranscripts"))
|
|
{
|
|
LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get();
|
|
S32 log_mode = keep_log_ctrlp->getValue();
|
|
keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2));
|
|
if (log_mode > 0)
|
|
{
|
|
enableLogging(log_mode);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string LLConversationLog::getFileName()
|
|
{
|
|
std::string filename = "conversation";
|
|
std::string log_address = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename);
|
|
if (!log_address.empty())
|
|
{
|
|
log_address += ".log";
|
|
}
|
|
return log_address;
|
|
}
|
|
|
|
bool LLConversationLog::saveToFile(const std::string& filename)
|
|
{
|
|
// <FS:Ansariel> Don't try to access
|
|
if (gDirUtilp->getLindenUserDir().empty())
|
|
{
|
|
LL_INFOS() << "Can't access conversation log - no user directory set yet." << LL_ENDL;
|
|
return false;
|
|
}
|
|
// </FS:Ansariel>
|
|
|
|
if (!filename.size())
|
|
{
|
|
LL_WARNS() << "Call log list filename is empty!" << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
LLFILE* fp = LLFile::fopen(filename, "wb");
|
|
if (!fp)
|
|
{
|
|
LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
std::string participant_id;
|
|
std::string conversation_id;
|
|
|
|
conversations_vec_t::const_iterator conv_it = mConversations.begin();
|
|
for (; conv_it != mConversations.end(); ++conv_it)
|
|
{
|
|
conv_it->getSessionID().toString(conversation_id);
|
|
conv_it->getParticipantID().toString(participant_id);
|
|
|
|
bool is_adhoc = (conv_it->getConversationType() == LLIMModel::LLIMSession::ADHOC_SESSION);
|
|
std::string conv_name = is_adhoc ? conv_it->getConversationName() : LLURI::escape(conv_it->getConversationName());
|
|
std::string file_name = is_adhoc ? conv_it->getHistoryFileName() : LLURI::escape(conv_it->getHistoryFileName());
|
|
|
|
// examples of two file entries
|
|
// [1343221177] 0 1 0 John Doe| 7e4ec5be-783f-49f5-71dz-16c58c64c145 4ec62a74-c246-0d25-2af6-846beac2aa55 john.doe|
|
|
// [1343222639] 2 0 0 Ad-hoc Conference| c3g67c89-c479-4c97-b21d-32869bcfe8rc 68f1c33e-4135-3e3e-a897-8c9b23115c09 Ad-hoc Conference hash597394a0-9982-766d-27b8-c75560213b9a|
|
|
fprintf(fp, "[%lld] %d %d %d %s| %s %s %s|\n",
|
|
(S64)conv_it->getTime().value(),
|
|
(S32)conv_it->getConversationType(),
|
|
(S32)0,
|
|
(S32)conv_it->hasOfflineMessages(),
|
|
conv_name.c_str(),
|
|
participant_id.c_str(),
|
|
conversation_id.c_str(),
|
|
file_name.c_str());
|
|
}
|
|
fclose(fp);
|
|
return true;
|
|
}
|
|
bool LLConversationLog::loadFromFile(const std::string& filename)
|
|
{
|
|
// <FS:Ansariel> Don't try to access
|
|
if (gDirUtilp->getLindenUserDir().empty())
|
|
{
|
|
LL_INFOS() << "Can't access conversation log - no user directory set yet." << LL_ENDL;
|
|
return false;
|
|
}
|
|
// </FS:Ansariel>
|
|
|
|
if(!filename.size())
|
|
{
|
|
LL_WARNS() << "Call log list filename is empty!" << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
LLFILE* fp = LLFile::fopen(filename, "rb");
|
|
if (!fp)
|
|
{
|
|
LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL;
|
|
return false;
|
|
}
|
|
bool purge_required = false;
|
|
|
|
static constexpr int UTF_BUFFER{ 1024 }; // long enough to handle the most extreme Unicode nonsense and some to spare
|
|
|
|
char buffer[UTF_BUFFER];
|
|
char conv_name_buffer[MAX_STRING];
|
|
char part_id_buffer[MAX_STRING];
|
|
char conv_id_buffer[MAX_STRING];
|
|
char history_file_name[MAX_STRING];
|
|
S32 has_offline_ims;
|
|
S32 stype;
|
|
S64 time;
|
|
// before CHUI-348 it was a flag of conversation voice state
|
|
int prereserved_unused;
|
|
|
|
memset(buffer, '\0', UTF_BUFFER);
|
|
while (!feof(fp) && fgets(buffer, UTF_BUFFER, fp))
|
|
{
|
|
// force blank for added safety
|
|
memset(conv_name_buffer, '\0', MAX_STRING);
|
|
memset(part_id_buffer, '\0', MAX_STRING);
|
|
memset(conv_id_buffer, '\0', MAX_STRING);
|
|
memset(history_file_name, '\0', MAX_STRING);
|
|
|
|
sscanf(buffer, "[%lld] %d %d %d %[^|]| %s %s %[^|]|",
|
|
&time,
|
|
&stype,
|
|
&prereserved_unused,
|
|
&has_offline_ims,
|
|
conv_name_buffer,
|
|
part_id_buffer,
|
|
conv_id_buffer,
|
|
history_file_name);
|
|
|
|
bool is_adhoc = ((SessionType)stype == LLIMModel::LLIMSession::ADHOC_SESSION);
|
|
std::string conv_name = is_adhoc ? conv_name_buffer : LLURI::unescape(conv_name_buffer);
|
|
std::string file_name = is_adhoc ? history_file_name : LLURI::unescape(history_file_name);
|
|
|
|
ConversationParams params;
|
|
params.time(LLUnits::Seconds::fromValue(time))
|
|
.conversation_type((SessionType)stype)
|
|
.has_offline_ims(has_offline_ims)
|
|
.conversation_name(conv_name)
|
|
.participant_id(LLUUID(part_id_buffer))
|
|
.session_id(LLUUID(conv_id_buffer))
|
|
.history_filename(file_name);
|
|
|
|
LLConversation conversation(params);
|
|
|
|
// CHUI-325
|
|
// The conversation log should be capped to the last 30 days. Conversations with the last utterance
|
|
// being over 30 days old should be purged from the conversation log text file on login.
|
|
// <FS:CR> Shut up, CHUI-325 Let the user decide.
|
|
U32 CONVERSATION_LIFETIME = gSavedSettings.getU32("FSConversationLogLifetime");
|
|
if (conversation.isOlderThan( U32Days(CONVERSATION_LIFETIME) ) )
|
|
{
|
|
purge_required = true;
|
|
continue;
|
|
}
|
|
|
|
mConversations.push_back(conversation);
|
|
memset(buffer, '\0', UTF_BUFFER);
|
|
}
|
|
fclose(fp);
|
|
|
|
if(purge_required)
|
|
{
|
|
LLFile::remove(filename);
|
|
cache();
|
|
}
|
|
|
|
notifyObservers();
|
|
return true;
|
|
}
|
|
|
|
void LLConversationLog::notifyObservers()
|
|
{
|
|
std::set<LLConversationLogObserver*>::const_iterator iter = mObservers.begin();
|
|
for (; iter != mObservers.end(); ++iter)
|
|
{
|
|
(*iter)->changed();
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::notifyParticularConversationObservers(const LLUUID& session_id, U32 mask)
|
|
{
|
|
std::set<LLConversationLogObserver*>::const_iterator iter = mObservers.begin();
|
|
for (; iter != mObservers.end(); ++iter)
|
|
{
|
|
(*iter)->changed(session_id, mask);
|
|
}
|
|
}
|
|
|
|
void LLConversationLog::onNewMessageReceived(const LLSD& data)
|
|
{
|
|
const LLUUID session_id = data["session_id"].asUUID();
|
|
logConversation(session_id, false);
|
|
}
|
|
|
|
void LLConversationLog::onAvatarNameCache(const LLUUID& participant_id, const LLAvatarName& av_name, const LLIMModel::LLIMSession* session)
|
|
{
|
|
mAvatarNameCacheConnection.disconnect();
|
|
updateConversationName(session, av_name.getCompleteName());
|
|
}
|
|
|
|
void LLConversationLog::onClearLog()
|
|
{
|
|
LLNotificationsUtil::add("PreferenceChatClearLog", LLSD(), LLSD(), boost::bind(&LLConversationLog::onClearLogResponse, this, _1, _2));
|
|
}
|
|
|
|
void LLConversationLog::onClearLogResponse(const LLSD& notification, const LLSD& response)
|
|
{
|
|
if (0 == LLNotificationsUtil::getSelectedOption(notification, response))
|
|
{
|
|
mConversations.clear();
|
|
notifyObservers();
|
|
cache();
|
|
deleteBackupLogs();
|
|
}
|
|
}
|