diff options
Diffstat (limited to 'indra/newview/llimview.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/newview/llimview.cpp | 943 |
1 files changed, 689 insertions, 254 deletions
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 9623554200..5d3a11e245 100644..100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -29,6 +29,8 @@ #include "llimview.h" #include "llavatarnamecache.h" // IDEVO +#include "llavataractions.h" +#include "llfloaterconversationlog.h" #include "llfloaterreg.h" #include "llfontgl.h" #include "llgl.h" @@ -41,15 +43,15 @@ #include "lltextutil.h" #include "lltrans.h" #include "lluictrlfactory.h" - +#include "llfloaterimsessiontab.h" #include "llagent.h" #include "llagentui.h" #include "llappviewer.h" #include "llavatariconctrl.h" -#include "llbottomtray.h" #include "llcallingcard.h" #include "llchat.h" -#include "llimfloater.h" +#include "llfloaterimsession.h" +#include "llfloaterimcontainer.h" #include "llgroupiconctrl.h" #include "llmd5.h" #include "llmutelist.h" @@ -58,11 +60,15 @@ #include "llviewerwindow.h" #include "llnotifications.h" #include "llnotificationsutil.h" -#include "llnearbychat.h" +#include "llfloaterimnearbychat.h" #include "llspeakers.h" //for LLIMSpeakerMgr #include "lltextbox.h" +#include "lltoolbarview.h" #include "llviewercontrol.h" #include "llviewerparcelmgr.h" +#include "llconversationlog.h" +#include "message.h" +#include "llviewerregion.h" const static std::string ADHOC_NAME_SUFFIX(" Conference"); @@ -97,6 +103,42 @@ BOOL LLSessionTimeoutTimer::tick() return TRUE; } + +void notify_of_message(const LLSD& msg, bool is_dnd_msg); + +void process_dnd_im(const LLSD& notification) +{ + LLSD data = notification["substitutions"]; + LLUUID sessionID = data["SESSION_ID"].asUUID(); + LLUUID fromID = data["FROM_ID"].asUUID(); + + //re-create the IM session if needed + //(when coming out of DND mode upon app restart) + if(!gIMMgr->hasSession(sessionID)) + { + //reconstruct session using data from the notification + std::string name = data["FROM"]; + LLAvatarName av_name; + if (LLAvatarNameCache::get(data["FROM_ID"], &av_name)) + { + name = av_name.getDisplayName(); + } + + + LLIMModel::getInstance()->newSession(sessionID, + name, + IM_NOTHING_SPECIAL, + fromID, + false, + false); //will need slight refactor to retrieve whether offline message or not (assume online for now) + } + + notify_of_message(data, true); + } + + + + static void on_avatar_name_cache_toast(const LLUUID& agent_id, const LLAvatarName& av_name, LLSD msg) @@ -108,77 +150,254 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id, args["FROM"] = av_name.getCompleteName(); args["FROM_ID"] = msg["from_id"]; args["SESSION_ID"] = msg["session_id"]; - LLNotificationsUtil::add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID())); + args["SESSION_TYPE"] = msg["session_type"]; + LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); } -void toast_callback(const LLSD& msg){ - // do not show toast in busy mode or it goes from agent - if (gAgent.getBusy() || gAgent.getID() == msg["from_id"]) +void notify_of_message(const LLSD& msg, bool is_dnd_msg) +{ + std::string user_preferences; + LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_id"].asUUID(); + LLUUID session_id = msg[is_dnd_msg ? "SESSION_ID" : "session_id"].asUUID(); + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); + + // do not show notification which goes from agent + if (gAgent.getID() == participant_id) + { + return; + } + + // determine state of conversations floater + enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status; + + + LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container"); + LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); + bool store_dnd_message = false; // flag storage of a dnd message + bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus(); + if (!LLFloater::isVisible(im_box) || im_box->isMinimized()) { - return; + conversations_floater_status = CLOSED; } - - // check whether incoming IM belongs to an active session or not - if (LLIMModel::getInstance()->getActiveSessionID().notNull() - && LLIMModel::getInstance()->getActiveSessionID() == msg["session_id"]) + else if (!im_box->hasFocus() && + !(session_floater && LLFloater::isVisible(session_floater) + && !session_floater->isMinimized() && session_floater->hasFocus())) { - return; + conversations_floater_status = NOT_ON_TOP; } - - // Skip toasting for system messages - if (msg["from_id"].asUUID() == LLUUID::null) + else if (im_box->getSelectedSession() != session_id) { - return; + conversations_floater_status = ON_TOP; + } + else + { + conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED; } - // *NOTE Skip toasting if the user disable it in preferences/debug settings ~Alexandrea - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession( - msg["session_id"]); - if (!gSavedSettings.getBOOL("EnableGroupChatPopups") - && session->isGroupSessionType()) - { - return; + // determine user prefs for this session + if (session_id.isNull()) + { + if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT) + { + user_preferences = gSavedSettings.getString("NotificationObjectIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundObjectIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + else + { + user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } } - if (!gSavedSettings.getBOOL("EnableIMChatPopups") - && !session->isGroupSessionType()) - { - return; + else if(session->isP2PSessionType()) + { + if (LLAvatarTracker::instance().isBuddy(participant_id)) + { + user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + else + { + user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + } + else if(session->isAdHocSessionType()) + { + user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + else if(session->isGroupSessionType()) + { + user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } + } + + // actions: + + // 0. nothing - exit + if (("noaction" == user_preferences || + ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status) + && session_floater->isMessagePaneExpanded()) + { + return; + } + + // 1. open floater and [optional] surface it + if ("openconversations" == user_preferences && + (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status)) + { + if(!gAgent.isDoNotDisturb()) + { + // Open conversations floater + LLFloaterReg::showInstance("im_container"); + im_box->collapseMessagesPane(false); + if (session_floater) + { + if (session_floater->getHost()) + { + if (NULL != im_box && im_box->isMinimized()) + { + LLFloater::onClickMinimize(im_box); + } + } + else + { + if (session_floater->isMinimized()) + { + LLFloater::onClickMinimize(session_floater); + } + } + } + } + else + { + store_dnd_message = true; + } + + } + + // 2. Flash line item + if ("openconversations" == user_preferences + || ON_TOP == conversations_floater_status + || ("toast" == user_preferences && ON_TOP != conversations_floater_status) + || ("flash" == user_preferences && (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status)) + || is_dnd_msg) + { + if(!LLMuteList::getInstance()->isMuted(participant_id)) + { + if(gAgent.isDoNotDisturb()) + { + store_dnd_message = true; + } + else + { + if (is_dnd_msg && (ON_TOP == conversations_floater_status || + NOT_ON_TOP == conversations_floater_status || + CLOSED == conversations_floater_status)) + { + im_box->highlightConversationItemWidget(session_id, true); + } + else + { + im_box->flashConversationItemWidget(session_id, true); + } + } + } } - // Skip toasting if we have open window of IM with this session id - LLIMFloater* open_im_floater = LLIMFloater::findInstance(msg["session_id"]); - if (open_im_floater && open_im_floater->getVisible()) + // 3. Flash FUI button + if (("toast" == user_preferences || "flash" == user_preferences) && + (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status) + && !is_session_focused + && !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened { - return; + if(!LLMuteList::getInstance()->isMuted(participant_id)) + { + if(!gAgent.isDoNotDisturb()) + { + gToolBarView->flashCommand(LLCommandId("chat"), true, im_box->isMinimized()); + } + else + { + store_dnd_message = true; + } + } } - LLAvatarNameCache::get(msg["from_id"].asUUID(), - boost::bind(&on_avatar_name_cache_toast, - _1, _2, msg)); -} + // 4. Toast + if ((("toast" == user_preferences) && + (ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) && + (!session_floater->isTornOff() || !LLFloater::isVisible(session_floater))) + || !session_floater->isMessagePaneExpanded()) -void LLIMModel::setActiveSessionID(const LLUUID& session_id) -{ - // check if such an ID really exists - if (!findIMSession(session_id)) + { + //Show IM toasts (upper right toasts) + // Skip toasting for system messages and for nearby chat + if(session_id.notNull() && participant_id.notNull()) + { + if(!is_dnd_msg) + { + if(gAgent.isDoNotDisturb()) + { + store_dnd_message = true; + } + else + { + LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); + } + } +} + } + if (store_dnd_message) { - llwarns << "Trying to set as active a non-existent session!" << llendl; - return; + // If in DND mode, allow notification to be stored so upon DND exit + // the user will be notified with some limitations (see 'is_dnd_msg' flag checks) + if(session_id.notNull() + && participant_id.notNull() + && !session_floater->isShown()) + { + LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); + } } +} - mActiveSessionID = session_id; +void on_new_message(const LLSD& msg) +{ + notify_of_message(msg, false); } LLIMModel::LLIMModel() { - addNewMsgCallback(LLIMFloater::newIMCallback); - addNewMsgCallback(toast_callback); + addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); + addNewMsgCallback(boost::bind(&on_new_message, _1)); } -LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice) +LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) : mSessionID(session_id), mName(name), mType(type), + mHasOfflineMessage(has_offline_msg), mParticipantUnreadMessageCount(0), mNumUnread(0), mOtherParticipantID(other_participant_id), @@ -190,12 +409,14 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& mTextIMPossible(true), mOtherParticipantIsAvatar(true), mStartCallOnInitialize(false), - mStartedAsIMCall(voice) + mStartedAsIMCall(voice), + mIsDNDsend(false), + mAvatarNameCacheConnection() { // set P2P type by default mSessionType = P2P_SESSION; - if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type) + if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType) { mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID); @@ -249,37 +470,29 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& new LLSessionTimeoutTimer(mSessionID, SESSION_INITIALIZATION_TIMEOUT); } - if (IM_NOTHING_SPECIAL == type) + if (IM_NOTHING_SPECIAL == mType) { mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); } buildHistoryFileName(); - - if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) - { - std::list<LLSD> chat_history; - - //involves parsing of a chat history - LLLogChat::loadAllHistory(mHistoryFileName, chat_history); - addMessagesFromHistory(chat_history); - } + loadHistory(); // Localizing name of ad-hoc session. STORM-153 // Changing name should happen here- after the history file was created, so that // history files have consistent (English) names in different locales. - if (isAdHocSessionType() && IM_SESSION_INVITE == type) + if (isAdHocSessionType() && IM_SESSION_INVITE == mType) { - LLAvatarNameCache::get(mOtherParticipantID, - boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache, - this, _2)); + mAvatarNameCacheConnection = LLAvatarNameCache::get(mOtherParticipantID,boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache,this, _2)); } } void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name) { - if (av_name.mIsTemporaryName) + mAvatarNameCacheConnection.disconnect(); + + if (!av_name.isValidName()) { S32 separator_index = mName.rfind(" "); std::string name = mName.substr(0, separator_index); @@ -375,6 +588,8 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES break; } } + default: + break; } // Update speakers list when connected if (LLVoiceChannel::STATE_CONNECTED == new_state) @@ -385,6 +600,11 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES LLIMModel::LLIMSession::~LLIMSession() { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + delete mSpeakers; mSpeakers = NULL; @@ -450,11 +670,11 @@ void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& histo { const LLSD& msg = *it; - std::string from = msg[IM_FROM]; + std::string from = msg[LL_IM_FROM]; LLUUID from_id; - if (msg[IM_FROM_ID].isDefined()) + if (msg[LL_IM_FROM_ID].isDefined()) { - from_id = msg[IM_FROM_ID].asUUID(); + from_id = msg[LL_IM_FROM_ID].asUUID(); } else { @@ -463,8 +683,8 @@ void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& histo gCacheName->getUUID(legacy_name, from_id); } - std::string timestamp = msg[IM_TIME]; - std::string text = msg[IM_TEXT]; + std::string timestamp = msg[LL_IM_TIME]; + std::string text = msg[LL_IM_TEXT]; addMessage(from, from_id, text, timestamp, true); @@ -488,10 +708,23 @@ void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const } } +void LLIMModel::LLIMSession::loadHistory() +{ + mMsgs.clear(); + + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) + { + std::list<LLSD> chat_history; + + //involves parsing of a chat history + LLLogChat::loadChatHistory(mHistoryFileName, chat_history); + addMessagesFromHistory(chat_history); + } +} + LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const { - return get_if_there(mId2SessionMap, session_id, - (LLIMModel::LLIMSession*) NULL); + return get_if_there(mId2SessionMap, session_id, (LLIMModel::LLIMSession*) NULL); } //*TODO consider switching to using std::set instead of std::list for holding LLUUIDs across the whole code @@ -533,7 +766,7 @@ LLIMModel::LLIMSession* LLIMModel::findAdHocIMSession(const uuid_vec_t& ids) return NULL; } -bool LLIMModel::LLIMSession::isOutgoingAdHoc() +bool LLIMModel::LLIMSession::isOutgoingAdHoc() const { return IM_SESSION_CONFERENCE_START == mType; } @@ -553,23 +786,23 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline() return !mOtherParticipantIsAvatar; } -void LLIMModel::LLIMSession::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name) +LLUUID LLIMModel::LLIMSession::generateOutgoingAdHocHash() const { - if (av_name.mUsername.empty()) + LLUUID hash = LLUUID::null; + + if (mInitialTargetIDs.size()) { - // display names is off, use mDisplayName which will be the legacy name - mHistoryFileName = LLCacheName::buildUsername(av_name.mDisplayName); - } - else - { - mHistoryFileName = av_name.mUsername; + std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); + hash = generateHash(sorted_uuids); } + + return hash; } void LLIMModel::LLIMSession::buildHistoryFileName() { mHistoryFileName = mName; - + //ad-hoc requires sophisticated chat history saving schemes if (isAdHoc()) { @@ -582,23 +815,33 @@ void LLIMModel::LLIMSession::buildHistoryFileName() if (mInitialTargetIDs.size()) { std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end()); - mHistoryFileName = mName + " hash" + generateHash(sorted_uuids); - return; + mHistoryFileName = mName + " hash" + generateHash(sorted_uuids).asString(); + } + else + { + //in case of incoming ad-hoc sessions + mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4); } - - //in case of incoming ad-hoc sessions - mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4); } - - // look up username to use as the log name - if (isP2P()) + else if (isP2P()) // look up username to use as the log name { - LLAvatarNameCache::get(mOtherParticipantID, boost::bind(&LLIMModel::LLIMSession::onAvatarNameCache, this, _1, _2)); + LLAvatarName av_name; + // For outgoing sessions we already have a cached name + // so no need for a callback in LLAvatarNameCache::get() + if (LLAvatarNameCache::get(mOtherParticipantID, &av_name)) + { + mHistoryFileName = LLCacheName::buildUsername(av_name.getUserName()); + } + else + { + // Incoming P2P sessions include a name that we can use to build a history file name + mHistoryFileName = LLCacheName::buildUsername(mName); + } } } //static -std::string LLIMModel::LLIMSession::generateHash(const std::set<LLUUID>& sorted_uuids) +LLUUID LLIMModel::LLIMSession::generateHash(const std::set<LLUUID>& sorted_uuids) { LLMD5 md5_uuid; @@ -612,10 +855,9 @@ std::string LLIMModel::LLIMSession::generateHash(const std::set<LLUUID>& sorted_ LLUUID participants_md5_hash; md5_uuid.raw_digest((unsigned char*) participants_md5_hash.mData); - return participants_md5_hash.asString(); + return participants_md5_hash; } - void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id) { LLIMSession* session = findIMSession(old_session_id); @@ -627,16 +869,19 @@ void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, con { mId2SessionMap.erase(old_session_id); mId2SessionMap[new_session_id] = session; - - gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); } - LLIMFloater* im_floater = LLIMFloater::findInstance(old_session_id); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(old_session_id); if (im_floater) { im_floater->sessionInitReplyReceived(new_session_id); } + if (old_session_id != new_session_id) + { + gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); + } + // auto-start the call on session initialization? if (session->mStartCallOnInitialize) { @@ -672,36 +917,37 @@ void LLIMModel::testMessages() //session name should not be empty bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, - const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice) + const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg) { if (name.empty()) { - llwarns << "Attempt to create a new session with empty name; id = " << session_id << llendl; + LL_WARNS() << "Attempt to create a new session with empty name; id = " << session_id << LL_ENDL; return false; } if (findIMSession(session_id)) { - llwarns << "IM Session " << session_id << " already exists" << llendl; + LL_WARNS() << "IM Session " << session_id << " already exists" << LL_ENDL; return false; } - LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice); + LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); mId2SessionMap[session_id] = session; // When notifying observer, name of session is used instead of "name", because they may not be the // same if it is an adhoc session (in this case name is localized in LLIMSession constructor). std::string session_name = LLIMModel::getInstance()->getName(session_id); - LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, session_name, other_participant_id); + LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, session_name, other_participant_id,has_offline_msg); return true; } -bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, bool voice) +bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, bool voice, bool has_offline_msg) { - uuid_vec_t no_ids; - return newSession(session_id, name, type, other_participant_id, no_ids, voice); + uuid_vec_t ids; + ids.push_back(other_participant_id); + return newSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg); } bool LLIMModel::clearSession(const LLUUID& session_id) @@ -712,12 +958,22 @@ bool LLIMModel::clearSession(const LLUUID& session_id) return true; } +void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index, const bool sendNoUnreadMsgs) +{ + getMessagesSilently(session_id, messages, start_index); + + if (sendNoUnreadMsgs) + { + sendNoUnreadMessages(session_id); + } +} + void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index) { LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return; } @@ -739,7 +995,7 @@ void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id) LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return; } @@ -753,20 +1009,13 @@ void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id) mNoUnreadMsgsSignal(arg); } -void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index) -{ - getMessagesSilently(session_id, messages, start_index); - - sendNoUnreadMessages(session_id); -} - bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return false; } @@ -777,19 +1026,20 @@ 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 (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) + if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1) { std::string from_name = from; LLAvatarName av_name; if (!from_id.isNull() && LLAvatarNameCache::get(from_id, &av_name) && - !av_name.mIsDisplayNameDefault) + !av_name.isDisplayNameDefault()) { from_name = av_name.getCompleteName(); } LLLogChat::saveHistory(file_name, from_name, from_id, utf8_text); + LLConversationLog::instance().cache(); // update the conversation log too return true; } else @@ -798,11 +1048,6 @@ bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, } } -bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) -{ - return logToFile(LLIMModel::getInstance()->getHistoryFileName(session_id), from, from_id, utf8_text); -} - bool LLIMModel::proccessOnlineOfflineNotification( const LLUUID& session_id, const std::string& utf8_text) @@ -832,6 +1077,7 @@ bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, co arg["from"] = from; arg["from_id"] = from_id; arg["time"] = LLLogChat::timestamp(false); + arg["session_type"] = session->mSessionType; mNewMsgSignal(arg); return true; @@ -844,7 +1090,7 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return NULL; } @@ -856,8 +1102,11 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, } addToHistory(session_id, from_name, from_id, utf8_text); - if (log2file) logToFile(session_id, from_name, from_id, utf8_text); - + if (log2file) + { + logToFile(getHistoryFileName(session_id), from_name, from_id, utf8_text); + } + session->mNumUnread++; //update count of unread messages from real participant @@ -876,9 +1125,9 @@ const std::string LLIMModel::getName(const LLUUID& session_id) const { LLIMSession* session = findIMSession(session_id); - if (!session) + if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return LLTrans::getString("no_session_message"); } @@ -890,7 +1139,7 @@ const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return -1; } @@ -902,7 +1151,7 @@ const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; return LLUUID::null; } @@ -914,7 +1163,7 @@ EInstantMessage LLIMModel::getType(const LLUUID& session_id) const LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return IM_COUNT; } @@ -926,7 +1175,7 @@ LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << "does not exist " << llendl; + LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return NULL; } @@ -938,7 +1187,7 @@ LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << " does not exist " << llendl; + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; return NULL; } @@ -950,7 +1199,7 @@ const std::string& LLIMModel::getHistoryFileName(const LLUUID& session_id) const LLIMSession* session = findIMSession(session_id); if (!session) { - llwarns << "session " << session_id << " does not exist " << llendl; + LL_WARNS() << "session " << session_id << " does not exist " << LL_ENDL; return LLStringUtil::null; } @@ -1105,7 +1354,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text, // IM_SESSION_INVITE means that this is an Ad-hoc incoming chat // (it can be also Group chat but it is checked above) // In this case mInitialTargetIDs contains Ad-hoc session ID and it should not be added - // to Recent People to prevent showing of an item with (???)(???). See EXT-8246. + // to Recent People to prevent showing of an item with (?? ?)(?? ?), sans the spaces. See EXT-8246. // Concrete participants will be added into this list once they sent message in chat. if (IM_SESSION_INVITE == dialog) return; @@ -1212,6 +1461,7 @@ void start_deprecated_conference_chat( class LLStartConferenceChatResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLStartConferenceChatResponder); public: LLStartConferenceChatResponder( const LLUUID& temp_session_id, @@ -1225,10 +1475,12 @@ public: mAgents = agents_to_invite; } - virtual void error(U32 statusNum, const std::string& reason) +protected: + virtual void httpFailure() { //try an "old school" way. - if ( statusNum == 400 ) + // *TODO: What about other error status codes? 4xx 5xx? + if ( getStatus() == HTTP_BAD_REQUEST ) { start_deprecated_conference_chat( mTempSessionID, @@ -1237,6 +1489,8 @@ public: mAgents); } + LL_WARNS() << dumpResponse() << LL_ENDL; + //else throw an error back to the client? //in theory we should have just have these error strings //etc. set up in this file as opposed to the IMMgr, @@ -1327,6 +1581,7 @@ bool LLIMModel::sendStartSession( class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Responder { + LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder); public: LLViewerChatterBoxInvitationAcceptResponder( const LLUUID& session_id, @@ -1336,8 +1591,15 @@ public: mInvitiationType = invitation_type; } - void result(const LLSD& content) +private: + void httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } if ( gIMMgr) { LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); @@ -1374,7 +1636,7 @@ public: && LLIMModel::getInstance()->findIMSession(mSessionID)) { // TODO remove in 2010, for voice calls we do not open an IM window - //LLIMFloater::show(mSessionID); + //LLFloaterIMSession::show(mSessionID); } gIMMgr->clearPendingAgentListUpdates(mSessionID); @@ -1382,17 +1644,17 @@ public: } } - void error(U32 statusNum, const std::string& reason) - { + void httpFailure() + { + LL_WARNS() << dumpResponse() << LL_ENDL; //throw something back to the viewer here? if ( gIMMgr ) { gIMMgr->clearPendingAgentListUpdates(mSessionID); gIMMgr->clearPendingInvitation(mSessionID); - if ( 404 == statusNum ) + if ( HTTP_NOT_FOUND == getStatus() ) { - std::string error_string; - error_string = "session_does_not_exist_error"; + static const std::string error_string("session_does_not_exist_error"); gIMMgr->showSessionStartError(error_string, mSessionID); } } @@ -1442,6 +1704,11 @@ LLUUID LLIMMgr::computeSessionID( session_id = other_participant_id ^ agent_id; } } + + if (gAgent.isInGroup(session_id) && (session_id != other_participant_id)) + { + LL_WARNS() << "Group session id different from group id: IM type = " << dialog << ", session id = " << session_id << ", group id = " << other_participant_id << LL_ENDL; + } return session_id; } @@ -1518,7 +1785,7 @@ LLIMMgr::onConfirmForceCloseError( //only 1 option really LLUUID session_id = notification["payload"]["session_id"]; - LLFloater* floater = LLIMFloater::findInstance(session_id); + LLFloater* floater = LLFloaterIMSession::findInstance(session_id); if ( floater ) { floater->closeFloater(FALSE); @@ -1673,27 +1940,48 @@ LLCallDialog::~LLCallDialog() LLUI::removePopup(this); } -void LLCallDialog::getAllowedRect(LLRect& rect) +BOOL LLCallDialog::postBuild() { - rect = gViewerWindow->getWorldViewRectScaled(); + if (!LLDockableFloater::postBuild() || !gToolBarView) + return FALSE; + + dockToToolbarButton("speak"); + + return TRUE; } -BOOL LLCallDialog::postBuild() +void LLCallDialog::dockToToolbarButton(const std::string& toolbarButtonName) { - if (!LLDockableFloater::postBuild()) - return FALSE; + LLDockControl::DocAt dock_pos = getDockControlPos(toolbarButtonName); + LLView *anchor_panel = gToolBarView->findChildView(toolbarButtonName); - // dock the dialog to the Speak Button, where other sys messages appear - LLView *anchor_panel = LLBottomTray::getInstance()->getChild<LLView>("speak_panel"); + setUseTongue(anchor_panel); - setDockControl(new LLDockControl( - anchor_panel, this, - getDockTongue(), LLDockControl::TOP, - boost::bind(&LLCallDialog::getAllowedRect, this, _1))); + setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos)); +} - return TRUE; +LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarButtonName) +{ + LLCommandId command_id(toolbarButtonName); + S32 toolbar_loc = gToolBarView->hasCommand(command_id); + + LLDockControl::DocAt doc_at = LLDockControl::TOP; + + switch (toolbar_loc) + { + case LLToolBarEnums::TOOLBAR_LEFT: + doc_at = LLDockControl::RIGHT; + break; + + case LLToolBarEnums::TOOLBAR_RIGHT: + doc_at = LLDockControl::LEFT; + break; + } + + return doc_at; } + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLOutgoingCallDialog //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1855,7 +2143,7 @@ void LLOutgoingCallDialog::show(const LLSD& key) LLAvatarName av_name; if (LLAvatarNameCache::get(callee_id, &av_name)) { - final_callee_name = av_name.mDisplayName; + final_callee_name = av_name.getDisplayName(); title = av_name.getCompleteName(); } } @@ -1957,7 +2245,8 @@ BOOL LLOutgoingCallDialog::postBuild() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : -LLCallDialog(payload) +LLCallDialog(payload), +mAvatarNameCacheConnection() { } @@ -2027,9 +2316,11 @@ BOOL LLIncomingCallDialog::postBuild() else { // Get the full name information - LLAvatarNameCache::get(caller_id, - boost::bind(&LLIncomingCallDialog::onAvatarNameCache, - this, _1, _2, call_type)); + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + mAvatarNameCacheConnection = LLAvatarNameCache::get(caller_id, boost::bind(&LLIncomingCallDialog::onAvatarNameCache, this, _1, _2, call_type)); } setIcon(session_id, caller_id); @@ -2055,7 +2346,6 @@ BOOL LLIncomingCallDialog::postBuild() getChildView("Start IM")->setVisible( is_avatar && notify_box_type != "VoiceInviteAdHoc" && notify_box_type != "VoiceInviteGroup"); setCanDrag(FALSE); - return TRUE; } @@ -2063,7 +2353,6 @@ void LLIncomingCallDialog::setCallerName(const std::string& ui_title, const std::string& ui_label, const std::string& call_type) { - setTitle(ui_title); // call_type may be a string like " is calling." LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name"); @@ -2074,14 +2363,15 @@ void LLIncomingCallDialog::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, const std::string& call_type) { + mAvatarNameCacheConnection.disconnect(); std::string title = av_name.getCompleteName(); - setCallerName(title, av_name.mDisplayName, call_type); + setCallerName(title, av_name.getCompleteName(), call_type); } void LLIncomingCallDialog::onOpen(const LLSD& key) { LLCallDialog::onOpen(key); - + make_ui_sound("UISndStartIM"); LLStringUtil::format_map_t args; LLGroupData data; // if it's a group call, retrieve group name to use it in question @@ -2089,18 +2379,6 @@ void LLIncomingCallDialog::onOpen(const LLSD& key) { args["[GROUP]"] = data.mName; } - // tell the user which voice channel they would be leaving - LLVoiceChannel *voice = LLVoiceChannel::getCurrentVoiceChannel(); - if (voice && !voice->getSessionName().empty()) - { - args["[CURRENT_CHAT]"] = voice->getSessionName(); - getChild<LLUICtrl>("question")->setValue(getString(key["question_type"].asString(), args)); - } - else - { - args["[CURRENT_CHAT]"] = getString("localchat"); - getChild<LLUICtrl>("question")->setValue(getString(key["question_type"].asString(), args)); - } } //static @@ -2161,6 +2439,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload { gIMMgr->startCall(session_id, LLVoiceChannel::INCOMING_CALL); } + else + { + LLAvatarActions::startIM(caller_id); + } gIMMgr->clearPendingAgentListUpdates(session_id); gIMMgr->clearPendingInvitation(session_id); @@ -2171,7 +2453,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload std::string correct_session_name = session_name; if (session_name.empty()) { - llwarns << "Received an empty session name from a server" << llendl; + LL_WARNS() << "Received an empty session name from a server" << LL_ENDL; switch(type){ case IM_SESSION_CONFERENCE_START: @@ -2193,10 +2475,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload correct_session_name.append(ADHOC_NAME_SUFFIX); } } - llinfos << "Corrected session name is " << correct_session_name << llendl; + LL_INFOS() << "Corrected session name is " << correct_session_name << LL_ENDL; break; default: - llwarning("Received an empty session name from a server and failed to generate a new proper session name", 0); + LL_WARNS() << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL; break; } } @@ -2363,7 +2645,7 @@ LLIMMgr::LLIMMgr() mPendingInvitations = LLSD::emptyMap(); mPendingAgentListUpdates = LLSD::emptyMap(); - LLIMModel::getInstance()->addNewMsgCallback(boost::bind(&LLIMFloater::sRemoveTypingIndicator, _1)); + LLIMModel::getInstance()->addNewMsgCallback(boost::bind(&LLFloaterIMSession::sRemoveTypingIndicator, _1)); } // Add a message to a session. @@ -2372,6 +2654,7 @@ void LLIMMgr::addMessage( const LLUUID& target_id, const std::string& from, const std::string& msg, + bool is_offline_msg, const std::string& session_name, EInstantMessage dialog, U32 parent_estate_id, @@ -2381,14 +2664,6 @@ void LLIMMgr::addMessage( { LLUUID other_participant_id = target_id; - // don't process muted IMs - if (LLMuteList::getInstance()->isMuted( - other_participant_id, - LLMute::flagTextChat) && !LLMuteList::getInstance()->isLinden(from)) - { - return; - } - LLUUID new_session_id = session_id; if (new_session_id.isNull()) { @@ -2398,16 +2673,37 @@ void LLIMMgr::addMessage( //*NOTE session_name is empty in case of incoming P2P sessions std::string fixed_session_name = from; + bool name_is_setted = false; if(!session_name.empty() && session_name.size()>1) { fixed_session_name = session_name; + name_is_setted = true; + } + bool skip_message = false; + bool from_linden = LLMuteList::getInstance()->isLinden(from); + if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && !from_linden) + { + // Evaluate if we need to skip this message when that setting is true (default is false) + skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... + skip_message &= !(other_participant_id == gAgentID); // You are your best friend... Don't skip yourself } bool new_session = !hasSession(new_session_id); if (new_session) { - LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id); + LLAvatarName av_name; + if (LLAvatarNameCache::get(other_participant_id, &av_name) && !name_is_setted) + { + fixed_session_name = av_name.getDisplayName(); + } + LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg); + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); + skip_message &= !session->isGroupSessionType(); // Do not skip group chats... + if(skip_message) + { + gIMMgr->leaveSession(new_session_id); + } // When we get a new IM, and if you are a god, display a bit // of information about the source. This is to help liaisons // when answering questions. @@ -2429,10 +2725,37 @@ void LLIMMgr::addMessage( LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str()); } - make_ui_sound("UISndNewIncomingIMSession"); + // Logically it would make more sense to reject the session sooner, in another area of the + // code, but the session has to be established inside the server before it can be left. + if (LLMuteList::getInstance()->isMuted(other_participant_id) && !from_linden) + { + LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; + if(!gIMMgr->leaveSession(new_session_id)) + { + LL_INFOS() << "Session " << new_session_id << " does not exist." << LL_ENDL; + } + return; + } + + //Play sound for new conversations + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) + { + make_ui_sound("UISndNewIncomingIMSession"); + } } - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg); + if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message) + { + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg); + } + + // Open conversation floater if offline messages are present + if (is_offline_msg && !skip_message) + { + LLFloaterReg::showInstance("im_container"); + LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")-> + flashConversationItemWidget(new_session_id, true); + } } void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args) @@ -2448,8 +2771,8 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess LLChat chat(message); chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); - if(nearby_chat) + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + if (nearby_chat) { nearby_chat->addMessage(chat); } @@ -2463,11 +2786,13 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); } // log message to file + else { std::string session_name; // since we select user to share item with - his name is already in cache gCacheName->getFullName(args["user_id"], session_name); + session_name = LLCacheName::buildUsername(session_name); LLIMModel::instance().logToFile(session_name, SYSTEM_FROM, LLUUID::null, message.getString()); } } @@ -2542,9 +2867,10 @@ LLUUID LLIMMgr::addSession( EInstantMessage dialog, const LLUUID& other_participant_id, bool voice) { - LLDynamicArray<LLUUID> ids; - ids.put(other_participant_id); - return addSession(name, dialog, other_participant_id, ids, voice); + std::vector<LLUUID> ids; + ids.push_back(other_participant_id); + LLUUID session_id = addSession(name, dialog, other_participant_id, ids, voice); + return session_id; } // Adds a session using the given session_id. If the session already exists @@ -2553,22 +2879,37 @@ LLUUID LLIMMgr::addSession( const std::string& name, EInstantMessage dialog, const LLUUID& other_participant_id, - const LLDynamicArray<LLUUID>& ids, bool voice) + const std::vector<LLUUID>& ids, bool voice, + const LLUUID& floater_id) { - if (0 == ids.getLength()) + if (ids.empty()) { return LLUUID::null; } if (name.empty()) { - llwarning("Session name cannot be null!", 0); + LL_WARNS() << "Session name cannot be null!" << LL_ENDL; return LLUUID::null; } LLUUID session_id = computeSessionID(dialog,other_participant_id); - bool new_session = !LLIMModel::getInstance()->findIMSession(session_id); + if (floater_id.notNull()) + { + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(floater_id); + + if (im_floater) + { + // The IM floater should be initialized with a new session_id + // so that it is found by that id when creating a chiclet in LLFloaterIMSession::onIMChicletCreated, + // and a new floater is not created. + im_floater->initIMSession(session_id); + im_floater->reloadMessages(); + } + } + + bool new_session = (LLIMModel::getInstance()->findIMSession(session_id) == NULL); //works only for outgoing ad-hoc sessions if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) @@ -2581,14 +2922,23 @@ LLUUID LLIMMgr::addSession( } } + //Notify observers that a session was added if (new_session) { LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids, voice); } + //Notifies observers that the session was already added + else + { + std::string session_name = LLIMModel::getInstance()->getName(session_id); + LLIMMgr::getInstance()->notifyObserverSessionActivated(session_id, session_name, other_participant_id); + } //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions if (!new_session) return session_id; + LL_INFOS() << "LLIMMgr::addSession, new session added, name = " << name << ", session id = " << session_id << LL_ENDL; + //Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609) //*TODO After February 2010 remove this commented out line if no one will be missing that warning //noteOfflineUsers(session_id, floater, ids); @@ -2599,6 +2949,8 @@ LLUUID LLIMMgr::addSession( noteMutedUsers(session_id, ids); } + notifyObserverSessionVoiceOrIMStarted(session_id); + return session_id; } @@ -2622,6 +2974,8 @@ void LLIMMgr::removeSession(const LLUUID& session_id) LLIMModel::getInstance()->clearSession(session_id); + LL_INFOS() << "LLIMMgr::removeSession, session removed, session id = " << session_id << LL_ENDL; + notifyObserverSessionRemoved(session_id); } @@ -2635,18 +2989,14 @@ void LLIMMgr::inviteToSession( const std::string& session_handle, const std::string& session_uri) { - //ignore invites from muted residents - if (LLMuteList::getInstance()->isMuted(caller_id)) - { - return; - } - std::string notify_box_type; // voice invite question is different from default only for group call (EXT-7118) std::string question_type = "VoiceInviteQuestionDefault"; - BOOL ad_hoc_invite = FALSE; BOOL voice_invite = FALSE; + bool is_linden = LLMuteList::getInstance()->isLinden(caller_name); + + if(type == IM_SESSION_P2P_INVITE) { //P2P is different...they only have voice invitations @@ -2665,13 +3015,11 @@ void LLIMMgr::inviteToSession( //else it's an ad-hoc //and a voice ad-hoc notify_box_type = "VoiceInviteAdHoc"; - ad_hoc_invite = TRUE; voice_invite = TRUE; } else if ( inv_type == INVITATION_TYPE_IMMEDIATE ) { notify_box_type = "InviteAdHoc"; - ad_hoc_invite = TRUE; } LLSD payload; @@ -2685,7 +3033,18 @@ void LLIMMgr::inviteToSession( payload["session_uri"] = session_uri; payload["notify_box_type"] = notify_box_type; payload["question_type"] = question_type; - + + //ignore invites from muted residents + if (LLMuteList::getInstance()->isMuted(caller_id) && !is_linden) + { + if (voice_invite && "VoiceInviteQuestionDefault" == question_type) + { + LL_INFOS() << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL; + LLIncomingCallDialog::processCallResponse(1, payload); + } + return; + } + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); if (channelp && channelp->callStarted()) { @@ -2696,12 +3055,34 @@ void LLIMMgr::inviteToSession( if (voice_invite) { - if ( // if we're rejecting all incoming call requests - gSavedSettings.getBOOL("VoiceCallsRejectAll") - // or we're rejecting non-friend voice calls and this isn't a friend - || (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)) - ) + bool isRejectGroupCall = (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && (notify_box_type == "VoiceInviteGroup")); + bool isRejectNonFriendCall = (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)); + if (isRejectGroupCall || isRejectNonFriendCall || gAgent.isDoNotDisturb()) { + if (gAgent.isDoNotDisturb() && !isRejectGroupCall && !isRejectNonFriendCall) + { + if (!hasSession(session_id) && (type == IM_SESSION_P2P_INVITE)) + { + std::string fixed_session_name = caller_name; + if(!session_name.empty() && session_name.size()>1) + { + fixed_session_name = session_name; + } + else + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(caller_id, &av_name)) + { + fixed_session_name = av_name.getDisplayName(); + } + } + LLIMModel::getInstance()->newSession(session_id, fixed_session_name, IM_NOTHING_SPECIAL, caller_id, false, false); + } + + LLSD args; + addSystemMessage(session_id, "you_auto_rejected_call", args); + send_do_not_disturb_message(gMessageSystem, caller_id, session_id); + } // silently decline the call LLIncomingCallDialog::processCallResponse(1, payload); return; @@ -2719,6 +3100,15 @@ void LLIMMgr::inviteToSession( { LLFloaterReg::showInstance("incoming_call", payload, FALSE); } + + // Add the caller to the Recent List here (at this point + // "incoming_call" floater is shown and the recipient can + // reject the call), because even if a recipient will reject + // the call, the caller should be added to the recent list + // anyway. STORM-507. + if(type == IM_SESSION_P2P_INVITE) + LLRecentPeople::instance().add(caller_id); + mPendingInvitations[session_id.asString()] = LLSD(); } } @@ -2754,7 +3144,7 @@ void LLIMMgr::clearPendingInvitation(const LLUUID& session_id) void LLIMMgr::processAgentListUpdates(const LLUUID& session_id, const LLSD& body) { - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); if ( im_floater ) { im_floater->processAgentListUpdates(body); @@ -2860,11 +3250,27 @@ void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id) } } -void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) +void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, bool has_offline_msg) { for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) { - (*it)->sessionAdded(session_id, name, other_participant_id); + (*it)->sessionAdded(session_id, name, other_participant_id, has_offline_msg); + } +} + +void LLIMMgr::notifyObserverSessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionActivated(session_id, name, other_participant_id); + } +} + +void LLIMMgr::notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionVoiceOrIMStarted(session_id); } } @@ -2928,11 +3334,54 @@ bool LLIMMgr::isVoiceCall(const LLUUID& session_id) return im_session->mStartedAsIMCall; } +void LLIMMgr::updateDNDMessageStatus() +{ + if (LLIMModel::getInstance()->mId2SessionMap.empty()) return; + + std::map<LLUUID, LLIMModel::LLIMSession*>::const_iterator it = LLIMModel::getInstance()->mId2SessionMap.begin(); + for (; it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + LLIMModel::LLIMSession* session = (*it).second; + + if (session->isP2P()) + { + setDNDMessageSent(session->mSessionID,false); + } + } +} + +bool LLIMMgr::isDNDMessageSend(const LLUUID& session_id) +{ + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; + + return im_session->mIsDNDsend; +} + +void LLIMMgr::setDNDMessageSent(const LLUUID& session_id, bool is_send) +{ + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return; + + im_session->mIsDNDsend = is_send; +} + +void LLIMMgr::addNotifiedNonFriendSessionID(const LLUUID& session_id) +{ + mNotifiedNonFriendSessions.insert(session_id); +} + +bool LLIMMgr::isNonFriendSessionNotified(const LLUUID& session_id) +{ + return mNotifiedNonFriendSessions.end() != mNotifiedNonFriendSessions.find(session_id); + +} + void LLIMMgr::noteOfflineUsers( const LLUUID& session_id, - const LLDynamicArray<LLUUID>& ids) + const std::vector<LLUUID>& ids) { - S32 count = ids.count(); + S32 count = ids.size(); if(count == 0) { const std::string& only_user = LLTrans::getString("only_user_message"); @@ -2945,15 +3394,15 @@ void LLIMMgr::noteOfflineUsers( LLIMModel& im_model = LLIMModel::instance(); for(S32 i = 0; i < count; ++i) { - info = at.getBuddyInfo(ids.get(i)); + info = at.getBuddyInfo(ids.at(i)); LLAvatarName av_name; if (info && !info->isOnline() - && LLAvatarNameCache::get(ids.get(i), &av_name)) + && LLAvatarNameCache::get(ids.at(i), &av_name)) { LLUIString offline = LLTrans::getString("offline_message"); // Use display name only because this user is your friend - offline.setArg("[NAME]", av_name.mDisplayName); + offline.setArg("[NAME]", av_name.getDisplayName()); im_model.proccessOnlineOfflineNotification(session_id, offline); } } @@ -2961,7 +3410,7 @@ void LLIMMgr::noteOfflineUsers( } void LLIMMgr::noteMutedUsers(const LLUUID& session_id, - const LLDynamicArray<LLUUID>& ids) + const std::vector<LLUUID>& ids) { // Don't do this if we don't have a mute list. LLMuteList *ml = LLMuteList::getInstance(); @@ -2970,14 +3419,14 @@ void LLIMMgr::noteMutedUsers(const LLUUID& session_id, return; } - S32 count = ids.count(); + S32 count = ids.size(); if(count > 0) { LLIMModel* im_model = LLIMModel::getInstance(); for(S32 i = 0; i < count; ++i) { - if( ml->isMuted(ids.get(i)) ) + if( ml->isMuted(ids.at(i)) ) { LLUIString muted = LLTrans::getString("muted_message"); @@ -3001,7 +3450,7 @@ void LLIMMgr::processIMTypingStop(const LLIMInfo* im_info) void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing) { LLUUID session_id = computeSessionID(im_info->mIMType, im_info->mFromID); - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); if ( im_floater ) { im_floater->processIMTyping(im_info, typing); @@ -3046,7 +3495,7 @@ public: speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); } - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); if ( im_floater ) { if ( body.has("session_info") ) @@ -3140,7 +3589,7 @@ public: const LLSD& input) const { LLUUID session_id = input["body"]["session_id"].asUUID(); - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id); if ( im_floater ) { im_floater->processSessionUpdate(input["body"]["info"]); @@ -3174,11 +3623,6 @@ public: //just like a normal IM //this is just replicated code from process_improved_im //and should really go in it's own function -jwolk - if (gNoRender) - { - return; - } - LLChat chat; std::string message = message_params["message"].asString(); std::string name = message_params["from_name"].asString(); @@ -3190,20 +3634,11 @@ public: time_t timestamp = (time_t) message_params["timestamp"].asInteger(); - BOOL is_busy = gAgent.getBusy(); - BOOL is_muted = LLMuteList::getInstance()->isMuted( - from_id, - name, - LLMute::flagTextChat); - - BOOL is_linden = LLMuteList::getInstance()->isLinden(name); - std::string separator_string(": "); - - chat.mMuted = is_muted && !is_linden; - chat.mFromID = from_id; - chat.mFromName = name; + BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); - if (!is_linden && (is_busy || is_muted)) + //don't return if user is muted b/c proper way to ignore a muted user who + //initiated an adhoc/group conference is to create then leave the session (see STORM-1731) + if (is_do_not_disturb) { return; } @@ -3218,16 +3653,16 @@ public: } std::string buffer = saved + message; - BOOL is_this_agent = FALSE; if(from_id == gAgentID) { - is_this_agent = TRUE; + return; } gIMMgr->addMessage( session_id, from_id, name, buffer, + IM_OFFLINE == offline, std::string((char*)&bin_bucket[0]), IM_SESSION_INVITE, message_params["parent_estate_id"].asInteger(), @@ -3235,6 +3670,11 @@ public: ll_vector3_from_sd(message_params["position"]), true); + if (LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat)) + { + return; + } + //K now we want to accept the invitation std::string url = gAgent.getRegion()->getCapability( "ChatSessionRequest"); @@ -3254,11 +3694,6 @@ public: } //end if invitation has instant message else if ( input["body"].has("voice") ) { - if (gNoRender) - { - return; - } - if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking()) { // Don't display voice invites unless the user has voice enabled. |