diff options
Diffstat (limited to 'indra/newview/lllogchat.cpp')
-rw-r--r-- | indra/newview/lllogchat.cpp | 1653 |
1 files changed, 837 insertions, 816 deletions
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 55a947a09d..4b650aeebe 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lllogchat.cpp * @brief LLLogChat class implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, 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$ */ @@ -44,7 +44,7 @@ #include <boost/regex.hpp> #if LL_MSVC -#pragma warning(push) +#pragma warning(push) // disable warning about boost::lexical_cast unreachable code // when it fails to parse the string #pragma warning (disable:4702) @@ -126,99 +126,99 @@ using namespace boost::gregorian; void append_to_last_message(std::list<LLSD>& messages, const std::string& line) { - if (!messages.size()) return; + if (!messages.size()) return; - std::string im_text = messages.back()[LL_IM_TEXT].asString(); - im_text.append(line); - messages.back()[LL_IM_TEXT] = im_text; + std::string im_text = messages.back()[LL_IM_TEXT].asString(); + im_text.append(line); + messages.back()[LL_IM_TEXT] = im_text; } const char* remove_utf8_bom(const char* buf) { const char* start = buf; - if (start[0] == (char)0xEF && start[1] == (char)0xBB && start[2] == (char)0xBF) - { // If string starts with the magic bytes, return pointer after it. + if (start[0] == (char)0xEF && start[1] == (char)0xBB && start[2] == (char)0xBF) + { // If string starts with the magic bytes, return pointer after it. start += 3; - } - return start; + } + return start; } class LLLogChatTimeScanner: public LLSingleton<LLLogChatTimeScanner> { - LLSINGLETON(LLLogChatTimeScanner); + LLSINGLETON(LLLogChatTimeScanner); public: - date getTodayPacificDate() - { - typedef boost::date_time::local_adjustor<ptime, -8, no_dst> pst; - typedef boost::date_time::local_adjustor<ptime, -7, no_dst> pdt; - time_t t_time = time(NULL); - ptime p_time = LLStringOps::getPacificDaylightTime() - ? pdt::utc_to_local(from_time_t(t_time)) - : pst::utc_to_local(from_time_t(t_time)); - struct tm s_tm = to_tm(p_time); - return date_from_tm(s_tm); - } - - void checkAndCutOffDate(std::string& time_str) - { - // Cuts off the "%Y/%m/%d" from string for todays timestamps. - // Assume that passed string has at least "%H:%M" time format. - date log_date(not_a_date_time); - date today(getTodayPacificDate()); - - // Parse the passed date - mDateStream.str(LLStringUtil::null); - mDateStream << time_str; - mDateStream >> log_date; - mDateStream.clear(); - - days zero_days(0); - days days_alive = today - log_date; - - if ( days_alive == zero_days ) - { - // Yep, today's so strip "%Y/%m/%d" info - ptime stripped_time(not_a_date_time); - - mTimeStream.str(LLStringUtil::null); - mTimeStream << time_str; - mTimeStream >> stripped_time; - mTimeStream.clear(); - - time_str.clear(); - - mTimeStream.str(LLStringUtil::null); - mTimeStream << stripped_time; - mTimeStream >> time_str; - mTimeStream.clear(); - } - - LL_DEBUGS("LLChatLogParser") - << " log_date: " - << log_date - << " today: " - << today - << " days alive: " - << days_alive - << " new time: " - << time_str - << LL_ENDL; - } + date getTodayPacificDate() + { + typedef boost::date_time::local_adjustor<ptime, -8, no_dst> pst; + typedef boost::date_time::local_adjustor<ptime, -7, no_dst> pdt; + time_t t_time = time(NULL); + ptime p_time = LLStringOps::getPacificDaylightTime() + ? pdt::utc_to_local(from_time_t(t_time)) + : pst::utc_to_local(from_time_t(t_time)); + struct tm s_tm = to_tm(p_time); + return date_from_tm(s_tm); + } + + void checkAndCutOffDate(std::string& time_str) + { + // Cuts off the "%Y/%m/%d" from string for todays timestamps. + // Assume that passed string has at least "%H:%M" time format. + date log_date(not_a_date_time); + date today(getTodayPacificDate()); + + // Parse the passed date + mDateStream.str(LLStringUtil::null); + mDateStream << time_str; + mDateStream >> log_date; + mDateStream.clear(); + + days zero_days(0); + days days_alive = today - log_date; + + if ( days_alive == zero_days ) + { + // Yep, today's so strip "%Y/%m/%d" info + ptime stripped_time(not_a_date_time); + + mTimeStream.str(LLStringUtil::null); + mTimeStream << time_str; + mTimeStream >> stripped_time; + mTimeStream.clear(); + + time_str.clear(); + + mTimeStream.str(LLStringUtil::null); + mTimeStream << stripped_time; + mTimeStream >> time_str; + mTimeStream.clear(); + } + + LL_DEBUGS("LLChatLogParser") + << " log_date: " + << log_date + << " today: " + << today + << " days alive: " + << days_alive + << " new time: " + << time_str + << LL_ENDL; + } private: - std::stringstream mDateStream; - std::stringstream mTimeStream; + std::stringstream mDateStream; + std::stringstream mTimeStream; }; inline LLLogChatTimeScanner::LLLogChatTimeScanner() { - // Note, date/time facets will be destroyed by string streams - mDateStream.imbue(std::locale(mDateStream.getloc(), new date_input_facet(DATE_FORMAT))); - mTimeStream.imbue(std::locale(mTimeStream.getloc(), new time_facet(TIME_FORMAT))); - mTimeStream.imbue(std::locale(mTimeStream.getloc(), new time_input_facet(DATE_FORMAT))); + // Note, date/time facets will be destroyed by string streams + mDateStream.imbue(std::locale(mDateStream.getloc(), new date_input_facet(DATE_FORMAT))); + mTimeStream.imbue(std::locale(mTimeStream.getloc(), new time_facet(TIME_FORMAT))); + mTimeStream.imbue(std::locale(mTimeStream.getloc(), new time_input_facet(DATE_FORMAT))); } LLLogChat::LLLogChat() @@ -244,41 +244,41 @@ LLLogChat::~LLLogChat() //static std::string LLLogChat::makeLogFileName(std::string filename) { - /** - * Testing for in bound and out bound ad-hoc file names - * if it is then skip date stamping. - **/ - - boost::match_results<std::string::const_iterator> matches; - bool inboundConf = ll_regex_match(filename, matches, INBOUND_CONFERENCE); - bool outboundConf = ll_regex_match(filename, matches, OUTBOUND_CONFERENCE); - if (!(inboundConf || outboundConf)) - { - if( gSavedPerAccountSettings.getBOOL("LogFileNamewithDate") ) - { - time_t now; - time(&now); - char dbuffer[20]; /* Flawfinder: ignore */ - if (filename == "chat") - { - strftime(dbuffer, 20, "-%Y-%m-%d", localtime(&now)); - } - else - { - strftime(dbuffer, 20, "-%Y-%m", localtime(&now)); - } - filename += dbuffer; - } - } - - filename = cleanFileName(filename); - filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename); - if (!filename.empty()) - { - filename += '.' + LL_TRANSCRIPT_FILE_EXTENSION; - } - - return filename; + /** + * Testing for in bound and out bound ad-hoc file names + * if it is then skip date stamping. + **/ + + boost::match_results<std::string::const_iterator> matches; + bool inboundConf = ll_regex_match(filename, matches, INBOUND_CONFERENCE); + bool outboundConf = ll_regex_match(filename, matches, OUTBOUND_CONFERENCE); + if (!(inboundConf || outboundConf)) + { + if( gSavedPerAccountSettings.getBOOL("LogFileNamewithDate") ) + { + time_t now; + time(&now); + char dbuffer[20]; /* Flawfinder: ignore */ + if (filename == "chat") + { + strftime(dbuffer, 20, "-%Y-%m-%d", localtime(&now)); + } + else + { + strftime(dbuffer, 20, "-%Y-%m", localtime(&now)); + } + filename += dbuffer; + } + } + + filename = cleanFileName(filename); + filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename); + if (!filename.empty()) + { + filename += '.' + LL_TRANSCRIPT_FILE_EXTENSION; + } + + return filename; } //static @@ -305,34 +305,34 @@ void LLLogChat::renameLogFile(const std::string& old_filename, const std::string std::string LLLogChat::cleanFileName(std::string filename) { - std::string invalidChars = "\"\'\\/?*:.<>|[]{}~"; // Cannot match glob or illegal filename chars - std::string::size_type position = filename.find_first_of(invalidChars); - while (position != filename.npos) - { - filename[position] = '_'; - position = filename.find_first_of(invalidChars, position); - } - return filename; + std::string invalidChars = "\"\'\\/?*:.<>|[]{}~"; // Cannot match glob or illegal filename chars + std::string::size_type position = filename.find_first_of(invalidChars); + while (position != filename.npos) + { + filename[position] = '_'; + position = filename.find_first_of(invalidChars, position); + } + return filename; } std::string LLLogChat::timestamp2LogString(U32 timestamp, bool withdate) { - std::string timeStr; - if (withdate) - { - timeStr = "[" + LLTrans::getString ("TimeYear") + "]/[" - + LLTrans::getString ("TimeMonth") + "]/[" - + LLTrans::getString ("TimeDay") + "] [" - + LLTrans::getString ("TimeHour") + "]:[" - + LLTrans::getString ("TimeMin") + "]"; - } - else - { - timeStr = "[" + LLTrans::getString("TimeHour") + "]:[" - + LLTrans::getString ("TimeMin")+"]"; - } - - LLSD substitution; + std::string timeStr; + if (withdate) + { + timeStr = "[" + LLTrans::getString ("TimeYear") + "]/[" + + LLTrans::getString ("TimeMonth") + "]/[" + + LLTrans::getString ("TimeDay") + "] [" + + LLTrans::getString ("TimeHour") + "]:[" + + LLTrans::getString ("TimeMin") + "]"; + } + else + { + timeStr = "[" + LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString ("TimeMin")+"]"; + } + + LLSD substitution; if (timestamp == 0) { substitution["datetime"] = (S32)time_corrected(); @@ -342,69 +342,69 @@ std::string LLLogChat::timestamp2LogString(U32 timestamp, bool withdate) substitution["datetime"] = (S32)timestamp; } - LLStringUtil::format (timeStr, substitution); - return timeStr; + LLStringUtil::format (timeStr, substitution); + return timeStr; } //static void LLLogChat::saveHistory(const std::string& filename, - const std::string& from, - const LLUUID& from_id, - const std::string& line) + const std::string& from, + const LLUUID& from_id, + const std::string& line) { - std::string tmp_filename = filename; - LLStringUtil::trim(tmp_filename); - if (tmp_filename.empty()) - { - std::string warn = "Chat history filename [" + filename + "] is empty!"; - LL_WARNS() << warn << LL_ENDL; - llassert(tmp_filename.size()); - return; - } - - llofstream file(LLLogChat::makeLogFileName(filename).c_str(), std::ios_base::app); - if (!file.is_open()) - { - LL_WARNS() << "Couldn't open chat history log! - " + filename << LL_ENDL; - return; - } - - LLSD item; - - if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) - item["time"] = LLLogChat::timestamp2LogString(0, gSavedPerAccountSettings.getBOOL("LogTimestampDate")); - - item["from_id"] = from_id; - item["message"] = line; - - //adding "Second Life:" for all system messages to make chat log history parsing more reliable - if (from.empty() && from_id.isNull()) - { - item["from"] = SYSTEM_FROM; - } - else - { - item["from"] = from; - } - - file << LLChatLogFormatter(item) << std::endl; - - file.close(); - - LLLogChat::getInstance()->triggerHistorySignal(); + std::string tmp_filename = filename; + LLStringUtil::trim(tmp_filename); + if (tmp_filename.empty()) + { + std::string warn = "Chat history filename [" + filename + "] is empty!"; + LL_WARNS() << warn << LL_ENDL; + llassert(tmp_filename.size()); + return; + } + + llofstream file(LLLogChat::makeLogFileName(filename).c_str(), std::ios_base::app); + if (!file.is_open()) + { + LL_WARNS() << "Couldn't open chat history log! - " + filename << LL_ENDL; + return; + } + + LLSD item; + + if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) + item["time"] = LLLogChat::timestamp2LogString(0, gSavedPerAccountSettings.getBOOL("LogTimestampDate")); + + item["from_id"] = from_id; + item["message"] = line; + + //adding "Second Life:" for all system messages to make chat log history parsing more reliable + if (from.empty() && from_id.isNull()) + { + item["from"] = SYSTEM_FROM; + } + else + { + item["from"] = from; + } + + file << LLChatLogFormatter(item) << std::endl; + + file.close(); + + LLLogChat::getInstance()->triggerHistorySignal(); } // static void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params, bool is_group) { - if (file_name.empty()) - { - LL_WARNS("LLLogChat::loadChatHistory") << "Local history file name is empty!" << LL_ENDL; - return ; - } + if (file_name.empty()) + { + LL_WARNS("LLLogChat::loadChatHistory") << "Local history file name is empty!" << LL_ENDL; + return ; + } - bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; + bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; // Stat the file to find it and get the last history entry time llstat stat_data; @@ -438,7 +438,7 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m if (no_stat) { LL_DEBUGS("ChatHistory") << "No previous conversation log file found for " << file_name << LL_ENDL; - return; //No previous conversation with this name. + return; //No previous conversation with this name. } } } @@ -446,64 +446,64 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m // If we got here, we managed to stat the file. // Open the file to read LLFILE* fptr = LLFile::fopen(log_file_name, "r"); /*Flawfinder: ignore*/ - if (!fptr) - { // Ok, this is strange but not really tragic in the big picture of things + if (!fptr) + { // Ok, this is strange but not really tragic in the big picture of things LL_WARNS("ChatHistory") << "Unable to read file " << log_file_name << " after stat was successful" << LL_ENDL; return; - } + } S32 save_num_messages = messages.size(); - char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ - char *bptr; - S32 len; - bool firstline = TRUE; - - if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END)) - { //We need to load the whole historyFile or it's smaller than recall size, so get it all. - firstline = FALSE; - if (fseek(fptr, 0, SEEK_SET)) - { - fclose(fptr); - return; - } - } - while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) - { - len = strlen(buffer) - 1; /*Flawfinder: ignore*/ + char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ + char *bptr; + S32 len; + bool firstline = TRUE; + + if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END)) + { //We need to load the whole historyFile or it's smaller than recall size, so get it all. + firstline = FALSE; + if (fseek(fptr, 0, SEEK_SET)) + { + fclose(fptr); + return; + } + } + while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) + { + len = strlen(buffer) - 1; /*Flawfinder: ignore*/ // backfill any end of line characters with nulls - for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; - - if (firstline) - { - firstline = FALSE; - continue; - } - - std::string line(remove_utf8_bom(buffer)); - - //updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message - if (' ' == line[0]) - { - line.erase(0, MULTI_LINE_PREFIX.length()); - append_to_last_message(messages, '\n' + line); - } - else if (0 == len && ('\n' == line[0] || '\r' == line[0])) - { - //to support old format's multilined messages with new lines used to divide paragraphs - append_to_last_message(messages, line); - } - else - { - LLSD item; - if (!LLChatLogParser::parse(line, item, load_params)) - { - item[LL_IM_TEXT] = line; - } - messages.push_back(item); - } - } - fclose(fptr); + for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; + + if (firstline) + { + firstline = FALSE; + continue; + } + + std::string line(remove_utf8_bom(buffer)); + + //updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message + if (' ' == line[0]) + { + line.erase(0, MULTI_LINE_PREFIX.length()); + append_to_last_message(messages, '\n' + line); + } + else if (0 == len && ('\n' == line[0] || '\r' == line[0])) + { + //to support old format's multilined messages with new lines used to divide paragraphs + append_to_last_message(messages, line); + } + else + { + LLSD item; + if (!LLChatLogParser::parse(line, item, load_params)) + { + item[LL_IM_TEXT] = line; + } + messages.push_back(item); + } + } + fclose(fptr); LL_DEBUGS("ChatHistory") << "Read " << (messages.size() - save_num_messages) << " messages of chat history from " << log_file_name @@ -512,96 +512,96 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m bool LLLogChat::historyThreadsFinished(LLUUID session_id) { - LLMutexLock lock(historyThreadsMutex()); - bool finished = true; - std::map<LLUUID,LLLoadHistoryThread *>::iterator it = mLoadHistoryThreads.find(session_id); - if (it != mLoadHistoryThreads.end()) - { - finished = it->second->isFinished(); - } - if (!finished) - { - return false; - } - std::map<LLUUID,LLDeleteHistoryThread *>::iterator dit = mDeleteHistoryThreads.find(session_id); - if (dit != mDeleteHistoryThreads.end()) - { - finished = finished && dit->second->isFinished(); - } - return finished; + LLMutexLock lock(historyThreadsMutex()); + bool finished = true; + std::map<LLUUID,LLLoadHistoryThread *>::iterator it = mLoadHistoryThreads.find(session_id); + if (it != mLoadHistoryThreads.end()) + { + finished = it->second->isFinished(); + } + if (!finished) + { + return false; + } + std::map<LLUUID,LLDeleteHistoryThread *>::iterator dit = mDeleteHistoryThreads.find(session_id); + if (dit != mDeleteHistoryThreads.end()) + { + finished = finished && dit->second->isFinished(); + } + return finished; } LLLoadHistoryThread* LLLogChat::getLoadHistoryThread(LLUUID session_id) { - LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLLoadHistoryThread *>::iterator it = mLoadHistoryThreads.find(session_id); - if (it != mLoadHistoryThreads.end()) - { - return it->second; - } - return NULL; + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLLoadHistoryThread *>::iterator it = mLoadHistoryThreads.find(session_id); + if (it != mLoadHistoryThreads.end()) + { + return it->second; + } + return NULL; } LLDeleteHistoryThread* LLLogChat::getDeleteHistoryThread(LLUUID session_id) { - LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLDeleteHistoryThread *>::iterator it = mDeleteHistoryThreads.find(session_id); - if (it != mDeleteHistoryThreads.end()) - { - return it->second; - } - return NULL; + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLDeleteHistoryThread *>::iterator it = mDeleteHistoryThreads.find(session_id); + if (it != mDeleteHistoryThreads.end()) + { + return it->second; + } + return NULL; } bool LLLogChat::addLoadHistoryThread(LLUUID& session_id, LLLoadHistoryThread* lthread) { - LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLLoadHistoryThread *>::const_iterator it = mLoadHistoryThreads.find(session_id); - if (it != mLoadHistoryThreads.end()) - { - return false; - } - mLoadHistoryThreads[session_id] = lthread; - return true; + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLLoadHistoryThread *>::const_iterator it = mLoadHistoryThreads.find(session_id); + if (it != mLoadHistoryThreads.end()) + { + return false; + } + mLoadHistoryThreads[session_id] = lthread; + return true; } bool LLLogChat::addDeleteHistoryThread(LLUUID& session_id, LLDeleteHistoryThread* dthread) { - LLMutexLock lock(historyThreadsMutex()); - std::map<LLUUID,LLDeleteHistoryThread *>::const_iterator it = mDeleteHistoryThreads.find(session_id); - if (it != mDeleteHistoryThreads.end()) - { - return false; - } - mDeleteHistoryThreads[session_id] = dthread; - return true; + LLMutexLock lock(historyThreadsMutex()); + std::map<LLUUID,LLDeleteHistoryThread *>::const_iterator it = mDeleteHistoryThreads.find(session_id); + if (it != mDeleteHistoryThreads.end()) + { + return false; + } + mDeleteHistoryThreads[session_id] = dthread; + return true; } void LLLogChat::cleanupHistoryThreads() { - LLMutexLock lock(historyThreadsMutex()); - std::vector<LLUUID> uuids; - std::map<LLUUID,LLLoadHistoryThread *>::iterator lit = mLoadHistoryThreads.begin(); - for (; lit != mLoadHistoryThreads.end(); lit++) - { - if (lit->second->isFinished() && mDeleteHistoryThreads[lit->first]->isFinished()) - { - delete lit->second; - delete mDeleteHistoryThreads[lit->first]; - uuids.push_back(lit->first); - } - } - std::vector<LLUUID>::iterator uuid_it = uuids.begin(); - for ( ;uuid_it != uuids.end(); uuid_it++) - { - mLoadHistoryThreads.erase(*uuid_it); - mDeleteHistoryThreads.erase(*uuid_it); - } + LLMutexLock lock(historyThreadsMutex()); + std::vector<LLUUID> uuids; + std::map<LLUUID,LLLoadHistoryThread *>::iterator lit = mLoadHistoryThreads.begin(); + for (; lit != mLoadHistoryThreads.end(); lit++) + { + if (lit->second->isFinished() && mDeleteHistoryThreads[lit->first]->isFinished()) + { + delete lit->second; + delete mDeleteHistoryThreads[lit->first]; + uuids.push_back(lit->first); + } + } + std::vector<LLUUID>::iterator uuid_it = uuids.begin(); + for ( ;uuid_it != uuids.end(); uuid_it++) + { + mLoadHistoryThreads.erase(*uuid_it); + mDeleteHistoryThreads.erase(*uuid_it); + } } LLMutex* LLLogChat::historyThreadsMutex() { - return mHistoryThreadsMutex; + return mHistoryThreadsMutex; } void LLLogChat::triggerHistorySignal() @@ -615,272 +615,293 @@ void LLLogChat::triggerHistorySignal() // static std::string LLLogChat::oldLogFileName(std::string filename) { - // get Users log directory - std::string directory = gDirUtilp->getPerAccountChatLogsDir(); - - // add final OS dependent delimiter - directory += gDirUtilp->getDirDelimiter(); - - // lest make sure the file name has no invalid characters before making the pattern - filename = cleanFileName(filename); - - // create search pattern - std::string pattern = filename + ( filename == "chat" ? "-???\?-?\?-??.txt" : "-???\?-??.txt"); - - std::vector<std::string> allfiles; - LLDirIterator iter(directory, pattern); - std::string scanResult; - - while (iter.next(scanResult)) - { - allfiles.push_back(scanResult); - } - - if (allfiles.size() == 0) // if no result from date search, return generic filename - { - scanResult = directory + filename + '.' + LL_TRANSCRIPT_FILE_EXTENSION; - } - else - { - sort(allfiles.begin(), allfiles.end()); - scanResult = directory + allfiles.back(); - // this file is now the most recent version of the file. - } - - return scanResult; + // get Users log directory + std::string directory = gDirUtilp->getPerAccountChatLogsDir(); + + // add final OS dependent delimiter + directory += gDirUtilp->getDirDelimiter(); + + // lest make sure the file name has no invalid characters before making the pattern + filename = cleanFileName(filename); + + // create search pattern + std::string pattern = filename + ( filename == "chat" ? "-???\?-?\?-??.txt" : "-???\?-??.txt"); + + std::vector<std::string> allfiles; + LLDirIterator iter(directory, pattern); + std::string scanResult; + + while (iter.next(scanResult)) + { + allfiles.push_back(scanResult); + } + + if (allfiles.size() == 0) // if no result from date search, return generic filename + { + scanResult = directory + filename + '.' + LL_TRANSCRIPT_FILE_EXTENSION; + } + else + { + sort(allfiles.begin(), allfiles.end()); + scanResult = directory + allfiles.back(); + // this file is now the most recent version of the file. + } + + return scanResult; } +bool LLLogChat::transcriptFilesExist() +{ + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; + // get Users log directory + std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); + + // add final OS dependent delimiter + dirname += gDirUtilp->getDirDelimiter(); + + LLDirIterator iter(dirname, pattern); + std::string filename; + while (iter.next(filename)) + { + std::string fullname = gDirUtilp->add(dirname, filename); + if (isTranscriptFileFound(fullname)) + { + return true; + } + } + return false; +} // static void LLLogChat::findTranscriptFiles(std::string pattern, std::vector<std::string>& list_of_transcriptions) { - // get Users log directory - std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); - - // add final OS dependent delimiter - dirname += gDirUtilp->getDirDelimiter(); - - LLDirIterator iter(dirname, pattern); - std::string filename; - while (iter.next(filename)) - { - std::string fullname = gDirUtilp->add(dirname, filename); - if (isTranscriptFileFound(fullname)) - { - list_of_transcriptions.push_back(fullname); - } - } + // get Users log directory + std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); + + // add final OS dependent delimiter + dirname += gDirUtilp->getDirDelimiter(); + + LLDirIterator iter(dirname, pattern); + std::string filename; + while (iter.next(filename)) + { + std::string fullname = gDirUtilp->add(dirname, filename); + if (isTranscriptFileFound(fullname)) + { + list_of_transcriptions.push_back(fullname); + } + } } // static void LLLogChat::getListOfTranscriptFiles(std::vector<std::string>& list_of_transcriptions) { - // create search pattern - std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; - findTranscriptFiles(pattern, list_of_transcriptions); + // create search pattern + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; + findTranscriptFiles(pattern, list_of_transcriptions); } // static void LLLogChat::getListOfTranscriptBackupFiles(std::vector<std::string>& list_of_transcriptions) { - // create search pattern - std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION + ".backup*"; - findTranscriptFiles(pattern, list_of_transcriptions); + // create search pattern + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION + ".backup*"; + findTranscriptFiles(pattern, list_of_transcriptions); } boost::signals2::connection LLLogChat::setSaveHistorySignal(const save_history_signal_t::slot_type& cb) { - if (NULL == mSaveHistorySignal) - { - mSaveHistorySignal = new save_history_signal_t(); - } + if (NULL == mSaveHistorySignal) + { + mSaveHistorySignal = new save_history_signal_t(); + } - return mSaveHistorySignal->connect(cb); + return mSaveHistorySignal->connect(cb); } //static -bool LLLogChat::moveTranscripts(const std::string originDirectory, - const std::string targetDirectory, - std::vector<std::string>& listOfFilesToMove, - std::vector<std::string>& listOfFilesMoved) +bool LLLogChat::moveTranscripts(const std::string originDirectory, + const std::string targetDirectory, + std::vector<std::string>& listOfFilesToMove, + std::vector<std::string>& listOfFilesMoved) { - std::string newFullPath; - bool movedAllTranscripts = true; - std::string backupFileName; - unsigned backupFileCount; - - for (const std::string& fullpath : listOfFilesToMove) - { - backupFileCount = 0; - newFullPath = targetDirectory + fullpath.substr(originDirectory.length(), std::string::npos); - - //The target directory contains that file already, so lets store it - if(LLFile::isfile(newFullPath)) - { - backupFileName = newFullPath + ".backup"; - - //If needed store backup file as .backup1 etc. - while(LLFile::isfile(backupFileName)) - { - ++backupFileCount; - backupFileName = newFullPath + ".backup" + std::to_string(backupFileCount); - } - - //Rename the file to its backup name so it is not overwritten - LLFile::rename(newFullPath, backupFileName); - } - - S32 retry_count = 0; - while (retry_count < 5) - { - //success is zero - if (LLFile::rename(fullpath, newFullPath) != 0) - { - retry_count++; - S32 result = errno; - LL_WARNS("LLLogChat::moveTranscripts") << "Problem renaming " << fullpath << " - errorcode: " - << result << " attempt " << retry_count << LL_ENDL; - - ms_sleep(100); - } - else - { - listOfFilesMoved.push_back(newFullPath); - - if (retry_count) - { - LL_WARNS("LLLogChat::moveTranscripts") << "Successfully renamed " << fullpath << LL_ENDL; - } - break; - } - } - } - - if(listOfFilesMoved.size() != listOfFilesToMove.size()) - { - movedAllTranscripts = false; - } - - return movedAllTranscripts; + std::string newFullPath; + bool movedAllTranscripts = true; + std::string backupFileName; + unsigned backupFileCount; + + for (const std::string& fullpath : listOfFilesToMove) + { + backupFileCount = 0; + newFullPath = targetDirectory + fullpath.substr(originDirectory.length(), std::string::npos); + + //The target directory contains that file already, so lets store it + if(LLFile::isfile(newFullPath)) + { + backupFileName = newFullPath + ".backup"; + + //If needed store backup file as .backup1 etc. + while(LLFile::isfile(backupFileName)) + { + ++backupFileCount; + backupFileName = newFullPath + ".backup" + std::to_string(backupFileCount); + } + + //Rename the file to its backup name so it is not overwritten + LLFile::rename(newFullPath, backupFileName); + } + + S32 retry_count = 0; + while (retry_count < 5) + { + //success is zero + if (LLFile::rename(fullpath, newFullPath) != 0) + { + retry_count++; + S32 result = errno; + LL_WARNS("LLLogChat::moveTranscripts") << "Problem renaming " << fullpath << " - errorcode: " + << result << " attempt " << retry_count << LL_ENDL; + + ms_sleep(100); + } + else + { + listOfFilesMoved.push_back(newFullPath); + + if (retry_count) + { + LL_WARNS("LLLogChat::moveTranscripts") << "Successfully renamed " << fullpath << LL_ENDL; + } + break; + } + } + } + + if(listOfFilesMoved.size() != listOfFilesToMove.size()) + { + movedAllTranscripts = false; + } + + return movedAllTranscripts; } //static -bool LLLogChat::moveTranscripts(const std::string currentDirectory, - const std::string newDirectory, - std::vector<std::string>& listOfFilesToMove) +bool LLLogChat::moveTranscripts(const std::string currentDirectory, + const std::string newDirectory, + std::vector<std::string>& listOfFilesToMove) { - std::vector<std::string> listOfFilesMoved; - return moveTranscripts(currentDirectory, newDirectory, listOfFilesToMove, listOfFilesMoved); + std::vector<std::string> listOfFilesMoved; + return moveTranscripts(currentDirectory, newDirectory, listOfFilesToMove, listOfFilesMoved); } //static void LLLogChat::deleteTranscripts() { - std::vector<std::string> list_of_transcriptions; - getListOfTranscriptFiles(list_of_transcriptions); - getListOfTranscriptBackupFiles(list_of_transcriptions); - - for (const std::string& fullpath : list_of_transcriptions) - { - S32 retry_count = 0; - while (retry_count < 5) - { - if (0 != LLFile::remove(fullpath)) - { - retry_count++; - S32 result = errno; - LL_WARNS("LLLogChat::deleteTranscripts") << "Problem removing " << fullpath << " - errorcode: " - << result << " attempt " << retry_count << LL_ENDL; - - if(retry_count >= 5) - { - LL_WARNS("LLLogChat::deleteTranscripts") << "Failed to remove " << fullpath << LL_ENDL; - return; - } - - ms_sleep(100); - } - else - { - if (retry_count) - { - LL_WARNS("LLLogChat::deleteTranscripts") << "Successfully removed " << fullpath << LL_ENDL; - } - break; - } - } - } - - LLFloaterIMSessionTab::processChatHistoryStyleUpdate(true); + std::vector<std::string> list_of_transcriptions; + getListOfTranscriptFiles(list_of_transcriptions); + getListOfTranscriptBackupFiles(list_of_transcriptions); + + for (const std::string& fullpath : list_of_transcriptions) + { + S32 retry_count = 0; + while (retry_count < 5) + { + if (0 != LLFile::remove(fullpath)) + { + retry_count++; + S32 result = errno; + LL_WARNS("LLLogChat::deleteTranscripts") << "Problem removing " << fullpath << " - errorcode: " + << result << " attempt " << retry_count << LL_ENDL; + + if(retry_count >= 5) + { + LL_WARNS("LLLogChat::deleteTranscripts") << "Failed to remove " << fullpath << LL_ENDL; + return; + } + + ms_sleep(100); + } + else + { + if (retry_count) + { + LL_WARNS("LLLogChat::deleteTranscripts") << "Successfully removed " << fullpath << LL_ENDL; + } + break; + } + } + } + + LLFloaterIMSessionTab::processChatHistoryStyleUpdate(true); } // static bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id, bool is_group) { - LLAvatarName avatar_name; - LLAvatarNameCache::get(avatar_id, &avatar_name); - std::string avatar_user_name = avatar_name.getAccountName(); - if(!is_group) - { - std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_'); - return isTranscriptFileFound(makeLogFileName(avatar_user_name)); - } - else - { - std::string file_name; - gCacheName->getGroupName(avatar_id, file_name); - file_name = makeLogFileName(file_name + GROUP_CHAT_SUFFIX); - return isTranscriptFileFound(file_name); - } - return false; + LLAvatarName avatar_name; + LLAvatarNameCache::get(avatar_id, &avatar_name); + std::string avatar_user_name = avatar_name.getAccountName(); + if(!is_group) + { + std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_'); + return isTranscriptFileFound(makeLogFileName(avatar_user_name)); + } + else + { + std::string file_name; + gCacheName->getGroupName(avatar_id, file_name); + file_name = makeLogFileName(file_name + GROUP_CHAT_SUFFIX); + return isTranscriptFileFound(file_name); + } + return false; } bool LLLogChat::isNearbyTranscriptExist() { - return isTranscriptFileFound(makeLogFileName("chat"));; + return isTranscriptFileFound(makeLogFileName("chat"));; } bool LLLogChat::isAdHocTranscriptExist(std::string file_name) { - return isTranscriptFileFound(makeLogFileName(file_name));; + return isTranscriptFileFound(makeLogFileName(file_name));; } // static bool LLLogChat::isTranscriptFileFound(std::string fullname) { - bool result = false; - LLFILE * filep = LLFile::fopen(fullname, "rb"); - if (NULL != filep) - { - if (makeLogFileName("chat") == fullname) - { - LLFile::close(filep); - return true; - } - char buffer[LOG_RECALL_SIZE]; - - fseek(filep, 0, SEEK_END); // seek to end of file - S32 bytes_to_read = ftell(filep); // get current file pointer - fseek(filep, 0, SEEK_SET); // seek back to beginning of file - - // limit the number characters to read from file - if (bytes_to_read >= LOG_RECALL_SIZE) - { - bytes_to_read = LOG_RECALL_SIZE - 1; - } - - if (bytes_to_read > 0 && NULL != fgets(buffer, bytes_to_read, filep)) - { - //matching a timestamp - boost::match_results<std::string::const_iterator> matches; + bool result = false; + LLFILE * filep = LLFile::fopen(fullname, "rb"); + if (NULL != filep) + { + if (makeLogFileName("chat") == fullname) + { + LLFile::close(filep); + return true; + } + char buffer[LOG_RECALL_SIZE]; + + fseek(filep, 0, SEEK_END); // seek to end of file + S32 bytes_to_read = ftell(filep); // get current file pointer + fseek(filep, 0, SEEK_SET); // seek back to beginning of file + + // limit the number characters to read from file + if (bytes_to_read >= LOG_RECALL_SIZE) + { + bytes_to_read = LOG_RECALL_SIZE - 1; + } + + if (bytes_to_read > 0 && NULL != fgets(buffer, bytes_to_read, filep)) + { + //matching a timestamp + boost::match_results<std::string::const_iterator> matches; std::string line(remove_utf8_bom(buffer)); - if (ll_regex_match(line, matches, TIMESTAMP)) - { - result = true; - } - } - LLFile::close(filep); - } - return result; + if (ll_regex_match(line, matches, TIMESTAMP)) + { + result = true; + } + } + LLFile::close(filep); + } + return result; } //*TODO mark object's names in a special way so that they will be distinguishable form avatar name @@ -888,167 +909,167 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname) //Example, an object's name can be written like "Object <actual_object's_name>" void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const { - if (!im.isMap()) - { - LL_WARNS() << "invalid LLSD type of an instant message" << LL_ENDL; - return; - } - - if (im[LL_IM_TIME].isDefined()) - { - std::string timestamp = im[LL_IM_TIME].asString(); - boost::trim(timestamp); - ostr << '[' << timestamp << ']' << TWO_SPACES; - } - - //*TODO mark object's names in a special way so that they will be distinguishable from avatar name - //which are more strict by its nature (only firstname and secondname) - //Example, an object's name can be written like "Object <actual_object's_name>" - if (im[LL_IM_FROM].isDefined()) - { - std::string from = im[LL_IM_FROM].asString(); - boost::trim(from); - - std::size_t found = from.find(IM_SYMBOL_SEPARATOR); - std::size_t len = from.size(); - std::size_t start = 0; - while (found != std::string::npos) - { - std::size_t sub_len = found - start; - if (sub_len > 0) - { - ostr << from.substr(start, sub_len); - } - LLURI::encodeCharacter(ostr, IM_SYMBOL_SEPARATOR); - start = found + 1; - found = from.find(IM_SYMBOL_SEPARATOR, start); - } - if (start < len) - { - std::string str_end = from.substr(start, len - start); - ostr << str_end; - } - if (len > 0) - { - ostr << IM_SEPARATOR; - } - } - - if (im[LL_IM_TEXT].isDefined()) - { - std::string im_text = im[LL_IM_TEXT].asString(); - - //multilined text will be saved with prepended spaces - boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX); - ostr << im_text; - } + if (!im.isMap()) + { + LL_WARNS() << "invalid LLSD type of an instant message" << LL_ENDL; + return; + } + + if (im[LL_IM_TIME].isDefined()) + { + std::string timestamp = im[LL_IM_TIME].asString(); + boost::trim(timestamp); + ostr << '[' << timestamp << ']' << TWO_SPACES; + } + + //*TODO mark object's names in a special way so that they will be distinguishable from avatar name + //which are more strict by its nature (only firstname and secondname) + //Example, an object's name can be written like "Object <actual_object's_name>" + if (im[LL_IM_FROM].isDefined()) + { + std::string from = im[LL_IM_FROM].asString(); + boost::trim(from); + + std::size_t found = from.find(IM_SYMBOL_SEPARATOR); + std::size_t len = from.size(); + std::size_t start = 0; + while (found != std::string::npos) + { + std::size_t sub_len = found - start; + if (sub_len > 0) + { + ostr << from.substr(start, sub_len); + } + LLURI::encodeCharacter(ostr, IM_SYMBOL_SEPARATOR); + start = found + 1; + found = from.find(IM_SYMBOL_SEPARATOR, start); + } + if (start < len) + { + std::string str_end = from.substr(start, len - start); + ostr << str_end; + } + if (len > 0) + { + ostr << IM_SEPARATOR; + } + } + + if (im[LL_IM_TEXT].isDefined()) + { + std::string im_text = im[LL_IM_TEXT].asString(); + + //multilined text will be saved with prepended spaces + boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX); + ostr << im_text; + } } bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params) { - if (!raw.length()) return false; - - bool cut_off_todays_date = parse_params.has("cut_off_todays_date") ? parse_params["cut_off_todays_date"].asBoolean() : true; - im = LLSD::emptyMap(); - - //matching a timestamp - boost::match_results<std::string::const_iterator> matches; - if (!ll_regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; - - bool has_timestamp = matches[IDX_TIMESTAMP].matched; - if (has_timestamp) - { - //timestamp was successfully parsed - std::string timestamp = matches[IDX_TIMESTAMP]; - boost::trim(timestamp); - timestamp.erase(0, 1); - timestamp.erase(timestamp.length()-1, 1); + if (!raw.length()) return false; + + bool cut_off_todays_date = parse_params.has("cut_off_todays_date") ? parse_params["cut_off_todays_date"].asBoolean() : true; + im = LLSD::emptyMap(); + + //matching a timestamp + boost::match_results<std::string::const_iterator> matches; + if (!ll_regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; + + bool has_timestamp = matches[IDX_TIMESTAMP].matched; + if (has_timestamp) + { + //timestamp was successfully parsed + std::string timestamp = matches[IDX_TIMESTAMP]; + boost::trim(timestamp); + timestamp.erase(0, 1); + timestamp.erase(timestamp.length()-1, 1); im[LL_IM_DATE_TIME] = timestamp; // Retain full date-time for merging chat histories if (cut_off_todays_date) - { - LLLogChatTimeScanner::instance().checkAndCutOffDate(timestamp); - } - - im[LL_IM_TIME] = timestamp; - } - else - { //timestamp is optional + { + LLLogChatTimeScanner::instance().checkAndCutOffDate(timestamp); + } + + im[LL_IM_TIME] = timestamp; + } + else + { //timestamp is optional im[LL_IM_DATE_TIME] = ""; im[LL_IM_TIME] = ""; - } - - bool has_stuff = matches[IDX_STUFF].matched; - if (!has_stuff) - { - return false; //*TODO should return false or not? - } - - //matching a name and a text - std::string stuff = matches[IDX_STUFF]; - boost::match_results<std::string::const_iterator> name_and_text; - if (!ll_regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; - - bool has_name = name_and_text[IDX_NAME].matched; - std::string name = LLURI::unescape(name_and_text[IDX_NAME]); - - //we don't need a name/text separator - if (has_name && name.length() && name[name.length()-1] == ':') - { - name.erase(name.length()-1, 1); - } - - if (!has_name || name == SYSTEM_FROM) - { - //name is optional too - im[LL_IM_FROM] = SYSTEM_FROM; - im[LL_IM_FROM_ID] = LLUUID::null; - } - - //possibly a case of complex object names consisting of 3+ words - if (!has_name) - { - std::string::size_type divider_pos = stuff.find(NAME_TEXT_DIVIDER); - if (divider_pos != std::string::npos && divider_pos < (stuff.length() - NAME_TEXT_DIVIDER.length())) - { - im[LL_IM_FROM] = LLURI::unescape(stuff.substr(0, divider_pos)); - im[LL_IM_TEXT] = stuff.substr(divider_pos + NAME_TEXT_DIVIDER.length()); - return true; - } - } - - if (!has_name) - { - //text is mandatory - im[LL_IM_TEXT] = stuff; - return true; //parse as a message from Second Life - } - - bool has_text = name_and_text[IDX_TEXT].matched; - if (!has_text) return false; - - //for parsing logs created in very old versions of a viewer - if (name == "You") - { - std::string agent_name; - LLAgentUI::buildFullname(agent_name); - im[LL_IM_FROM] = agent_name; - im[LL_IM_FROM_ID] = gAgentID; - } - else - { - im[LL_IM_FROM] = name; - } - - im[LL_IM_TEXT] = name_and_text[IDX_TEXT]; - return true; //parsed name and message text, maybe have a timestamp too + } + + bool has_stuff = matches[IDX_STUFF].matched; + if (!has_stuff) + { + return false; //*TODO should return false or not? + } + + //matching a name and a text + std::string stuff = matches[IDX_STUFF]; + boost::match_results<std::string::const_iterator> name_and_text; + if (!ll_regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; + + bool has_name = name_and_text[IDX_NAME].matched; + std::string name = LLURI::unescape(name_and_text[IDX_NAME]); + + //we don't need a name/text separator + if (has_name && name.length() && name[name.length()-1] == ':') + { + name.erase(name.length()-1, 1); + } + + if (!has_name || name == SYSTEM_FROM) + { + //name is optional too + im[LL_IM_FROM] = SYSTEM_FROM; + im[LL_IM_FROM_ID] = LLUUID::null; + } + + //possibly a case of complex object names consisting of 3+ words + if (!has_name) + { + std::string::size_type divider_pos = stuff.find(NAME_TEXT_DIVIDER); + if (divider_pos != std::string::npos && divider_pos < (stuff.length() - NAME_TEXT_DIVIDER.length())) + { + im[LL_IM_FROM] = LLURI::unescape(stuff.substr(0, divider_pos)); + im[LL_IM_TEXT] = stuff.substr(divider_pos + NAME_TEXT_DIVIDER.length()); + return true; + } + } + + if (!has_name) + { + //text is mandatory + im[LL_IM_TEXT] = stuff; + return true; //parse as a message from Second Life + } + + bool has_text = name_and_text[IDX_TEXT].matched; + if (!has_text) return false; + + //for parsing logs created in very old versions of a viewer + if (name == "You") + { + std::string agent_name; + LLAgentUI::buildFullname(agent_name); + im[LL_IM_FROM] = agent_name; + im[LL_IM_FROM_ID] = gAgentID; + } + else + { + im[LL_IM_FROM] = name; + } + + im[LL_IM_TEXT] = name_and_text[IDX_TEXT]; + return true; //parsed name and message text, maybe have a timestamp too } LLDeleteHistoryThread::LLDeleteHistoryThread(std::list<LLSD>* messages, LLLoadHistoryThread* loadThread) - : LLActionThread("delete chat history"), - mMessages(messages), - mLoadThread(loadThread) + : LLActionThread("delete chat history"), + mMessages(messages), + mLoadThread(loadThread) { } LLDeleteHistoryThread::~LLDeleteHistoryThread() @@ -1056,23 +1077,23 @@ LLDeleteHistoryThread::~LLDeleteHistoryThread() } void LLDeleteHistoryThread::run() { - if (mLoadThread != NULL) - { - mLoadThread->waitFinished(); - } - if (NULL != mMessages) - { - delete mMessages; - } - mMessages = NULL; - setFinished(); + if (mLoadThread != NULL) + { + mLoadThread->waitFinished(); + } + if (NULL != mMessages) + { + delete mMessages; + } + mMessages = NULL; + setFinished(); } LLActionThread::LLActionThread(const std::string& name) - : LLThread(name), - mMutex(), - mRunCondition(), - mFinished(false) + : LLThread(name), + mMutex(), + mRunCondition(), + mFinished(false) { } @@ -1082,33 +1103,33 @@ LLActionThread::~LLActionThread() void LLActionThread::waitFinished() { - mMutex.lock(); - if (!mFinished) - { - mMutex.unlock(); - mRunCondition.wait(); - } - else - { - mMutex.unlock(); - } + mMutex.lock(); + if (!mFinished) + { + mMutex.unlock(); + mRunCondition.wait(); + } + else + { + mMutex.unlock(); + } } void LLActionThread::setFinished() { - mMutex.lock(); - mFinished = true; - mMutex.unlock(); - mRunCondition.signal(); + mMutex.lock(); + mFinished = true; + mMutex.unlock(); + mRunCondition.signal(); } LLLoadHistoryThread::LLLoadHistoryThread(const std::string& file_name, std::list<LLSD>* messages, const LLSD& load_params) - : LLActionThread("load chat history"), - mMessages(messages), - mFileName(file_name), - mLoadParams(load_params), - mNewLoad(true), - mLoadEndSignal(NULL) + : LLActionThread("load chat history"), + mMessages(messages), + mFileName(file_name), + mLoadParams(load_params), + mNewLoad(true), + mLoadEndSignal(NULL) { } @@ -1118,129 +1139,129 @@ LLLoadHistoryThread::~LLLoadHistoryThread() void LLLoadHistoryThread::run() { - if(mNewLoad) - { - loadHistory(mFileName, mMessages, mLoadParams); - int count = mMessages->size(); - LL_INFOS() << "mMessages->size(): " << count << LL_ENDL; - setFinished(); - } + if(mNewLoad) + { + loadHistory(mFileName, mMessages, mLoadParams); + int count = mMessages->size(); + LL_INFOS() << "mMessages->size(): " << count << LL_ENDL; + setFinished(); + } } void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LLSD>* messages, const LLSD& load_params) { - if (file_name.empty()) - { - LL_WARNS("LLLogChat::loadHistory") << "Session name is Empty!" << LL_ENDL; - return ; - } - - bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; - LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ - - if (!fptr) - { - bool is_group = load_params.has("is_group") ? load_params["is_group"].asBoolean() : false; - if (is_group) - { - std::string old_name(file_name); - old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); - fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); - if (fptr) - { - fclose(fptr); - LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); - } - fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); - } - if (!fptr) - { - fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ - if (!fptr) - { - mNewLoad = false; - (*mLoadEndSignal)(messages, file_name); - return; //No previous conversation with this name. - } - } - } - - char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ - - char *bptr; - S32 len; - bool firstline = TRUE; - - if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END)) - { //We need to load the whole historyFile or it's smaller than recall size, so get it all. - firstline = FALSE; - if (fseek(fptr, 0, SEEK_SET)) - { - fclose(fptr); - mNewLoad = false; - (*mLoadEndSignal)(messages, file_name); - return; - } - } - - - while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) - { - len = strlen(buffer) - 1; /*Flawfinder: ignore*/ - - for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; - - - if (firstline) - { - firstline = FALSE; - continue; - } - std::string line(remove_utf8_bom(buffer)); - - //updated 1.23 plaint text log format requires a space added before subsequent lines in a multilined message - if (' ' == line[0]) - { - line.erase(0, MULTI_LINE_PREFIX.length()); - append_to_last_message(*messages, '\n' + line); - } - else if (0 == len && ('\n' == line[0] || '\r' == line[0])) - { - //to support old format's multilined messages with new lines used to divide paragraphs - append_to_last_message(*messages, line); - } - else - { - LLSD item; - if (!LLChatLogParser::parse(line, item, load_params)) - { - item[LL_IM_TEXT] = line; - } - messages->push_back(item); - } - } - - fclose(fptr); - mNewLoad = false; - (*mLoadEndSignal)(messages, file_name); + if (file_name.empty()) + { + LL_WARNS("LLLogChat::loadHistory") << "Session name is Empty!" << LL_ENDL; + return ; + } + + bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; + LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ + + if (!fptr) + { + bool is_group = load_params.has("is_group") ? load_params["is_group"].asBoolean() : false; + if (is_group) + { + std::string old_name(file_name); + old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); + fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); + if (fptr) + { + fclose(fptr); + LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); + } + fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); + } + if (!fptr) + { + fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + mNewLoad = false; + (*mLoadEndSignal)(messages, file_name); + return; //No previous conversation with this name. + } + } + } + + char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ + + char *bptr; + S32 len; + bool firstline = TRUE; + + if (load_all_history || fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END)) + { //We need to load the whole historyFile or it's smaller than recall size, so get it all. + firstline = FALSE; + if (fseek(fptr, 0, SEEK_SET)) + { + fclose(fptr); + mNewLoad = false; + (*mLoadEndSignal)(messages, file_name); + return; + } + } + + + while (fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr)) + { + len = strlen(buffer) - 1; /*Flawfinder: ignore*/ + + for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; + + + if (firstline) + { + firstline = FALSE; + continue; + } + std::string line(remove_utf8_bom(buffer)); + + //updated 1.23 plaint text log format requires a space added before subsequent lines in a multilined message + if (' ' == line[0]) + { + line.erase(0, MULTI_LINE_PREFIX.length()); + append_to_last_message(*messages, '\n' + line); + } + else if (0 == len && ('\n' == line[0] || '\r' == line[0])) + { + //to support old format's multilined messages with new lines used to divide paragraphs + append_to_last_message(*messages, line); + } + else + { + LLSD item; + if (!LLChatLogParser::parse(line, item, load_params)) + { + item[LL_IM_TEXT] = line; + } + messages->push_back(item); + } + } + + fclose(fptr); + mNewLoad = false; + (*mLoadEndSignal)(messages, file_name); } - + boost::signals2::connection LLLoadHistoryThread::setLoadEndSignal(const load_end_signal_t::slot_type& cb) { - if (NULL == mLoadEndSignal) - { - mLoadEndSignal = new load_end_signal_t(); - } + if (NULL == mLoadEndSignal) + { + mLoadEndSignal = new load_end_signal_t(); + } - return mLoadEndSignal->connect(cb); + return mLoadEndSignal->connect(cb); } void LLLoadHistoryThread::removeLoadEndSignal(const load_end_signal_t::slot_type& cb) { - if (NULL != mLoadEndSignal) - { - mLoadEndSignal->disconnect_all_slots(); - delete mLoadEndSignal; - } - mLoadEndSignal = NULL; + if (NULL != mLoadEndSignal) + { + mLoadEndSignal->disconnect_all_slots(); + delete mLoadEndSignal; + } + mLoadEndSignal = NULL; } |