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 8940117f0d..adced99a95 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;  }  | 
