summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/llstring.h62
-rw-r--r--indra/llui/llchat.h19
-rw-r--r--indra/newview/llchathistory.cpp38
-rw-r--r--indra/newview/llchathistory.h3
-rw-r--r--indra/newview/llchatitemscontainerctrl.cpp5
-rw-r--r--indra/newview/llchatitemscontainerctrl.h6
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp3
-rw-r--r--indra/newview/llfloaterimnearbychathandler.cpp13
-rw-r--r--indra/newview/llfloaterimnearbychatlistener.cpp35
-rw-r--r--indra/newview/llfloaterimnearbychatlistener.h6
-rw-r--r--indra/newview/llviewerchat.cpp9
-rw-r--r--indra/newview/llviewermessage.cpp5
-rw-r--r--indra/newview/scripts/lua/LLChat.lua17
-rw-r--r--indra/newview/scripts/lua/test_LLChat.lua18
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml4
15 files changed, 199 insertions, 44 deletions
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 21b0da4822..cd8b2a2dcd 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -315,6 +315,14 @@ public:
static void trim(string_type& string) { trimHead(string); trimTail(string); }
static void truncate(string_type& string, size_type count);
+ // if string startsWith prefix, remove it and return true
+ static bool removePrefix(string_type& string, const string_type& prefix);
+ // if string startsWith prefix, return (string without prefix, true), else (string, false)
+ static std::pair<string_type, bool> withoutPrefix(const string_type& string, const string_type& prefix);
+ // like removePrefix()
+ static bool removeSuffix(string_type& string, const string_type& suffix);
+ static std::pair<string_type, bool> withoutSuffix(const string_type& string, const string_type& suffix);
+
static void toUpper(string_type& string);
static void toLower(string_type& string);
@@ -1479,6 +1487,60 @@ void LLStringUtilBase<T>::trimTail(string_type& string)
}
}
+// if string startsWith prefix, remove it and return true
+template<class T>
+bool LLStringUtilBase<T>::removePrefix(string_type& string, const string_type& prefix)
+{
+ bool found{ startsWith(string, prefix) };
+ if (found)
+ {
+ string.erase(0, prefix.length());
+ }
+ return found;
+}
+
+// if string startsWith prefix, return (string without prefix, true), else (string, false)
+template<class T>
+std::pair<typename LLStringUtilBase<T>::string_type, bool>
+LLStringUtilBase<T>::withoutPrefix(const string_type& string, const string_type& prefix)
+{
+ bool found{ startsWith(string, prefix) };
+ if (! found)
+ {
+ return { string, false };
+ }
+ else
+ {
+ return { string.substr(prefix.length()), true };
+ }
+}
+
+// like removePrefix()
+template<class T>
+bool LLStringUtilBase<T>::removeSuffix(string_type& string, const string_type& suffix)
+{
+ bool found{ endsWith(string, suffix) };
+ if (found)
+ {
+ string.erase(string.length() - suffix.length());
+ }
+ return found;
+}
+
+template<class T>
+std::pair<typename LLStringUtilBase<T>::string_type, bool>
+LLStringUtilBase<T>::withoutSuffix(const string_type& string, const string_type& suffix)
+{
+ bool found{ endsWith(string, suffix) };
+ if (! found)
+ {
+ return { string, false };
+ }
+ else
+ {
+ return { string.substr(0, string.length() - suffix.length()), true };
+ }
+}
// Replace line feeds with carriage return-line feed pairs.
//static
diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h
index 56105add7e..70d7e82970 100644
--- a/indra/llui/llchat.h
+++ b/indra/llui/llchat.h
@@ -89,7 +89,8 @@ public:
mPosAgent(),
mURL(),
mChatStyle(CHAT_STYLE_NORMAL),
- mSessionID()
+ mSessionID(),
+ mIsScript(false)
{ }
std::string mText; // UTF-8 line of text
@@ -107,6 +108,22 @@ public:
std::string mURL;
EChatStyle mChatStyle;
LLUUID mSessionID;
+
+ bool mIsScript;
};
+static const std::string LUA_PREFIX("[LUA]");
+
+inline
+std::string without_LUA_PREFIX(const std::string& string, bool is_lua)
+{
+ if (is_lua)
+ {
+ return string.substr(LUA_PREFIX.size());
+ }
+ else
+ {
+ return string;
+ }
+}
#endif
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 4a08eace62..d549f372e3 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -125,6 +125,7 @@ public:
mUserNameTextBox(NULL),
mTimeBoxTextBox(NULL),
mNeedsTimeBox(true),
+ mIsFromScript(false),
mAvatarNameCacheConnection()
{}
@@ -658,11 +659,13 @@ public:
const LLUUID& getAvatarId () const { return mAvatarID;}
- void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args)
+ void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args, bool is_script)
{
mAvatarID = chat.mFromID;
mSessionID = chat.mSessionID;
mSourceType = chat.mSourceType;
+ mIsFromScript = is_script;
+ mPrefix = mIsFromScript ? LLTrans::getString("ScriptBy") : "";
// To be able to report a message, we need a copy of it's text
// and it's easier to store text directly than trying to get
@@ -732,7 +735,7 @@ public:
username_end == (chat.mFromName.length() - 1))
{
mFrom = chat.mFromName.substr(0, username_start);
- user_name->setValue(mFrom);
+ user_name->setValue(mPrefix + mFrom);
if (gSavedSettings.getBOOL("NameTagShowUsernames"))
{
@@ -774,7 +777,7 @@ public:
switch (mSourceType)
{
case CHAT_SOURCE_AGENT:
- icon->setValue(chat.mFromID);
+ icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(chat.mFromID));
break;
case CHAT_SOURCE_OBJECT:
icon->setValue(LLSD("OBJECT_Icon"));
@@ -787,7 +790,7 @@ public:
icon->setValue(LLSD("Command_Destinations_Icon"));
break;
case CHAT_SOURCE_UNKNOWN:
- icon->setValue(LLSD("Unknown_Icon"));
+ icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD("Unknown_Icon"));
}
// In case the message came from an object, save the object info
@@ -1029,7 +1032,7 @@ private:
mFrom = av_name.getDisplayName();
LLTextBox* user_name = getChild<LLTextBox>("user_name");
- user_name->setValue( LLSD(av_name.getDisplayName() ) );
+ user_name->setValue(LLSD(mPrefix + av_name.getDisplayName()));
user_name->setToolTip( av_name.getUserName() );
if (gSavedSettings.getBOOL("NameTagShowUsernames") &&
@@ -1071,6 +1074,9 @@ protected:
bool mNeedsTimeBox;
+ bool mIsFromScript;
+ std::string mPrefix;
+
private:
boost::signals2::connection mAvatarNameCacheConnection;
};
@@ -1088,6 +1094,7 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
mTopHeaderPad(p.top_header_pad),
mBottomHeaderPad(p.bottom_header_pad),
mIsLastMessageFromLog(false),
+ mIsLastFromScript(false),
mNotifyAboutUnreadMsg(p.notify_unread_msg)
{
LLTextEditor::Params editor_params(p);
@@ -1185,11 +1192,11 @@ LLView* LLChatHistory::getSeparator()
return separator;
}
-LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args)
+LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args, bool is_script)
{
LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
if (header)
- header->setup(chat, style_params, args);
+ header->setup(chat, style_params, args, is_script);
return header;
}
@@ -1258,8 +1265,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
name_params.color(name_color);
name_params.readonly_color(name_color);
- std::string prefix = chat.mText.substr(0, 4);
-
+ auto [message, is_lua] = LLStringUtil::withoutPrefix(chat.mText, LUA_PREFIX);
+ std::string prefix = message.substr(0, 4);
//IRC styled /me messages.
bool irc_me = prefix == "/me " || prefix == "/me'";
@@ -1335,6 +1342,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
// names showing
if (args["show_names_for_p2p_conv"].asBoolean() && utf8str_trim(chat.mFromName).size())
{
+ std::string script_prefix = is_lua ? LLTrans::getString("ScriptBy") : "";
// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
if (chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
{
@@ -1359,7 +1367,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID));
// Add link to avatar's inspector and delimiter to message.
- mEditor->appendText(std::string(link_params.link_href) + delimiter,
+ mEditor->appendText(script_prefix + std::string(link_params.link_href) + delimiter,
prependNewLineState, link_params);
prependNewLineState = false;
}
@@ -1372,7 +1380,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
}
else
{
- mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter,
+ mEditor->appendText(script_prefix + "<nolink>" + chat.mFromName + "</nolink>" + delimiter,
prependNewLineState, body_message_params);
prependNewLineState = false;
}
@@ -1393,7 +1401,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
&& mLastFromID == chat.mFromID
&& mLastMessageTime.notNull()
&& (new_message_time.secondsSinceEpoch() - mLastMessageTime.secondsSinceEpoch()) < 60.0
- && mIsLastMessageFromLog == message_from_log) //distinguish between current and previous chat session's histories
+ && mIsLastMessageFromLog == message_from_log //distinguish between current and previous chat session's histories
+ && mIsLastFromScript == is_lua)
{
view = getSeparator();
if (!view)
@@ -1408,7 +1417,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
}
else
{
- view = getHeader(chat, name_params, args);
+ view = getHeader(chat, name_params, args, is_lua);
if (!view)
{
LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL;
@@ -1437,6 +1446,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
mLastFromID = chat.mFromID;
mLastMessageTime = new_message_time;
mIsLastMessageFromLog = message_from_log;
+ mIsLastFromScript = is_lua;
}
// body of the message processing
@@ -1491,7 +1501,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
// usual messages showing
else if (!teleport_separator)
{
- std::string message = irc_me ? chat.mText.substr(3) : chat.mText;
+ message = irc_me ? message.substr(3) : message;
//MESSAGE TEXT PROCESSING
//*HACK getting rid of redundant sender names in system notifications sent using sender name (see EXT-5010)
diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h
index b8364ff860..8acbea6ed5 100644
--- a/indra/newview/llchathistory.h
+++ b/indra/newview/llchathistory.h
@@ -101,7 +101,7 @@ class LLChatHistory : public LLUICtrl
* Builds a message header.
* @return pointer to LLView header object.
*/
- LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args);
+ LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args, bool is_script = false);
public:
~LLChatHistory();
LLSD getValue() const;
@@ -127,6 +127,7 @@ class LLChatHistory : public LLUICtrl
LLDate mLastMessageTime;
bool mIsLastMessageFromLog;
bool mNotifyAboutUnreadMsg;
+ bool mIsLastFromScript;
//std::string mLastMessageTimeStr;
std::string mMessageHeaderFilename;
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index 2b875c708d..0561d56fe1 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -187,6 +187,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)
int sType = notification["source"].asInteger();
mSourceType = (EChatSourceType)sType;
+ mIsFromScript = notification["is_lua"].asBoolean();
std::string color_name = notification["text_color"].asString();
@@ -214,7 +215,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)
{
std::string str_sender;
- str_sender = fromName;
+ str_sender = mIsFromScript ? LLTrans::getString("ScriptBy") + fromName : fromName;
str_sender+=" ";
@@ -401,7 +402,7 @@ void LLFloaterIMNearbyChatToastPanel::draw()
else if(mSourceType == CHAT_SOURCE_SYSTEM)
icon->setValue(LLSD("SL_Logo"));
else if(mSourceType == CHAT_SOURCE_AGENT)
- icon->setValue(mFromID);
+ icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(mFromID));
else if(!mFromID.isNull())
icon->setValue(mFromID);
}
diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h
index d041615060..7df00e8fd9 100644
--- a/indra/newview/llchatitemscontainerctrl.h
+++ b/indra/newview/llchatitemscontainerctrl.h
@@ -48,7 +48,8 @@ protected:
LLFloaterIMNearbyChatToastPanel()
:
mIsDirty(false),
- mSourceType(CHAT_SOURCE_OBJECT)
+ mSourceType(CHAT_SOURCE_OBJECT),
+ mIsFromScript(false)
{};
public:
~LLFloaterIMNearbyChatToastPanel(){}
@@ -58,6 +59,8 @@ public:
const LLUUID& getFromID() const { return mFromID;}
const std::string& getFromName() const { return mFromName; }
+ bool isFromScript() { return mIsFromScript; }
+
//void addText (const std::string& message , const LLStyle::Params& input_params = LLStyle::Params());
//void setMessage (const LLChat& msg);
void snapToMessageHeight ();
@@ -88,6 +91,7 @@ private:
std::string mFromName;
EChatSourceType mSourceType;
LLChatMsgBox* mMsgText;
+ bool mIsFromScript;
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index e64f468cbe..6b817c7cf1 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -52,6 +52,7 @@
#include "llfirstuse.h"
#include "llfloaterimnearbychat.h"
+#include "llfloaterimnearbychatlistener.h"
#include "llagent.h" // gAgent
#include "llgesturemgr.h"
#include "llmultigesture.h"
@@ -71,6 +72,8 @@
S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0;
+static LLFloaterIMNearbyChatListener sChatListener;
+
const S32 EXPANDED_HEIGHT = 266;
const S32 COLLAPSED_HEIGHT = 60;
const S32 EXPANDED_MIN_HEIGHT = 150;
diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp
index 77ceea19af..cda71f97d4 100644
--- a/indra/newview/llfloaterimnearbychathandler.cpp
+++ b/indra/newview/llfloaterimnearbychathandler.cpp
@@ -301,12 +301,13 @@ void LLFloaterIMNearbyChatScreenChannel::addChat(LLSD& chat)
{
LLUUID fromID = chat["from_id"].asUUID(); // agent id or object id
std::string from = chat["from"].asString();
+ bool is_lua = chat["is_lua"].asBoolean();
LLToast* toast = m_active_toasts[0].get();
if (toast)
{
LLFloaterIMNearbyChatToastPanel* panel = dynamic_cast<LLFloaterIMNearbyChatToastPanel*>(toast->getPanel());
- if(panel && panel->messageID() == fromID && panel->getFromName() == from && panel->canAddText())
+ if(panel && panel->messageID() == fromID && panel->getFromName() == from && panel->isFromScript() == is_lua && panel->canAddText())
{
panel->addMessage(chat);
toast->reshapeToPanel();
@@ -598,17 +599,22 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
{
// Handle IRC styled messages.
std::string toast_msg;
+ std::string msg_text = without_LUA_PREFIX(chat_msg.mText, chat_msg.mIsScript);
if (chat_msg.mChatStyle == CHAT_STYLE_IRC)
{
+ if (chat_msg.mIsScript)
+ {
+ toast_msg += LLTrans::getString("ScriptStr");
+ }
if (!chat_msg.mFromName.empty())
{
toast_msg += chat_msg.mFromName;
}
- toast_msg += chat_msg.mText.substr(3);
+ toast_msg += msg_text.substr(3);
}
else
{
- toast_msg = chat_msg.mText;
+ toast_msg = msg_text;
}
bool chat_overlaps = false;
@@ -658,6 +664,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
chat["color_alpha"] = r_color_alpha;
chat["font_size"] = (S32)LLViewerChat::getChatFontSize() ;
chat["message"] = toast_msg;
+ chat["is_lua"] = chat_msg.mIsScript;
channel->addChat(chat);
}
diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp
index 616acf0eae..0618741cc4 100644
--- a/indra/newview/llfloaterimnearbychatlistener.cpp
+++ b/indra/newview/llfloaterimnearbychatlistener.cpp
@@ -34,12 +34,14 @@
#include "llagent.h"
#include "llchat.h"
#include "llviewercontrol.h"
+#include "stringize.h"
+static const F32 CHAT_THROTTLE_PERIOD = 1.f;
-LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar)
+LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener()
: LLEventAPI("LLChatBar",
"LLChatBar listener to (e.g.) sendChat, etc."),
- mChatbar(chatbar)
+ mLastThrottleTime(0)
{
add("sendChat",
"Send chat to the simulator:\n"
@@ -51,10 +53,19 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyCh
// "sendChat" command
-void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const
+void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data)
{
+ F64 cur_time = LLTimer::getElapsedSeconds();
+
+ if (cur_time < mLastThrottleTime + CHAT_THROTTLE_PERIOD)
+ {
+ LL_DEBUGS("LLFloaterIMNearbyChatListener") << "'sendChat' was throttled" << LL_ENDL;
+ return;
+ }
+ mLastThrottleTime = cur_time;
+
// Extract the data
- std::string chat_text = chat_data["message"].asString();
+ std::string chat_text = LUA_PREFIX + chat_data["message"].asString();
S32 channel = 0;
if (chat_data.has("channel"))
@@ -81,20 +92,14 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const
}
// Have to prepend /42 style channel numbers
- std::string chat_to_send;
- if (channel == 0)
- {
- chat_to_send = chat_text;
- }
- else
+ if (channel)
{
- chat_to_send += "/";
- chat_to_send += chat_data["channel"].asString();
- chat_to_send += " ";
- chat_to_send += chat_text;
+ chat_text = stringize("/", chat_data["channel"].asString(), " ", chat_text);
}
// Send it as if it was typed in
- mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, ((BOOL)(channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim"));
+ LLFloaterIMNearbyChat::sendChatFromViewer(chat_text, type_o_chat,
+ (channel == 0) &&
+ gSavedSettings.getBOOL("PlayChatAnim"));
}
diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h
index 96184d95b3..18a8bacfaa 100644
--- a/indra/newview/llfloaterimnearbychatlistener.h
+++ b/indra/newview/llfloaterimnearbychatlistener.h
@@ -38,12 +38,12 @@ class LLFloaterIMNearbyChat;
class LLFloaterIMNearbyChatListener : public LLEventAPI
{
public:
- LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar);
+ LLFloaterIMNearbyChatListener();
private:
- void sendChat(LLSD const & chat_data) const;
+ void sendChat(LLSD const & chat_data);
- LLFloaterIMNearbyChat & mChatbar;
+ F64 mLastThrottleTime{ 0.0 };
};
#endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H
diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp
index 597cf3c98c..00520f100e 100644
--- a/indra/newview/llviewerchat.cpp
+++ b/indra/newview/llviewerchat.cpp
@@ -30,6 +30,7 @@
// newview includes
#include "llagent.h" // gAgent
#include "llslurl.h"
+#include "lltrans.h"
#include "lluicolor.h"
#include "lluicolortable.h"
#include "llviewercontrol.h" // gSavedSettings
@@ -216,8 +217,7 @@ S32 LLViewerChat::getChatFontSize()
//static
void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg)
{
- std::string tmpmsg = chat.mText;
-
+ std::string tmpmsg = without_LUA_PREFIX(chat.mText, chat.mIsScript);
if(chat.mChatStyle == CHAT_STYLE_IRC)
{
formated_msg = chat.mFromName + tmpmsg.substr(3);
@@ -227,6 +227,11 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg)
formated_msg = tmpmsg;
}
+ if (chat.mIsScript)
+ {
+ formated_msg = LLTrans::getString("ScriptStr") + formated_msg;
+ }
+
}
//static
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 5399301218..01d4695eda 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2600,8 +2600,11 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
BOOL ircstyle = FALSE;
+ auto [message, is_script] = LLStringUtil::withoutPrefix(mesg, LUA_PREFIX);
+ chat.mIsScript = is_script;
+
// Look for IRC-style emotes here so chatbubbles work
- std::string prefix = mesg.substr(0, 4);
+ std::string prefix = message.substr(0, 4);
if (prefix == "/me " || prefix == "/me'")
{
ircstyle = TRUE;
diff --git a/indra/newview/scripts/lua/LLChat.lua b/indra/newview/scripts/lua/LLChat.lua
new file mode 100644
index 0000000000..7db538e837
--- /dev/null
+++ b/indra/newview/scripts/lua/LLChat.lua
@@ -0,0 +1,17 @@
+leap = require 'leap'
+
+local LLChat = {}
+
+function LLChat.sendNearby(msg)
+ leap.send('LLChatBar', {op='sendChat', message=msg})
+end
+
+function LLChat.sendWhisper(msg)
+ leap.send('LLChatBar', {op='sendChat', type='whisper', message=msg})
+end
+
+function LLChat.sendShout(msg)
+ leap.send('LLChatBar', {op='sendChat', type='shout', message=msg})
+end
+
+return LLChat
diff --git a/indra/newview/scripts/lua/test_LLChat.lua b/indra/newview/scripts/lua/test_LLChat.lua
new file mode 100644
index 0000000000..3abaf28e42
--- /dev/null
+++ b/indra/newview/scripts/lua/test_LLChat.lua
@@ -0,0 +1,18 @@
+LLChat = require 'LLChat'
+
+function generateRandomWord(length)
+ local alphabet = "abcdefghijklmnopqrstuvwxyz"
+ local wordTable = {}
+ for i = 1, length do
+ local randomIndex = math.random(1, #alphabet)
+ table.insert(wordTable, alphabet:sub(randomIndex, randomIndex))
+ end
+ return table.concat(wordTable)
+end
+
+local msg = {'AI says:'}
+math.randomseed(os.time())
+for i = 1, math.random(1, 10) do
+ table.insert(msg, generateRandomWord(math.random(1, 8)))
+end
+LLChat.sendNearby(table.concat(msg, ' '))
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index bee58da6b0..76a2660dbb 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -534,7 +534,9 @@ http://secondlife.com/support for help fixing this problem.
<string name="ChangeYourDefaultAnimations">Change your default animations</string>
<string name="ForceSitAvatar">Force your avatar to sit</string>
<string name="ChangeEnvSettings">Change your environment settings</string>
-
+ <string name="ScriptBy" value="Script by "/>
+ <string name="ScriptStr" value="Script: "/>
+
<string name="NotConnected">Not Connected</string>
<string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name -->
<string name="JoinAnExperience"/><!-- intentionally blank -->