llimview.cpp

Go to the documentation of this file.
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 "linked_lists.h"
00044 #include "llvieweruictrlfactory.h"
00045 
00046 #include "llagent.h"
00047 #include "llcallingcard.h"
00048 #include "llchat.h"
00049 #include "llviewerwindow.h"
00050 #include "llresmgr.h"
00051 #include "llfloaterchat.h"
00052 #include "llfloaterchatterbox.h"
00053 #include "llfloaternewim.h"
00054 #include "llhttpnode.h"
00055 #include "llimpanel.h"
00056 #include "llresizebar.h"
00057 #include "lltabcontainer.h"
00058 #include "viewer.h"
00059 #include "llfloater.h"
00060 #include "llmutelist.h"
00061 #include "llresizehandle.h"
00062 #include "llkeyboard.h"
00063 #include "llui.h"
00064 #include "llviewermenu.h"
00065 #include "llcallingcard.h"
00066 #include "lltoolbar.h"
00067 #include "llviewermessage.h"
00068 #include "llnotify.h"
00069 #include "llviewerregion.h"
00070 
00071 #include "llfirstuse.h"
00072 
00073 const EInstantMessage GROUP_DIALOG = IM_SESSION_GROUP_START;
00074 const EInstantMessage DEFAULT_DIALOG = IM_NOTHING_SPECIAL;
00075 
00076 //
00077 // Globals
00078 //
00079 LLIMMgr* gIMMgr = NULL;
00080 
00081 //
00082 // Statics
00083 //
00084 //*FIXME: make these all either UIStrings or Strings
00085 static LLString sOnlyUserMessage;
00086 static LLUIString sOfflineMessage;
00087 
00088 static std::map<std::string,LLString> sEventStringsMap;
00089 static std::map<std::string,LLString> sErrorStringsMap;
00090 static std::map<std::string,LLString> sForceCloseSessionMap;
00091 static LLUIString sInviteMessage;
00092 //
00093 // Helper Functions
00094 //
00095 
00096 // returns true if a should appear before b
00097 //static BOOL group_dictionary_sort( LLGroupData* a, LLGroupData* b )
00098 //{
00099 //      return (LLString::compareDict( a->mName, b->mName ) < 0);
00100 //}
00101 
00102 
00103 // the other_participant_id is either an agent_id, a group_id, or an inventory
00104 // folder item_id (collection of calling cards)
00105 
00106 // static
00107 LLUUID LLIMMgr::computeSessionID(
00108         EInstantMessage dialog,
00109         const LLUUID& other_participant_id)
00110 {
00111         LLUUID session_id;
00112         if (IM_SESSION_GROUP_START == dialog)
00113         {
00114                 // slam group session_id to the group_id (other_participant_id)
00115                 session_id = other_participant_id;
00116         }
00117         else if (IM_SESSION_CONFERENCE_START == dialog)
00118         {
00119                 session_id.generate();
00120         }
00121         else if (IM_SESSION_INVITE == dialog)
00122         {
00123                 // use provided session id for invites
00124                 session_id = other_participant_id;
00125         }
00126         else
00127         {
00128                 LLUUID agent_id = gAgent.getID();
00129                 if (other_participant_id == agent_id)
00130                 {
00131                         // if we try to send an IM to ourselves then the XOR would be null
00132                         // so we just make the session_id the same as the agent_id
00133                         session_id = agent_id;
00134                 }
00135                 else
00136                 {
00137                         // peer-to-peer or peer-to-asset session_id is the XOR
00138                         session_id = other_participant_id ^ agent_id;
00139                 }
00140         }
00141         return session_id;
00142 }
00143 
00144 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00145 // LLFloaterIM
00146 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00147 
00148 LLFloaterIM::LLFloaterIM() 
00149 {
00150         // autoresize=false is necessary to avoid resizing of the IM window whenever 
00151         // a session is opened or closed (it would otherwise resize the window to match
00152         // the size of the im-sesssion when they were created.  This happens in 
00153         // LLMultiFloater::resizeToContents() when called through LLMultiFloater::addFloater())
00154         this->mAutoResize = FALSE;
00155         gUICtrlFactory->buildFloater(this, "floater_im.xml");
00156 }
00157 
00158 BOOL LLFloaterIM::postBuild()
00159 {
00160         sOnlyUserMessage = getFormattedUIString("only_user_message");
00161         sOfflineMessage = getUIString("offline_message");
00162 
00163         sErrorStringsMap["generic"] =
00164                 getFormattedUIString("generic_request_error");
00165         sErrorStringsMap["unverified"] =
00166                 getFormattedUIString("insufficient_perms_error");
00167         sErrorStringsMap["no_user_911"] =
00168                 getFormattedUIString("user_no_help");
00169 
00170         sEventStringsMap["add"] =
00171                 getFormattedUIString("add_session_event");
00172         sEventStringsMap["message"] =
00173                 getFormattedUIString("message_session_event");
00174 
00175         sForceCloseSessionMap["removed"] =
00176                 getFormattedUIString("removed_from_group");
00177 
00178         sInviteMessage = getUIString("invite_message");
00179         return TRUE;
00180 }
00181 
00182 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00183 // Class LLIMViewFriendObserver
00184 //
00185 // Bridge to suport knowing when the inventory has changed.
00186 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00187 
00188 class LLIMViewFriendObserver : public LLFriendObserver
00189 {
00190 public:
00191         LLIMViewFriendObserver(LLIMMgr* tv) : mTV(tv) {}
00192         virtual ~LLIMViewFriendObserver() {}
00193         virtual void changed(U32 mask)
00194         {
00195                 if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
00196                 {
00197                         mTV->refresh();
00198                 }
00199         }
00200 protected:
00201         LLIMMgr* mTV;
00202 };
00203 
00204 
00205 class LLIMMgr::LLIMSessionInvite
00206 {
00207 public:
00208         LLIMSessionInvite(const LLUUID& session_id, const LLString& session_name, const LLUUID& caller_id,const LLString& caller_name, EInstantMessage type, const LLString& session_handle, const LLString& notify_box) : 
00209                                                 mSessionID(session_id),
00210                                                 mSessionName(session_name),
00211                                                 mCallerID(caller_id),
00212                                                 mCallerName(caller_name),
00213                                                 mType(type),
00214                                                 mSessionHandle(session_handle),
00215                                                 mNotifyBox(notify_box)
00216                                                 {};
00217 
00218         LLUUID          mSessionID;
00219         LLString        mSessionName;
00220         LLUUID          mCallerID;
00221         LLString        mCallerName;
00222         EInstantMessage mType;
00223         LLString        mSessionHandle;
00224         LLString        mNotifyBox;
00225 };
00226 
00227 
00228 //
00229 // Public Static Member Functions
00230 //
00231 
00232 // This is a helper function to determine what kind of im session
00233 // should be used for the given agent.
00234 // static
00235 EInstantMessage LLIMMgr::defaultIMTypeForAgent(const LLUUID& agent_id)
00236 {
00237         EInstantMessage type = IM_NOTHING_SPECIAL;
00238         if(is_agent_friend(agent_id))
00239         {
00240                 if(LLAvatarTracker::instance().isBuddyOnline(agent_id))
00241                 {
00242                         type = IM_SESSION_CONFERENCE_START;
00243                 }
00244         }
00245         return type;
00246 }
00247 
00248 // static
00249 //void LLIMMgr::onPinButton(void*)
00250 //{
00251 //      BOOL state = gSavedSettings.getBOOL( "PinTalkViewOpen" );
00252 //      gSavedSettings.setBOOL( "PinTalkViewOpen", !state );
00253 //}
00254 
00255 // static 
00256 void LLIMMgr::toggle(void*)
00257 {
00258         static BOOL return_to_mouselook = FALSE;
00259 
00260         // Hide the button and show the floater or vice versa.
00261         llassert( gIMMgr );
00262         BOOL old_state = gIMMgr->getFloaterOpen();
00263         
00264         // If we're in mouselook and we triggered the Talk View, we want to talk.
00265         if( gAgent.cameraMouselook() && old_state )
00266         {
00267                 return_to_mouselook = TRUE;
00268                 gAgent.changeCameraToDefault();
00269                 return;
00270         }
00271 
00272         BOOL new_state = !old_state;
00273 
00274         if (new_state)
00275         {
00276                 // ...making visible
00277                 if ( gAgent.cameraMouselook() )
00278                 {
00279                         return_to_mouselook = TRUE;
00280                         gAgent.changeCameraToDefault();
00281                 }
00282         }
00283         else
00284         {
00285                 // ...hiding
00286                 if ( gAgent.cameraThirdPerson() && return_to_mouselook )
00287                 {
00288                         gAgent.changeCameraToMouselook();
00289                 }
00290                 return_to_mouselook = FALSE;
00291         }
00292 
00293         gIMMgr->setFloaterOpen( new_state );
00294 }
00295 
00296 //
00297 // Member Functions
00298 //
00299 
00300 LLIMMgr::LLIMMgr() :
00301         mFriendObserver(NULL),
00302         mIMReceived(FALSE)
00303 {
00304         mFriendObserver = new LLIMViewFriendObserver(this);
00305         LLAvatarTracker::instance().addObserver(mFriendObserver);
00306 
00307         //*HACK: use floater to initialize string constants from xml file
00308         // then delete it right away
00309         LLFloaterIM* dummy_floater = new LLFloaterIM();
00310         delete dummy_floater;
00311 
00312         mPendingVoiceInvitations = LLSD::emptyMap();
00313         mPendingAgentListUpdates = LLSD::emptyMap();
00314 }
00315 
00316 LLIMMgr::~LLIMMgr()
00317 {
00318         LLAvatarTracker::instance().removeObserver(mFriendObserver);
00319         delete mFriendObserver;
00320         // Children all cleaned up by default view destructor.
00321 }
00322 
00323 // Add a message to a session. 
00324 void LLIMMgr::addMessage(
00325         const LLUUID& session_id,
00326         const LLUUID& target_id,
00327         const char* from,
00328         const char* msg,
00329         const char* session_name,
00330         EInstantMessage dialog,
00331         U32 parent_estate_id,
00332         const LLUUID& region_id,
00333         const LLVector3& position)
00334 {
00335         LLUUID other_participant_id = target_id;
00336         bool is_from_system = target_id.isNull();
00337 
00338         // don't process muted IMs
00339         if (gMuteListp->isMuted(
00340                         other_participant_id,
00341                         LLMute::flagTextChat) && !gMuteListp->isLinden(from))
00342         {
00343                 return;
00344         }
00345 
00346         //not sure why...but if it is from ourselves we set the target_id
00347         //to be NULL
00348         if( other_participant_id == gAgent.getID() )
00349         {
00350                 other_participant_id = LLUUID::null;
00351         }
00352 
00353         LLFloaterIMPanel* floater;
00354         LLUUID new_session_id = session_id;
00355         if (new_session_id.isNull())
00356         {
00357                 //no session ID...compute new one
00358                 new_session_id = computeSessionID(dialog, other_participant_id);
00359         }
00360         floater = findFloaterBySession(new_session_id);
00361         if (!floater)
00362         {
00363                 floater = findFloaterBySession(other_participant_id);
00364                 if (floater)
00365                 {
00366                         llinfos << "found the IM session " << session_id 
00367                                 << " by participant " << other_participant_id << llendl;
00368                 }
00369         }
00370 
00371         // create IM window as necessary
00372         if(!floater)
00373         {
00374                 const char* name = from;
00375                 if(session_name && (strlen(session_name)>1))
00376                 {
00377                         name = session_name;
00378                 }
00379 
00380                 
00381                 floater = createFloater(
00382                         new_session_id,
00383                         other_participant_id,
00384                         name,
00385                         dialog,
00386                         FALSE);
00387 
00388                 // When we get a new IM, and if you are a god, display a bit
00389                 // of information about the source. This is to help liaisons
00390                 // when answering questions.
00391                 if(gAgent.isGodlike())
00392                 {
00393                         // *TODO:translate (low priority, god ability)
00394                         std::ostringstream bonus_info;
00395                         bonus_info << "*** parent estate: "
00396                                 << parent_estate_id
00397                                 << ((parent_estate_id == 1) ? ", mainland" : "")
00398                                 << ((parent_estate_id == 5) ? ", teen" : "");
00399 
00400                         // once we have web-services (or something) which returns
00401                         // information about a region id, we can print this out
00402                         // and even have it link to map-teleport or something.
00403                         //<< "*** region_id: " << region_id << std::endl
00404                         //<< "*** position: " << position << std::endl;
00405 
00406                         floater->addHistoryLine(bonus_info.str(), gSavedSettings.getColor4("SystemChatColor"));
00407                 }
00408 
00409                 make_ui_sound("UISndNewIncomingIMSession");
00410         }
00411 
00412         // now add message to floater
00413         if ( is_from_system ) // chat came from system
00414         {
00415                 floater->addHistoryLine(
00416                         other_participant_id,
00417                         msg,
00418                         gSavedSettings.getColor4("SystemChatColor"));
00419         }
00420         else
00421         {
00422                 floater->addHistoryLine(other_participant_id, msg);
00423         }
00424 
00425         LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(LLSD());
00426 
00427         if( !chat_floater->getVisible() && !floater->getVisible())
00428         {
00429                 //if the IM window is not open and the floater is not visible (i.e. not torn off)
00430                 LLFloater* previouslyActiveFloater = chat_floater->getActiveFloater();
00431 
00432                 // select the newly added floater (or the floater with the new line added to it).
00433                 // it should be there.
00434                 chat_floater->selectFloater(floater);
00435 
00436                 //there was a previously unseen IM, make that old tab flashing
00437                 //it is assumed that the most recently unseen IM tab is the one current selected/active
00438                 if ( previouslyActiveFloater && getIMReceived() )
00439                 {
00440                         chat_floater->setFloaterFlashing(previouslyActiveFloater, TRUE);
00441                 }
00442 
00443                 //notify of a new IM
00444                 notifyNewIM();
00445         }
00446 }
00447 
00448 void LLIMMgr::addSystemMessage(const LLUUID& session_id, const LLString& message_name, const LLString::format_map_t& args)
00449 {
00450         LLUIString message;
00451         
00452         // null session id means near me (chat history)
00453         if (session_id.isNull())
00454         {
00455                 LLFloaterChat* floaterp = LLFloaterChat::getInstance();
00456 
00457                 message = floaterp->getUIString(message_name);
00458                 message.setArgList(args);
00459 
00460                 LLChat chat(message);
00461                 chat.mSourceType = CHAT_SOURCE_SYSTEM;
00462                 LLFloaterChat::getInstance()->addChatHistory(chat);
00463         }
00464         else // going to IM session
00465         {
00466                 LLFloaterIMPanel* floaterp = findFloaterBySession(session_id);
00467                 if (floaterp)
00468                 {
00469                         message = floaterp->getUIString(message_name);
00470                         message.setArgList(args);
00471 
00472                         gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString().c_str());
00473                 }
00474         }
00475 }
00476 
00477 void LLIMMgr::notifyNewIM()
00478 {
00479         if(!gIMMgr->getFloaterOpen())
00480         {
00481                 mIMReceived = TRUE;
00482         }
00483 }
00484 
00485 void LLIMMgr::clearNewIMNotification()
00486 {
00487         mIMReceived = FALSE;
00488 }
00489 
00490 BOOL LLIMMgr::getIMReceived() const
00491 {
00492         return mIMReceived;
00493 }
00494 
00495 // This method returns TRUE if the local viewer has a session
00496 // currently open keyed to the uuid. 
00497 BOOL LLIMMgr::isIMSessionOpen(const LLUUID& uuid)
00498 {
00499         LLFloaterIMPanel* floater = findFloaterBySession(uuid);
00500         if(floater) return TRUE;
00501         return FALSE;
00502 }
00503 
00504 LLUUID LLIMMgr::addP2PSession(const std::string& name,
00505                                                         const LLUUID& other_participant_id,
00506                                                         const LLString& voice_session_handle)
00507 {
00508         LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id);
00509 
00510         LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00511         if(floater)
00512         {
00513                 LLVoiceChannelP2P* voice_channelp = (LLVoiceChannelP2P*)floater->getVoiceChannel();
00514                 voice_channelp->setSessionHandle(voice_session_handle);
00515         }
00516 
00517         return session_id;
00518 }
00519 
00520 // This adds a session to the talk view. The name is the local name of
00521 // the session, dialog specifies the type of session. If the session
00522 // exists, it is brought forward.  Specifying id = NULL results in an
00523 // im session to everyone. Returns the uuid of the session.
00524 LLUUID LLIMMgr::addSession(const std::string& name,
00525                                                         EInstantMessage dialog,
00526                                                         const LLUUID& other_participant_id)
00527 {
00528         LLUUID session_id = computeSessionID(dialog, other_participant_id);
00529 
00530         LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00531         if(!floater)
00532         {
00533                 LLDynamicArray<LLUUID> ids;
00534                 ids.put(other_participant_id);
00535 
00536                 floater = createFloater(session_id,
00537                                                                 other_participant_id,
00538                                                                 name,
00539                                                                 ids,
00540                                                                 dialog,
00541                                                                 TRUE);
00542 
00543                 noteOfflineUsers(floater, ids);
00544                 LLFloaterChatterBox::getInstance(LLSD())->showFloater(floater);
00545         }
00546         else
00547         {
00548                 floater->open();
00549         }
00550         //mTabContainer->selectTabPanel(panel);
00551         floater->setInputFocus(TRUE);
00552         return floater->getSessionID();
00553 }
00554 
00555 // Adds a session using the given session_id.  If the session already exists 
00556 // the dialog type is assumed correct. Returns the uuid of the session.
00557 LLUUID LLIMMgr::addSession(const std::string& name,
00558                                                         EInstantMessage dialog,
00559                                                         const LLUUID& other_participant_id,
00560                                                         const LLDynamicArray<LLUUID>& ids)
00561 {
00562         if (0 == ids.getLength())
00563         {
00564                 return LLUUID::null;
00565         }
00566 
00567         LLUUID session_id = computeSessionID(dialog,
00568                                                                                    other_participant_id);
00569 
00570         LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00571         if(!floater)
00572         {
00573                 // On creation, use the first element of ids as the
00574                 // "other_participant_id"
00575                 floater = createFloater(session_id,
00576                                                                 other_participant_id,
00577                                                                 name,
00578                                                                 ids,
00579                                                                 dialog,
00580                                                                 TRUE);
00581 
00582                 if ( !floater ) return LLUUID::null;
00583 
00584                 noteOfflineUsers(floater, ids);
00585         }
00586         LLFloaterChatterBox::getInstance(LLSD())->showFloater(floater);
00587         //mTabContainer->selectTabPanel(panel);
00588         floater->setInputFocus(TRUE);
00589         return floater->getSessionID();
00590 }
00591 
00592 // This removes the panel referenced by the uuid, and then restores
00593 // internal consistency. The internal pointer is not deleted.
00594 void LLIMMgr::removeSession(const LLUUID& session_id)
00595 {
00596         LLFloaterIMPanel* floater = findFloaterBySession(session_id);
00597         if(floater)
00598         {
00599                 mFloaters.erase(floater->getHandle());
00600                 LLFloaterChatterBox::getInstance(LLSD())->removeFloater(floater);
00601                 //mTabContainer->removeTabPanel(floater);
00602         }
00603 }
00604 
00605 void LLIMMgr::inviteToSession(
00606         const LLUUID& session_id, 
00607         const LLString& session_name, 
00608         const LLUUID& caller_id, 
00609         const LLString& caller_name,
00610         EInstantMessage type,
00611         const LLString& session_handle)
00612 {
00613         //ignore voice invites from voice-muted residents
00614         if (gMuteListp->isMuted(caller_id))
00615         {
00616                 return;
00617         }
00618 
00619         LLString notify_box_type;
00620 
00621         BOOL ad_hoc_invite = FALSE;
00622         if(type == IM_SESSION_P2P_INVITE)
00623         {
00624                 notify_box_type = "VoiceInviteP2P";
00625         }
00626         else if (gAgent.isInGroup(session_id))
00627         {
00628                 notify_box_type = "VoiceInviteGroup";
00629         }
00630         else    
00631         {
00632                 notify_box_type = "VoiceInviteAdHoc";
00633                 ad_hoc_invite = TRUE;
00634         }
00635 
00636         LLIMSessionInvite* invite = new LLIMSessionInvite(
00637                 session_id,
00638                 session_name,
00639                 caller_id,
00640                 caller_name,
00641                 type,
00642                 session_handle,
00643                 notify_box_type);
00644         
00645         LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id);
00646         if (channelp && channelp->callStarted())
00647         {
00648                 // you have already started a call to the other user, so just accept the invite
00649                 inviteUserResponse(0, invite);
00650                 return;
00651         }
00652 
00653         if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite)
00654         {
00655                 // is the inviter a friend?
00656                 if (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)
00657                 {
00658                         // if not, and we are ignoring voice invites from non-friends
00659                         // then silently decline
00660                         if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly"))
00661                         {
00662                                 // invite not from a friend, so decline
00663                                 inviteUserResponse(1, invite);
00664                                 return;
00665                         }
00666                 }
00667         }
00668 
00669         if ( !mPendingVoiceInvitations.has(session_id.asString()) )
00670         {
00671                 if (caller_name.empty())
00672                 {
00673                         gCacheName->getName(caller_id, onInviteNameLookup, invite);
00674                 }
00675                 else
00676                 {
00677                         LLString::format_map_t args;
00678                         args["[NAME]"] = caller_name;
00679                         args["[GROUP]"] = session_name;
00680 
00681                         LLNotifyBox::showXml(notify_box_type, 
00682                                                                  args, 
00683                                                                  inviteUserResponse, 
00684                                                                  (void*)invite);
00685 
00686                 }
00687                 mPendingVoiceInvitations[session_id.asString()] = LLSD();
00688         }
00689 }
00690 
00691 //static 
00692 void LLIMMgr::onInviteNameLookup(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* userdata)
00693 {
00694         LLIMSessionInvite* invite = (LLIMSessionInvite*)userdata;
00695 
00696         invite->mCallerName = llformat("%s %s", first, last);
00697         invite->mSessionName = invite->mCallerName;
00698 
00699         LLString::format_map_t args;
00700         args["[NAME]"] = invite->mCallerName;
00701 
00702         LLNotifyBox::showXml(invite->mNotifyBox,
00703                                                 args, 
00704                                                 inviteUserResponse, 
00705                                                 (void*)invite);
00706 }
00707 
00708 class LLViewerChatterBoxInvitationAcceptResponder :
00709         public LLHTTPClient::Responder
00710 {
00711 public:
00712         LLViewerChatterBoxInvitationAcceptResponder(
00713                 const LLUUID& session_id,
00714                 bool is_voice_invitation)
00715         {
00716                 mSessionID = session_id;
00717                 mIsVoiceInvitiation = is_voice_invitation;
00718         }
00719 
00720         void result(const LLSD& content)
00721         {
00722                 if ( gIMMgr)
00723                 {
00724                         LLFloaterIMPanel* floaterp =
00725                                 gIMMgr->findFloaterBySession(mSessionID);
00726 
00727                         if (floaterp)
00728                         {
00729                                 //we've accepted our invitation
00730                                 //and received a list of agents that were
00731                                 //currently in the session when the reply was sent
00732                                 //to us.  Now, it is possible that there were some agents
00733                                 //to slip in/out between when that message was sent to us
00734                                 //and now.
00735 
00736                                 //the agent list updates we've received have been
00737                                 //accurate from the time we were added to the session
00738                                 //but unfortunately, our base that we are receiving here
00739                                 //may not be the most up to date.  It was accurate at
00740                                 //some point in time though.
00741                                 floaterp->setSpeakersList(content["agents"]);
00742 
00743                                 //we now have our base of users in the session
00744                                 //that was accurate at some point, but maybe not now
00745                                 //so now we apply all of the udpates we've received
00746                                 //in case of race conditions
00747 
00748                                 //reapplying a user entrance will do nothing
00749                                 //reapplying a user leaving will not have the user
00750                                 //in our base.  So it's all good
00751                                 floaterp->updateSpeakersList(
00752                                         gIMMgr->getPendingAgentListUpdates(mSessionID));
00753 
00754                                 if ( mIsVoiceInvitiation )
00755                                 {
00756                                         floaterp->requestAutoConnect();
00757                                         LLFloaterIMPanel::onClickStartCall(floaterp);
00758                                         // always open IM window when connecting to voice
00759                                         LLFloaterChatterBox::showInstance(TRUE);
00760                                 }
00761                         }
00762 
00763                         gIMMgr->clearPendingAgentListUpdates(mSessionID);
00764                         if ( mIsVoiceInvitiation )
00765                         {
00766                                 gIMMgr->clearPendingVoiceInviation(mSessionID);
00767                         }
00768                 }
00769         }
00770 
00771         void error(U32 statusNum, const std::string& reason)
00772         {
00773                 //throw something back to the viewer here?
00774                 if ( gIMMgr && mIsVoiceInvitiation )
00775                 {
00776                         gIMMgr->clearPendingVoiceInviation(mSessionID);
00777                 }
00778         }
00779 
00780 private:
00781         LLUUID mSessionID;
00782         bool mIsVoiceInvitiation;
00783 };
00784 
00785 //static
00786 void LLIMMgr::inviteUserResponse(S32 option, void* user_data)
00787 {
00788         LLIMSessionInvite* invitep = (LLIMSessionInvite*)user_data;
00789 
00790         switch(option) 
00791         {
00792         case 0: // accept
00793                 {
00794                         if (invitep->mType == IM_SESSION_P2P_INVITE)
00795                         {
00796                                 // create a normal IM session
00797                                 invitep->mSessionID = gIMMgr->addP2PSession(
00798                                         invitep->mSessionName,
00799                                         invitep->mCallerID,
00800                                         invitep->mSessionHandle);
00801 
00802                                 LLFloaterIMPanel* im_floater =
00803                                         gIMMgr->findFloaterBySession(
00804                                                 invitep->mSessionID);
00805                                 if (im_floater)
00806                                 {
00807                                         im_floater->requestAutoConnect();
00808                                         LLFloaterIMPanel::onClickStartCall(im_floater);
00809                                         // always open IM window when connecting to voice
00810                                         LLFloaterChatterBox::showInstance(TRUE);
00811                                 }
00812                                 
00813                                 gIMMgr->clearPendingVoiceInviation(invitep->mSessionID);
00814                         }
00815                         else
00816                         {
00817                                 gIMMgr->addSession(
00818                                         invitep->mSessionName,
00819                                         invitep->mType,
00820                                         invitep->mSessionID);
00821 
00822                                 std::string url = gAgent.getRegion()->getCapability(
00823                                         "ChatSessionRequest");
00824 
00825                                 LLSD data;
00826                                 data["method"] = "accept invitation";
00827                                 data["session-id"] = invitep->mSessionID;
00828                                 LLHTTPClient::post(
00829                                         url,
00830                                         data,
00831                                         new LLViewerChatterBoxInvitationAcceptResponder(
00832                                                 invitep->mSessionID,
00833                                                 true));
00834                         }
00835                 }
00836                 break;
00837         case 2: // mute (also implies ignore, so this falls through to the "ignore" case below)
00838                 {
00839                         // mute the sender of this invite
00840                         if (!gMuteListp->isMuted(invitep->mCallerID))
00841                         {
00842                                 LLMute mute(invitep->mCallerID, invitep->mCallerName, LLMute::AGENT);
00843                                 gMuteListp->add(mute);
00844                         }
00845                 }
00846         /* FALLTHROUGH */
00847         
00848         case 1: // ignore
00849                 {
00850                         if (invitep->mType == IM_SESSION_P2P_INVITE)
00851                         {
00852                                 if(gVoiceClient)
00853                                 {
00854                                         gVoiceClient->declineInvite(invitep->mSessionHandle);
00855                                 }
00856                         }
00857                 }
00858                 break;
00859         }
00860 
00861         delete invitep;
00862 }
00863 
00864 void LLIMMgr::refresh()
00865 {
00866 }
00867 
00868 void LLIMMgr::setFloaterOpen(BOOL set_open)
00869 {
00870         if (set_open)
00871         {
00872                 LLFloaterChatterBox::showInstance(LLSD());
00873         }
00874         else
00875         {
00876                 LLFloaterChatterBox::hideInstance(LLSD());
00877         }
00878 }
00879 
00880 
00881 BOOL LLIMMgr::getFloaterOpen()
00882 {
00883         return LLFloaterChatterBox::instanceVisible(LLSD());
00884 }
00885  
00886 void LLIMMgr::disconnectAllSessions()
00887 {
00888         LLFloaterIMPanel* floater = NULL;
00889         std::set<LLViewHandle>::iterator handle_it;
00890         for(handle_it = mFloaters.begin();
00891                 handle_it != mFloaters.end();
00892                 )
00893         {
00894                 floater = (LLFloaterIMPanel*)LLFloater::getFloaterByHandle(*handle_it);
00895 
00896                 // MUST do this BEFORE calling floater->onClose() because that may remove the item from the set, causing the subsequent increment to crash.
00897                 ++handle_it;
00898 
00899                 if (floater)
00900                 {
00901                         floater->setEnabled(FALSE);
00902                         floater->close(TRUE);
00903                 }
00904         }
00905 }
00906 
00907 
00908 // This method returns the im panel corresponding to the uuid
00909 // provided. The uuid can either be a session id or an agent
00910 // id. Returns NULL if there is no matching panel.
00911 LLFloaterIMPanel* LLIMMgr::findFloaterBySession(const LLUUID& session_id)
00912 {
00913         LLFloaterIMPanel* rv = NULL;
00914         std::set<LLViewHandle>::iterator handle_it;
00915         for(handle_it = mFloaters.begin();
00916                 handle_it != mFloaters.end();
00917                 ++handle_it)
00918         {
00919                 rv = (LLFloaterIMPanel*)LLFloater::getFloaterByHandle(*handle_it);
00920                 if(rv && session_id == rv->getSessionID())
00921                 {
00922                         break;
00923                 }
00924                 rv = NULL;
00925         }
00926         return rv;
00927 }
00928 
00929 
00930 BOOL LLIMMgr::hasSession(const LLUUID& session_id)
00931 {
00932         return (findFloaterBySession(session_id) != NULL);
00933 }
00934 
00935 void LLIMMgr::clearPendingVoiceInviation(const LLUUID& session_id)
00936 {
00937         if ( mPendingVoiceInvitations.has(session_id.asString()) )
00938         {
00939                 mPendingVoiceInvitations.erase(session_id.asString());
00940         }
00941 }
00942 
00943 LLSD LLIMMgr::getPendingAgentListUpdates(const LLUUID& session_id)
00944 {
00945         if ( mPendingAgentListUpdates.has(session_id.asString()) )
00946         {
00947                 return mPendingAgentListUpdates[session_id.asString()];
00948         }
00949         else
00950         {
00951                 return LLSD();
00952         }
00953 }
00954 
00955 void LLIMMgr::addPendingAgentListUpdates(
00956         const LLUUID& session_id,
00957         const LLSD& updates)
00958 {
00959         LLSD::map_const_iterator iter;
00960 
00961         for ( iter = updates.beginMap();
00962                   iter != updates.endMap();
00963                   iter++)
00964         {
00965                 //we only want to include the last update for a given agent
00966                 mPendingAgentListUpdates[session_id.asString()][iter->first] =
00967                         iter->second;
00968         }
00969 }
00970 
00971 void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id)
00972 {
00973         if ( mPendingAgentListUpdates.has(session_id.asString()) )
00974         {
00975                 mPendingAgentListUpdates.erase(session_id.asString());
00976         }
00977 }
00978 
00979 // create a floater and update internal representation for
00980 // consistency. Returns the pointer, caller (the class instance since
00981 // it is a private method) is not responsible for deleting the
00982 // pointer.  Add the floater to this but do not select it.
00983 LLFloaterIMPanel* LLIMMgr::createFloater(
00984         const LLUUID& session_id,
00985         const LLUUID& other_participant_id,
00986         const std::string& session_label,
00987         EInstantMessage dialog,
00988         BOOL user_initiated)
00989 {
00990         if (session_id.isNull())
00991         {
00992                 llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl;
00993         }
00994 
00995         llinfos << "LLIMMgr::createFloater: from " << other_participant_id 
00996                         << " in session " << session_id << llendl;
00997         LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
00998                                                                                                          LLRect(),
00999                                                                                                          session_label,
01000                                                                                                          session_id,
01001                                                                                                          other_participant_id,
01002                                                                                                          dialog);
01003         LLTabContainerCommon::eInsertionPoint i_pt = user_initiated ? LLTabContainerCommon::RIGHT_OF_CURRENT : LLTabContainerCommon::END;
01004         LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt);
01005         mFloaters.insert(floater->getHandle());
01006         return floater;
01007 }
01008 
01009 LLFloaterIMPanel* LLIMMgr::createFloater(
01010         const LLUUID& session_id,
01011         const LLUUID& other_participant_id,
01012         const std::string& session_label,
01013         const LLDynamicArray<LLUUID>& ids,
01014         EInstantMessage dialog,
01015         BOOL user_initiated)
01016 {
01017         if (session_id.isNull())
01018         {
01019                 llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl;
01020         }
01021 
01022         llinfos << "LLIMMgr::createFloater: from " << other_participant_id 
01023                         << " in session " << session_id << llendl;
01024         LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
01025                                                                                                          LLRect(),
01026                                                                                                          session_label,
01027                                                                                                          session_id,
01028                                                                                                          other_participant_id,
01029                                                                                                          ids,
01030                                                                                                          dialog);
01031         LLTabContainerCommon::eInsertionPoint i_pt = user_initiated ? LLTabContainerCommon::RIGHT_OF_CURRENT : LLTabContainerCommon::END;
01032         LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt);
01033         mFloaters.insert(floater->getHandle());
01034         return floater;
01035 }
01036 
01037 void LLIMMgr::noteOfflineUsers(LLFloaterIMPanel* floater,
01038                                                                   const LLDynamicArray<LLUUID>& ids)
01039 {
01040         S32 count = ids.count();
01041         if(count == 0)
01042         {
01043                 floater->addHistoryLine(sOnlyUserMessage, gSavedSettings.getColor4("SystemChatColor"));
01044         }
01045         else
01046         {
01047                 const LLRelationship* info = NULL;
01048                 LLAvatarTracker& at = LLAvatarTracker::instance();
01049                 for(S32 i = 0; i < count; ++i)
01050                 {
01051                         info = at.getBuddyInfo(ids.get(i));
01052                         char first[DB_FIRST_NAME_BUF_SIZE];             /*Flawfinder: ignore*/
01053                         char last[DB_LAST_NAME_BUF_SIZE];               /*Flawfinder: ignore*/
01054                         if(info && !info->isOnline()
01055                            && gCacheName->getName(ids.get(i), first, last))
01056                         {
01057                                 LLUIString offline = sOfflineMessage;
01058                                 offline.setArg("[FIRST]", first);
01059                                 offline.setArg("[LAST]", last);
01060                                 floater->addHistoryLine(offline, gSavedSettings.getColor4("SystemChatColor"));
01061                         }
01062                 }
01063         }
01064 }
01065 
01066 void LLIMMgr::processIMTypingStart(const LLIMInfo* im_info)
01067 {
01068         processIMTypingCore(im_info, TRUE);
01069 }
01070 
01071 void LLIMMgr::processIMTypingStop(const LLIMInfo* im_info)
01072 {
01073         processIMTypingCore(im_info, FALSE);
01074 }
01075 
01076 void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing)
01077 {
01078         LLUUID session_id = computeSessionID(im_info->mIMType, im_info->mFromID);
01079         LLFloaterIMPanel* floater = findFloaterBySession(session_id);
01080         if (floater)
01081         {
01082                 floater->processIMTyping(im_info, typing);
01083         }
01084 }
01085 
01086 void LLIMMgr::updateFloaterSessionID(
01087         const LLUUID& old_session_id,
01088         const LLUUID& new_session_id)
01089 {
01090         LLFloaterIMPanel* floater = findFloaterBySession(old_session_id);
01091         if (floater)
01092         {
01093                 floater->sessionInitReplyReceived(new_session_id);
01094         }
01095 }
01096 
01097 LLFloaterChatterBox* LLIMMgr::getFloater()
01098 { 
01099         return LLFloaterChatterBox::getInstance(LLSD()); 
01100 }
01101 
01102 void onConfirmForceCloseError(S32 option, void* data)
01103 {
01104         //only 1 option really
01105         LLFloaterIMPanel* floater = ((LLFloaterIMPanel*) data);
01106 
01107         if ( floater ) floater->close(FALSE);
01108 }
01109 
01110 class LLViewerChatterBoxSessionStartReply : public LLHTTPNode
01111 {
01112 public:
01113         virtual void describe(Description& desc) const
01114         {
01115                 desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session");
01116                 desc.postAPI();
01117                 desc.input(
01118                         "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string");
01119                 desc.source(__FILE__, __LINE__);
01120         }
01121 
01122         virtual void post(ResponsePtr response,
01123                                           const LLSD& context,
01124                                           const LLSD& input) const
01125         {
01126                 LLSD body;
01127                 LLUUID temp_session_id;
01128                 LLUUID session_id;
01129                 bool success;
01130 
01131                 body = input["body"];
01132                 success = body["success"].asBoolean();
01133                 temp_session_id = body["temp_session_id"].asUUID();
01134 
01135                 if ( success )
01136                 {
01137                         session_id = body["session_id"].asUUID();
01138                         gIMMgr->updateFloaterSessionID(
01139                                 temp_session_id,
01140                                 session_id);
01141                         LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id);
01142                         if (floaterp)
01143                         {
01144                                 floaterp->setSpeakersList(body["agents"]);
01145 
01146                                 //aply updates we've possibly received previously
01147                                 floaterp->updateSpeakersList(
01148                                         gIMMgr->getPendingAgentListUpdates(session_id));
01149                         }
01150                         gIMMgr->clearPendingAgentListUpdates(session_id);
01151                 }
01152                 else
01153                 {
01154                         //throw an error dialog and close the temp session's
01155                         //floater
01156                         LLFloaterIMPanel* floater = 
01157                                 gIMMgr->findFloaterBySession(temp_session_id);
01158                         if (floater)
01159                         {
01160                                 LLString::format_map_t args;
01161                                 args["[REASON]"] =
01162                                         sErrorStringsMap[body["error"].asString()];
01163                                 args["[RECIPIENT]"] = floater->getTitle();
01164 
01165                                 gViewerWindow->alertXml("ChatterBoxSessionStartError",
01166                                                                                 args,
01167                                                                                 onConfirmForceCloseError,
01168                                                                                 floater);
01169 
01170                         }
01171                 }
01172         }
01173 };
01174 
01175 class LLViewerChatterBoxSessionEventReply : public LLHTTPNode
01176 {
01177 public:
01178         virtual void describe(Description& desc) const
01179         {
01180                 desc.shortInfo("Used for receiving a reply to a ChatterBox session event");
01181                 desc.postAPI();
01182                 desc.input(
01183                         "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID");
01184                 desc.source(__FILE__, __LINE__);
01185         }
01186 
01187         virtual void post(ResponsePtr response,
01188                                           const LLSD& context,
01189                                           const LLSD& input) const
01190         {
01191                 LLUUID session_id;
01192                 bool success;
01193 
01194                 LLSD body = input["body"];
01195                 success = body["success"].asBoolean();
01196                 session_id = body["session_id"].asUUID();
01197 
01198                 if ( !success )
01199                 {
01200                         //throw an error dialog
01201                         LLFloaterIMPanel* floater = 
01202                                 gIMMgr->findFloaterBySession(session_id);
01203                         if (floater)
01204                         {
01205                                 LLString::format_map_t args;
01206                                 args["[REASON]"] = 
01207                                         sErrorStringsMap[body["error"].asString()];
01208                                 args["[EVENT]"] =
01209                                         sEventStringsMap[body["event"].asString()];
01210                                 args["[RECIPIENT]"] = floater->getTitle();
01211 
01212                                 gViewerWindow->alertXml("ChatterBoxSessionEventError",
01213                                                                                 args);
01214                         }
01215                 }
01216         }
01217 };
01218 
01219 class LLViewerForceCloseChatterBoxSession: public LLHTTPNode
01220 {
01221 public:
01222         virtual void post(ResponsePtr response,
01223                                           const LLSD& context,
01224                                           const LLSD& input) const
01225         {
01226                 LLUUID session_id;
01227                 LLString reason;
01228 
01229                 session_id = input["body"]["session_id"].asUUID();
01230                 reason = input["body"]["reason"].asString();
01231 
01232                 LLFloaterIMPanel* floater =
01233                         gIMMgr ->findFloaterBySession(session_id);
01234 
01235                 if ( floater )
01236                 {
01237                         LLString::format_map_t args;
01238 
01239                         args["[NAME]"] = floater->getTitle();
01240                         args["[REASON]"] = sForceCloseSessionMap[reason];
01241 
01242                         gViewerWindow->alertXml("ForceCloseChatterBoxSession",
01243                                                                         args,
01244                                                                         onConfirmForceCloseError,
01245                                                                         floater);
01246                 }
01247         }
01248 };
01249 
01250 class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode
01251 {
01252 public:
01253         virtual void post(
01254                 ResponsePtr responder,
01255                 const LLSD& context,
01256                 const LLSD& input) const
01257         {
01258                 LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID());
01259                 if (floaterp)
01260                 {
01261                         floaterp->updateSpeakersList(input["body"]["updates"]);
01262                 }
01263                 else
01264                 {
01265                         //we don't have a floater yet..something went wrong
01266                         //we are probably receiving an update here before
01267                         //a start or an acceptance of an invitation.  Race condition.
01268                         gIMMgr->addPendingAgentListUpdates(
01269                                 input["body"]["session_id"].asUUID(),
01270                                 input["body"]["updates"]);
01271                 }
01272         }
01273 };
01274 
01275 class LLViewerChatterBoxInvitation : public LLHTTPNode
01276 {
01277 public:
01278 
01279         virtual void post(
01280                 ResponsePtr response,
01281                 const LLSD& context,
01282                 const LLSD& input) const
01283         {
01284                 if ( input["body"].has("instantmessage") )
01285                 {
01286                         LLString capability = input["body"]["capabilities"]["call"].asString();
01287 
01288                         LLSD message_params =
01289                                 input["body"]["instantmessage"]["message_params"];
01290 
01291                         //do something here to have the IM invite behave
01292                         //just like a normal IM
01293                         //this is just replicated code from process_improved_im
01294                         //and should really go in it's own function -jwolk
01295                         if (gNoRender)
01296                         {
01297                                 return;
01298                         }
01299                         char buffer[DB_IM_MSG_BUF_SIZE * 2];  /* Flawfinder: ignore */
01300                         LLChat chat;
01301 
01302                         std::string message = message_params["message"].asString();
01303                         std::string name = message_params["from_name"].asString();
01304                         LLUUID from_id = message_params["from_id"].asUUID();
01305                         LLUUID session_id = message_params["id"].asUUID();
01306                         std::vector<U8> bin_bucket = message_params["data"]["binary_bucket"].asBinary();
01307                         U8 offline = (U8)message_params["offline"].asInteger();
01308                         
01309                         time_t timestamp =
01310                                 (time_t) message_params["timestamp"].asInteger();
01311 
01312                         BOOL is_busy = gAgent.getBusy();
01313                         BOOL is_muted = gMuteListp->isMuted(
01314                                 from_id,
01315                                 name.c_str(),
01316                                 LLMute::flagTextChat);
01317 
01318                         BOOL is_linden = gMuteListp->isLinden(
01319                                 name.c_str());
01320                         char separator_string[3]=": ";          /* Flawfinder: ignore */
01321                         int message_offset=0;
01322 
01323                         //Handle IRC styled /me messages.
01324                         if (!strncmp(message.c_str(), "/me ", 4) ||
01325                                 !strncmp(message.c_str(), "/me'", 4))
01326                         {
01327                                 strcpy(separator_string,"");       /* Flawfinder: ignore */
01328                                 message_offset = 3;
01329                         }
01330                         
01331                         chat.mMuted = is_muted && !is_linden;
01332                         chat.mFromID = from_id;
01333                         chat.mFromName = name;
01334 
01335                         if (!is_linden && (is_busy || is_muted))
01336                         {
01337                                 return;
01338                         }
01339 
01340                         // standard message, not from system
01341                         char saved[MAX_STRING];         /* Flawfinder: ignore */
01342                         saved[0] = '\0';
01343                         if(offline == IM_OFFLINE)
01344                         {
01345                                 char time_buf[TIME_STR_LENGTH]; /* Flawfinder: ignore */
01346                                 snprintf(saved,         /* Flawfinder: ignore */
01347                                                  MAX_STRING, 
01348                                                  "(Saved %s) ", 
01349                                                  formatted_time(timestamp, time_buf));
01350                         }
01351                         snprintf(
01352                                 buffer,
01353                                 sizeof(buffer),
01354                                 "%s%s%s%s",
01355                                 name.c_str(),
01356                                 separator_string,
01357                                 saved,
01358                                 (message.c_str() + message_offset)); /*Flawfinder: ignore*/
01359 
01360                         BOOL is_this_agent = FALSE;
01361                         if(from_id == gAgentID)
01362                         {
01363                                 is_this_agent = TRUE;
01364                         }
01365                         gIMMgr->addMessage(
01366                                 session_id,
01367                                 from_id,
01368                                 name.c_str(),
01369                                 buffer,
01370                                 (char*)&bin_bucket[0],
01371                                 IM_SESSION_INVITE,
01372                                 message_params["parent_estate_id"].asInteger(),
01373                                 message_params["region_id"].asUUID(),
01374                                 ll_vector3_from_sd(message_params["position"]));
01375 
01376                         snprintf(
01377                                 buffer,
01378                                 sizeof(buffer),
01379                                 "%s%s%s%s",
01380                                 name.c_str(),
01381                                 separator_string,
01382                                 saved,
01383                                 (message.c_str()+message_offset)); /* Flawfinder: ignore */
01384                         chat.mText = buffer;
01385                         chat.mFromIM = true;
01386                         LLFloaterChat::addChat(chat, is_this_agent);
01387 
01388                         //K now we want to accept the invitation
01389                         std::string url = gAgent.getRegion()->getCapability(
01390                                 "ChatSessionRequest");
01391 
01392                         if ( url != "" )
01393                         {
01394                                 LLSD data;
01395                                 data["method"] = "accept invitation";
01396                                 data["session-id"] = input["body"]["session_id"];
01397                                 LLHTTPClient::post(
01398                                         url,
01399                                         data,
01400                                         new LLViewerChatterBoxInvitationAcceptResponder(
01401                                                 input["body"]["session_id"],
01402                                                 false));
01403                         }
01404                 } //end if invitation has instant message
01405                 else if ( input["body"].has("voice") )
01406                 {
01407                         if (gNoRender)
01408                         {
01409                                 return;
01410                         }
01411                         
01412                         if(!LLVoiceClient::voiceEnabled())
01413                         {
01414                                 // Don't display voice invites unless the user has voice enabled.
01415                                 return;
01416                         }
01417 
01418                         gIMMgr->inviteToSession(
01419                                 input["body"]["session_id"].asUUID(), 
01420                                 input["body"]["session_name"].asString(), 
01421                                 input["body"]["from_id"].asUUID(),
01422                                 input["body"]["from_name"].asString(),
01423                                 IM_SESSION_INVITE);
01424                 }
01425         }
01426 };
01427 
01428 LLHTTPRegistration<LLViewerChatterBoxSessionStartReply>
01429    gHTTPRegistrationMessageChatterboxsessionstartreply(
01430            "/message/ChatterBoxSessionStartReply");
01431 
01432 LLHTTPRegistration<LLViewerChatterBoxSessionEventReply>
01433    gHTTPRegistrationMessageChatterboxsessioneventreply(
01434            "/message/ChatterBoxSessionEventReply");
01435 
01436 LLHTTPRegistration<LLViewerForceCloseChatterBoxSession>
01437     gHTTPRegistrationMessageForceclosechatterboxsession(
01438                 "/message/ForceCloseChatterBoxSession");
01439 
01440 LLHTTPRegistration<LLViewerChatterBoxSessionAgentListUpdates>
01441     gHTTPRegistrationMessageChatterboxsessionagentlistupdates(
01442             "/message/ChatterBoxSessionAgentListUpdates");
01443 
01444 LLHTTPRegistration<LLViewerChatterBoxInvitation>
01445     gHTTPRegistrationMessageChatterBoxInvitation(
01446                 "/message/ChatterBoxInvitation");

Generated on Thu Jul 1 06:08:44 2010 for Second Life Viewer by  doxygen 1.4.7