summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMerov Linden <merov@lindenlab.com>2013-02-06 18:18:44 -0800
committerMerov Linden <merov@lindenlab.com>2013-02-06 18:18:44 -0800
commit560aba3aa4d5eb2c65132db4da355adae82a47f0 (patch)
treee8739806c7f7beb8efc20e59442d60c0e5c88bd9
parent7ed270ff9dfdbc905dbee70907d3057a5ae490e7 (diff)
parentec0ac12eba9d944ade7bd734226a03ea2eb47229 (diff)
Pull merge from lindenlab/viewer-chui
-rw-r--r--indra/llui/lltoolbar.cpp12
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/app_settings/settings_per_account.xml11
-rw-r--r--indra/newview/llconversationlog.cpp17
-rw-r--r--indra/newview/llconversationlog.h6
-rw-r--r--indra/newview/llconversationloglist.cpp24
-rw-r--r--indra/newview/llfloaterconversationlog.cpp9
-rw-r--r--indra/newview/llfloaterconversationlog.h2
-rw-r--r--indra/newview/llfloaterimcontainer.cpp4
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp2
-rwxr-xr-xindra/newview/llfloaterpreference.cpp2
-rw-r--r--indra/newview/llimview.cpp2
-rw-r--r--indra/newview/lllogchat.cpp147
-rw-r--r--indra/newview/lllogchat.h9
-rw-r--r--indra/newview/skins/default/xui/en/floater_conversation_log.xml3
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml11
16 files changed, 153 insertions, 119 deletions
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index 071046fe6d..b9256dd890 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -872,8 +872,15 @@ void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent)
void LLToolBar::createButtons()
{
+ std::set<LLUUID> set_flashing;
+
BOOST_FOREACH(LLToolBarButton* button, mButtons)
{
+ if (button->getFlashTimer() && button->getFlashTimer()->isFlashingInProgress())
+ {
+ set_flashing.insert(button->getCommandId().uuid());
+ }
+
if (mButtonRemoveSignal)
{
(*mButtonRemoveSignal)(button);
@@ -896,6 +903,11 @@ void LLToolBar::createButtons()
{
(*mButtonAddSignal)(button);
}
+
+ if (set_flashing.find(button->getCommandId().uuid()) != set_flashing.end())
+ {
+ button->setFlashing(true);
+ }
}
mNeedsLayout = true;
}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index fb4cc6de62..79376f7467 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4667,17 +4667,6 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>KeepConversationLogTranscripts</key>
- <map>
- <key>Comment</key>
- <string>Keep a conversation log and transcripts</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
<key>LandBrushSize</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index 6864328339..0b589e2da6 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -281,6 +281,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>KeepConversationLogTranscripts</key>
+ <map>
+ <key>Comment</key>
+ <string>Keep a conversation log and transcripts</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
<key>ShowFavoritesOnLogin</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp
index bfaffdd73b..82176b3a06 100644
--- a/indra/newview/llconversationlog.cpp
+++ b/indra/newview/llconversationlog.cpp
@@ -187,9 +187,10 @@ void LLConversationLogFriendObserver::changed(U32 mask)
/************************************************************************/
LLConversationLog::LLConversationLog() :
- mAvatarNameCacheConnection()
+ mAvatarNameCacheConnection(),
+ mLoggingEnabled(false)
{
- LLControlVariable * keep_log_ctrlp = gSavedSettings.getControl("KeepConversationLogTranscripts").get();
+ LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get();
S32 log_mode = keep_log_ctrlp->getValue();
if (log_mode > 0)
@@ -202,6 +203,7 @@ LLConversationLog::LLConversationLog() :
void LLConversationLog::enableLogging(S32 log_mode)
{
+ mLoggingEnabled = log_mode > 0;
if (log_mode > 0)
{
LLIMMgr::instance().addSessionObserver(this);
@@ -217,7 +219,6 @@ void LLConversationLog::enableLogging(S32 log_mode)
LLIMMgr::instance().removeSessionObserver(this);
mNewMessageSignalConnection.disconnect();
LLAvatarTracker::instance().removeObserver(mFriendObserver);
- mConversations.clear();
}
notifyObservers();
@@ -368,7 +369,7 @@ void LLConversationLog::sessionAdded(const LLUUID& session_id, const std::string
void LLConversationLog::cache()
{
- if (gSavedSettings.getS32("KeepConversationLogTranscripts") > 0)
+ if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0)
{
saveToFile(getFileName());
}
@@ -531,14 +532,8 @@ void LLConversationLog::onClearLogResponse(const LLSD& notification, const LLSD&
{
if (0 == LLNotificationsUtil::getSelectedOption(notification, response))
{
- deleteTranscripts();
+ LLLogChat::deleteTranscripts();
mConversations.clear();
notifyObservers();
}
}
-
-void LLConversationLog::deleteTranscripts()
-{
- gDirUtilp->deleteFilesInDir(gDirUtilp->getPerAccountChatLogsDir(), "*." + LL_TRANSCRIPT_FILE_EXTENSION);
- LLFloaterIMSessionTab::processChatHistoryStyleUpdate(true);
-}
diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h
index 88df17a8f7..d5b6eccb29 100644
--- a/indra/newview/llconversationlog.h
+++ b/indra/newview/llconversationlog.h
@@ -140,7 +140,9 @@ public:
void onClearLog();
void onClearLogResponse(const LLSD& notification, const LLSD& response);
- void deleteTranscripts();
+
+ bool getIsLoggingEnabled() { return mLoggingEnabled; }
+ bool isLogEmpty() { return mConversations.empty(); }
private:
@@ -188,6 +190,8 @@ private:
boost::signals2::connection mNewMessageSignalConnection;
boost::signals2::connection mAvatarNameCacheConnection;
+
+ bool mLoggingEnabled;
};
class LLConversationLogObserver
diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp
index 6dbcb7bef7..96b225b841 100644
--- a/indra/newview/llconversationloglist.cpp
+++ b/indra/newview/llconversationloglist.cpp
@@ -33,6 +33,7 @@
#include "llconversationloglist.h"
#include "llconversationloglistitem.h"
#include "llviewermenu.h"
+#include "lltrans.h"
static LLDefaultChildRegistry::Register<LLConversationLogList> r("conversation_log_list");
@@ -200,8 +201,9 @@ void LLConversationLogList::rebuildList()
clear();
bool have_filter = !mNameFilter.empty();
+ LLConversationLog &log_instance = LLConversationLog::instance();
- const std::vector<LLConversation>& conversations = LLConversationLog::instance().getConversations();
+ const std::vector<LLConversation>& conversations = log_instance.getConversations();
std::vector<LLConversation>::const_iterator iter = conversations.begin();
for (; iter != conversations.end(); ++iter)
@@ -212,6 +214,26 @@ void LLConversationLogList::rebuildList()
addNewItem(&*iter);
}
+
+
+ bool logging_enabled = log_instance.getIsLoggingEnabled();
+ bool log_empty = log_instance.isLogEmpty();
+ if (!logging_enabled && log_empty)
+ {
+ setNoItemsCommentText(LLTrans::getString("logging_calls_disabled_log_empty"));
+ }
+ else if (!logging_enabled && !log_empty)
+ {
+ setNoItemsCommentText(LLTrans::getString("logging_calls_disabled_log_not_empty"));
+ }
+ else if (logging_enabled && log_empty)
+ {
+ setNoItemsCommentText(LLTrans::getString("logging_calls_enabled_log_empty"));
+ }
+ else if (logging_enabled && !log_empty)
+ {
+ setNoItemsCommentText("");
+ }
}
void LLConversationLogList::onCustomAction(const LLSD& userdata)
diff --git a/indra/newview/llfloaterconversationlog.cpp b/indra/newview/llfloaterconversationlog.cpp
index 07723ce44d..4c910c5655 100644
--- a/indra/newview/llfloaterconversationlog.cpp
+++ b/indra/newview/llfloaterconversationlog.cpp
@@ -63,10 +63,6 @@ BOOL LLFloaterConversationLog::postBuild()
getChild<LLFilterEditor>("people_filter_input")->setCommitCallback(boost::bind(&LLFloaterConversationLog::onFilterEdit, this, _2));
- LLControlVariable * keep_log_ctrlp = gSavedSettings.getControl("KeepConversationLogTranscripts").get();
- keep_log_ctrlp->getSignal()->connect(boost::bind(&LLFloaterConversationLog::onCallLoggingEnabledDisabled, this, _2));
- onCallLoggingEnabledDisabled(keep_log_ctrlp->getValue());
-
return LLFloater::postBuild();
}
@@ -136,8 +132,3 @@ bool LLFloaterConversationLog::isActionChecked(const LLSD& userdata)
return false;
}
-void LLFloaterConversationLog::onCallLoggingEnabledDisabled(S32 log_mode)
-{
- std::string no_items_msg = log_mode > 0 ? "" : getString("logging_calls_disabled");
- mConversationLogList->setNoItemsCommentText(no_items_msg);
-}
diff --git a/indra/newview/llfloaterconversationlog.h b/indra/newview/llfloaterconversationlog.h
index aa0f480aae..e971330f3d 100644
--- a/indra/newview/llfloaterconversationlog.h
+++ b/indra/newview/llfloaterconversationlog.h
@@ -49,8 +49,6 @@ private:
bool isActionEnabled(const LLSD& userdata);
bool isActionChecked(const LLSD& userdata);
- void onCallLoggingEnabledDisabled(S32 log_mode);
-
LLConversationLogList* mConversationLogList;
};
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 5a284cc7b7..2b13ce6377 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -1141,7 +1141,7 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
if ("conversation_log" == item)
{
- return gSavedSettings.getS32("KeepConversationLogTranscripts") > 0;
+ return gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0;
}
//Enable Chat history item for ad-hoc and group conversations
@@ -1792,7 +1792,7 @@ void LLFloaterIMContainer::updateSpeakBtnState()
bool LLFloaterIMContainer::isConversationLoggingAllowed()
{
- return gSavedSettings.getS32("KeepConversationLogTranscripts") > 0;
+ return gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0;
}
void LLFloaterIMContainer::flashConversationItemWidget(const LLUUID& session_id, bool is_flashes)
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 345418bffc..430326203f 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -542,7 +542,7 @@ void LLFloaterIMNearbyChat::addMessage(const LLChat& chat,bool archive,const LLS
}
// logging
- if (!args["do_not_log"].asBoolean() && gSavedSettings.getS32("KeepConversationLogTranscripts") > 1)
+ if (!args["do_not_log"].asBoolean() && gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1)
{
std::string from_name = chat.mFromName;
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 4f86c26a67..da24bb3b8f 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1584,7 +1584,7 @@ void LLFloaterPreference::onDeleteTranscriptsResponse(const LLSD& notification,
{
if (0 == LLNotificationsUtil::getSelectedOption(notification, response))
{
- LLConversationLog::instance().deleteTranscripts();
+ LLLogChat::deleteTranscripts();
updateDeleteTranscriptsButton();
}
}
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 1cceb68e2a..d4c8d8c4f4 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -928,7 +928,7 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,
bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
{
- if (gSavedSettings.getS32("KeepConversationLogTranscripts") > 1)
+ if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1)
{
std::string from_name = from;
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 545b44ef92..17b72c5023 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -33,6 +33,7 @@
#include "llviewercontrol.h"
#include "lldiriterator.h"
+#include "llfloaterimsessiontab.h"
#include "llinstantmessage.h"
#include "llsingleton.h" // for LLSingleton
@@ -40,6 +41,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/regex.hpp>
#include <boost/regex/v4/match_results.hpp>
+#include <boost/foreach.hpp>
#if LL_MSVC
#pragma warning(push)
@@ -62,7 +64,7 @@ const std::string LL_IM_TIME("time");
const std::string LL_IM_TEXT("message");
const std::string LL_IM_FROM("from");
const std::string LL_IM_FROM_ID("from_id");
-const std::string LL_TRANSCRIPT_FILE_EXTENSION("ll.txt");
+const std::string LL_TRANSCRIPT_FILE_EXTENSION("txt");
const static std::string IM_SEPARATOR(": ");
const static std::string NEW_LINE("\n");
@@ -85,6 +87,7 @@ const static std::string MULTI_LINE_PREFIX(" ");
* Note: "You" was used as an avatar names in viewers of previous versions
*/
const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]\\s+|\\[\\d{1,2}:\\d{2}\\]\\s+)?(.*)$");
+const static boost::regex TIMESTAMP("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]|\\[\\d{1,2}:\\d{2}\\]).*");
/**
* Regular expression suitable to match names like
@@ -328,69 +331,6 @@ void LLLogChat::saveHistory(const std::string& filename,
}
}
-void LLLogChat::loadHistory(const std::string& filename, void (*callback)(ELogLineType, const LLSD&, void*), void* userdata)
-{
- if(!filename.size())
- {
- llwarns << "Filename is Empty!" << llendl;
- return ;
- }
-
- LLFILE* fptr = LLFile::fopen(makeLogFileName(filename), "r"); /*Flawfinder: ignore*/
- if (!fptr)
- {
- callback(LOG_EMPTY, LLSD(), userdata);
- return; //No previous conversation with this name.
- }
- else
- {
- char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/
- char *bptr;
- S32 len;
- bool firstline=TRUE;
-
- if ( fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END) )
- { //File is smaller than recall size. 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*/
- for ( bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0';
-
- if (!firstline)
- {
- LLSD item;
- std::string line(buffer);
- std::istringstream iss(line);
-
- if (!LLChatLogParser::parse(line, item))
- {
- item["message"] = line;
- callback(LOG_LINE, item, userdata);
- }
- else
- {
- callback(LOG_LLSD, item, userdata);
- }
- }
- else
- {
- firstline = FALSE;
- }
- }
- callback(LOG_END, LLSD(), userdata);
-
- fclose(fptr);
- }
-}
-
// static
void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params)
{
@@ -506,19 +446,46 @@ std::string LLLogChat::oldLogFileName(std::string filename)
void LLLogChat::getListOfTranscriptFiles(std::vector<std::string>& list_of_transcriptions)
{
// get Users log directory
- std::string directory = gDirUtilp->getPerAccountChatLogsDir();
+ std::string dirname = gDirUtilp->getPerAccountChatLogsDir();
// add final OS dependent delimiter
- directory += gDirUtilp->getDirDelimiter();
+ dirname += gDirUtilp->getDirDelimiter();
// create search pattern
std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION;
- LLDirIterator iter(directory, pattern);
- std::string scanResult;
- while (iter.next(scanResult))
+ LLDirIterator iter(dirname, pattern);
+ std::string filename;
+ while (iter.next(filename))
{
- list_of_transcriptions.push_back(scanResult);
+ std::string fullname = gDirUtilp->add(dirname, filename);
+
+ LLFILE * filep = LLFile::fopen(fullname, "rb");
+ if (NULL != filep)
+ {
+ 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;
+ if (boost::regex_match(std::string(buffer), matches, TIMESTAMP))
+ {
+ list_of_transcriptions.push_back(gDirUtilp->add(dirname, filename));
+ }
+ }
+ LLFile::close(filep);
+ }
}
}
@@ -533,6 +500,46 @@ boost::signals2::connection LLLogChat::setSaveHistorySignal(const save_history_s
return sSaveHistorySignal->connect(cb);
}
+//static
+void LLLogChat::deleteTranscripts()
+{
+ std::vector<std::string> list_of_transcriptions;
+ getListOfTranscriptFiles(list_of_transcriptions);
+
+ BOOST_FOREACH(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);
+}
+
//*TODO mark object's names in a special way so that they will be distinguishable form 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>"
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index b35a94b4b3..5fbb4ade96 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -51,16 +51,13 @@ public:
const std::string& line);
static void getListOfTranscriptFiles(std::vector<std::string>& list);
- /** @deprecated @see loadChatHistory() */
- static void loadHistory(const std::string& filename,
- void (*callback)(ELogLineType, const LLSD&, void*),
- void* userdata);
-
static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD());
typedef boost::signals2::signal<void ()> save_history_signal_t;
static boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb);
+ static void deleteTranscripts();
+
private:
static std::string cleanFileName(std::string filename);
static save_history_signal_t * sSaveHistorySignal;
@@ -123,6 +120,6 @@ extern const std::string LL_IM_TIME; //("time");
extern const std::string LL_IM_TEXT; //("message");
extern const std::string LL_IM_FROM; //("from");
extern const std::string LL_IM_FROM_ID; //("from_id");
-extern const std::string LL_TRANSCRIPT_FILE_EXTENSION; //("ll.txt");
+extern const std::string LL_TRANSCRIPT_FILE_EXTENSION; //("txt");
#endif
diff --git a/indra/newview/skins/default/xui/en/floater_conversation_log.xml b/indra/newview/skins/default/xui/en/floater_conversation_log.xml
index 256e03c4d7..7229292a14 100644
--- a/indra/newview/skins/default/xui/en/floater_conversation_log.xml
+++ b/indra/newview/skins/default/xui/en/floater_conversation_log.xml
@@ -13,9 +13,6 @@
reuse_instance="true"
title="CONVERSATION LOG"
width="300">
- <string name="logging_calls_disabled">
- Conversations are not being logged. To log conversations in the future, select "Save IM logs on my computer" under Preferences > Privacy.
- </string>
<panel
follows="left|top|right"
height="32"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index d6a2383e52..5aa743b32d 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3908,4 +3908,15 @@ Try enclosing path to the editor with double quotes.
<!-- Spell check settings floater -->
<string name="UserDictionary">[User]</string>
+ <!-- Conversation log messages -->
+ <string name="logging_calls_disabled_log_empty">
+ Conversations are not being logged. To begin keeping a log, choose "Save: Log only" or "Save: Log and transcripts" under Preferences > Chat.
+ </string>
+ <string name="logging_calls_disabled_log_not_empty">
+ No more conversations will be logged. To resume keeping a log, choose "Save: Log only" or "Save: Log and transcripts" under Preferences > Chat.
+ </string>
+ <string name="logging_calls_enabled_log_empty">
+ There are no logged conversations. After you contact someone, or someone contacts you, a log entry will be shown here.
+ </string>
+
</strings>