From c6fbf529fce49017cbb7f3cbbfd3a11d611aa137 Mon Sep 17 00:00:00 2001 From: McCabe Maxsted Date: Tue, 6 Apr 2010 22:27:24 -0700 Subject: Ported IM autoresponse options from Emerald, added them to a new window in Preferences > IM --- linden/indra/newview/CMakeLists.txt | 3 + .../newview/app_settings/settings_per_account.xml | 126 +++++++++++ linden/indra/newview/floaterbusy.cpp | 242 ++++++++++++++++++++ linden/indra/newview/floaterbusy.h | 88 +++++++ linden/indra/newview/llprefsim.cpp | 12 + linden/indra/newview/llviewermessage.cpp | 252 ++++++++++++++++++++- .../skins/default/xui/en-us/floater_busy.xml | 93 ++++++++ .../default/xui/en-us/panel_preferences_im.xml | 7 +- 8 files changed, 820 insertions(+), 3 deletions(-) create mode 100644 linden/indra/newview/floaterbusy.cpp create mode 100644 linden/indra/newview/floaterbusy.h create mode 100644 linden/indra/newview/skins/default/xui/en-us/floater_busy.xml diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt index f75360c..1af5e9e 100644 --- a/linden/indra/newview/CMakeLists.txt +++ b/linden/indra/newview/CMakeLists.txt @@ -67,6 +67,7 @@ include_directories( set(viewer_SOURCE_FILES emeraldboobutils.cpp floaterao.cpp + floaterbusy.cpp floaterlogin.cpp hippoGridManager.cpp hippoLimits.cpp @@ -491,6 +492,7 @@ set(viewer_HEADER_FILES ViewerInstall.cmake emeraldboobutils.h floaterao.h + floaterbusy.h floaterlogin.h hippoGridManager.h hippoLimits.h @@ -1096,6 +1098,7 @@ set(viewer_XUI_FILES skins/default/xui/en-us/floater_build_options.xml skins/default/xui/en-us/floater_bulk_perms.xml skins/default/xui/en-us/floater_bumps.xml + skins/default/xui/en-us/floater_busy.xml skins/default/xui/en-us/floater_buy_contents.xml skins/default/xui/en-us/floater_buy_currency.xml skins/default/xui/en-us/floater_buy_land.xml diff --git a/linden/indra/newview/app_settings/settings_per_account.xml b/linden/indra/newview/app_settings/settings_per_account.xml index e43df49..071e53c 100644 --- a/linden/indra/newview/app_settings/settings_per_account.xml +++ b/linden/indra/newview/app_settings/settings_per_account.xml @@ -228,6 +228,132 @@ + + + + InstantMessageResponseFriends + + Comment + Whether to auto-respond to non-friends + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageResponseMuted + + Comment + Whether to auto-respond to muted people + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageResponseAnyone + + Comment + Whether to auto-respond to anyone + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageShowResponded + + Comment + Whether to hide IMs entirely from those you have chosen to send autoresponses + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageShowOnTyping + + Comment + Whether to perform the autorespond the moment they begin to type instead of waiting for a actual message + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageResponseRepeat + + Comment + Whether to keep on resending the autoresponse every line they send + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageResponseItem + + Comment + Whether to send a item along with the autoresponse + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageResponse + + Comment + Auto response to instant messages + Persist + 1 + Type + String + Value + This is an autoresponse! + + InstantMessageResponseItemData + + Comment + UUID + Persist + 1 + Type + String + Value + + + InstantMessageAnnounceIncoming + + Comment + Open a new IM tab when another person begins typing to you and announce that they are doing so. + Persist + 1 + Type + Boolean + Value + 0 + + InstantMessageAnnounceStealFocus + + Comment + Steal focus when opening new IM tab due to other person begins first typing this session + Persist + 1 + Type + Boolean + Value + 1 + + + RLVaLoginLastLocation diff --git a/linden/indra/newview/floaterbusy.cpp b/linden/indra/newview/floaterbusy.cpp new file mode 100644 index 0000000..5823dfa --- /dev/null +++ b/linden/indra/newview/floaterbusy.cpp @@ -0,0 +1,242 @@ +/** +* @file floaterbusy.cpp +* @brief Custom busy mode settings for Imprudence +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2010, McCabe Maxsted +* +* Imprudence Viewer Source Code +* The source code in this file ("Source Code") is provided to you +* under the terms of the GNU General Public License, version 2.0 +* ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in +* this distribution, or online at +* http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "floaterbusy.h" + +#include "llinventorymodel.h" +#include "llstartup.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h" +#include "llviewercontrol.h" +#include "llviewerinventory.h" + +////////begin drop utility///////////// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class InvDropTarget +// +// This handy class is a simple way to drop something on another +// view. It handles drop events, always setting itself to the size of +// its parent. +// +// altered to support a callback so i can slap it in things and it just return the item to a func of my choice +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +InvDropTarget::InvDropTarget(const std::string& name, const LLRect& rect, + void (*callback)(LLViewerInventoryItem*)) : + LLView(name, rect, NOT_MOUSE_OPAQUE, FOLLOWS_ALL), + mDownCallback(callback) +{ +} + +InvDropTarget::~InvDropTarget() +{ +} + +void InvDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) +{ + llinfos << "InvDropTarget::doDrop()" << llendl; +} + +BOOL InvDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL handled = FALSE; + if (getParent()) + { + handled = TRUE; + // check the type + //switch(cargo_type) + //{ + //case DAD_ANIMATION: + //{ + LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; + if (gInventory.getItem(inv_item->getUUID())) + { + *accept = ACCEPT_YES_COPY_SINGLE; + if (drop) + { + //printchat("accepted"); + mDownCallback(inv_item); + } + } + else + { + *accept = ACCEPT_NO; + } + // break; + //} + //default: + // *accept = ACCEPT_NO; + // break; + //} + } + return handled; +} +////////end drop utility/////////////// + +// static +InvDropTarget * FloaterBusy::mObjectDropTarget; + +FloaterBusy::FloaterBusy(const LLSD& seed) : LLFloater("floater_busy") +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_busy.xml"); +} + +BOOL FloaterBusy::postBuild() +{ + childSetAction("btn_ok", onClickOK, this); + childSetAction("btn_cancel", onClickCancel, this); + + LLView *target_view = getChild("im_give_drop_target_rect"); + if (target_view) + { + if (mObjectDropTarget)//shouldn't happen + { + delete mObjectDropTarget; + } + mObjectDropTarget = new InvDropTarget("drop target", target_view->getRect(), IMAutoResponseItemDrop);//, mAvatarID); + addChild(mObjectDropTarget); + } + + if (LLStartUp::getStartupState() == STATE_STARTED) + { + LLUUID itemid = (LLUUID)gSavedPerAccountSettings.getString("InstantMessageResponseItemData"); + LLViewerInventoryItem* item = gInventory.getItem(itemid); + + if (item) + { + childSetValue("im_give_disp_rect_txt","Currently set to: "+item->getName()); + } + else if (itemid.isNull()) + { + childSetValue("im_give_disp_rect_txt","Currently not set"); + } + else + { + childSetValue("im_give_disp_rect_txt","Currently set to a item not on this account"); + } + + itemid = (LLUUID)gSavedSettings.getString("EmeraldBuildPrefs_Item"); + item = gInventory.getItem(itemid); + + if (item) + { + childSetValue("build_item_add_disp_rect_txt","Currently set to: "+item->getName()); + } + else if (itemid.isNull()) + { + childSetValue("build_item_add_disp_rect_txt","Currently not set"); + } + else + { + childSetValue("build_item_add_disp_rect_txt","Currently set to a item not on this account"); + } + } + else + { + childSetValue("im_give_disp_rect_txt","Not logged in"); + childSetValue("build_item_add_disp_rect_txt","Not logged in"); + } + + LLWString auto_response = utf8str_to_wstring( gSavedPerAccountSettings.getString("InstantMessageResponse") ); + LLWStringUtil::replaceChar(auto_response, '^', '\n'); + LLWStringUtil::replaceChar(auto_response, '%', ' '); + childSetText("im_response", wstring_to_utf8str(auto_response)); + + childSetValue("InstantMessageResponseFriends", gSavedPerAccountSettings.getBOOL("InstantMessageResponseFriends")); + childSetValue("InstantMessageResponseMuted", gSavedPerAccountSettings.getBOOL("InstantMessageResponseMuted")); + childSetValue("InstantMessageResponseAnyone", gSavedPerAccountSettings.getBOOL("InstantMessageResponseAnyone")); + childSetValue("InstantMessageShowResponded", gSavedPerAccountSettings.getBOOL("InstantMessageShowResponded")); + childSetValue("InstantMessageShowOnTyping", gSavedPerAccountSettings.getBOOL("InstantMessageShowOnTyping")); + childSetValue("InstantMessageResponseRepeat", gSavedPerAccountSettings.getBOOL("InstantMessageResponseRepeat" )); + childSetValue("InstantMessageResponseItem", gSavedPerAccountSettings.getBOOL("InstantMessageResponseItem")); + childSetValue("InstantMessageAnnounceIncoming", gSavedPerAccountSettings.getBOOL("InstantMessageAnnounceIncoming")); + childSetValue("InstantMessageAnnounceStealFocus", gSavedPerAccountSettings.getBOOL("InstantMessageAnnounceStealFocus")); + + return TRUE; +} + +FloaterBusy::~FloaterBusy() +{ + delete mObjectDropTarget; + mObjectDropTarget = NULL; +} + +void FloaterBusy::IMAutoResponseItemDrop(LLViewerInventoryItem* item) +{ + gSavedPerAccountSettings.setString("InstantMessageResponseItemData", item->getUUID().asString()); + FloaterBusy::getInstance()->childSetValue("im_give_disp_rect_txt","Currently set to: "+item->getName()); +} + +// static +void FloaterBusy::onClickOK(void* userdata) +{ + FloaterBusy* self = (FloaterBusy*)userdata; + self->apply(); + self->close(); +} + +// static +void FloaterBusy::onClickCancel(void* userdata) +{ + FloaterBusy* self = (FloaterBusy*)userdata; + self->cancel(); +} + +void FloaterBusy::cancel() +{ + close(); +} + +void FloaterBusy::apply() +{ + LLTextEditor* im = getChild("im_response"); + LLWString im_response; + if (im) im_response = im->getWText(); + LLWStringUtil::replaceTabsWithSpaces(im_response, 4); + LLWStringUtil::replaceChar(im_response, '\n', '^'); + LLWStringUtil::replaceChar(im_response, ' ', '%'); + gSavedPerAccountSettings.setString("InstantMessageResponse", std::string(wstring_to_utf8str(im_response))); + gSavedPerAccountSettings.setBOOL("InstantMessageResponseMuted", childGetValue("InstantMessageResponseMuted").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageResponseFriends", childGetValue("InstantMessageResponseFriends").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageResponseMuted", childGetValue("InstantMessageResponseMuted").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageResponseAnyone", childGetValue("InstantMessageResponseAnyone").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageShowResponded", childGetValue("InstantMessageShowResponded").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageShowOnTyping", childGetValue("InstantMessageShowOnTyping").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageResponseRepeat", childGetValue("InstantMessageResponseRepeat").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageResponseItem", childGetValue("InstantMessageResponseItem").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageAnnounceIncoming", childGetValue("InstantMessageAnnounceIncoming").asBoolean()); + gSavedPerAccountSettings.setBOOL("InstantMessageAnnounceStealFocus", childGetValue("InstantMessageAnnounceStealFocus").asBoolean()); +} diff --git a/linden/indra/newview/floaterbusy.h b/linden/indra/newview/floaterbusy.h new file mode 100644 index 0000000..821d00d --- /dev/null +++ b/linden/indra/newview/floaterbusy.h @@ -0,0 +1,88 @@ +/** +* @file floaterbusy.h +* @brief Custom busy mode settings for Imprudence +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2010, McCabe Maxsted +* +* Imprudence Viewer Source Code +* The source code in this file ("Source Code") is provided to you +* under the terms of the GNU General Public License, version 2.0 +* ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in +* this distribution, or online at +* http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef FLOATERBUSY_H +#define FLOATERBUSY_H + +#include "llfloater.h" + +class LLViewerInventoryItem; + +////////begin drop utility///////////// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class InvDropTarget +// +// This handy class is a simple way to drop something on another +// view. It handles drop events, always setting itself to the size of +// its parent. +// +// altered to support a callback so i can slap it in things and it just return the item to a func of my choice +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class InvDropTarget : public LLView +{ +public: + InvDropTarget(const std::string& name, const LLRect& rect, void (*callback)(LLViewerInventoryItem*)); + ~InvDropTarget(); + + void doDrop(EDragAndDropType cargo_type, void* cargo_data); + + // + // LLView functionality + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); +protected: + void (*mDownCallback)(LLViewerInventoryItem*); +}; +////////end drop utility/////////////// + +class FloaterBusy : public LLFloater, public LLFloaterSingleton +{ +public: + FloaterBusy(const LLSD& seed); + virtual ~FloaterBusy(); + + BOOL postBuild(); + + void apply(); + void cancel(); + +private: + static InvDropTarget* mObjectDropTarget; + + static void onClickOK(void* userdata); + static void onClickCancel(void* userdata); + + static void IMAutoResponseItemDrop(LLViewerInventoryItem* item); +}; + +#endif FLOATERBUSY_H diff --git a/linden/indra/newview/llprefsim.cpp b/linden/indra/newview/llprefsim.cpp index 0c06122..045139c 100644 --- a/linden/indra/newview/llprefsim.cpp +++ b/linden/indra/newview/llprefsim.cpp @@ -35,6 +35,7 @@ #include "llprefsim.h" +#include "floaterbusy.h" #include "llpanel.h" #include "llcheckboxctrl.h" #include "llstring.h" @@ -65,6 +66,8 @@ public: static void onClickLogPath(void* user_data); static void onCommitLogging(LLUICtrl* ctrl, void* user_data); + static void onClickBusyAdvanced(void* user_data); + protected: bool mGotPersonalInfo; @@ -136,6 +139,8 @@ BOOL LLPrefsIMImpl::postBuild() childSetAction("log_path_button", onClickLogPath, this); childSetCommitCallback("log_chat",onCommitLogging,this); childSetCommitCallback("log_instant_messages",onCommitLogging,this); + + childSetAction("busy_adv_btn", onClickBusyAdvanced, this); return TRUE; } @@ -287,6 +292,13 @@ void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_e // static +void LLPrefsIMImpl::onClickBusyAdvanced(void* user_data) +{ + FloaterBusy::getInstance()->open(); + FloaterBusy::getInstance()->center(); +} + +// static void LLPrefsIMImpl::onClickLogPath(void* user_data) { LLPrefsIMImpl* self=(LLPrefsIMImpl*)user_data; diff --git a/linden/indra/newview/llviewermessage.cpp b/linden/indra/newview/llviewermessage.cpp index 8bdbc30..ba01583 100644 --- a/linden/indra/newview/llviewermessage.cpp +++ b/linden/indra/newview/llviewermessage.cpp @@ -139,6 +139,7 @@ #include "llkeythrottle.h" #include +#include // Boost Reg Expresions #if LL_WINDOWS // For Windows specific error handler #include "llwindebug.h" // For the invalid message handler @@ -1479,6 +1480,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat); BOOL is_linden = LLMuteList::getInstance()->isLinden(name); BOOL is_owned_by_me = FALSE; + + LLUUID computed_session_id = LLIMMgr::computeSessionID(dialog,from_id); chat.mMuted = is_muted && !is_linden; chat.mFromID = from_id; @@ -1502,12 +1505,259 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) message_offset = 3; } + if(dialog == IM_TYPING_START + || dialog == IM_NOTHING_SPECIAL + || dialog == IM_TYPING_STOP + || dialog == IM_BUSY_AUTO_RESPONSE) + { + + if(session_id != computed_session_id) + { + session_id = computed_session_id; + /*if(!gIMMgr->hasSession(correct_session)) + { + //LLUUID sess = gIMMgr->addSession(name, dialog, from_id); + LLUUID sess = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, from_id); + make_ui_sound("UISndNewIncomingIMSession"); + gIMMgr->addMessage( + sess, + from_id, + SYSTEM_FROM, + "Invalid session id used by "+name+", corrected.", + LLStringUtil::null, + IM_NOTHING_SPECIAL, + parent_estate_id, + region_id, + position, + false); + }*/ + } + } + /*if(dialog == IM_NOTHING_SPECIAL) + { + LLVOAvatar* avatarp = find_avatar(from_id); + if(avatarp) + { + if(avatarp->mCheckingCryolife < 2 && avatarp->mIsCryolife == FALSE) + { + boost::regex re( + ".* \\d+\\.\\d+\\.\\d+ \\(\\d+\\) \\w{3,5} \\d+ \\d+ \\d+:\\d+:\\d+ \\(.*\\) <.+,.+,.+>:.+" + , boost::regex_constants::icase); + if(boost::regex_match(message,re)) + { + //llinfos << "CryoLife user detected " << from_id.asString() << llendl; + avatarp->mCheckingCryolife = 2; + avatarp->mIsCryolife = TRUE; + LLVector3 root_pos_last = avatarp->mRoot.getWorldPosition(); + avatarp->idleUpdateNameTag(root_pos_last); + return; + } + else + { + llinfos << "CryoLife user not detected " << from_id.asString() << llendl; + } + } + } + }*/ + bool typing_init = false; + if( dialog == IM_TYPING_START && !is_muted ) + { + if(!gIMMgr->hasSession(computed_session_id) && gSavedPerAccountSettings.getBOOL("InstantMessageAnnounceIncoming")) + { + typing_init = true; + if( gSavedPerAccountSettings.getBOOL("InstantMessageAnnounceStealFocus") ) + { + /*LLUUID sess =*/ gIMMgr->addSession(name, IM_NOTHING_SPECIAL, from_id); + make_ui_sound("UISndNewIncomingIMSession"); + } + gIMMgr->addMessage( + computed_session_id, + from_id, + name, + llformat("You sense a disturbance in the force... (%s is typing)",name.c_str()), + name, + IM_NOTHING_SPECIAL, + parent_estate_id, + region_id, + position, + false); + } + } + + bool is_auto_response = false; + if(dialog == IM_NOTHING_SPECIAL) { + // detect auto responses from GreenLife and compatible viewers + is_auto_response = ( message.substr(0, 21) == "/me (auto-response): " ); + } + + bool do_auto_response = false; + if( gSavedPerAccountSettings.getBOOL("InstantMessageResponseAnyone" ) ) + do_auto_response = true; + + // odd name for auto respond to non-friends + if( gSavedPerAccountSettings.getBOOL("InstantMessageResponseFriends") && + LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL ) + do_auto_response = true; + + if( is_muted && !gSavedPerAccountSettings.getBOOL("InstantMessageResponseMuted") ) + do_auto_response = false; + + if( offline != IM_ONLINE ) + do_auto_response = false; + + if( is_auto_response ) + do_auto_response = false; + + // handle cases where IM_NOTHING_SPECIAL is not an IM + if( name == SYSTEM_FROM || + from_id.isNull() || + to_id.isNull() ) + do_auto_response = false; + +// if( do_auto_response ) +// [RLVa:KB] - Alternate: Emerald-370 + // Emerald specific: auto-response should be blocked if the avie is RLV @sendim=n restricted and the recipient is not an exception + if ( (do_auto_response) && ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) || (gRlvHandler.isException(RLV_BHVR_SENDIM, from_id)) ) ) +// [/RLVa:KB] + { + if((dialog == IM_NOTHING_SPECIAL && !is_auto_response) || + (dialog == IM_TYPING_START && gSavedPerAccountSettings.getBOOL("InstantMessageShowOnTyping")) + ) + { + BOOL has = gIMMgr->hasSession(computed_session_id); + if(!has || gSavedPerAccountSettings.getBOOL("InstantMessageResponseRepeat") || typing_init) + { + BOOL show = !gSavedPerAccountSettings.getBOOL("InstantMessageShowResponded"); + if(!has && show) + { + gIMMgr->addSession(name, IM_NOTHING_SPECIAL, from_id); + } + if(show) + { + gIMMgr->addMessage( + computed_session_id, + from_id, + SYSTEM_FROM, + llformat("Autoresponse sent to %s.",name.c_str()), + LLStringUtil::null, + IM_NOTHING_SPECIAL, + parent_estate_id, + region_id, + position, + false); + } + std::string my_name; + gAgent.buildFullname(my_name); + + //<-- Personalized Autoresponse by Madgeek + std::string autoresponse = gSavedPerAccountSettings.getText("InstantMessageResponse"); + //Define Wildcards + std::string fname_wildcard = "#f"; + std::string lname_wildcard = "#l"; + std::string time_wildcard = "#t"; + //Extract Name + std::string f_name, l_name; + std::istringstream inname(name); + inname >> f_name >> l_name; + //Generate a Timestamp + time_t rawtime; + time(&rawtime); + char * timestamp_chars; + timestamp_chars = asctime(localtime(&rawtime)); + std::string timestamp; + timestamp.assign(timestamp_chars); + timestamp = timestamp.substr(0, timestamp.find('\n')); + //Handle Replacements + size_t found = autoresponse.find(fname_wildcard); + while(found != std::string::npos) + { + autoresponse.replace(found, 2, f_name); + found = autoresponse.find(fname_wildcard); + } + found = autoresponse.find(lname_wildcard); + while(found != std::string::npos) + { + autoresponse.replace(found, 2, l_name); + found = autoresponse.find(lname_wildcard); + } + found = autoresponse.find(time_wildcard); + while(found != std::string::npos) + { + autoresponse.replace(found, 2, timestamp); + found = autoresponse.find(time_wildcard); + } + //--> Personalized Autoresponse + + if(gSavedPerAccountSettings.getBOOL("InstantMessageResponseRepeat") && has && !typing_init) { + // send as busy auto response instead to prevent endless repeating replies + // when other end is a bot or broken client that answers to every usual IM + // reasoning for this decision can be found in RFC2812 3.3.2 Notices + // where PRIVMSG can be seen as IM_NOTHING_SPECIAL and NOTICE can be seen as + // IM_BUSY_AUTO_RESPONSE. The assumption here is that no existing client + // responds to IM_BUSY_AUTO_RESPONSE. --TS + std::string response = autoresponse; + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + from_id, + my_name, + response, + IM_OFFLINE, + IM_BUSY_AUTO_RESPONSE, + session_id); + } else { + std::string response = "/me (auto-response): "+autoresponse; + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + from_id, + my_name, + response, + IM_OFFLINE, + IM_NOTHING_SPECIAL, + session_id); + } + gAgent.sendReliableMessage(); + if(gSavedPerAccountSettings.getBOOL("InstantMessageResponseItem") && (!has || typing_init)) + { + LLUUID itemid = (LLUUID)gSavedPerAccountSettings.getString("InstantMessageResponseItemData"); + LLViewerInventoryItem* item = gInventory.getItem(itemid); + if(item) + { + //childSetValue("im_give_disp_rect_txt","Currently set to: "+item->getName()); + if(show) + { + gIMMgr->addMessage( + computed_session_id, + from_id, + SYSTEM_FROM, + llformat("Sent %s auto-response item \"%s\"",name.c_str(),item->getName().c_str()), + LLStringUtil::null, + IM_NOTHING_SPECIAL, + parent_estate_id, + region_id, + position, + false); + } + LLToolDragAndDrop::giveInventory(from_id, item); + } + } + //InstantMessageResponseItem< + + } + } + } + LLSD args; switch(dialog) { case IM_CONSOLE_AND_CHAT_HISTORY: // These are used for system messages, hence don't need the name, - // as it is always "Second Life". + // as it is always "Imprudence". // *TODO:translate args["MESSAGE"] = message; diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_busy.xml b/linden/indra/newview/skins/default/xui/en-us/floater_busy.xml new file mode 100644 index 0000000..a9bd613 --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_busy.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + Response Text: + + + Use "#f" for recipient's first name + + + Use "#l" for last name + + + Use "#t" for timestamp + + + + + + + + + + Drop an inventory item here + + + + + + Currently set to: ITEM + + +