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 "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 // Globals
00077 //
00078 LLIMMgr* gIMMgr = NULL;
00079 
00080 //
00081 // Statics
00082 //
00083 // *FIXME: make these all either UIStrings or Strings
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 // Helper Functions
00095 //
00096 
00097 // returns true if a should appear before b
00098 //static BOOL group_dictionary_sort( LLGroupData* a, LLGroupData* b )
00099 //{
00100 //      return (LLString::compareDict( a->mName, b->mName ) < 0);
00101 //}
00102 
00103 
00104 // the other_participant_id is either an agent_id, a group_id, or an inventory
00105 // folder item_id (collection of calling cards)
00106 
00107 // static
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                 // slam group session_id to the group_id (other_participant_id)
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                 // use provided session id for invites
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                         // if we try to send an IM to ourselves then the XOR would be null
00133                         // so we just make the session_id the same as the agent_id
00134                         session_id = agent_id;
00135                 }
00136                 else
00137                 {
00138                         // peer-to-peer or peer-to-asset session_id is the XOR
00139                         session_id = other_participant_id ^ agent_id;
00140                 }
00141         }
00142         return session_id;
00143 }
00144 
00145 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00146 // LLFloaterIM
00147 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00148 
00149 LLFloaterIM::LLFloaterIM() 
00150 {
00151         // autoresize=false is necessary to avoid resizing of the IM window whenever 
00152         // a session is opened or closed (it would otherwise resize the window to match
00153         // the size of the im-sesssion when they were created.  This happens in 
00154         // LLMultiFloater::resizeToContents() when called through LLMultiFloater::addFloater())
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 // Class LLIMViewFriendObserver
00246 //
00247 // Bridge to suport knowing when the inventory has changed.
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 // Public Static Member Functions
00302 //
00303 
00304 // This is a helper function to determine what kind of im session
00305 // should be used for the given agent.
00306 // static
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 // static
00321 //void LLIMMgr::onPinButton(void*)
00322 //{
00323 //      BOOL state = gSavedSettings.getBOOL( "PinTalkViewOpen" );
00324 //      gSavedSettings.setBOOL( "PinTalkViewOpen", !state );
00325 //}
00326 
00327 // static 
00328 void LLIMMgr::toggle(void*)
00329 {
00330         static BOOL return_to_mouselook = FALSE;
00331 
00332         // Hide the button and show the floater or vice versa.
00333         llassert( gIMMgr );
00334         BOOL old_state = gIMMgr->getFloaterOpen();
00335         
00336         // If we're in mouselook and we triggered the Talk View, we want to talk.
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                 // ...making visible
00349                 if ( gAgent.cameraMouselook() )
00350                 {
00351                         return_to_mouselook = TRUE;
00352                         gAgent.changeCameraToDefault();
00353                 }
00354         }
00355         else
00356         {
00357                 // ...hiding
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 // Member Functions
00370 //
00371 
00372 LLIMMgr::LLIMMgr() :
00373         mFriendObserver(NULL),
00374         mIMReceived(FALSE)
00375 {
00376         mFriendObserver = new LLIMViewFriendObserver(this);
00377         LLAvatarTracker::instance().addObserver(mFriendObserver);
00378 
00379         // *HACK: use floater to initialize string constants from xml file
00380         // then delete it right away
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         // Children all cleaned up by default view destructor.
00393 }
00394 
00395 // Add a message to a session. 
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) // If this is true, then we insert the name and link it to a profile
00407 {
00408         LLUUID other_participant_id = target_id;
00409 
00410         // don't process muted IMs
00411         if (LLMuteList::getInstance()->isMuted(
00412                         other_participant_id,
00413                         LLMute::flagTextChat) && !LLMuteList::getInstance()->isLinden(from))
00414         {
00415                 return;
00416         }
00417 
00418         //not sure why...but if it is from ourselves we set the target_id
00419         //to be NULL
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                 //no session ID...compute new one
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         // create IM window as necessary
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                 // When we get a new IM, and if you are a god, display a bit
00461                 // of information about the source. This is to help liaisons
00462                 // when answering questions.
00463                 if(gAgent.isGodlike())
00464                 {
00465                         // *TODO:translate (low priority, god ability)
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                         // once we have web-services (or something) which returns
00473                         // information about a region id, we can print this out
00474                         // and even have it link to map-teleport or something.
00475                         //<< "*** region_id: " << region_id << std::endl
00476                         //<< "*** position: " << position << std::endl;
00477 
00478                         floater->addHistoryLine(bonus_info.str(), gSavedSettings.getColor4("SystemChatColor"));
00479                 }
00480 
00481                 make_ui_sound("UISndNewIncomingIMSession");
00482         }
00483 
00484         // now add message to floater
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); // No name to prepend, so just add the message normally
00492         }
00493         else
00494         {
00495                 floater->addHistoryLine(msg, color, true, other_participant_id, from); // Insert linked name to front of message
00496         }
00497 
00498         LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(LLSD());
00499 
00500         if( !chat_floater->getVisible() && !floater->getVisible())
00501         {
00502                 //if the IM window is not open and the floater is not visible (i.e. not torn off)
00503                 LLFloater* previouslyActiveFloater = chat_floater->getActiveFloater();
00504 
00505                 // select the newly added floater (or the floater with the new line added to it).
00506                 // it should be there.
00507                 chat_floater->selectFloater(floater);
00508 
00509                 //there was a previously unseen IM, make that old tab flashing
00510                 //it is assumed that the most recently unseen IM tab is the one current selected/active
00511                 if ( previouslyActiveFloater && getIMReceived() )
00512                 {
00513                         chat_floater->setFloaterFlashing(previouslyActiveFloater, TRUE);
00514                 }
00515 
00516                 //notify of a new IM
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         // null session id means near me (chat history)
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 // going to IM session
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 // This method returns TRUE if the local viewer has a session
00569 // currently open keyed to the uuid. 
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 // This adds a session to the talk view. The name is the local name of
00594 // the session, dialog specifies the type of session. If the session
00595 // exists, it is brought forward.  Specifying id = NULL results in an
00596 // im session to everyone. Returns the uuid of the session.
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         //mTabContainer->selectTabPanel(panel);
00628         floater->setInputFocus(TRUE);
00629         return floater->getSessionID();
00630 }
00631 
00632 // Adds a session using the given session_id.  If the session already exists 
00633 // the dialog type is assumed correct. Returns the uuid of the session.
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                 // On creation, use the first element of ids as the
00653                 // "other_participant_id"
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         //mTabContainer->selectTabPanel(panel);
00673         floater->setInputFocus(TRUE);
00674         return floater->getSessionID();
00675 }
00676 
00677 // This removes the panel referenced by the uuid, and then restores
00678 // internal consistency. The internal pointer is not deleted.
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                 //mTabContainer->removeTabPanel(floater);
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         //ignore invites from muted residents
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                 //P2P is different...they only have voice invitations
00714                 notify_box_type = "VoiceInviteP2P";
00715         }
00716         else if ( gAgent.isInGroup(session_id) )
00717         {
00718                 //only really old school groups have voice invitations
00719                 notify_box_type = "VoiceInviteGroup";
00720         }
00721         else if ( inv_type == INVITATION_TYPE_VOICE )
00722         {
00723                 //else it's an ad-hoc
00724                 //and a voice ad-hoc
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                 // you have already started a call to the other user, so just accept the invite
00748                 inviteUserResponse(0, invite); // inviteUserResponse deletes
00749                 return;
00750         }
00751 
00752         if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite)
00753         {
00754                 // is the inviter a friend?
00755                 if (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)
00756                 {
00757                         // if not, and we are ignoring voice invites from non-friends
00758                         // then silently decline
00759                         if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly"))
00760                         {
00761                                 // invite not from a friend, so decline
00762                                 inviteUserResponse(1, invite); // inviteUserResponse deletes
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); // inviteUserResponse deletes
00784 
00785                 }
00786                 mPendingInvitations[session_id.asString()] = LLSD();
00787         }
00788         else
00789         {
00790                 delete invite;
00791         }
00792 }
00793 
00794 //static 
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                                 //we've accepted our invitation
00834                                 //and received a list of agents that were
00835                                 //currently in the session when the reply was sent
00836                                 //to us.  Now, it is possible that there were some agents
00837                                 //to slip in/out between when that message was sent to us
00838                                 //and now.
00839 
00840                                 //the agent list updates we've received have been
00841                                 //accurate from the time we were added to the session
00842                                 //but unfortunately, our base that we are receiving here
00843                                 //may not be the most up to date.  It was accurate at
00844                                 //some point in time though.
00845                                 floaterp->setSpeakers(content);
00846 
00847                                 //we now have our base of users in the session
00848                                 //that was accurate at some point, but maybe not now
00849                                 //so now we apply all of the udpates we've received
00850                                 //in case of race conditions
00851                                 floaterp->updateSpeakersList(
00852                                         gIMMgr->getPendingAgentListUpdates(mSessionID));
00853 
00854                                 if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE )
00855                                 {
00856                                         floaterp->requestAutoConnect();
00857                                         LLFloaterIMPanel::onClickStartCall(floaterp);
00858                                         // always open IM window when connecting to voice
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                 //throw something back to the viewer here?
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 //static
00903 void LLIMMgr::inviteUserResponse(S32 option, void* user_data)
00904 {
00905         LLIMSessionInvite* invitep = (LLIMSessionInvite*)user_data;
00906 
00907         switch(option) 
00908         {
00909         case 0: // accept
00910                 {
00911                         if (invitep->mType == IM_SESSION_P2P_INVITE)
00912                         {
00913                                 // create a normal IM session
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                                         // always open IM window when connecting to voice
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: // mute (also implies ignore, so this falls through to the "ignore" case below)
00956         {
00957                 // mute the sender of this invite
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         /* FALLTHROUGH */
00965         
00966         case 1: // decline
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                 // MUST do this BEFORE calling floater->onClose() because that may remove the item from the set, causing the subsequent increment to crash.
01031                 ++handle_it;
01032 
01033                 if (floater)
01034                 {
01035                         floater->setEnabled(FALSE);
01036                         floater->close(TRUE);
01037                 }
01038         }
01039 }
01040 
01041 
01042 // This method returns the im panel corresponding to the uuid
01043 // provided. The uuid can either be a session id or an agent
01044 // id. Returns NULL if there is no matching panel.
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                 //this is a new agent list update for this session
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                 //new school update
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                         //we only want to include the last update for a given agent
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                 //old school update where the SD contained just mappings
01135                 //of agent_id -> "LEAVE"/"ENTER"
01136 
01137                 //only want to keep last update for each agent
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 // create a floater and update internal representation for
01158 // consistency. Returns the pointer, caller (the class instance since
01159 // it is a private method) is not responsible for deleting the
01160 // pointer.  Add the floater to this but do not select it.
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];             /*Flawfinder: ignore*/
01252                         char last[DB_LAST_NAME_BUF_SIZE];               /*Flawfinder: ignore*/
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                                 //apply updates we've possibly received previously
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                                 //aply updates we've possibly received previously
01347                                 floaterp->updateSpeakersList(
01348                                         gIMMgr->getPendingAgentListUpdates(session_id));
01349                         }
01350                         gIMMgr->clearPendingAgentListUpdates(session_id);
01351                 }
01352                 else
01353                 {
01354                         //throw an error dialog and close the temp session's
01355                         //floater
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                         //throw an error dialog
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                         //we don't have a floater yet..something went wrong
01448                         //we are probably receiving an update here before
01449                         //a start or an acceptance of an invitation.  Race condition.
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                 //for backwards compatiblity reasons...we need to still
01484                 //check for 'text' or 'voice' invitations...bleh
01485                 if ( input["body"].has("instantmessage") )
01486                 {
01487                         LLSD message_params =
01488                                 input["body"]["instantmessage"]["message_params"];
01489 
01490                         //do something here to have the IM invite behave
01491                         //just like a normal IM
01492                         //this is just replicated code from process_improved_im
01493                         //and should really go in it's own function -jwolk
01494                         if (gNoRender)
01495                         {
01496                                 return;
01497                         }
01498                         char buffer[DB_IM_MSG_BUF_SIZE * 2];  /* Flawfinder: ignore */
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]=": ";          /* Flawfinder: ignore */
01520                         int message_offset=0;
01521 
01522                         //Handle IRC styled /me messages.
01523                         if (!strncmp(message.c_str(), "/me ", 4) ||
01524                                 !strncmp(message.c_str(), "/me'", 4))
01525                         {
01526                                 strcpy(separator_string,"");       /* Flawfinder: ignore */
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                         // standard message, not from system
01540                         char saved[MAX_STRING];         /* Flawfinder: ignore */
01541                         saved[0] = '\0';
01542                         if(offline == IM_OFFLINE)
01543                         {
01544                                 char time_buf[TIME_STR_LENGTH]; /* Flawfinder: ignore */
01545                                 snprintf(saved,         /* Flawfinder: ignore */
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)); /*Flawfinder: ignore*/
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)); /* Flawfinder: ignore */
01583                         chat.mText = buffer;
01584                         LLFloaterChat::addChat(chat, TRUE, is_this_agent);
01585 
01586                         //K now we want to accept the invitation
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                 } //end if invitation has instant message
01603                 else if ( input["body"].has("voice") )
01604                 {
01605                         if (gNoRender)
01606                         {
01607                                 return;
01608                         }
01609                         
01610                         if(!LLVoiceClient::voiceEnabled())
01611                         {
01612                                 // Don't display voice invites unless the user has voice enabled.
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 

Generated on Fri May 16 08:33:41 2008 for SecondLife by  doxygen 1.5.5