00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llimview.h"
00035
00036 #include "llfontgl.h"
00037 #include "llrect.h"
00038 #include "llerror.h"
00039 #include "llbutton.h"
00040 #include "llhttpclient.h"
00041 #include "llsdutil.h"
00042 #include "llstring.h"
00043 #include "lluictrlfactory.h"
00044
00045 #include "llagent.h"
00046 #include "llcallingcard.h"
00047 #include "llchat.h"
00048 #include "llresmgr.h"
00049 #include "llfloaterchat.h"
00050 #include "llfloaterchatterbox.h"
00051 #include "llfloaternewim.h"
00052 #include "llhttpnode.h"
00053 #include "llimpanel.h"
00054 #include "llresizebar.h"
00055 #include "lltabcontainer.h"
00056 #include "llviewercontrol.h"
00057 #include "llfloater.h"
00058 #include "llmutelist.h"
00059 #include "llresizehandle.h"
00060 #include "llkeyboard.h"
00061 #include "llui.h"
00062 #include "llviewermenu.h"
00063 #include "llcallingcard.h"
00064 #include "lltoolbar.h"
00065 #include "llviewermessage.h"
00066 #include "llviewerwindow.h"
00067 #include "llnotify.h"
00068 #include "llviewerregion.h"
00069
00070 #include "llfirstuse.h"
00071
00072 const EInstantMessage GROUP_DIALOG = IM_SESSION_GROUP_START;
00073 const EInstantMessage DEFAULT_DIALOG = IM_NOTHING_SPECIAL;
00074
00075
00076
00077
00078 LLIMMgr* gIMMgr = NULL;
00079
00080
00081
00082
00083
00084 static LLString sOnlyUserMessage;
00085 static LLUIString sOfflineMessage;
00086 static LLString sMutedMessage;
00087 static LLUIString sInviteMessage;
00088
00089 std::map<std::string,LLString> LLFloaterIM::sEventStringsMap;
00090 std::map<std::string,LLString> LLFloaterIM::sErrorStringsMap;
00091 std::map<std::string,LLString> LLFloaterIM::sForceCloseSessionMap;
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 LLUUID LLIMMgr::computeSessionID(
00109 EInstantMessage dialog,
00110 const LLUUID& other_participant_id)
00111 {
00112 LLUUID session_id;
00113 if (IM_SESSION_GROUP_START == dialog)
00114 {
00115
00116 session_id = other_participant_id;
00117 }
00118 else if (IM_SESSION_CONFERENCE_START == dialog)
00119 {
00120 session_id.generate();
00121 }
00122 else if (IM_SESSION_INVITE == dialog)
00123 {
00124
00125 session_id = other_participant_id;
00126 }
00127 else
00128 {
00129 LLUUID agent_id = gAgent.getID();
00130 if (other_participant_id == agent_id)
00131 {
00132
00133
00134 session_id = agent_id;
00135 }
00136 else
00137 {
00138
00139 session_id = other_participant_id ^ agent_id;
00140 }
00141 }
00142 return session_id;
00143 }
00144
00145
00146
00147
00148
00149 LLFloaterIM::LLFloaterIM()
00150 {
00151
00152
00153
00154
00155 this->mAutoResize = FALSE;
00156 LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im.xml");
00157 }
00158
00159 BOOL LLFloaterIM::postBuild()
00160 {
00161 sOnlyUserMessage = getString("only_user_message");
00162 sOfflineMessage = getUIString("offline_message");
00163
00164 sInviteMessage = getUIString("invite_message");
00165 sMutedMessage = childGetText("muted_message");
00166
00167 if ( sErrorStringsMap.find("generic") == sErrorStringsMap.end() )
00168 {
00169 sErrorStringsMap["generic"] =
00170 getString("generic_request_error");
00171 }
00172
00173 if ( sErrorStringsMap.find("unverified") ==
00174 sErrorStringsMap.end() )
00175 {
00176 sErrorStringsMap["unverified"] =
00177 getString("insufficient_perms_error");
00178 }
00179
00180 if ( sErrorStringsMap.end() ==
00181 sErrorStringsMap.find("no_ability") )
00182 {
00183 sErrorStringsMap["no_ability"] =
00184 getString("no_ability_error");
00185 }
00186
00187 if ( sErrorStringsMap.end() ==
00188 sErrorStringsMap.find("muted") )
00189 {
00190 sErrorStringsMap["muted"] =
00191 getString("muted_error");
00192 }
00193
00194 if ( sErrorStringsMap.end() ==
00195 sErrorStringsMap.find("not_a_moderator") )
00196 {
00197 sErrorStringsMap["not_a_moderator"] =
00198 getString("not_a_mod_error");
00199 }
00200
00201 if ( sErrorStringsMap.end() ==
00202 sErrorStringsMap.find("does not exist") )
00203 {
00204 sErrorStringsMap["does not exist"] =
00205 getString("session_does_not_exist_error");
00206 }
00207
00208 if ( sEventStringsMap.end() == sEventStringsMap.find("add") )
00209 {
00210 sEventStringsMap["add"] =
00211 getString("add_session_event");
00212 }
00213
00214 if ( sEventStringsMap.end() == sEventStringsMap.find("message") )
00215 {
00216 sEventStringsMap["message"] =
00217 getString("message_session_event");
00218 }
00219
00220
00221 if ( sEventStringsMap.end() == sEventStringsMap.find("mute") )
00222 {
00223 sEventStringsMap["mute"] =
00224 getString("mute_agent_event");
00225 }
00226
00227 if ( sForceCloseSessionMap.end() ==
00228 sForceCloseSessionMap.find("removed") )
00229 {
00230 sForceCloseSessionMap["removed"] =
00231 getString("removed_from_group");
00232 }
00233
00234 if ( sForceCloseSessionMap.end() ==
00235 sForceCloseSessionMap.find("no ability") )
00236 {
00237 sForceCloseSessionMap["no ability"] =
00238 getString("close_on_no_ability");
00239 }
00240
00241 return TRUE;
00242 }
00243
00244
00245
00246
00247
00248
00249
00250 class LLIMViewFriendObserver : public LLFriendObserver
00251 {
00252 public:
00253 LLIMViewFriendObserver(LLIMMgr* tv) : mTV(tv) {}
00254 virtual ~LLIMViewFriendObserver() {}
00255 virtual void changed(U32 mask)
00256 {
00257 if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
00258 {
00259 mTV->refresh();
00260 }
00261 }
00262 protected:
00263 LLIMMgr* mTV;
00264 };
00265
00266
00267 class LLIMMgr::LLIMSessionInvite
00268 {
00269 public:
00270 LLIMSessionInvite(
00271 const LLUUID& session_id,
00272 const LLString& session_name,
00273 const LLUUID& caller_id,
00274 const LLString& caller_name,
00275 EInstantMessage type,
00276 EInvitationType inv_type,
00277 const LLString& session_handle,
00278 const LLString& notify_box) :
00279 mSessionID(session_id),
00280 mSessionName(session_name),
00281 mCallerID(caller_id),
00282 mCallerName(caller_name),
00283 mType(type),
00284 mInvType(inv_type),
00285 mSessionHandle(session_handle),
00286 mNotifyBox(notify_box)
00287 {};
00288
00289 LLUUID mSessionID;
00290 LLString mSessionName;
00291 LLUUID mCallerID;
00292 LLString mCallerName;
00293 EInstantMessage mType;
00294 EInvitationType mInvType;
00295 LLString mSessionHandle;
00296 LLString mNotifyBox;
00297 };
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 EInstantMessage LLIMMgr::defaultIMTypeForAgent(const LLUUID& agent_id)
00308 {
00309 EInstantMessage type = IM_NOTHING_SPECIAL;
00310 if(is_agent_friend(agent_id))
00311 {
00312 if(LLAvatarTracker::instance().isBuddyOnline(agent_id))
00313 {
00314 type = IM_SESSION_CONFERENCE_START;
00315 }
00316 }
00317 return type;
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 void LLIMMgr::toggle(void*)
00329 {
00330 static BOOL return_to_mouselook = FALSE;
00331
00332
00333 llassert( gIMMgr );
00334 BOOL old_state = gIMMgr->getFloaterOpen();
00335
00336
00337 if( gAgent.cameraMouselook() && old_state )
00338 {
00339 return_to_mouselook = TRUE;
00340 gAgent.changeCameraToDefault();
00341 return;
00342 }
00343
00344 BOOL new_state = !old_state;
00345
00346 if (new_state)
00347 {
00348
00349 if ( gAgent.cameraMouselook() )
00350 {
00351 return_to_mouselook = TRUE;
00352 gAgent.changeCameraToDefault();
00353 }
00354 }
00355 else
00356 {
00357
00358 if ( gAgent.cameraThirdPerson() && return_to_mouselook )
00359 {
00360 gAgent.changeCameraToMouselook();
00361 }
00362 return_to_mouselook = FALSE;
00363 }
00364
00365 gIMMgr->setFloaterOpen( new_state );
00366 }
00367
00368
00369
00370
00371
00372 LLIMMgr::LLIMMgr() :
00373 mFriendObserver(NULL),
00374 mIMReceived(FALSE)
00375 {
00376 mFriendObserver = new LLIMViewFriendObserver(this);
00377 LLAvatarTracker::instance().addObserver(mFriendObserver);
00378
00379
00380
00381 LLFloaterIM* dummy_floater = new LLFloaterIM();
00382 delete dummy_floater;
00383
00384 mPendingInvitations = LLSD::emptyMap();
00385 mPendingAgentListUpdates = LLSD::emptyMap();
00386 }
00387
00388 LLIMMgr::~LLIMMgr()
00389 {
00390 LLAvatarTracker::instance().removeObserver(mFriendObserver);
00391 delete mFriendObserver;
00392
00393 }
00394
00395
00396 void LLIMMgr::addMessage(
00397 const LLUUID& session_id,
00398 const LLUUID& target_id,
00399 const char* from,
00400 const char* msg,
00401 const char* session_name,
00402 EInstantMessage dialog,
00403 U32 parent_estate_id,
00404 const LLUUID& region_id,
00405 const LLVector3& position,
00406 bool link_name)
00407 {
00408 LLUUID other_participant_id = target_id;
00409
00410
00411 if (LLMuteList::getInstance()->isMuted(
00412 other_participant_id,
00413 LLMute::flagTextChat) && !LLMuteList::getInstance()->isLinden(from))
00414 {
00415 return;
00416 }
00417
00418
00419
00420 if( other_participant_id == gAgent.getID() )
00421 {
00422 other_participant_id = LLUUID::null;
00423 }
00424
00425 LLFloaterIMPanel* floater;
00426 LLUUID new_session_id = session_id;
00427 if (new_session_id.isNull())
00428 {
00429
00430 new_session_id = computeSessionID(dialog, other_participant_id);
00431 }
00432 floater = findFloaterBySession(new_session_id);
00433 if (!floater)
00434 {
00435 floater = findFloaterBySession(other_participant_id);
00436 if (floater)
00437 {
00438 llinfos << "found the IM session " << session_id
00439 << " by participant " << other_participant_id << llendl;
00440 }
00441 }
00442
00443
00444 if(!floater)
00445 {
00446 const char* name = from;
00447 if(session_name && (strlen(session_name)>1))
00448 {
00449 name = session_name;
00450 }
00451
00452
00453 floater = createFloater(
00454 new_session_id,
00455 other_participant_id,
00456 name,
00457 dialog,
00458 FALSE);
00459
00460
00461
00462
00463 if(gAgent.isGodlike())
00464 {
00465
00466 std::ostringstream bonus_info;
00467 bonus_info << "*** parent estate: "
00468 << parent_estate_id
00469 << ((parent_estate_id == 1) ? ", mainland" : "")
00470 << ((parent_estate_id == 5) ? ", teen" : "");
00471
00472
00473
00474
00475
00476
00477
00478 floater->addHistoryLine(bonus_info.str(), gSavedSettings.getColor4("SystemChatColor"));
00479 }
00480
00481 make_ui_sound("UISndNewIncomingIMSession");
00482 }
00483
00484
00485 bool is_from_system = target_id.isNull() || !strcmp(from, SYSTEM_FROM);
00486 const LLColor4& color = ( is_from_system ?
00487 gSavedSettings.getColor4("SystemChatColor") :
00488 gSavedSettings.getColor("IMChatColor"));
00489 if ( !link_name )
00490 {
00491 floater->addHistoryLine(msg,color);
00492 }
00493 else
00494 {
00495 floater->addHistoryLine(msg, color, true, other_participant_id, from);
00496 }
00497
00498 LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(LLSD());
00499
00500 if( !chat_floater->getVisible() && !floater->getVisible())
00501 {
00502
00503 LLFloater* previouslyActiveFloater = chat_floater->getActiveFloater();
00504
00505
00506
00507 chat_floater->selectFloater(floater);
00508
00509
00510
00511 if ( previouslyActiveFloater && getIMReceived() )
00512 {
00513 chat_floater->setFloaterFlashing(previouslyActiveFloater, TRUE);
00514 }
00515
00516
00517 notifyNewIM();
00518 }
00519 }
00520
00521 void LLIMMgr::addSystemMessage(const LLUUID& session_id, const LLString& message_name, const LLString::format_map_t& args)
00522 {
00523 LLUIString message;
00524
00525
00526 if (session_id.isNull())
00527 {
00528 LLFloaterChat* floaterp = LLFloaterChat::getInstance();
00529
00530 message = floaterp->getUIString(message_name);
00531 message.setArgList(args);
00532
00533 LLChat chat(message);
00534 chat.mSourceType = CHAT_SOURCE_SYSTEM;
00535 LLFloaterChat::getInstance()->addChatHistory(chat);
00536 }
00537 else
00538 {
00539 LLFloaterIMPanel* floaterp = findFloaterBySession(session_id);
00540 if (floaterp)
00541 {
00542 message = floaterp->getUIString(message_name);
00543 message.setArgList(args);
00544
00545 gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString().c_str());
00546 }
00547 }
00548 }
00549
00550 void LLIMMgr::notifyNewIM()
00551 {
00552 if(!gIMMgr->getFloaterOpen())
00553 {
00554 mIMReceived = TRUE;
00555 }
00556 }
00557
00558 void LLIMMgr::clearNewIMNotification()
00559 {
00560 mIMReceived = FALSE;
00561 }
00562
00563 BOOL LLIMMgr::getIMReceived() const
00564 {
00565 return mIMReceived;
00566 }
00567
00568
00569
00570 BOOL LLIMMgr::isIMSessionOpen(const LLUUID& uuid)
00571 {
00572 LLFloaterIMPanel* floater = findFloaterBySession(uuid);
00573 if(floater) return TRUE;
00574 return FALSE;
00575 }
00576
00577 LLUUID LLIMMgr::addP2PSession(const std::string& name,
00578 const LLUUID& other_participant_id,
00579 const LLString& voice_session_handle)
00580 {
00581 LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id);
00582
00583 LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00584 if(floater)
00585 {
00586 LLVoiceChannelP2P* voice_channelp = (LLVoiceChannelP2P*)floater->getVoiceChannel();
00587 voice_channelp->setSessionHandle(voice_session_handle);
00588 }
00589
00590 return session_id;
00591 }
00592
00593
00594
00595
00596
00597 LLUUID LLIMMgr::addSession(
00598 const std::string& name,
00599 EInstantMessage dialog,
00600 const LLUUID& other_participant_id)
00601 {
00602 LLUUID session_id = computeSessionID(dialog, other_participant_id);
00603
00604 LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00605 if(!floater)
00606 {
00607 LLDynamicArray<LLUUID> ids;
00608 ids.put(other_participant_id);
00609
00610 floater = createFloater(
00611 session_id,
00612 other_participant_id,
00613 name,
00614 ids,
00615 dialog,
00616 TRUE);
00617
00618 noteOfflineUsers(floater, ids);
00619 LLFloaterChatterBox::showInstance(session_id);
00620 noteMutedUsers(floater, ids);
00621 LLFloaterChatterBox::getInstance(LLSD())->showFloater(floater);
00622 }
00623 else
00624 {
00625 floater->open();
00626 }
00627
00628 floater->setInputFocus(TRUE);
00629 return floater->getSessionID();
00630 }
00631
00632
00633
00634 LLUUID LLIMMgr::addSession(
00635 const std::string& name,
00636 EInstantMessage dialog,
00637 const LLUUID& other_participant_id,
00638 const LLDynamicArray<LLUUID>& ids)
00639 {
00640 if (0 == ids.getLength())
00641 {
00642 return LLUUID::null;
00643 }
00644
00645 LLUUID session_id = computeSessionID(
00646 dialog,
00647 other_participant_id);
00648
00649 LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00650 if(!floater)
00651 {
00652
00653
00654 floater = createFloater(
00655 session_id,
00656 other_participant_id,
00657 name,
00658 ids,
00659 dialog,
00660 TRUE);
00661
00662 if ( !floater ) return LLUUID::null;
00663
00664 noteOfflineUsers(floater, ids);
00665 LLFloaterChatterBox::showInstance(session_id);
00666 noteMutedUsers(floater, ids);
00667 }
00668 else
00669 {
00670 floater->open();
00671 }
00672
00673 floater->setInputFocus(TRUE);
00674 return floater->getSessionID();
00675 }
00676
00677
00678
00679 void LLIMMgr::removeSession(const LLUUID& session_id)
00680 {
00681 LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00682 if(floater)
00683 {
00684 mFloaters.erase(floater->getHandle());
00685 LLFloaterChatterBox::getInstance(LLSD())->removeFloater(floater);
00686
00687
00688 clearPendingInviation(session_id);
00689 clearPendingAgentListUpdates(session_id);
00690 }
00691 }
00692
00693 void LLIMMgr::inviteToSession(
00694 const LLUUID& session_id,
00695 const LLString& session_name,
00696 const LLUUID& caller_id,
00697 const LLString& caller_name,
00698 EInstantMessage type,
00699 EInvitationType inv_type,
00700 const LLString& session_handle)
00701 {
00702
00703 if (LLMuteList::getInstance()->isMuted(caller_id))
00704 {
00705 return;
00706 }
00707
00708 LLString notify_box_type;
00709
00710 BOOL ad_hoc_invite = FALSE;
00711 if(type == IM_SESSION_P2P_INVITE)
00712 {
00713
00714 notify_box_type = "VoiceInviteP2P";
00715 }
00716 else if ( gAgent.isInGroup(session_id) )
00717 {
00718
00719 notify_box_type = "VoiceInviteGroup";
00720 }
00721 else if ( inv_type == INVITATION_TYPE_VOICE )
00722 {
00723
00724
00725 notify_box_type = "VoiceInviteAdHoc";
00726 ad_hoc_invite = TRUE;
00727 }
00728 else if ( inv_type == INVITATION_TYPE_IMMEDIATE )
00729 {
00730 notify_box_type = "InviteAdHoc";
00731 ad_hoc_invite = TRUE;
00732 }
00733
00734 LLIMSessionInvite* invite = new LLIMSessionInvite(
00735 session_id,
00736 session_name,
00737 caller_id,
00738 caller_name,
00739 type,
00740 inv_type,
00741 session_handle,
00742 notify_box_type);
00743
00744 LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id);
00745 if (channelp && channelp->callStarted())
00746 {
00747
00748 inviteUserResponse(0, invite);
00749 return;
00750 }
00751
00752 if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite)
00753 {
00754
00755 if (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)
00756 {
00757
00758
00759 if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly"))
00760 {
00761
00762 inviteUserResponse(1, invite);
00763 return;
00764 }
00765 }
00766 }
00767
00768 if ( !mPendingInvitations.has(session_id.asString()) )
00769 {
00770 if (caller_name.empty())
00771 {
00772 gCacheName->getName(caller_id, onInviteNameLookup, invite);
00773 }
00774 else
00775 {
00776 LLString::format_map_t args;
00777 args["[NAME]"] = caller_name;
00778 args["[GROUP]"] = session_name;
00779
00780 LLNotifyBox::showXml(notify_box_type,
00781 args,
00782 inviteUserResponse,
00783 (void*)invite);
00784
00785 }
00786 mPendingInvitations[session_id.asString()] = LLSD();
00787 }
00788 else
00789 {
00790 delete invite;
00791 }
00792 }
00793
00794
00795 void LLIMMgr::onInviteNameLookup(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* userdata)
00796 {
00797 LLIMSessionInvite* invite = (LLIMSessionInvite*)userdata;
00798
00799 invite->mCallerName = llformat("%s %s", first, last);
00800 invite->mSessionName = invite->mCallerName;
00801
00802 LLString::format_map_t args;
00803 args["[NAME]"] = invite->mCallerName;
00804
00805 LLNotifyBox::showXml(
00806 invite->mNotifyBox,
00807 args,
00808 inviteUserResponse,
00809 (void*)invite);
00810 }
00811
00812 class LLViewerChatterBoxInvitationAcceptResponder :
00813 public LLHTTPClient::Responder
00814 {
00815 public:
00816 LLViewerChatterBoxInvitationAcceptResponder(
00817 const LLUUID& session_id,
00818 LLIMMgr::EInvitationType invitation_type)
00819 {
00820 mSessionID = session_id;
00821 mInvitiationType = invitation_type;
00822 }
00823
00824 void result(const LLSD& content)
00825 {
00826 if ( gIMMgr)
00827 {
00828 LLFloaterIMPanel* floaterp =
00829 gIMMgr->findFloaterBySession(mSessionID);
00830
00831 if (floaterp)
00832 {
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845 floaterp->setSpeakers(content);
00846
00847
00848
00849
00850
00851 floaterp->updateSpeakersList(
00852 gIMMgr->getPendingAgentListUpdates(mSessionID));
00853
00854 if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE )
00855 {
00856 floaterp->requestAutoConnect();
00857 LLFloaterIMPanel::onClickStartCall(floaterp);
00858
00859 LLFloaterChatterBox::showInstance(TRUE);
00860 }
00861 else if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE )
00862 {
00863 LLFloaterChatterBox::showInstance(TRUE);
00864 }
00865 }
00866
00867 gIMMgr->clearPendingAgentListUpdates(mSessionID);
00868 gIMMgr->clearPendingInviation(mSessionID);
00869 }
00870 }
00871
00872 void error(U32 statusNum, const std::string& reason)
00873 {
00874
00875 if ( gIMMgr )
00876 {
00877 gIMMgr->clearPendingAgentListUpdates(mSessionID);
00878 gIMMgr->clearPendingInviation(mSessionID);
00879
00880 LLFloaterIMPanel* floaterp =
00881 gIMMgr->findFloaterBySession(mSessionID);
00882
00883 if ( floaterp )
00884 {
00885 if ( 404 == statusNum )
00886 {
00887 std::string error_string;
00888 error_string = "does not exist";
00889
00890 floaterp->showSessionStartError(
00891 error_string);
00892 }
00893 }
00894 }
00895 }
00896
00897 private:
00898 LLUUID mSessionID;
00899 LLIMMgr::EInvitationType mInvitiationType;
00900 };
00901
00902
00903 void LLIMMgr::inviteUserResponse(S32 option, void* user_data)
00904 {
00905 LLIMSessionInvite* invitep = (LLIMSessionInvite*)user_data;
00906
00907 switch(option)
00908 {
00909 case 0:
00910 {
00911 if (invitep->mType == IM_SESSION_P2P_INVITE)
00912 {
00913
00914 invitep->mSessionID = gIMMgr->addP2PSession(
00915 invitep->mSessionName,
00916 invitep->mCallerID,
00917 invitep->mSessionHandle);
00918
00919 LLFloaterIMPanel* im_floater =
00920 gIMMgr->findFloaterBySession(
00921 invitep->mSessionID);
00922 if (im_floater)
00923 {
00924 im_floater->requestAutoConnect();
00925 LLFloaterIMPanel::onClickStartCall(im_floater);
00926
00927 LLFloaterChatterBox::showInstance(invitep->mSessionID);
00928 }
00929
00930 gIMMgr->clearPendingAgentListUpdates(invitep->mSessionID);
00931 gIMMgr->clearPendingInviation(invitep->mSessionID);
00932 }
00933 else
00934 {
00935 gIMMgr->addSession(
00936 invitep->mSessionName,
00937 invitep->mType,
00938 invitep->mSessionID);
00939
00940 std::string url = gAgent.getRegion()->getCapability(
00941 "ChatSessionRequest");
00942
00943 LLSD data;
00944 data["method"] = "accept invitation";
00945 data["session-id"] = invitep->mSessionID;
00946 LLHTTPClient::post(
00947 url,
00948 data,
00949 new LLViewerChatterBoxInvitationAcceptResponder(
00950 invitep->mSessionID,
00951 invitep->mInvType));
00952 }
00953 }
00954 break;
00955 case 2:
00956 {
00957
00958 if (!LLMuteList::getInstance()->isMuted(invitep->mCallerID))
00959 {
00960 LLMute mute(invitep->mCallerID, invitep->mCallerName, LLMute::AGENT);
00961 LLMuteList::getInstance()->add(mute);
00962 }
00963 }
00964
00965
00966 case 1:
00967 {
00968 if (invitep->mType == IM_SESSION_P2P_INVITE)
00969 {
00970 if(gVoiceClient)
00971 {
00972 gVoiceClient->declineInvite(invitep->mSessionHandle);
00973 }
00974 }
00975 else
00976 {
00977 std::string url = gAgent.getRegion()->getCapability(
00978 "ChatSessionRequest");
00979
00980 LLSD data;
00981 data["method"] = "decline invitation";
00982 data["session-id"] = invitep->mSessionID;
00983 LLHTTPClient::post(
00984 url,
00985 data,
00986 NULL);
00987 }
00988 }
00989
00990 gIMMgr->clearPendingAgentListUpdates(invitep->mSessionID);
00991 gIMMgr->clearPendingInviation(invitep->mSessionID);
00992 break;
00993 }
00994
00995 delete invitep;
00996 }
00997
00998 void LLIMMgr::refresh()
00999 {
01000 }
01001
01002 void LLIMMgr::setFloaterOpen(BOOL set_open)
01003 {
01004 if (set_open)
01005 {
01006 LLFloaterChatterBox::showInstance();
01007 }
01008 else
01009 {
01010 LLFloaterChatterBox::hideInstance();
01011 }
01012 }
01013
01014
01015 BOOL LLIMMgr::getFloaterOpen()
01016 {
01017 return LLFloaterChatterBox::instanceVisible(LLSD());
01018 }
01019
01020 void LLIMMgr::disconnectAllSessions()
01021 {
01022 LLFloaterIMPanel* floater = NULL;
01023 std::set<LLHandle<LLFloater> >::iterator handle_it;
01024 for(handle_it = mFloaters.begin();
01025 handle_it != mFloaters.end();
01026 )
01027 {
01028 floater = (LLFloaterIMPanel*)handle_it->get();
01029
01030
01031 ++handle_it;
01032
01033 if (floater)
01034 {
01035 floater->setEnabled(FALSE);
01036 floater->close(TRUE);
01037 }
01038 }
01039 }
01040
01041
01042
01043
01044
01045 LLFloaterIMPanel* LLIMMgr::findFloaterBySession(const LLUUID& session_id)
01046 {
01047 LLFloaterIMPanel* rv = NULL;
01048 std::set<LLHandle<LLFloater> >::iterator handle_it;
01049 for(handle_it = mFloaters.begin();
01050 handle_it != mFloaters.end();
01051 ++handle_it)
01052 {
01053 rv = (LLFloaterIMPanel*)handle_it->get();
01054 if(rv && session_id == rv->getSessionID())
01055 {
01056 break;
01057 }
01058 rv = NULL;
01059 }
01060 return rv;
01061 }
01062
01063
01064 BOOL LLIMMgr::hasSession(const LLUUID& session_id)
01065 {
01066 return (findFloaterBySession(session_id) != NULL);
01067 }
01068
01069 void LLIMMgr::clearPendingInviation(const LLUUID& session_id)
01070 {
01071 if ( mPendingInvitations.has(session_id.asString()) )
01072 {
01073 mPendingInvitations.erase(session_id.asString());
01074 }
01075 }
01076
01077 LLSD LLIMMgr::getPendingAgentListUpdates(const LLUUID& session_id)
01078 {
01079 if ( mPendingAgentListUpdates.has(session_id.asString()) )
01080 {
01081 return mPendingAgentListUpdates[session_id.asString()];
01082 }
01083 else
01084 {
01085 return LLSD();
01086 }
01087 }
01088
01089 void LLIMMgr::addPendingAgentListUpdates(
01090 const LLUUID& session_id,
01091 const LLSD& updates)
01092 {
01093 LLSD::map_const_iterator iter;
01094
01095 if ( !mPendingAgentListUpdates.has(session_id.asString()) )
01096 {
01097
01098 mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap();
01099 }
01100
01101 if (
01102 updates.has("agent_updates") &&
01103 updates["agent_updates"].isMap() &&
01104 updates.has("updates") &&
01105 updates["updates"].isMap() )
01106 {
01107
01108 LLSD update_types = LLSD::emptyArray();
01109 LLSD::array_iterator array_iter;
01110
01111 update_types.append("agent_updates");
01112 update_types.append("updates");
01113
01114 for (
01115 array_iter = update_types.beginArray();
01116 array_iter != update_types.endArray();
01117 ++array_iter)
01118 {
01119
01120 for (
01121 iter = updates[array_iter->asString()].beginMap();
01122 iter != updates[array_iter->asString()].endMap();
01123 ++iter)
01124 {
01125 mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] =
01126 iter->second;
01127 }
01128 }
01129 }
01130 else if (
01131 updates.has("updates") &&
01132 updates["updates"].isMap() )
01133 {
01134
01135
01136
01137
01138 for (
01139 iter = updates["updates"].beginMap();
01140 iter != updates["updates"].endMap();
01141 ++iter)
01142 {
01143 mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] =
01144 iter->second;
01145 }
01146 }
01147 }
01148
01149 void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id)
01150 {
01151 if ( mPendingAgentListUpdates.has(session_id.asString()) )
01152 {
01153 mPendingAgentListUpdates.erase(session_id.asString());
01154 }
01155 }
01156
01157
01158
01159
01160
01161 LLFloaterIMPanel* LLIMMgr::createFloater(
01162 const LLUUID& session_id,
01163 const LLUUID& other_participant_id,
01164 const std::string& session_label,
01165 EInstantMessage dialog,
01166 BOOL user_initiated)
01167 {
01168 if (session_id.isNull())
01169 {
01170 llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl;
01171 }
01172
01173 llinfos << "LLIMMgr::createFloater: from " << other_participant_id
01174 << " in session " << session_id << llendl;
01175 LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
01176 session_id,
01177 other_participant_id,
01178 dialog);
01179 LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END;
01180 LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt);
01181 mFloaters.insert(floater->getHandle());
01182 return floater;
01183 }
01184
01185 LLFloaterIMPanel* LLIMMgr::createFloater(
01186 const LLUUID& session_id,
01187 const LLUUID& other_participant_id,
01188 const std::string& session_label,
01189 const LLDynamicArray<LLUUID>& ids,
01190 EInstantMessage dialog,
01191 BOOL user_initiated)
01192 {
01193 if (session_id.isNull())
01194 {
01195 llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl;
01196 }
01197
01198 llinfos << "LLIMMgr::createFloater: from " << other_participant_id
01199 << " in session " << session_id << llendl;
01200 LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
01201 session_id,
01202 other_participant_id,
01203 ids,
01204 dialog);
01205 LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END;
01206 LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt);
01207 mFloaters.insert(floater->getHandle());
01208 return floater;
01209 }
01210
01211 void LLIMMgr::noteOfflineUsers(
01212 LLFloaterIMPanel* floater,
01213 const LLDynamicArray<LLUUID>& ids)
01214 {
01215 S32 count = ids.count();
01216 if(count == 0)
01217 {
01218 floater->addHistoryLine(sOnlyUserMessage, gSavedSettings.getColor4("SystemChatColor"));
01219 }
01220 else
01221 {
01222 const LLRelationship* info = NULL;
01223 LLAvatarTracker& at = LLAvatarTracker::instance();
01224 for(S32 i = 0; i < count; ++i)
01225 {
01226 info = at.getBuddyInfo(ids.get(i));
01227 std::string first, last;
01228 if(info && !info->isOnline()
01229 && gCacheName->getName(ids.get(i), first, last))
01230 {
01231 LLUIString offline = sOfflineMessage;
01232 offline.setArg("[FIRST]", first);
01233 offline.setArg("[LAST]", last);
01234 floater->addHistoryLine(offline, gSavedSettings.getColor4("SystemChatColor"));
01235 }
01236 }
01237 }
01238 }
01239
01240 void LLIMMgr::noteMutedUsers(LLFloaterIMPanel* floater,
01241 const LLDynamicArray<LLUUID>& ids)
01242 {
01243 S32 count = ids.count();
01244 if(count > 0)
01245 {
01246 const LLRelationship* info = NULL;
01247 LLAvatarTracker& at = LLAvatarTracker::instance();
01248 for(S32 i = 0; i < count; ++i)
01249 {
01250 info = at.getBuddyInfo(ids.get(i));
01251 char first[DB_FIRST_NAME_BUF_SIZE];
01252 char last[DB_LAST_NAME_BUF_SIZE];
01253 if(info && LLMuteList::getInstance() && LLMuteList::getInstance()->isMuted(ids.get(i))
01254 && gCacheName->getName(ids.get(i), first, last))
01255 {
01256 LLUIString muted = sMutedMessage;
01257 muted.setArg("[FIRST]", first);
01258 muted.setArg("[LAST]", last);
01259 floater->addHistoryLine(muted);
01260 }
01261 }
01262 }
01263 }
01264
01265 void LLIMMgr::processIMTypingStart(const LLIMInfo* im_info)
01266 {
01267 processIMTypingCore(im_info, TRUE);
01268 }
01269
01270 void LLIMMgr::processIMTypingStop(const LLIMInfo* im_info)
01271 {
01272 processIMTypingCore(im_info, FALSE);
01273 }
01274
01275 void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing)
01276 {
01277 LLUUID session_id = computeSessionID(im_info->mIMType, im_info->mFromID);
01278 LLFloaterIMPanel* floater = findFloaterBySession(session_id);
01279 if (floater)
01280 {
01281 floater->processIMTyping(im_info, typing);
01282 }
01283 }
01284
01285 void LLIMMgr::updateFloaterSessionID(
01286 const LLUUID& old_session_id,
01287 const LLUUID& new_session_id)
01288 {
01289 LLFloaterIMPanel* floater = findFloaterBySession(old_session_id);
01290 if (floater)
01291 {
01292 floater->sessionInitReplyReceived(new_session_id);
01293 }
01294 }
01295
01296 LLFloaterChatterBox* LLIMMgr::getFloater()
01297 {
01298 return LLFloaterChatterBox::getInstance(LLSD());
01299 }
01300
01301 class LLViewerChatterBoxSessionStartReply : public LLHTTPNode
01302 {
01303 public:
01304 virtual void describe(Description& desc) const
01305 {
01306 desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session");
01307 desc.postAPI();
01308 desc.input(
01309 "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string");
01310 desc.source(__FILE__, __LINE__);
01311 }
01312
01313 virtual void post(ResponsePtr response,
01314 const LLSD& context,
01315 const LLSD& input) const
01316 {
01317 LLSD body;
01318 LLUUID temp_session_id;
01319 LLUUID session_id;
01320 bool success;
01321
01322 body = input["body"];
01323 success = body["success"].asBoolean();
01324 temp_session_id = body["temp_session_id"].asUUID();
01325
01326 if ( success )
01327 {
01328 session_id = body["session_id"].asUUID();
01329 gIMMgr->updateFloaterSessionID(
01330 temp_session_id,
01331 session_id);
01332 LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id);
01333 if (floaterp)
01334 {
01335 floaterp->setSpeakers(body);
01336
01337
01338 floaterp->updateSpeakersList(
01339 gIMMgr->getPendingAgentListUpdates(session_id));
01340
01341 if ( body.has("session_info") )
01342 {
01343 floaterp->processSessionUpdate(body["session_info"]);
01344 }
01345
01346
01347 floaterp->updateSpeakersList(
01348 gIMMgr->getPendingAgentListUpdates(session_id));
01349 }
01350 gIMMgr->clearPendingAgentListUpdates(session_id);
01351 }
01352 else
01353 {
01354
01355
01356 LLFloaterIMPanel* floater =
01357 gIMMgr->findFloaterBySession(temp_session_id);
01358
01359 if ( floater )
01360 {
01361 floater->showSessionStartError(body["error"].asString());
01362 }
01363 }
01364
01365 gIMMgr->clearPendingAgentListUpdates(session_id);
01366 }
01367 };
01368
01369 class LLViewerChatterBoxSessionEventReply : public LLHTTPNode
01370 {
01371 public:
01372 virtual void describe(Description& desc) const
01373 {
01374 desc.shortInfo("Used for receiving a reply to a ChatterBox session event");
01375 desc.postAPI();
01376 desc.input(
01377 "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID");
01378 desc.source(__FILE__, __LINE__);
01379 }
01380
01381 virtual void post(ResponsePtr response,
01382 const LLSD& context,
01383 const LLSD& input) const
01384 {
01385 LLUUID session_id;
01386 bool success;
01387
01388 LLSD body = input["body"];
01389 success = body["success"].asBoolean();
01390 session_id = body["session_id"].asUUID();
01391
01392 if ( !success )
01393 {
01394
01395 LLFloaterIMPanel* floater =
01396 gIMMgr->findFloaterBySession(session_id);
01397
01398 if (floater)
01399 {
01400 floater->showSessionEventError(
01401 body["event"].asString(),
01402 body["error"].asString());
01403 }
01404 }
01405 }
01406 };
01407
01408 class LLViewerForceCloseChatterBoxSession: public LLHTTPNode
01409 {
01410 public:
01411 virtual void post(ResponsePtr response,
01412 const LLSD& context,
01413 const LLSD& input) const
01414 {
01415 LLUUID session_id;
01416 LLString reason;
01417
01418 session_id = input["body"]["session_id"].asUUID();
01419 reason = input["body"]["reason"].asString();
01420
01421 LLFloaterIMPanel* floater =
01422 gIMMgr ->findFloaterBySession(session_id);
01423
01424 if ( floater )
01425 {
01426 floater->showSessionForceClose(reason);
01427 }
01428 }
01429 };
01430
01431 class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode
01432 {
01433 public:
01434 virtual void post(
01435 ResponsePtr responder,
01436 const LLSD& context,
01437 const LLSD& input) const
01438 {
01439 LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID());
01440 if (floaterp)
01441 {
01442 floaterp->updateSpeakersList(
01443 input["body"]);
01444 }
01445 else
01446 {
01447
01448
01449
01450 gIMMgr->addPendingAgentListUpdates(
01451 input["body"]["session_id"].asUUID(),
01452 input["body"]);
01453 }
01454 }
01455 };
01456
01457 class LLViewerChatterBoxSessionUpdate : public LLHTTPNode
01458 {
01459 public:
01460 virtual void post(
01461 ResponsePtr responder,
01462 const LLSD& context,
01463 const LLSD& input) const
01464 {
01465 LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID());
01466 if (floaterp)
01467 {
01468 floaterp->processSessionUpdate(input["body"]["info"]);
01469 }
01470 }
01471 };
01472
01473
01474 class LLViewerChatterBoxInvitation : public LLHTTPNode
01475 {
01476 public:
01477
01478 virtual void post(
01479 ResponsePtr response,
01480 const LLSD& context,
01481 const LLSD& input) const
01482 {
01483
01484
01485 if ( input["body"].has("instantmessage") )
01486 {
01487 LLSD message_params =
01488 input["body"]["instantmessage"]["message_params"];
01489
01490
01491
01492
01493
01494 if (gNoRender)
01495 {
01496 return;
01497 }
01498 char buffer[DB_IM_MSG_BUF_SIZE * 2];
01499 LLChat chat;
01500
01501 std::string message = message_params["message"].asString();
01502 std::string name = message_params["from_name"].asString();
01503 LLUUID from_id = message_params["from_id"].asUUID();
01504 LLUUID session_id = message_params["id"].asUUID();
01505 std::vector<U8> bin_bucket = message_params["data"]["binary_bucket"].asBinary();
01506 U8 offline = (U8)message_params["offline"].asInteger();
01507
01508 time_t timestamp =
01509 (time_t) message_params["timestamp"].asInteger();
01510
01511 BOOL is_busy = gAgent.getBusy();
01512 BOOL is_muted = LLMuteList::getInstance()->isMuted(
01513 from_id,
01514 name.c_str(),
01515 LLMute::flagTextChat);
01516
01517 BOOL is_linden = LLMuteList::getInstance()->isLinden(
01518 name.c_str());
01519 char separator_string[3]=": ";
01520 int message_offset=0;
01521
01522
01523 if (!strncmp(message.c_str(), "/me ", 4) ||
01524 !strncmp(message.c_str(), "/me'", 4))
01525 {
01526 strcpy(separator_string,"");
01527 message_offset = 3;
01528 }
01529
01530 chat.mMuted = is_muted && !is_linden;
01531 chat.mFromID = from_id;
01532 chat.mFromName = name;
01533
01534 if (!is_linden && (is_busy || is_muted))
01535 {
01536 return;
01537 }
01538
01539
01540 char saved[MAX_STRING];
01541 saved[0] = '\0';
01542 if(offline == IM_OFFLINE)
01543 {
01544 char time_buf[TIME_STR_LENGTH];
01545 snprintf(saved,
01546 MAX_STRING,
01547 "(Saved %s) ",
01548 formatted_time(timestamp, time_buf));
01549 }
01550 snprintf(
01551 buffer,
01552 sizeof(buffer),
01553 "%s%s%s",
01554 separator_string,
01555 saved,
01556 (message.c_str() + message_offset));
01557
01558 BOOL is_this_agent = FALSE;
01559 if(from_id == gAgentID)
01560 {
01561 is_this_agent = TRUE;
01562 }
01563 gIMMgr->addMessage(
01564 session_id,
01565 from_id,
01566 name.c_str(),
01567 buffer,
01568 (char*)&bin_bucket[0],
01569 IM_SESSION_INVITE,
01570 message_params["parent_estate_id"].asInteger(),
01571 message_params["region_id"].asUUID(),
01572 ll_vector3_from_sd(message_params["position"]),
01573 true);
01574
01575 snprintf(
01576 buffer,
01577 sizeof(buffer),
01578 "IM: %s%s%s%s",
01579 name.c_str(),
01580 separator_string,
01581 saved,
01582 (message.c_str()+message_offset));
01583 chat.mText = buffer;
01584 LLFloaterChat::addChat(chat, TRUE, is_this_agent);
01585
01586
01587 std::string url = gAgent.getRegion()->getCapability(
01588 "ChatSessionRequest");
01589
01590 if ( url != "" )
01591 {
01592 LLSD data;
01593 data["method"] = "accept invitation";
01594 data["session-id"] = session_id;
01595 LLHTTPClient::post(
01596 url,
01597 data,
01598 new LLViewerChatterBoxInvitationAcceptResponder(
01599 session_id,
01600 LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE));
01601 }
01602 }
01603 else if ( input["body"].has("voice") )
01604 {
01605 if (gNoRender)
01606 {
01607 return;
01608 }
01609
01610 if(!LLVoiceClient::voiceEnabled())
01611 {
01612
01613 return;
01614 }
01615
01616 gIMMgr->inviteToSession(
01617 input["body"]["session_id"].asUUID(),
01618 input["body"]["session_name"].asString(),
01619 input["body"]["from_id"].asUUID(),
01620 input["body"]["from_name"].asString(),
01621 IM_SESSION_INVITE,
01622 LLIMMgr::INVITATION_TYPE_VOICE);
01623 }
01624 else if ( input["body"].has("immediate") )
01625 {
01626 gIMMgr->inviteToSession(
01627 input["body"]["session_id"].asUUID(),
01628 input["body"]["session_name"].asString(),
01629 input["body"]["from_id"].asUUID(),
01630 input["body"]["from_name"].asString(),
01631 IM_SESSION_INVITE,
01632 LLIMMgr::INVITATION_TYPE_IMMEDIATE);
01633 }
01634 }
01635 };
01636
01637 LLHTTPRegistration<LLViewerChatterBoxSessionStartReply>
01638 gHTTPRegistrationMessageChatterboxsessionstartreply(
01639 "/message/ChatterBoxSessionStartReply");
01640
01641 LLHTTPRegistration<LLViewerChatterBoxSessionEventReply>
01642 gHTTPRegistrationMessageChatterboxsessioneventreply(
01643 "/message/ChatterBoxSessionEventReply");
01644
01645 LLHTTPRegistration<LLViewerForceCloseChatterBoxSession>
01646 gHTTPRegistrationMessageForceclosechatterboxsession(
01647 "/message/ForceCloseChatterBoxSession");
01648
01649 LLHTTPRegistration<LLViewerChatterBoxSessionAgentListUpdates>
01650 gHTTPRegistrationMessageChatterboxsessionagentlistupdates(
01651 "/message/ChatterBoxSessionAgentListUpdates");
01652
01653 LLHTTPRegistration<LLViewerChatterBoxSessionUpdate>
01654 gHTTPRegistrationMessageChatterBoxSessionUpdate(
01655 "/message/ChatterBoxSessionUpdate");
01656
01657 LLHTTPRegistration<LLViewerChatterBoxInvitation>
01658 gHTTPRegistrationMessageChatterBoxInvitation(
01659 "/message/ChatterBoxInvitation");
01660